MythTV  0.26-pre
vimeo_api.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 # Copyright (C) 2009 Marc Poulhiès
00004 #
00005 # Python module for Vimeo
00006 # originaly part of 'plopifier'
00007 #
00008 # Plopifier is free software: you can redistribute it and/or modify
00009 # it under the terms of the GNU General Public License as published by
00010 # the Free Software Foundation, either version 3 of the License, or
00011 # (at your option) any later version.
00012 #
00013 # Plopifier is distributed in the hope that it will be useful,
00014 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 # GNU General Public License for more details.
00017 #
00018 # You should have received a copy of the GNU General Public License
00019 # along with Plopifier.  If not, see <http://www.gnu.org/licenses/>.
00020 # ------------------------------------------------------------------
00021 # Name: vimeo_api - Simple-to-use Python interface to the vimeo API (http://vimeo.com)
00022 # Python Script
00023 # Author:   Marc Poulhiès and modified by R.D. Vaughan
00024 # Purpose:  This python script is intended to perform a variety of utility functions to search and access text
00025 #           metadata and video/image URLs from vimeo. These routines are based on the v2 api. Specifications
00026 #           for this api are published at http://vimeo.com/api/docs/advanced-api
00027 #
00028 # License:Creative Commons GNU GPL v2
00029 # (http://creativecommons.org/licenses/GPL/2.0/)
00030 #-------------------------------------
00031 __title__ ="vimeo_api - Simple-to-use Python interface to the vimeo API (http://vimeo.com)"
00032 __author__="Marc Poulhiès and modified by R.D. Vaughan"
00033 __purpose__='''
00034  This python script is intended to perform a variety of utility functions to search and access text
00035 metadata and video/image URLs from vimeo. These routines are based on the v2 api. Specifications
00036 for this api are published at http://vimeo.com/api/docs/advanced-api
00037 '''
00038 
00039 __version__="v0.2.5"
00040 # 0.1.0 Initial development
00041 # 0.1.1 Added Tree view processing
00042 # 0.1.2 Documentation review
00043 # 0.2.0 Public release
00044 # 0.2.1 Fixed bug where some videos cannot be embedded (played fullscreen automatically)
00045 # 0.2.2 New python bindings conversion
00046 #       Better exception error reporting
00047 #       Better handling of invalid unicode data from source
00048 # 0.2.3 Completed the exception error reporting improvements
00049 #       Fixed an exception message error when vimeo returns poorly formed XML.
00050 #       For example search term "flute" returns bad XML while "Flute music" returns proper XML
00051 # 0.2.4 Fixed an exception message output code error
00052 # 0.2.5 Removed the need for python MythTV bindings and added "%SHAREDIR%" to icon directory path
00053 
00054 """
00055 Python module to interact with Vimeo through its API (version 2)
00056 """
00057 import os, struct, sys, re, time, datetime
00058 import urllib, urllib2
00059 import logging
00060 import pycurl
00061 import xml.etree.ElementTree as ET
00062 import inspect
00063 import oauth.oauth_api as oauth
00064 from MythTV import MythXML
00065 
00066 from vimeo_exceptions import (VimeoUrlError, VimeoHttpError, VimeoResponseError, VimeoVideoNotFound, VimeoRequestTokenError, VimeoAuthorizeTokenError, VimeoVideosSearchError, VimeoAllChannelError, __errmsgs__)
00067 
00068 from vimeo_data import getData
00069 
00070 
00071 REQUEST_TOKEN_URL = 'http://vimeo.com/oauth/request_token'
00072 ACCESS_TOKEN_URL = 'http://vimeo.com/oauth/access_token'
00073 AUTHORIZATION_URL = 'http://vimeo.com/oauth/authorize'
00074 
00075 API_REST_URL = 'http://vimeo.com/api/rest/v2/'
00076 API_V2_CALL_URL = 'http://vimeo.com/api/v2/'
00077 
00078 USER_AGENT = 'python-vimeo http://github.com/dkm/python-vimeo'
00079 
00080 PORT=80
00081 
00082 HMAC_SHA1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
00083 
00084 
00085 class VimeoException(Exception):
00086     def __init__(self, msg):
00087         Exception.__init__(self)
00088         self.msg = msg
00089 
00090     def __str__(self):
00091         return self.msg
00092 
00093 class CurlyRestException(Exception):
00094     def __init__(self, code, msg, full):
00095         Exception.__init__(self)
00096         self.code = code
00097         self.msg = msg
00098         self.full = full
00099 
00100     def __str__(self):
00101         return "Error code: %s, message: %s\nFull message: %s" % (self.code,
00102                                                                   self.msg,
00103                                                                   self.full)
00104 
00105 
00106 class CurlyRequest:
00107     """
00108     A CurlyRequest object is used to send HTTP requests.
00109     It's a simple wrapper around basic curl methods.
00110     In particular, it can upload files and display a progress bar.
00111     """
00112     def __init__(self, pbarsize=19):
00113         self.buf = None
00114         self.pbar_size = pbarsize
00115         self.pidx = 0
00116         self.debug = False
00117 
00118     def do_rest_call(self, url):
00119         """
00120         Send a simple GET request and interpret the answer as a REST reply.
00121         """
00122 
00123         res = self.do_request(url)
00124         try:
00125             t = ET.fromstring(res)
00126 
00127             if t.attrib['stat'] == 'fail':
00128                 err_code = t.find('err').attrib['code']
00129                 err_msg = t.find('err').attrib['msg']
00130                 raise Exception(err_code, err_msg, ET.tostring(t))
00131             return t
00132         except Exception,e:
00133             raise Exception(u'%s' % (e))
00134 
00135     def _body_callback(self, buf):
00136         self.buf += buf
00137 
00138     def do_request(self, url):
00139         """
00140         Send a simple GET request
00141         """
00142         if self.debug:
00143             print "Request URL:"
00144             print url
00145             print
00146 
00147         self.buf = ""
00148         curl = pycurl.Curl()
00149         curl.setopt(pycurl.USERAGENT, USER_AGENT)
00150         curl.setopt(curl.URL, url)
00151         curl.setopt(curl.WRITEFUNCTION, self._body_callback)
00152         curl.perform()
00153         curl.close()
00154         p = self.buf
00155         self.buf = ""
00156 
00157         if self.debug:
00158             print "Raw response:"
00159             print p
00160             print
00161 
00162         return p
00163 
00164     def _upload_progress(self, download_t, download_d, upload_t, upload_d):
00165         # this is only for upload progress bar
00166         if upload_t == 0:
00167             return 0
00168 
00169         self.pidx = (self.pidx + 1) % len(TURNING_BAR)
00170 
00171         done = int(self.pbar_size * upload_d / upload_t)
00172 
00173         if done != self.pbar_size:
00174             pstr = '#'*done  +'>' + ' '*(self.pbar_size - done - 1)
00175         else:
00176             pstr = '#'*done
00177 
00178         print "\r%s[%s]  " %(TURNING_BAR[self.pidx], pstr),
00179         return 0
00180 
00181     def do_post_call(self, url, args, use_progress=False):
00182         """
00183         Send a simple POST request
00184         """
00185         c = pycurl.Curl()
00186         c.setopt(c.POST, 1)
00187         c.setopt(c.URL, url)
00188         c.setopt(c.HTTPPOST, args)
00189         c.setopt(c.WRITEFUNCTION, self.body_callback)
00190         #c.setopt(c.VERBOSE, 1)
00191         self.buf = ""
00192 
00193         c.setopt(c.NOPROGRESS, 0)
00194 
00195         if use_progress:
00196             c.setopt(c.PROGRESSFUNCTION, self._upload_progress)
00197 
00198         c.perform()
00199         c.close()
00200         res = self.buf
00201         self.buf = ""
00202         return res
00203 
00204 class SimpleOAuthClient(oauth.OAuthClient):
00205     """
00206     Class used for handling authenticated call to the API.
00207     """
00208 
00209     def __init__(self, key, secret,
00210                  server="vimeo.com", port=PORT,
00211                  request_token_url=REQUEST_TOKEN_URL,
00212                  access_token_url=ACCESS_TOKEN_URL,
00213                  authorization_url=AUTHORIZATION_URL,
00214                  token=None,
00215                  token_secret=None):
00216         """
00217         You need to give both key (consumer key) and secret (consumer secret).
00218         If you already have an access token (token+secret), you can use it
00219         by giving it through token and token_secret parameters.
00220         If not, then you need to call both get_request_token(), get_authorize_token_url() and
00221         finally get_access_token().
00222         """
00223 
00224         self.curly = CurlyRequest()
00225         self.key = key
00226         self.secret = secret
00227         self.server = server
00228         self.port = PORT
00229         self.request_token_url = request_token_url
00230         self.access_token_url = access_token_url
00231         self.authorization_url = authorization_url
00232         self.consumer = oauth.OAuthConsumer(self.key, self.secret)
00233 
00234         if token != None and token_secret != None:
00235             self.token = oauth.OAuthToken(token, token_secret)
00236         else:
00237             self.token = None
00238 
00239     def get_request_token(self):
00240         """
00241         Requests a request token and return it on success.
00242         """
00243         oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
00244                                                                  http_url=self.request_token_url)
00245         oauth_request.sign_request(HMAC_SHA1, self.consumer, None)
00246         self.token = self._fetch_token(oauth_request)
00247 
00248 
00249     def get_authorize_token_url(self):
00250         """
00251         Returns a URL used to verify and authorize the application to access
00252         user's account. The pointed page should contain a simple 'password' that
00253         acts as the 'verifier' in oauth.
00254         """
00255 
00256         oauth_request = oauth.OAuthRequest.from_token_and_callback(token=self.token,
00257                                                                  http_url=self.authorization_url)
00258         return oauth_request.to_url()
00259 
00260 
00261     def get_access_token(self, verifier):
00262         """
00263         Should be called after having received the 'verifier' from the authorization page.
00264         See 'get_authorize_token_url()' method.
00265         """
00266 
00267         self.token.set_verifier(verifier)
00268         oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
00269                                                                  token=self.token,
00270                                                                  verifier=verifier,
00271                                                                  http_url=self.access_token_url)
00272         oauth_request.sign_request(HMAC_SHA1, self.consumer, self.token)
00273         self.token = self._fetch_token(oauth_request)
00274 
00275     def _fetch_token(self, oauth_request):
00276         """
00277         Sends a requests and interprets the result as a token string.
00278         """
00279         ans = self.curly.do_request(oauth_request.to_url())
00280         return oauth.OAuthToken.from_string(ans)
00281 
00282     def vimeo_oauth_checkAccessToken(self, auth_token):
00283         pass
00284 
00285 
00286     def _do_vimeo_authenticated_call(self, method, parameters={}):
00287         """
00288         Wrapper to send an authenticated call to vimeo. You first need to have
00289         an access token.
00290         """
00291 
00292         parameters['method'] = method
00293         oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
00294                                                                  token=self.token,
00295                                                                  http_method='GET',
00296                                                                  http_url=API_REST_URL,
00297                                                                  parameters=parameters)
00298         oauth_request.sign_request(HMAC_SHA1, self.consumer, self.token)
00299         return self.curly.do_rest_call(oauth_request.to_url())
00300 
00301     def _do_vimeo_unauthenticated_call(self, method, parameters={}):
00302         """
00303         Wrapper to send an unauthenticated call to vimeo. You don't need to have
00304         an access token.
00305         """
00306         parameters['method'] = method
00307         oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
00308                                                                  http_method='GET',
00309                                                                  http_url=API_REST_URL,
00310                                                                  parameters=parameters)
00311         oauth_request.sign_request(HMAC_SHA1, self.consumer, None)
00312         return self.curly.do_rest_call(oauth_request.to_url())
00313 
00314 ###
00315 ### Album section
00316 ###
00317     def  vimeo_albums_getAll(self, user_id, sort=None,
00318                              per_page=None,
00319                              page=None):
00320         """
00321         Get a list of a user's albums.
00322         This method does not require authentication.
00323         """
00324         params = {'user_id': user_id}
00325         if sort in ('newest', 'oldest', 'alphabetical'):
00326             params['sort'] = sort
00327         if per_page != None:
00328             params['per_page'] = per_page
00329         if page != None:
00330             params['page'] = page
00331         return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
00332                                                    parameters=params)
00333 
00334 ###
00335 ### Video section
00336 ###
00337     def  vimeo_videos_search(self, query, sort=None,
00338                              per_page=None,
00339                              page=None):
00340         """
00341         Search for matching Videos.
00342         This method does not require authentication.
00343         """
00344         params = {}
00345         if sort in ('newest', 'most_played', 'relevant', 'most_liked', 'oldest'):
00346             params['sort'] = sort
00347         else:
00348             params['sort'] = 'most_liked'
00349         if per_page != None:
00350             params['per_page'] = per_page
00351         if page != None:
00352             params['page'] = page
00353         params['full_response'] = '1'
00354         #params['query'] = query.replace(u' ', u'_')
00355         params['query'] = query
00356         return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
00357                                                    parameters=params)
00358 
00359 ###
00360 ### Channel section
00361 ###
00362     def vimeo_channels_getAll(self, sort=None,
00363                               per_page=None,
00364                               page=None):
00365         """
00366         Get a list of all public channels.
00367         This method does not require authentication.
00368         """
00369         params = {}
00370         if sort in ('newest', 'oldest', 'alphabetical',
00371                     'most_videos', 'most_subscribed', 'most_recently_updated'):
00372             params['sort'] = sort
00373         if per_page != None:
00374             params['per_page'] = per_page
00375         if page != None:
00376             params['page'] = page
00377 
00378         return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
00379                                                    parameters=params)
00380 
00381     def vimeo_channels_getVideos(self, channel_id=None, full_response=None,
00382                               per_page=None,
00383                               page=None):
00384         """
00385         Get a list of Videos for a specific channels.
00386         This method does not require authentication.
00387         """
00388         # full_response channel_id
00389         params = {}
00390         if channel_id != None:
00391             params['channel_id'] = channel_id
00392         if full_response != None:
00393             params['full_response'] = 1
00394         if per_page != None:
00395             params['per_page'] = per_page
00396         if page != None:
00397             params['page'] = page
00398 
00399         return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
00400                                                    parameters=params)
00401 
00402 
00403 ###
00404 ### Contacts section
00405 ###
00406 
00407 
00408 ###
00409 ### Groups section
00410 ###
00411 
00412 ###
00413 ### Groups Events section
00414 ###
00415 
00416 ###
00417 ### Groups forums section
00418 ###
00419 
00420 ###
00421 ### OAuth section
00422 ###
00423 
00424 ###
00425 ### People section
00426 ###
00427 
00428 ###
00429 ### Test section
00430 ###
00431     def vimeo_test_echo(self, params={}):
00432         """
00433         This will just repeat back any parameters that you send.
00434         No auth required
00435         """
00436         ## for simplicity, I'm using a signed call, but it's
00437         ## useless. Tokens & stuff will simply get echoed as the
00438         ## others parameters are.
00439         return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
00440                                                    parameters=params)
00441 
00442 
00443     def vimeo_test_login(self):
00444         """
00445         Is the user logged in?
00446         """
00447         return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
00448 
00449 
00450     def vimeo_test_null(self):
00451         """
00452         This is just a simple null/ping test.
00453 
00454         You can use this method to make sure that you are properly
00455         contacting to the Vimeo API.
00456         """
00457         return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
00458 
00459 
00460 ###
00461 ### Videos section
00462 ###
00463 
00464 ###
00465 ### Videos comments section
00466 ###
00467 
00468 ###
00469 ### Videos embed section
00470 ###
00471 
00472 
00473 ###
00474 ### Videos Upload section
00475 ###
00476 
00477     def vimeo_videos_upload_getQuota(self):
00478         """
00479         (from vimeo API documentation)
00480         Get the space and number of HD uploads left for a user.
00481 
00482         Numbers are provided in bytes. It's a good idea to check this
00483         method before you upload a video to let the user know if their
00484         video will be converted to HD. hd_quota will have a value of 0
00485         if the user reached the max number of uploads, 1
00486         otherwise. Resets is the number of the day of the week,
00487         starting with Sunday.
00488         """
00489         return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
00490 
00491 
00492 
00493 
00494 def _simple_request(url, format):
00495     if format != 'xml':
00496         raise VimeoException("Sorry, only 'xml' supported. '%s' was requested." %format)
00497 
00498     curly = CurlyRequest()
00499     url = url %(format)
00500     ans = curly.do_request(url)
00501 
00502     if format == 'xml':
00503         return ET.fromstring(ans)
00504 
00505 ##
00506 ## User related call from the "Simple API".
00507 ## See : http://vimeo.com/api/docs/simple-api
00508 ##
00509 
00510 def _user_request(user, info, format):
00511     url = API_V2_CALL_URL + '%s/%s.%%s' %(user,info)
00512     return _simple_request(url, format)
00513 
00514 def user_info(user, format="xml"):
00515     """
00516     User info for the specified user
00517     """
00518     return _user_request(user, inspect.stack()[0][3][5:], format)
00519 
00520 
00521 def user_videos(user, format="xml"):
00522     """
00523     Videos created by user
00524     """
00525     return _user_request(user, inspect.stack()[0][3][5:], format)
00526 
00527 def user_likes(user, format="xml"):
00528     """
00529     Videos the user likes
00530     """
00531     return _user_request(user, inspect.stack()[0][3][5:], format)
00532 
00533 def user_appears_in(user, format="xml"):
00534     """
00535     Videos that the user appears in
00536     """
00537     return _user_request(user, inspect.stack()[0][3][5:], format)
00538 
00539 def user_all_videos(user, format="xml"):
00540     """
00541     Videos that the user appears in and created
00542     """
00543     return _user_request(user, inspect.stack()[0][3][5:], format)
00544 
00545 def user_subscriptions(user, format="xml"):
00546     """
00547     Videos the user is subscribed to
00548     """
00549     return _user_request(user, inspect.stack()[0][3][5:], format)
00550 
00551 def user_albums(user, format="xml"):
00552     """
00553     Albums the user has created
00554     """
00555     return _user_request(user, inspect.stack()[0][3][5:], format)
00556 
00557 def user_channels(user, format="xml"):
00558     """
00559     Channels the user has created and subscribed to
00560     """
00561     return _user_request(user, inspect.stack()[0][3][5:], format)
00562 
00563 def user_groups(user, format="xml"):
00564     """
00565     Groups the user has created and joined
00566     """
00567     return _user_request(user, inspect.stack()[0][3][5:], format)
00568 
00569 def user_contacts_videos(user, format="xml"):
00570     """
00571     Videos that the user's contacts created
00572     """
00573     return _user_request(user, inspect.stack()[0][3][5:], format)
00574 
00575 def user_contacts_like(user, format="xml"):
00576     """
00577     Videos that the user's contacts like
00578     """
00579     return _user_request(user, inspect.stack()[0][3][5:], format)
00580 
00581 
00582 ##
00583 ## get a specific video
00584 ##
00585 def video_request(video, format):
00586     url = API_V2_CALL_URL + 'video/%s.%%s' %(video)
00587     return _simple_request(url)
00588 
00589 #################################################################################################
00590 # MythTV Netvideo specific classes start here
00591 #################################################################################################
00592 
00593 class OutStreamEncoder(object):
00594     """Wraps a stream with an encoder"""
00595     def __init__(self, outstream, encoding=None):
00596         self.out = outstream
00597         if not encoding:
00598             self.encoding = sys.getfilesystemencoding()
00599         else:
00600             self.encoding = encoding
00601 
00602     def write(self, obj):
00603         """Wraps the output stream, encoding Unicode strings with the specified encoding"""
00604         if isinstance(obj, unicode):
00605             try:
00606                 self.out.write(obj.encode(self.encoding))
00607             except IOError:
00608                 pass
00609         else:
00610             try:
00611                 self.out.write(obj)
00612             except IOError:
00613                 pass
00614 
00615     def __getattr__(self, attr):
00616         """Delegate everything but write to the stream"""
00617         return getattr(self.out, attr)
00618 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
00619 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
00620 
00621 
00622 class Videos(object):
00623     """Main interface to http://vimeo.com/
00624     This is done to support a common naming framework for all python Netvision plugins no matter their site
00625     target.
00626 
00627     Supports search and tree view methods
00628     The apikey is a not passed but is created as a session token to access http://vimeo.com/
00629     """
00630     def __init__(self,
00631                 apikey,
00632                 mythtv = True,
00633                 interactive = False,
00634                 select_first = False,
00635                 debug = False,
00636                 custom_ui = None,
00637                 language = None,
00638                 search_all_languages = False,
00639                 ):
00640         """apikey (str/unicode):
00641             Specify the target site API key. Applications need their own key in some cases
00642 
00643         mythtv (True/False):
00644             When True, the returned meta data is being returned has the key and values massaged to match MythTV
00645             When False, the returned meta data  is being returned matches what target site returned
00646 
00647         interactive (True/False): (This option is not supported by all target site apis)
00648             When True, uses built-in console UI is used to select the correct show.
00649             When False, the first search result is used.
00650 
00651         select_first (True/False): (This option is not supported currently implemented in any grabbers)
00652             Automatically selects the first series search result (rather
00653             than showing the user a list of more than one series).
00654             Is overridden by interactive = False, or specifying a custom_ui
00655 
00656         debug (True/False):
00657              shows verbose debugging information
00658 
00659         custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers)
00660             A callable subclass of interactive class (overrides interactive option)
00661 
00662         language (2 character language abbreviation): (This option is not supported by all target site apis)
00663             The language of the returned data. Is also the language search
00664             uses. Default is "en" (English). For full list, run..
00665 
00666         search_all_languages (True/False): (This option is not supported by all target site apis)
00667             By default, a Netvision grabber will only search in the language specified using
00668             the language option. When this is True, it will search for the
00669             show in any language
00670 
00671         """
00672         self.config = {}
00673         self.mythxml = MythXML()
00674 
00675         self.config['debug_enabled'] = debug # show debugging messages
00676 
00677         self.log_name = "vimeo"
00678         self.log = self._initLogger() # Setups the logger (self.log.debug() etc)
00679 
00680         self.config['custom_ui'] = custom_ui
00681 
00682         self.config['interactive'] = interactive # prompt for correct series?
00683 
00684         self.config['select_first'] = select_first
00685 
00686         self.config['search_all_languages'] = search_all_languages
00687 
00688         # Defaulting to ENGISH but the vimeo.com apis do not support specifying a language
00689         self.config['language'] = "en"
00690 
00691         self.error_messages = {'VimeoUrlError': u"! Error: The URL (%s) cause the exception error (%s)\n", 'VimeoHttpError': u"! Error: An HTTP communications error with vimeo.com was raised (%s)\n", 'VimeoResponseError': u"! Error: Invalid XML metadata\nwas received from vimeo.com error (%s). Skipping item.\n", 'VimeoVideoNotFound': u"! Error: Video search with vimeo.com did not return any results for (%s)\n", 'VimeoRequestTokenError': u"! Error: Vimeo get request token failed (%s)\n", 'VimeoAuthorizeTokenError': u"! Error: Video get authorise token failed (%s)\n", 'VimeoVideosSearchError': u"! Error: Video search failed (%s)\n", 'VimeoException': u"! Error: VimeoException (%s)\n", 'VimeoAllChannelError': u"! Error: Access Video Channel information failed (%s)\n", }
00692 
00693         # This is an example that must be customized for each target site
00694         self.key_translation = [{'channel_title': 'channel_title', 'channel_link': 'channel_link', 'channel_description': 'channel_description', 'channel_numresults': 'channel_numresults', 'channel_returned': 'channel_returned', 'channel_startindex': 'channel_startindex'}, {'title': 'item_title', 'display_name': 'item_author', 'upload_date': 'item_pubdate', 'description': 'item_description', 'url': 'item_link', 'thumbnail': 'item_thumbnail', 'url': 'item_url', 'duration': 'item_duration', 'number_of_likes': 'item_rating', 'width': 'item_width', 'height': 'item_height', 'language': 'item_lang'}]
00695 
00696         # The following url_ configs are based of the
00697         # http://vimeo.com/api/docs/advanced-api
00698         self.config[u'methods'] = {}
00699         # Methods are actually set in initializeVimeo()
00700         self.config[u'methods']['channels'] = None
00701         self.config[u'methods']['channels_videos'] = None
00702 
00703         # Functions that parse video data from RSS data
00704         self.config['item_parser'] = {}
00705         self.config['item_parser']['channels'] = self.getVideosForChannels
00706 
00707         # Tree view url and the function that parses that urls meta data
00708         self.config[u'methods'][u'tree.view'] = {
00709             'N_R_S': {
00710                 '__all__': ['channels_videos', 'channels'],
00711                 },
00712             'Everything HD': {
00713                 '__all__': ['channels_videos', 'channels'],
00714                 },
00715             }
00716 
00717         self.config[u'image_extentions'] = ["png", "jpg", "bmp"] # Acceptable image extentions
00718 
00719         self.tree_key_list = ['newest', 'most_recently_updated', 'most_subscribed']
00720 
00721         self.tree_order = ['N_R_S', 'Everything HD', ]
00722 
00723         self.tree_org = {
00724             'N_R_S': [
00725                 ['Newest Channels/Most ...', u''],
00726                 ['', self.tree_key_list],
00727                 [u'',u'']
00728                 ],
00729             'Everything HD': [
00730                 ['Everything HD: Newest Channels/Most ...', self.tree_key_list ]
00731                 ],
00732             }
00733 
00734         self.tree_customize = {
00735             'N_R_S': {
00736                 '__default__': { },
00737                 #'cat name': {},
00738             },
00739             'Everything HD': {
00740                 '__default__': { },
00741                 #'cat name': {},
00742             },
00743             }
00744 
00745         self.feed_names = {
00746             'N_R_S': {'newest': 'Most Recent Channels', 'most_recently_updated': "This Month's Channels'", 'most_subscribed': 'Most Subscribed Channels',
00747             },
00748             'Everything HD': {'newest': 'Most Recent Channels', 'most_recently_updated': "This Month's Channels'", 'most_subscribed': 'Most Subscribed Channels',
00749             },
00750 
00751             }
00752 
00753         self.feed_icons = {
00754             'N_R_S': {'newest': 'directories/topics/most_recent', 'most_recently_updated': 'directories/topics/month', 'most_subscribed': 'directories/topics/most_subscribed',
00755             },
00756             'Everything HD': {'newest': 'directories/topics/most_recent', 'most_recently_updated': 'directories/topics/month', 'most_subscribed': 'directories/topics/most_subscribed',  'Everything HD': 'directories/topics/hd'
00757             },
00758 
00759             }
00760 
00761         # Initialize the tree view flag so that the item parsing code can be used for multiple purposes
00762         self.treeview = False
00763         self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/vimeo.jpg'
00764     # end __init__()
00765 
00766 ###########################################################################################################
00767 #
00768 # Start - Utility functions
00769 #
00770 ###########################################################################################################
00771 
00772     def massageDescription(self, text):
00773         '''Removes HTML markup from a text string.
00774         @param text The HTML source.
00775         @return The plain text.  If the HTML source contains non-ASCII
00776         entities or character references, this is a Unicode string.
00777         '''
00778         def fixup(m):
00779             text = m.group(0)
00780             if text[:1] == "<":
00781                 return "" # ignore tags
00782             if text[:2] == "&#":
00783                 try:
00784                     if text[:3] == "&#x":
00785                         return unichr(int(text[3:-1], 16))
00786                     else:
00787                         return unichr(int(text[2:-1]))
00788                 except ValueError:
00789                     pass
00790             elif text[:1] == "&":
00791                 import htmlentitydefs
00792                 entity = htmlentitydefs.entitydefs.get(text[1:-1])
00793                 if entity:
00794                     if entity[:2] == "&#":
00795                         try:
00796                             return unichr(int(entity[2:-1]))
00797                         except ValueError:
00798                             pass
00799                     else:
00800                         return unicode(entity, "iso-8859-1")
00801             return text # leave as is
00802         return self.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.textUtf8(text))).replace(u'\n',u' ')
00803     # end massageDescription()
00804 
00805 
00806     def _initLogger(self):
00807         """Setups a logger using the logging module, returns a log object
00808         """
00809         logger = logging.getLogger(self.log_name)
00810         formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
00811 
00812         hdlr = logging.StreamHandler(sys.stdout)
00813 
00814         hdlr.setFormatter(formatter)
00815         logger.addHandler(hdlr)
00816 
00817         if self.config['debug_enabled']:
00818             logger.setLevel(logging.DEBUG)
00819         else:
00820             logger.setLevel(logging.WARNING)
00821         return logger
00822     #end initLogger
00823 
00824 
00825     def textUtf8(self, text):
00826         if text == None:
00827             return text
00828         try:
00829             return unicode(text, 'utf8')
00830         except UnicodeDecodeError:
00831             return u''
00832         except (UnicodeEncodeError, TypeError):
00833             return text
00834     # end textUtf8()
00835 
00836 
00837     def ampReplace(self, text):
00838         '''Replace all "&" characters with "&amp;"
00839         '''
00840         text = self.textUtf8(text)
00841         return text.replace(u'&amp;',u'~~~~~').replace(u'&',u'&amp;').replace(u'~~~~~', u'&amp;')
00842     # end ampReplace()
00843 
00844 
00845     def setTreeViewIcon(self, dir_icon=None):
00846         '''Check if there is a specific generic tree view icon. If not default to the channel icon.
00847         return self.tree_dir_icon
00848         '''
00849         self.tree_dir_icon = self.channel_icon
00850         if not dir_icon:
00851             if not self.feed_icons.has_key(self.tree_key):
00852                 return self.tree_dir_icon
00853             if not self.feed_icons[self.tree_key].has_key(self.feed):
00854                 return self.tree_dir_icon
00855             dir_icon = self.feed_icons[self.tree_key][self.feed]
00856             if not dir_icon:
00857                 return self.tree_dir_icon
00858         self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, )
00859         return self.tree_dir_icon
00860     # end setTreeViewIcon()
00861 
00862 ###########################################################################################################
00863 #
00864 # End of Utility functions
00865 #
00866 ###########################################################################################################
00867 
00868     def initializeVimeo(self):
00869         '''Initialize acccess methods for all Vimeo API calls
00870         raise errors if there are issues during the initalization steps
00871         return nothing
00872         '''
00873         #
00874         self.client = SimpleOAuthClient(getData().update(getData().a), getData().update(getData().s))
00875         if self.config['debug_enabled']:
00876             self.client.curly.debug = True
00877         try:
00878             self.client.get_request_token()
00879         except Exception, msg:
00880             raise VimeoRequestTokenError(u'%s', msg)
00881         try:
00882             self.client.get_authorize_token_url()
00883         except Exception, msg:
00884             raise VimeoAuthorizeTokenError(u'%s', msg)
00885 
00886         self.config[u'methods']['channels'] = self.client.vimeo_channels_getAll
00887         self.config[u'methods']['channels_videos'] = self.client.vimeo_channels_getVideos
00888 
00889     # end initializeVimeo()
00890 
00891     def processVideoUrl(self, url):
00892         playerUrl = self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/vimeo.html", \
00893                                                        url.replace(u'http://vimeo.com/', ''))
00894         return self.ampReplace(playerUrl)
00895 
00896     def searchTitle(self, title, pagenumber, pagelen):
00897         '''Key word video search of the vimeo.com web site
00898         return an array of matching item dictionaries
00899         return
00900         '''
00901         self.initializeVimeo()
00902 
00903         # Used for debugging usually commented out
00904 #        xml_data = self.client.vimeo_videos_search(title, sort='most_liked',
00905 #                         per_page=pagelen,
00906 #                         page=pagenumber)
00907 #        print xml_data
00908 
00909         try:
00910             xml_data = self.client.vimeo_videos_search(urllib.quote_plus(title.encode("utf-8")),
00911                              sort='most_liked',
00912                              per_page=pagelen,
00913                              page=pagenumber)
00914         except Exception, msg:
00915             raise VimeoVideosSearchError(u'%s' % msg)
00916 
00917         if xml_data == None:
00918             raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
00919 
00920         if not len(xml_data.keys()):
00921             raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
00922 
00923         if xml_data.tag == 'rsp':
00924             if not xml_data.get('stat') == 'ok':
00925                 if __errmsgs__.has_key(xml_data.get('stat')):
00926                     errmsg = __errmsg__[xml_data.get('stat')]
00927                     raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
00928                 else:
00929                     errmsg = u'Unknown error'
00930                     raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
00931 
00932         elements_final = []
00933         videos = xml_data.find(u"videos")
00934         if videos:
00935             if videos.get('total'):
00936                 if not int(videos.get('total')):
00937                     raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
00938                 self.channel['channel_numresults'] = int(videos.get('total'))
00939 
00940         # Collect video meta data that matched the search value
00941         for video in xml_data.find(u"videos").getchildren():
00942             hd_flag = False
00943             embed_flag = False
00944             if video.tag == 'video':
00945                 if video.get('embed_privacy') == "anywhere":
00946                     embed_flag = True
00947                 if video.get('is_hd') == "1":
00948                     hd_flag = True
00949             v_details = {}
00950             for details in video.getchildren():
00951                 if details.tag in ['tags', 'cast']:
00952                     continue
00953                 if details.tag == 'width':
00954                     if details.text:
00955                         v_details['width'] = details.text.strip()
00956                     continue
00957                 if details.tag == 'height':
00958                     if details.text:
00959                         v_details['height'] = details.text.strip()
00960                     continue
00961                 if details.tag == 'duration':
00962                     if details.text:
00963                         v_details['duration'] = details.text.strip()
00964                     continue
00965                 if details.tag == 'owner':
00966                     if details.text:
00967                         v_details['display_name'] = self.massageDescription(details.get('display_name').strip())
00968                     else:
00969                         v_details['display_name'] = u''
00970                     continue
00971                 if details.tag == 'description':
00972                     if details.text:
00973                         v_details[details.tag] = self.massageDescription(details.text.strip())
00974                     else:
00975                         v_details[details.tag] = u''
00976                     continue
00977                 if details.tag == 'upload_date':
00978                     if details.text:
00979                         pub_time = time.strptime(details.text.strip(), "%Y-%m-%d %H:%M:%S")
00980                         v_details[details.tag] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', pub_time)
00981                     else:
00982                         v_details[details.tag] = u''
00983                     continue
00984                 if details.tag == 'urls':
00985                     for url in details.getchildren():
00986                         if url.get('type') == 'video':
00987                             if url.text: # Make the link fullscreen and auto play
00988                                 if embed_flag:
00989                                     v_details[url.tag] = self.processVideoUrl(url.text.strip())
00990                                 else:
00991                                     v_details[url.tag] = self.ampReplace(url.text.strip())
00992                             else:
00993                                 v_details[url.tag] = u''
00994                     continue
00995                 if details.tag == 'thumbnails':
00996                     largest = 0
00997                     for image in details.getchildren():
00998                         if image.tag == 'thumbnail':
00999                             height = int(image.get('height'))
01000                             width = int(image.get('width'))
01001                             default = image.text.find('default')
01002                             if largest < height * width and not default != -1:
01003                                 if image.text:
01004                                     v_details[image.tag] = self.ampReplace(image.text.strip())
01005                                     if width >= 200:
01006                                         break
01007                     continue
01008                 if details.text:
01009                     v_details[details.tag] = self.massageDescription(details.text.strip())
01010                 else:
01011                     v_details[details.tag] = u''
01012             if hd_flag and not v_details.has_key('width'):
01013                 v_details['width'] = 1280
01014                 v_details['height'] = 720
01015             elements_final.append(v_details)
01016 
01017         if not len(elements_final):
01018             raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
01019 
01020         return elements_final
01021         # end searchTitle()
01022 
01023 
01024     def searchForVideos(self, title, pagenumber):
01025         """Common name for a video search. Used to interface with MythTV plugin NetVision
01026         """
01027         # Channel details and search results
01028         self.channel = {'channel_title': u'Vimeo', 'channel_link': u'http://vimeo.com', 'channel_description': u"Vimeo is a respectful community of creative people who are passionate about sharing the videos they make.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
01029 
01030         # Easier for debugging usually commented out
01031 #        data = self.searchTitle(title, pagenumber, self.page_limit)
01032 #        print data
01033 #        sys.exit()
01034 
01035         try:
01036             data = self.searchTitle(title, pagenumber, self.page_limit)
01037         except VimeoVideoNotFound, msg:
01038             sys.stderr.write(u'%s' % msg)
01039             return None
01040         except VimeoUrlError, msg:
01041             sys.stderr.write(self.error_messages['VimeoUrlError'] % msg)
01042             sys.exit(1)
01043         except VimeoHttpError, msg:
01044             sys.stderr.write(self.error_messages['VimeoHttpError'] % msg)
01045             sys.exit(1)
01046         except VimeoResponseError, msg:
01047             sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
01048             sys.exit(1)
01049         except VimeoAuthorizeTokenError, msg:
01050             sys.stderr.write(self.error_messages['VimeoAuthorizeTokenError'] % msg)
01051             sys.exit(1)
01052         except VimeoVideosSearchError, msg:
01053             sys.stderr.write(self.error_messages['VimeoVideosSearchError'] % msg)
01054             sys.exit(1)
01055         except VimeoRequestTokenError, msg:
01056             sys.stderr.write(self.error_messages['VimeoRequestTokenError'] % msg)
01057             sys.exit(1)
01058         except VimeoException, msg:
01059             sys.stderr.write(self.error_messages['VimeoException'] % msg)
01060             sys.exit(1)
01061         except Exception, e:
01062             sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e))
01063             sys.exit(1)
01064 
01065         if data == None:
01066             return None
01067         if not len(data):
01068             return None
01069 
01070         items = []
01071         for match in data:
01072             item_data = {}
01073             for key in self.key_translation[1].keys():
01074                 if key == 'url':
01075                     item_data['item_link'] = match[key]
01076                     item_data['item_url'] = match[key]
01077                     continue
01078                 if key in match.keys():
01079                     item_data[self.key_translation[1][key]] = match[key]
01080                 else:
01081                     item_data[self.key_translation[1][key]] = u''
01082             items.append(item_data)
01083 
01084         self.channel['channel_startindex'] = self.page_limit * int(pagenumber)
01085         self.channel['channel_returned'] = len(items)
01086 
01087         if len(items):
01088             return [[self.channel, items]]
01089         return None
01090     # end searchForVideos()
01091 
01092 
01093     def getChannels(self):
01094         '''Get the channel directory information and fill out the tree view directory structures as required
01095         raise exceptions if the there was an issue getting Channel information or no channel data
01096         return True if successful
01097         '''
01098         self.channel_dict = {'N_R_S': {}, 'Everything HD': {}, }
01099         self.channel_count = {}
01100         for key in self.tree_key_list:
01101             self.channel_dict['N_R_S'][key] = []
01102             self.channel_dict['Everything HD'][key] = []
01103         self.channel_list_max = 2
01104         self.channel_count['N_R_S'] = {'newest': [10, 2], 'most_recently_updated': [10, 1], 'most_subscribed': [10, 10]}
01105         self.channel_count['Everything HD'] = {'newest': [10, 2], 'most_recently_updated': [10, 1], 'most_subscribed': [5, 20]}
01106 
01107         for sort in self.tree_key_list:
01108             page = 0
01109             not_HD_count = 0
01110             HD_count = 0
01111             not_HD_list = []
01112             HD_list = []
01113             while True:
01114                 try:
01115                     page+=1
01116                     if page > 20: # Throttles excessive searching for HD groups within a category
01117                         break
01118                     try:
01119                         xml_data = self.config[u'methods']['channels'](sort=sort,
01120                                           per_page=None,
01121                                           page=page)
01122                     except Exception, msg:
01123                         raise VimeoAllChannelError(u'%s' % msg)
01124 
01125                     if xml_data == None:
01126                         raise VimeoAllChannelError(self.error_messages['1-VimeoAllChannelError'] % sort)
01127 
01128                     if not len(xml_data.keys()):
01129                         raise VimeoAllChannelError(self.error_messages['2-VimeoAllChannelError'] % sort)
01130 
01131                     if xml_data.tag == 'rsp':
01132                         if not xml_data.get('stat') == 'ok':
01133                             if __errmsgs__.has_key(xml_data.get('stat')):
01134                                 errmsg = __errmsg__[xml_data.get('stat')]
01135                                 raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
01136                             else:
01137                                 errmsg = u'Unknown error'
01138                                 raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
01139 
01140                     for channel in xml_data.find('channels'):
01141                         index = channel.find('name').text.find(u'HD')
01142                         if index != -1:
01143                             if HD_count < self.channel_count['Everything HD'][sort][0]:
01144                                 if not channel.get('id') in HD_list:
01145                                     self.channel_dict['Everything HD'][sort].append([channel.get('id'), channel.find('name').text])
01146                                     HD_list.append(channel.get('id'))
01147                                     HD_count+=1
01148                         else:
01149                             if not_HD_count < self.channel_count['N_R_S'][sort][0]:
01150                                 if not channel.get('id') in not_HD_list:
01151                                     self.channel_dict['N_R_S'][sort].append([channel.get('id'), channel.find('name').text])
01152                                     not_HD_list.append(channel.get('id'))
01153                                     not_HD_count+=1
01154                         if not_HD_count >= self.channel_count['N_R_S'][sort][0] and HD_count >= self.channel_count['Everything HD']:
01155                             break
01156                     if not_HD_count >= self.channel_count['N_R_S'][sort][0] and HD_count >= self.channel_count['Everything HD']:
01157                         break
01158                 except:
01159                     break
01160 
01161         return True
01162     #end getChannels()
01163 
01164 
01165     def displayTreeView(self):
01166         '''Gather the Vimeo Groups/Channels...etc then get a max page of videos meta data in each of them
01167         return array of directories and their video metadata
01168         '''
01169         try:
01170             self.initializeVimeo()
01171         except VimeoAuthorizeTokenError, msg:
01172             sys.stderr.write(self.error_messages['VimeoAuthorizeTokenError'] % msg)
01173             sys.exit(1)
01174         except VimeoRequestTokenError, msg:
01175             sys.stderr.write(self.error_messages['VimeoRequestTokenError'] % msg)
01176             sys.exit(1)
01177         except VimeoException, msg:
01178             sys.stderr.write(self.error_messages['VimeoException'] % msg)
01179             sys.exit(1)
01180         except Exception, msg:
01181             sys.stderr.write(u"! Error: Unknown error during a Vimeo API initialization (%s)\n" % msg)
01182             sys.exit(1)
01183 
01184         # Channel details and search results
01185         self.channel = {'channel_title': u'Vimeo', 'channel_link': u'http://vimeo.com', 'channel_description': u"Vimeo is a respectful community of creative people who are passionate about sharing the videos they make.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
01186 
01187         if self.config['debug_enabled']:
01188             print self.config[u'methods']
01189             print
01190 
01191         # Initialize the Video channels data
01192         try:
01193             self.getChannels()
01194         except VimeoResponseError, msg:
01195             sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
01196             sys.exit(1)
01197         except VimeoAllChannelError, msg:
01198             sys.stderr.write(self.error_messages['VimeoAllChannelError'] % msg)
01199             sys.exit(1)
01200         except VimeoException, msg:
01201             sys.stderr.write(self.error_messages['VimeoException'] % msg)
01202             sys.exit(1)
01203         except Exception, msg:
01204             sys.stderr.write(u"! Error: Unknown error while getting all Channels (%s)\n" % msg)
01205             sys.exit(1)
01206 
01207         dictionaries = []
01208 
01209         self.treeview = True
01210 
01211         # Process the various video feeds/categories/... etc
01212         for key in self.tree_order:
01213             self.tree_key = key
01214             dictionaries = self.getVideos(self.tree_org[key], dictionaries)
01215 
01216         return [[self.channel, dictionaries]]
01217     # end displayTreeView()
01218 
01219 
01220     def getVideos(self, dir_dict, dictionaries):
01221         '''Parse a list made of category lists and retrieve video meta data
01222         return a dictionary of directory names and categories video metadata
01223         '''
01224         for sets in dir_dict:
01225             if not isinstance(sets[1], list):
01226                 if sets[0] != '': # Add the nested dictionaries display name
01227                     try:
01228                         dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
01229                     except KeyError:
01230                         dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
01231                 else:
01232                     dictionaries.append(['', u'']) # Add the nested dictionary indicator
01233                 continue
01234             temp_dictionary = []
01235             for self.feed in sets[1]:
01236                 if self.config[u'methods'][u'tree.view'][self.tree_key].has_key('__all__'):
01237                     URL = self.config[u'methods'][u'tree.view'][self.tree_key]['__all__']
01238                 else:
01239                     URL = self.config[u'methods'][u'tree.view'][self.tree_key][self.feed]
01240                 temp_dictionary = self.config['item_parser'][URL[1]](self.config[u'methods'][URL[0]], temp_dictionary)
01241             if len(temp_dictionary):
01242                 if len(sets[0]): # Add the nested dictionaries display name
01243                     try:
01244                         dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
01245                     except KeyError:
01246                         dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
01247                 for element in temp_dictionary:
01248                     dictionaries.append(element)
01249                 if len(sets[0]):
01250                     dictionaries.append(['', u'']) # Add the nested dictionary indicator
01251         return dictionaries
01252     # end getVideos()
01253 
01254 
01255     def getVideosForChannels(self, method, dictionary):
01256         '''Process all channel related directory videos
01257         return dictionary of new video items
01258         '''
01259         self.next_page = 1
01260         self.max_page = self.channel_count[self.tree_key][self.feed][1]
01261         self.tree_list = False
01262         # Sometimes it is beter to see a list of videos rather than split them up by their channel names
01263         if self.max_page <= self.channel_list_max:
01264             self.tree_list = True
01265         tmp_dictionary = []
01266         for channel in self.channel_dict[self.tree_key][self.feed]:
01267             self.channel_id = channel[0]
01268             self.dir_name = channel[1]
01269 
01270             # Easier for debugging
01271             #tmp_dictionary = self.getTreeVideos(method, tmp_dictionary)
01272 
01273             try:
01274                 tmp_dictionary = self.getTreeVideos(method, tmp_dictionary)
01275             except VimeoVideoNotFound, msg:
01276                 sys.stderr.write(self.error_messages['VimeoVideoNotFound'] % msg)
01277                 continue
01278             except VimeoVideosSearchError, msg:
01279                 sys.stderr.write(self.error_messages['VimeoVideosSearchError'] % msg)
01280                 sys.exit(1)
01281             except VimeoResponseError, msg:
01282                 sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
01283                 sys.exit(1)
01284             except VimeoException, msg:
01285                 sys.stderr.write(self.error_messages['VimeoException'] % msg)
01286                 sys.exit(1)
01287             except Exception, e:
01288                 sys.stderr.write(u"! Error: Unknown error during while getting all Channels (%s)\nError(%s)\n" % (self.dir_name, e))
01289                 sys.exit(1)
01290 
01291         if len(tmp_dictionary):
01292             dictionary.append([self.feed_names[self.tree_key][self.feed], self.setTreeViewIcon()])
01293             for element in tmp_dictionary:
01294                 dictionary.append(element)
01295             dictionary.append(['', u''])
01296         return dictionary
01297     # end getVideosForChannels()
01298 
01299 
01300 
01301     def getTreeVideos(self, method, dictionaries):
01302         '''Get the video metadata for url search
01303         return the video dictionary of directories and their video mata data
01304         '''
01305         initial_length = len(dictionaries)
01306         try:
01307             xml_data = method(channel_id=self.channel_id, full_response=1,
01308                              per_page=self.max_page,
01309                              page=self.next_page)
01310         except Exception, msg:
01311             raise VimeoVideosSearchError(u'%s' % msg)
01312 
01313         if xml_data == None:
01314             raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % self.dir_name)
01315 
01316         if not len(xml_data.keys()):
01317             raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % self.dir_name)
01318 
01319         if xml_data.tag == 'rsp':
01320             if not xml_data.get('stat') == 'ok':
01321                 if __errmsgs__.has_key(xml_data.get('stat')):
01322                     errmsg = __errmsg__[xml_data.get('stat')]
01323                     raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
01324                 else:
01325                     errmsg = u'Unknown error'
01326                     raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
01327 
01328         videos = xml_data.find(u"videos")
01329         if videos:
01330             if videos.get('total'):
01331                 self.channel['channel_numresults'] = int(videos.get('total'))
01332 
01333         # Collect video meta data that matched the search value
01334         dictionary_first = False
01335         for video in xml_data.find(u"videos").getchildren():
01336             hd_flag = False
01337             embed_flag = False
01338             if video.tag == 'video':
01339                 if video.get('embed_privacy') == "anywhere":
01340                     embed_flag = True
01341                 if video.get('is_hd') == "1":
01342                     hd_flag = True
01343             v_details = {}
01344             for details in video.getchildren():
01345                 if details.tag in ['tags', 'cast']:
01346                     continue
01347                 if details.tag == 'width':
01348                     if details.text:
01349                         v_details['width'] = details.text.strip()
01350                     continue
01351                 if details.tag == 'height':
01352                     if details.text:
01353                         v_details['height'] = details.text.strip()
01354                     continue
01355                 if details.tag == 'duration':
01356                     if details.text:
01357                         v_details['duration'] = details.text.strip()
01358                     continue
01359                 if details.tag == 'owner':
01360                     if details.text:
01361                         v_details['display_name'] = self.massageDescription(details.get('display_name').strip())
01362                     else:
01363                         v_details['display_name'] = u''
01364                     continue
01365                 if details.tag == 'description':
01366                     if details.text:
01367                         if self.tree_list:
01368                             v_details[details.tag] = self.massageDescription(u'Channel "%s": %s' % (self.dir_name, details.text.strip()))
01369                         else:
01370                             v_details[details.tag] = self.massageDescription(details.text.strip())
01371                     else:
01372                         if self.tree_list:
01373                             v_details[details.tag] = self.massageDescription(u'Channel "%s"' % self.dir_name)
01374                     continue
01375                 if details.tag == 'upload_date':
01376                     if details.text:
01377                         pub_time = time.strptime(details.text.strip(), "%Y-%m-%d %H:%M:%S")
01378                         v_details[details.tag] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', pub_time)
01379                     else:
01380                         v_details[details.tag] = u''
01381                     continue
01382                 if details.tag == 'urls':
01383                     for url in details.getchildren():
01384                         if url.get('type') == 'video':
01385                             if url.text: # Make the link fullscreen and auto play
01386                                 if embed_flag:
01387                                     v_details[url.tag] = self.processVideoUrl(url.text.strip())
01388                                 else:
01389                                     v_details[url.tag] = self.ampReplace(url.text.strip())
01390                             else:
01391                                 v_details[url.tag] = u''
01392                     continue
01393                 if details.tag == 'thumbnails':
01394                     largest = 0
01395                     for image in details.getchildren():
01396                         if image.tag == 'thumbnail':
01397                             height = int(image.get('height'))
01398                             width = int(image.get('width'))
01399                             default = image.text.find('default')
01400                             if largest < height * width and not default != -1:
01401                                 if image.text:
01402                                     v_details[image.tag] = self.ampReplace(image.text.strip())
01403                                     if width >= 200:
01404                                         break
01405                     continue
01406                 if details.text:
01407                     v_details[details.tag] = self.massageDescription(details.text.strip())
01408                 else:
01409                     v_details[details.tag] = u''
01410 
01411             if hd_flag and not v_details.has_key('width'):
01412                 v_details['width'] = 1280
01413                 v_details['height'] = 720
01414 
01415             if not v_details.has_key('url'):
01416                 continue
01417 
01418             if not dictionary_first and not self.tree_list:  # Add the dictionaries display name
01419                 dictionaries.append([self.dir_name, self.setTreeViewIcon()])
01420                 dictionary_first = True
01421 
01422             final_item = {}
01423             for key in self.key_translation[1].keys():
01424                 if key == 'url':
01425                     final_item['item_link'] = v_details[key]
01426                     final_item['item_url'] = v_details[key]
01427                     continue
01428                 if v_details.has_key(key):
01429                     final_item[self.key_translation[1][key]] = v_details[key]
01430                 else:
01431                     final_item[self.key_translation[1][key]] = u''
01432             dictionaries.append(final_item)
01433 
01434         # Need to check if there was any items for this directory
01435         if initial_length < len(dictionaries) and not self.tree_list:
01436             dictionaries.append(['', u'']) # Add the nested dictionary indicator
01437         return dictionaries
01438     # end getTreeVideos()
01439 # end Videos() class
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends