MythTV  master
vimeo_api.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2009 Marc Poulhiès
4 #
5 # Python module for Vimeo
6 # originaly part of 'plopifier'
7 #
8 # Plopifier is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Plopifier is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Plopifier. If not, see <http://www.gnu.org/licenses/>.
20 # ------------------------------------------------------------------
21 # Name: vimeo_api - Simple-to-use Python interface to the vimeo API (http://vimeo.com)
22 # Python Script
23 # Author: Marc Poulhiès and modified by R.D. Vaughan
24 # Purpose: This python script is intended to perform a variety of utility functions to search and access text
25 # metadata and video/image URLs from vimeo. These routines are based on the v2 api. Specifications
26 # for this api are published at http://vimeo.com/api/docs/advanced-api
27 #
28 # License:Creative Commons GNU GPL v2
29 # (http://creativecommons.org/licenses/GPL/2.0/)
30 #-------------------------------------
31 __title__ ="vimeo_api - Simple-to-use Python interface to the vimeo API (http://vimeo.com)"
32 __author__="Marc Poulhiès and modified by R.D. Vaughan"
33 __purpose__='''
34  This python script is intended to perform a variety of utility functions to search and access text
35 metadata and video/image URLs from vimeo. These routines are based on the v2 api. Specifications
36 for this api are published at http://vimeo.com/api/docs/advanced-api
37 '''
38 
39 __version__="v0.2.5"
40 # 0.1.0 Initial development
41 # 0.1.1 Added Tree view processing
42 # 0.1.2 Documentation review
43 # 0.2.0 Public release
44 # 0.2.1 Fixed bug where some videos cannot be embedded (played fullscreen automatically)
45 # 0.2.2 New python bindings conversion
46 # Better exception error reporting
47 # Better handling of invalid unicode data from source
48 # 0.2.3 Completed the exception error reporting improvements
49 # Fixed an exception message error when vimeo returns poorly formed XML.
50 # For example search term "flute" returns bad XML while "Flute music" returns proper XML
51 # 0.2.4 Fixed an exception message output code error
52 # 0.2.5 Removed the need for python MythTV bindings and added "%SHAREDIR%" to icon directory path
53 
54 """
55 Python module to interact with Vimeo through its API (version 2)
56 """
57 import os, struct, sys, re, time, datetime
58 import urllib, urllib2
59 import logging
60 import pycurl
61 import xml.etree.ElementTree as ET
62 import inspect
63 import oauth.oauth_api as oauth
64 from MythTV import MythXML
65 
66 from vimeo_exceptions import (VimeoUrlError, VimeoHttpError, VimeoResponseError, VimeoVideoNotFound, VimeoRequestTokenError, VimeoAuthorizeTokenError, VimeoVideosSearchError, VimeoAllChannelError, __errmsgs__)
67 
68 from vimeo_data import getData
69 
70 
71 REQUEST_TOKEN_URL = 'http://vimeo.com/oauth/request_token'
72 ACCESS_TOKEN_URL = 'http://vimeo.com/oauth/access_token'
73 AUTHORIZATION_URL = 'http://vimeo.com/oauth/authorize'
74 
75 API_REST_URL = 'http://vimeo.com/api/rest/v2/'
76 API_V2_CALL_URL = 'http://vimeo.com/api/v2/'
77 
78 USER_AGENT = 'python-vimeo http://github.com/dkm/python-vimeo'
79 
80 PORT=80
81 
82 HMAC_SHA1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
83 
84 
85 class VimeoException(Exception):
86  def __init__(self, msg):
87  Exception.__init__(self)
88  self.msg = msg
89 
90  def __str__(self):
91  return self.msg
92 
93 class CurlyRestException(Exception):
94  def __init__(self, code, msg, full):
95  Exception.__init__(self)
96  self.code = code
97  self.msg = msg
98  self.full = full
99 
100  def __str__(self):
101  return "Error code: %s, message: %s\nFull message: %s" % (self.code,
102  self.msg,
103  self.full)
104 
105 
107  """
108  A CurlyRequest object is used to send HTTP requests.
109  It's a simple wrapper around basic curl methods.
110  In particular, it can upload files and display a progress bar.
111  """
112  def __init__(self, pbarsize=19):
113  self.buf = None
114  self.pbar_size = pbarsize
115  self.pidx = 0
116  self.debug = False
117 
118  def do_rest_call(self, url):
119  """
120  Send a simple GET request and interpret the answer as a REST reply.
121  """
122 
123  res = self.do_request(url)
124  try:
125  t = ET.fromstring(res)
126 
127  if t.attrib['stat'] == 'fail':
128  err_code = t.find('err').attrib['code']
129  err_msg = t.find('err').attrib['msg']
130  raise Exception(err_code, err_msg, ET.tostring(t))
131  return t
132  except Exception,e:
133  raise Exception(u'%s' % (e))
134 
135  def _body_callback(self, buf):
136  self.buf += buf
137 
138  def do_request(self, url):
139  """
140  Send a simple GET request
141  """
142  if self.debug:
143  print "Request URL:"
144  print url
145  print
146 
147  self.buf = ""
148  curl = pycurl.Curl()
149  curl.setopt(pycurl.USERAGENT, USER_AGENT)
150  curl.setopt(curl.URL, url)
151  curl.setopt(curl.WRITEFUNCTION, self._body_callback)
152  curl.perform()
153  curl.close()
154  p = self.buf
155  self.buf = ""
156 
157  if self.debug:
158  print "Raw response:"
159  print p
160  print
161 
162  return p
163 
164  def _upload_progress(self, download_t, download_d, upload_t, upload_d):
165  # this is only for upload progress bar
166  if upload_t == 0:
167  return 0
168 
169  self.pidx = (self.pidx + 1) % len(TURNING_BAR)
170 
171  done = int(self.pbar_size * upload_d / upload_t)
172 
173  if done != self.pbar_size:
174  pstr = '#'*done +'>' + ' '*(self.pbar_size - done - 1)
175  else:
176  pstr = '#'*done
177 
178  print "\r%s[%s] " %(TURNING_BAR[self.pidx], pstr),
179  return 0
180 
181  def do_post_call(self, url, args, use_progress=False):
182  """
183  Send a simple POST request
184  """
185  c = pycurl.Curl()
186  c.setopt(c.POST, 1)
187  c.setopt(c.URL, url)
188  c.setopt(c.HTTPPOST, args)
189  c.setopt(c.WRITEFUNCTION, self.body_callback)
190  #c.setopt(c.VERBOSE, 1)
191  self.buf = ""
192 
193  c.setopt(c.NOPROGRESS, 0)
194 
195  if use_progress:
196  c.setopt(c.PROGRESSFUNCTION, self._upload_progress)
197 
198  c.perform()
199  c.close()
200  res = self.buf
201  self.buf = ""
202  return res
203 
204 class SimpleOAuthClient(oauth.OAuthClient):
205  """
206  Class used for handling authenticated call to the API.
207  """
208 
209  def __init__(self, key, secret,
210  server="vimeo.com", port=PORT,
211  request_token_url=REQUEST_TOKEN_URL,
212  access_token_url=ACCESS_TOKEN_URL,
213  authorization_url=AUTHORIZATION_URL,
214  token=None,
215  token_secret=None):
216  """
217  You need to give both key (consumer key) and secret (consumer secret).
218  If you already have an access token (token+secret), you can use it
219  by giving it through token and token_secret parameters.
220  If not, then you need to call both get_request_token(), get_authorize_token_url() and
221  finally get_access_token().
222  """
225  self.key = key
226  self.secret = secret
227  self.server = server
228  self.port = PORT
229  self.request_token_url = request_token_url
230  self.access_token_url = access_token_url
231  self.authorization_url = authorization_url
232  self.consumer = oauth.OAuthConsumer(self.key, self.secret)
233 
234  if token != None and token_secret != None:
235  self.token = oauth.OAuthToken(token, token_secret)
236  else:
237  self.token = None
238 
239  def get_request_token(self):
240  """
241  Requests a request token and return it on success.
242  """
243  oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
244  http_url=self.request_token_url,
245  callback="oob")
246  oauth_request.sign_request(HMAC_SHA1, self.consumer, None)
247  self.token = self._fetch_token(oauth_request)
248 
249 
251  """
252  Returns a URL used to verify and authorize the application to access
253  user's account. The pointed page should contain a simple 'password' that
254  acts as the 'verifier' in oauth.
255  """
256 
257  oauth_request = oauth.OAuthRequest.from_token_and_callback(token=self.token,
258  http_url=self.authorization_url)
259  return oauth_request.to_url()
260 
261 
262  def get_access_token(self, verifier):
263  """
264  Should be called after having received the 'verifier' from the authorization page.
265  See 'get_authorize_token_url()' method.
266  """
267 
268  self.token.set_verifier(verifier)
269  oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
270  token=self.token,
271  verifier=verifier,
272  http_url=self.access_token_url)
273  oauth_request.sign_request(HMAC_SHA1, self.consumer, self.token)
274  self.token = self._fetch_token(oauth_request)
275 
276  def _fetch_token(self, oauth_request):
277  """
278  Sends a requests and interprets the result as a token string.
279  """
280  ans = self.curly.do_request(oauth_request.to_url())
281  return oauth.OAuthToken.from_string(ans)
282 
283  def vimeo_oauth_checkAccessToken(self, auth_token):
284  pass
285 
286 
287  def _do_vimeo_authenticated_call(self, method, parameters={}):
288  """
289  Wrapper to send an authenticated call to vimeo. You first need to have
290  an access token.
291  """
292 
293  parameters['method'] = method
294  oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
295  token=self.token,
296  http_method='GET',
297  http_url=API_REST_URL,
298  parameters=parameters)
299  oauth_request.sign_request(HMAC_SHA1, self.consumer, self.token)
300  return self.curly.do_rest_call(oauth_request.to_url())
301 
302  def _do_vimeo_unauthenticated_call(self, method, parameters={}):
303  """
304  Wrapper to send an unauthenticated call to vimeo. You don't need to have
305  an access token.
306  """
307  parameters['method'] = method
308  oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
309  http_method='GET',
310  http_url=API_REST_URL,
311  parameters=parameters)
312  oauth_request.sign_request(HMAC_SHA1, self.consumer, None)
313  return self.curly.do_rest_call(oauth_request.to_url())
314 
315 
318  def vimeo_albums_getAll(self, user_id, sort=None,
319  per_page=None,
320  page=None):
321  """
322  Get a list of a user's albums.
323  This method does not require authentication.
324  """
325  params = {'user_id': user_id}
326  if sort in ('newest', 'oldest', 'alphabetical'):
327  params['sort'] = sort
328  if per_page != None:
329  params['per_page'] = per_page
330  if page != None:
331  params['page'] = page
332  return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
333  parameters=params)
334 
335 
338  def vimeo_videos_search(self, query, sort=None,
339  per_page=None,
340  page=None):
341  """
342  Search for matching Videos.
343  This method does not require authentication.
344  """
345  params = {}
346  if sort in ('newest', 'most_played', 'relevant', 'most_liked', 'oldest'):
347  params['sort'] = sort
348  else:
349  params['sort'] = 'most_liked'
350  if per_page != None:
351  params['per_page'] = per_page
352  if page != None:
353  params['page'] = page
354  params['full_response'] = '1'
355  #params['query'] = query.replace(u' ', u'_')
356  params['query'] = query
357  return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
358  parameters=params)
359 
360 
363  def vimeo_channels_getAll(self, sort=None,
364  per_page=None,
365  page=None):
366  """
367  Get a list of all public channels.
368  This method does not require authentication.
369  """
370  params = {}
371  if sort in ('newest', 'oldest', 'alphabetical',
372  'most_videos', 'most_subscribed', 'most_recently_updated'):
373  params['sort'] = sort
374  if per_page != None:
375  params['per_page'] = per_page
376  if page != None:
377  params['page'] = page
378 
379  return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
380  parameters=params)
381 
382  def vimeo_channels_getVideos(self, channel_id=None, full_response=None,
383  per_page=None,
384  page=None):
385  """
386  Get a list of Videos for a specific channels.
387  This method does not require authentication.
388  """
389  # full_response channel_id
390  params = {}
391  if channel_id != None:
392  params['channel_id'] = channel_id
393  if full_response != None:
394  params['full_response'] = 1
395  if per_page != None:
396  params['per_page'] = per_page
397  if page != None:
398  params['page'] = page
399 
400  return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
401  parameters=params)
402 
403 
404 
407 
408 
409 
412 
413 
416 
417 
420 
421 
424 
425 
428 
429 
432  def vimeo_test_echo(self, params={}):
433  """
434  This will just repeat back any parameters that you send.
435  No auth required
436  """
437 
440  return self._do_vimeo_unauthenticated_call(inspect.stack()[0][3].replace('_', '.'),
441  parameters=params)
442 
443 
444  def vimeo_test_login(self):
445  """
446  Is the user logged in?
447  """
448  return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
449 
450 
451  def vimeo_test_null(self):
452  """
453  This is just a simple null/ping test.
454 
455  You can use this method to make sure that you are properly
456  contacting to the Vimeo API.
457  """
458  return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
459 
460 
461 
464 
465 
468 
469 
472 
473 
474 
477 
479  """
480  (from vimeo API documentation)
481  Get the space and number of HD uploads left for a user.
482 
483  Numbers are provided in bytes. It's a good idea to check this
484  method before you upload a video to let the user know if their
485  video will be converted to HD. hd_quota will have a value of 0
486  if the user reached the max number of uploads, 1
487  otherwise. Resets is the number of the day of the week,
488  starting with Sunday.
489  """
490  return self._do_vimeo_authenticated_call(inspect.stack()[0][3].replace('_', '.'))
491 
492 
493 
494 
495 def _simple_request(url, format):
496  if format != 'xml':
497  raise VimeoException("Sorry, only 'xml' supported. '%s' was requested." %format)
498 
499  curly = CurlyRequest()
500  url = url %(format)
501  ans = curly.do_request(url)
502 
503  if format == 'xml':
504  return ET.fromstring(ans)
505 
506 
510 
511 def _user_request(user, info, format):
512  url = API_V2_CALL_URL + '%s/%s.%%s' %(user,info)
513  return _simple_request(url, format)
514 
515 def user_info(user, format="xml"):
516  """
517  User info for the specified user
518  """
519  return _user_request(user, inspect.stack()[0][3][5:], format)
520 
521 
522 def user_videos(user, format="xml"):
523  """
524  Videos created by user
525  """
526  return _user_request(user, inspect.stack()[0][3][5:], format)
527 
528 def user_likes(user, format="xml"):
529  """
530  Videos the user likes
531  """
532  return _user_request(user, inspect.stack()[0][3][5:], format)
533 
534 def user_appears_in(user, format="xml"):
535  """
536  Videos that the user appears in
537  """
538  return _user_request(user, inspect.stack()[0][3][5:], format)
539 
540 def user_all_videos(user, format="xml"):
541  """
542  Videos that the user appears in and created
543  """
544  return _user_request(user, inspect.stack()[0][3][5:], format)
545 
546 def user_subscriptions(user, format="xml"):
547  """
548  Videos the user is subscribed to
549  """
550  return _user_request(user, inspect.stack()[0][3][5:], format)
551 
552 def user_albums(user, format="xml"):
553  """
554  Albums the user has created
555  """
556  return _user_request(user, inspect.stack()[0][3][5:], format)
557 
558 def user_channels(user, format="xml"):
559  """
560  Channels the user has created and subscribed to
561  """
562  return _user_request(user, inspect.stack()[0][3][5:], format)
563 
564 def user_groups(user, format="xml"):
565  """
566  Groups the user has created and joined
567  """
568  return _user_request(user, inspect.stack()[0][3][5:], format)
569 
570 def user_contacts_videos(user, format="xml"):
571  """
572  Videos that the user's contacts created
573  """
574  return _user_request(user, inspect.stack()[0][3][5:], format)
575 
576 def user_contacts_like(user, format="xml"):
577  """
578  Videos that the user's contacts like
579  """
580  return _user_request(user, inspect.stack()[0][3][5:], format)
581 
582 
583 
586 def video_request(video, format):
587  url = API_V2_CALL_URL + 'video/%s.%%s' %(video)
588  return _simple_request(url)
589 
590 
593 
594 class OutStreamEncoder(object):
595  """Wraps a stream with an encoder"""
596  def __init__(self, outstream, encoding=None):
597  self.out = outstream
598  if not encoding:
599  self.encoding = sys.getfilesystemencoding()
600  else:
601  self.encoding = encoding
602 
603  def write(self, obj):
604  """Wraps the output stream, encoding Unicode strings with the specified encoding"""
605  if isinstance(obj, unicode):
606  try:
607  self.out.write(obj.encode(self.encoding))
608  except IOError:
609  pass
610  else:
611  try:
612  self.out.write(obj)
613  except IOError:
614  pass
615 
616  def __getattr__(self, attr):
617  """Delegate everything but write to the stream"""
618  return getattr(self.out, attr)
619 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
620 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
621 
622 
623 class Videos(object):
624  """Main interface to http://vimeo.com/
625  This is done to support a common naming framework for all python Netvision plugins no matter their site
626  target.
627 
628  Supports search and tree view methods
629  The apikey is a not passed but is created as a session token to access http://vimeo.com/
630  """
631  def __init__(self,
632  apikey,
633  mythtv = True,
634  interactive = False,
635  select_first = False,
636  debug = False,
637  custom_ui = None,
638  language = None,
639  search_all_languages = False,
640  ):
641  """apikey (str/unicode):
642  Specify the target site API key. Applications need their own key in some cases
643 
644  mythtv (True/False):
645  When True, the returned meta data is being returned has the key and values massaged to match MythTV
646  When False, the returned meta data is being returned matches what target site returned
647 
648  interactive (True/False): (This option is not supported by all target site apis)
649  When True, uses built-in console UI is used to select the correct show.
650  When False, the first search result is used.
651 
652  select_first (True/False): (This option is not supported currently implemented in any grabbers)
653  Automatically selects the first series search result (rather
654  than showing the user a list of more than one series).
655  Is overridden by interactive = False, or specifying a custom_ui
656 
657  debug (True/False):
658  shows verbose debugging information
659 
660  custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers)
661  A callable subclass of interactive class (overrides interactive option)
662 
663  language (2 character language abbreviation): (This option is not supported by all target site apis)
664  The language of the returned data. Is also the language search
665  uses. Default is "en" (English). For full list, run..
666 
667  search_all_languages (True/False): (This option is not supported by all target site apis)
668  By default, a Netvision grabber will only search in the language specified using
669  the language option. When this is True, it will search for the
670  show in any language
671 
672  """
673  self.config = {}
674  self.mythxml = MythXML()
675 
676  self.config['debug_enabled'] = debug # show debugging messages
677 
678  self.log_name = "vimeo"
679  self.log = self._initLogger() # Setups the logger (self.log.debug() etc)
680 
681  self.config['custom_ui'] = custom_ui
682 
683  self.config['interactive'] = interactive # prompt for correct series?
684 
685  self.config['select_first'] = select_first
687  self.config['search_all_languages'] = search_all_languages
688 
689  # Defaulting to ENGISH but the vimeo.com apis do not support specifying a language
690  self.config['language'] = "en"
691 
692  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", }
693 
694  # This is an example that must be customized for each target site
695  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'}]
696 
697  # The following url_ configs are based of the
698  # http://vimeo.com/api/docs/advanced-api
699  self.config[u'methods'] = {}
700  # Methods are actually set in initializeVimeo()
701  self.config[u'methods']['channels'] = None
702  self.config[u'methods']['channels_videos'] = None
703 
704  # Functions that parse video data from RSS data
705  self.config['item_parser'] = {}
706  self.config['item_parser']['channels'] = self.getVideosForChannels
707 
708  # Tree view url and the function that parses that urls meta data
709  self.config[u'methods'][u'tree.view'] = {
710  'N_R_S': {
711  '__all__': ['channels_videos', 'channels'],
712  },
713  'Everything HD': {
714  '__all__': ['channels_videos', 'channels'],
715  },
716  }
717 
718  self.config[u'image_extentions'] = ["png", "jpg", "bmp"] # Acceptable image extentions
719 
720  self.tree_key_list = ['newest', 'most_recently_updated', 'most_subscribed']
721 
722  self.tree_order = ['N_R_S', 'Everything HD', ]
723 
724  self.tree_org = {
725  'N_R_S': [
726  ['Newest Channels/Most ...', u''],
727  ['', self.tree_key_list],
728  [u'',u'']
729  ],
730  'Everything HD': [
731  ['Everything HD: Newest Channels/Most ...', self.tree_key_list ]
732  ],
733  }
734 
735  self.tree_customize = {
736  'N_R_S': {
737  '__default__': { },
738  #'cat name': {},
739  },
740  'Everything HD': {
741  '__default__': { },
742  #'cat name': {},
743  },
744  }
746  self.feed_names = {
747  'N_R_S': {'newest': 'Most Recent Channels', 'most_recently_updated': "This Month's Channels'", 'most_subscribed': 'Most Subscribed Channels',
748  },
749  'Everything HD': {'newest': 'Most Recent Channels', 'most_recently_updated': "This Month's Channels'", 'most_subscribed': 'Most Subscribed Channels',
750  },
751 
752  }
753 
754  self.feed_icons = {
755  'N_R_S': {'newest': 'directories/topics/most_recent', 'most_recently_updated': 'directories/topics/month', 'most_subscribed': 'directories/topics/most_subscribed',
756  },
757  'Everything HD': {'newest': 'directories/topics/most_recent', 'most_recently_updated': 'directories/topics/month', 'most_subscribed': 'directories/topics/most_subscribed', 'Everything HD': 'directories/topics/hd'
758  },
759 
760  }
761 
762  # Initialize the tree view flag so that the item parsing code can be used for multiple purposes
763  self.treeview = False
764  self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/vimeo.jpg'
765  # end __init__()
766 
767 
772 
773  def massageDescription(self, text):
774  '''Removes HTML markup from a text string.
775  @param text The HTML source.
776  @return The plain text. If the HTML source contains non-ASCII
777  entities or character references, this is a Unicode string.
778  '''
779  def fixup(m):
780  text = m.group(0)
781  if text[:1] == "<":
782  return "" # ignore tags
783  if text[:2] == "&#":
784  try:
785  if text[:3] == "&#x":
786  return unichr(int(text[3:-1], 16))
787  else:
788  return unichr(int(text[2:-1]))
789  except ValueError:
790  pass
791  elif text[:1] == "&":
792  import htmlentitydefs
793  entity = htmlentitydefs.entitydefs.get(text[1:-1])
794  if entity:
795  if entity[:2] == "&#":
796  try:
797  return unichr(int(entity[2:-1]))
798  except ValueError:
799  pass
800  else:
801  return unicode(entity, "iso-8859-1")
802  return text # leave as is
803  return self.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.textUtf8(text))).replace(u'\n',u' ')
804  # end massageDescription()
805 
806 
807  def _initLogger(self):
808  """Setups a logger using the logging module, returns a log object
809  """
810  logger = logging.getLogger(self.log_name)
811  formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
812 
813  hdlr = logging.StreamHandler(sys.stdout)
814 
815  hdlr.setFormatter(formatter)
816  logger.addHandler(hdlr)
817 
818  if self.config['debug_enabled']:
819  logger.setLevel(logging.DEBUG)
820  else:
821  logger.setLevel(logging.WARNING)
822  return logger
823  #end initLogger
824 
825 
826  def textUtf8(self, text):
827  if text == None:
828  return text
829  try:
830  return unicode(text, 'utf8')
831  except UnicodeDecodeError:
832  return u''
833  except (UnicodeEncodeError, TypeError):
834  return text
835  # end textUtf8()
836 
837 
838  def ampReplace(self, text):
839  '''Replace all "&" characters with "&amp;"
840  '''
841  text = self.textUtf8(text)
842  return text.replace(u'&amp;',u'~~~~~').replace(u'&',u'&amp;').replace(u'~~~~~', u'&amp;')
843  # end ampReplace()
844 
845 
846  def setTreeViewIcon(self, dir_icon=None):
847  '''Check if there is a specific generic tree view icon. If not default to the channel icon.
848  return self.tree_dir_icon
849  '''
851  if not dir_icon:
852  if not self.feed_icons.has_key(self.tree_key):
853  return self.tree_dir_icon
854  if not self.feed_icons[self.tree_key].has_key(self.feed):
855  return self.tree_dir_icon
856  dir_icon = self.feed_icons[self.tree_key][self.feed]
857  if not dir_icon:
858  return self.tree_dir_icon
859  self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, )
860  return self.tree_dir_icon
861  # end setTreeViewIcon()
862 
863 
868 
869  def initializeVimeo(self):
870  '''Initialize acccess methods for all Vimeo API calls
871  raise errors if there are issues during the initalization steps
872  return nothing
873  '''
874  #
875  self.client = SimpleOAuthClient(getData().update(getData().a), getData().update(getData().s))
876  if self.config['debug_enabled']:
877  self.client.curly.debug = True
878  try:
879  self.client.get_request_token()
880  except Exception, msg:
881  raise VimeoRequestTokenError(u'%s', msg)
882  try:
883  self.client.get_authorize_token_url()
884  except Exception, msg:
885  raise VimeoAuthorizeTokenError(u'%s', msg)
886 
887  self.config[u'methods']['channels'] = self.client.vimeo_channels_getAll
888  self.config[u'methods']['channels_videos'] = self.client.vimeo_channels_getVideos
889 
890  # end initializeVimeo()
891 
892  def processVideoUrl(self, url):
893  playerUrl = self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/vimeo.html", \
894  url.replace(u'http://vimeo.com/', ''))
895  return self.ampReplace(playerUrl)
896 
897  def searchTitle(self, title, pagenumber, pagelen):
898  '''Key word video search of the vimeo.com web site
899  return an array of matching item dictionaries
900  return
901  '''
902  self.initializeVimeo()
903 
904  # Used for debugging usually commented out
905 # xml_data = self.client.vimeo_videos_search(title, sort='most_liked',
906 # per_page=pagelen,
907 # page=pagenumber)
908 # print xml_data
909 
910  try:
911  xml_data = self.client.vimeo_videos_search(urllib.quote_plus(title.encode("utf-8")),
912  sort='most_liked',
913  per_page=pagelen,
914  page=pagenumber)
915  except Exception, msg:
916  raise VimeoVideosSearchError(u'%s' % msg)
917 
918  if xml_data == None:
919  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
920 
921  if not len(xml_data.keys()):
922  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
923 
924  if xml_data.tag == 'rsp':
925  if not xml_data.get('stat') == 'ok':
926  if __errmsgs__.has_key(xml_data.get('stat')):
927  errmsg = __errmsg__[xml_data.get('stat')]
928  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
929  else:
930  errmsg = u'Unknown error'
931  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
932 
933  elements_final = []
934  videos = xml_data.find(u"videos")
935  if videos:
936  if videos.get('total'):
937  if not int(videos.get('total')):
938  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
939  self.channel['channel_numresults'] = int(videos.get('total'))
940 
941  # Collect video meta data that matched the search value
942  for video in xml_data.find(u"videos").getchildren():
943  hd_flag = False
944  embed_flag = False
945  if video.tag == 'video':
946  if video.get('embed_privacy') == "anywhere":
947  embed_flag = True
948  if video.get('is_hd') == "1":
949  hd_flag = True
950  v_details = {}
951  for details in video.getchildren():
952  if details.tag in ['tags', 'cast']:
953  continue
954  if details.tag == 'width':
955  if details.text:
956  v_details['width'] = details.text.strip()
957  continue
958  if details.tag == 'height':
959  if details.text:
960  v_details['height'] = details.text.strip()
961  continue
962  if details.tag == 'duration':
963  if details.text:
964  v_details['duration'] = details.text.strip()
965  continue
966  if details.tag == 'owner':
967  if details.text:
968  v_details['display_name'] = self.massageDescription(details.get('display_name').strip())
969  else:
970  v_details['display_name'] = u''
971  continue
972  if details.tag == 'description':
973  if details.text:
974  v_details[details.tag] = self.massageDescription(details.text.strip())
975  else:
976  v_details[details.tag] = u''
977  continue
978  if details.tag == 'upload_date':
979  if details.text:
980  pub_time = time.strptime(details.text.strip(), "%Y-%m-%d %H:%M:%S")
981  v_details[details.tag] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', pub_time)
982  else:
983  v_details[details.tag] = u''
984  continue
985  if details.tag == 'urls':
986  for url in details.getchildren():
987  if url.get('type') == 'video':
988  if url.text: # Make the link fullscreen and auto play
989  if embed_flag:
990  v_details[url.tag] = self.processVideoUrl(url.text.strip())
991  else:
992  v_details[url.tag] = self.ampReplace(url.text.strip())
993  else:
994  v_details[url.tag] = u''
995  continue
996  if details.tag == 'thumbnails':
997  largest = 0
998  for image in details.getchildren():
999  if image.tag == 'thumbnail':
1000  height = int(image.get('height'))
1001  width = int(image.get('width'))
1002  default = image.text.find('default')
1003  if largest < height * width and not default != -1:
1004  if image.text:
1005  v_details[image.tag] = self.ampReplace(image.text.strip())
1006  if width >= 200:
1007  break
1008  continue
1009  if details.text:
1010  v_details[details.tag] = self.massageDescription(details.text.strip())
1011  else:
1012  v_details[details.tag] = u''
1013  if hd_flag and not v_details.has_key('width'):
1014  v_details['width'] = 1280
1015  v_details['height'] = 720
1016  elements_final.append(v_details)
1017 
1018  if not len(elements_final):
1019  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % title)
1020 
1021  return elements_final
1022  # end searchTitle()
1023 
1024 
1025  def searchForVideos(self, title, pagenumber):
1026  """Common name for a video search. Used to interface with MythTV plugin NetVision
1027  """
1028  # Channel details and search results
1029  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}
1030 
1031  # Easier for debugging usually commented out
1032 # data = self.searchTitle(title, pagenumber, self.page_limit)
1033 # print data
1034 # sys.exit()
1035 
1036  try:
1037  data = self.searchTitle(title, pagenumber, self.page_limit)
1038  except VimeoVideoNotFound, msg:
1039  sys.stderr.write(u'%s' % msg)
1040  return None
1041  except VimeoUrlError, msg:
1042  sys.stderr.write(self.error_messages['VimeoUrlError'] % msg)
1043  sys.exit(1)
1044  except VimeoHttpError, msg:
1045  sys.stderr.write(self.error_messages['VimeoHttpError'] % msg)
1046  sys.exit(1)
1047  except VimeoResponseError, msg:
1048  sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
1049  sys.exit(1)
1050  except VimeoAuthorizeTokenError, msg:
1051  sys.stderr.write(self.error_messages['VimeoAuthorizeTokenError'] % msg)
1052  sys.exit(1)
1053  except VimeoVideosSearchError, msg:
1054  sys.stderr.write(self.error_messages['VimeoVideosSearchError'] % msg)
1055  sys.exit(1)
1056  except VimeoRequestTokenError, msg:
1057  sys.stderr.write(self.error_messages['VimeoRequestTokenError'] % msg)
1058  sys.exit(1)
1059  except VimeoException, msg:
1060  sys.stderr.write(self.error_messages['VimeoException'] % msg)
1061  sys.exit(1)
1062  except Exception, e:
1063  sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e))
1064  sys.exit(1)
1065 
1066  if data == None:
1067  return None
1068  if not len(data):
1069  return None
1070 
1071  items = []
1072  for match in data:
1073  item_data = {}
1074  for key in self.key_translation[1].keys():
1075  if key == 'url':
1076  item_data['item_link'] = match[key]
1077  item_data['item_url'] = match[key]
1078  continue
1079  if key in match.keys():
1080  item_data[self.key_translation[1][key]] = match[key]
1081  else:
1082  item_data[self.key_translation[1][key]] = u''
1083  items.append(item_data)
1084 
1085  self.channel['channel_startindex'] = self.page_limit * int(pagenumber)
1086  self.channel['channel_returned'] = len(items)
1087 
1088  if len(items):
1089  return [[self.channel, items]]
1090  return None
1091  # end searchForVideos()
1092 
1093 
1094  def getChannels(self):
1095  '''Get the channel directory information and fill out the tree view directory structures as required
1096  raise exceptions if the there was an issue getting Channel information or no channel data
1097  return True if successful
1098  '''
1099  self.channel_dict = {'N_R_S': {}, 'Everything HD': {}, }
1100  self.channel_count = {}
1101  for key in self.tree_key_list:
1102  self.channel_dict['N_R_S'][key] = []
1103  self.channel_dict['Everything HD'][key] = []
1105  self.channel_count['N_R_S'] = {'newest': [10, 2], 'most_recently_updated': [10, 1], 'most_subscribed': [10, 10]}
1106  self.channel_count['Everything HD'] = {'newest': [10, 2], 'most_recently_updated': [10, 1], 'most_subscribed': [5, 20]}
1107 
1108  for sort in self.tree_key_list:
1109  page = 0
1110  not_HD_count = 0
1111  HD_count = 0
1112  not_HD_list = []
1113  HD_list = []
1114  while True:
1115  try:
1116  page+=1
1117  if page > 20: # Throttles excessive searching for HD groups within a category
1118  break
1119  try:
1120  xml_data = self.config[u'methods']['channels'](sort=sort,
1121  per_page=None,
1122  page=page)
1123  except Exception, msg:
1124  raise VimeoAllChannelError(u'%s' % msg)
1125 
1126  if xml_data == None:
1127  raise VimeoAllChannelError(self.error_messages['1-VimeoAllChannelError'] % sort)
1128 
1129  if not len(xml_data.keys()):
1130  raise VimeoAllChannelError(self.error_messages['2-VimeoAllChannelError'] % sort)
1131 
1132  if xml_data.tag == 'rsp':
1133  if not xml_data.get('stat') == 'ok':
1134  if __errmsgs__.has_key(xml_data.get('stat')):
1135  errmsg = __errmsg__[xml_data.get('stat')]
1136  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
1137  else:
1138  errmsg = u'Unknown error'
1139  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
1140 
1141  for channel in xml_data.find('channels'):
1142  index = channel.find('name').text.find(u'HD')
1143  if index != -1:
1144  if HD_count < self.channel_count['Everything HD'][sort][0]:
1145  if not channel.get('id') in HD_list:
1146  self.channel_dict['Everything HD'][sort].append([channel.get('id'), channel.find('name').text])
1147  HD_list.append(channel.get('id'))
1148  HD_count+=1
1149  else:
1150  if not_HD_count < self.channel_count['N_R_S'][sort][0]:
1151  if not channel.get('id') in not_HD_list:
1152  self.channel_dict['N_R_S'][sort].append([channel.get('id'), channel.find('name').text])
1153  not_HD_list.append(channel.get('id'))
1154  not_HD_count+=1
1155  if not_HD_count >= self.channel_count['N_R_S'][sort][0] and HD_count >= self.channel_count['Everything HD']:
1156  break
1157  if not_HD_count >= self.channel_count['N_R_S'][sort][0] and HD_count >= self.channel_count['Everything HD']:
1158  break
1159  except:
1160  break
1161 
1162  return True
1163  #end getChannels()
1164 
1165 
1166  def displayTreeView(self):
1167  '''Gather the Vimeo Groups/Channels...etc then get a max page of videos meta data in each of them
1168  return array of directories and their video metadata
1169  '''
1170  try:
1171  self.initializeVimeo()
1172  except VimeoAuthorizeTokenError, msg:
1173  sys.stderr.write(self.error_messages['VimeoAuthorizeTokenError'] % msg)
1174  sys.exit(1)
1175  except VimeoRequestTokenError, msg:
1176  sys.stderr.write(self.error_messages['VimeoRequestTokenError'] % msg)
1177  sys.exit(1)
1178  except VimeoException, msg:
1179  sys.stderr.write(self.error_messages['VimeoException'] % msg)
1180  sys.exit(1)
1181  except Exception, msg:
1182  sys.stderr.write(u"! Error: Unknown error during a Vimeo API initialization (%s)\n" % msg)
1183  sys.exit(1)
1184 
1185  # Channel details and search results
1186  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}
1187 
1188  if self.config['debug_enabled']:
1189  print self.config[u'methods']
1190  print
1191 
1192  # Initialize the Video channels data
1193  try:
1194  self.getChannels()
1195  except VimeoResponseError, msg:
1196  sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
1197  sys.exit(1)
1198  except VimeoAllChannelError, msg:
1199  sys.stderr.write(self.error_messages['VimeoAllChannelError'] % msg)
1200  sys.exit(1)
1201  except VimeoException, msg:
1202  sys.stderr.write(self.error_messages['VimeoException'] % msg)
1203  sys.exit(1)
1204  except Exception, msg:
1205  sys.stderr.write(u"! Error: Unknown error while getting all Channels (%s)\n" % msg)
1206  sys.exit(1)
1207 
1208  dictionaries = []
1209 
1210  self.treeview = True
1211 
1212  # Process the various video feeds/categories/... etc
1213  for key in self.tree_order:
1214  self.tree_key = key
1215  dictionaries = self.getVideos(self.tree_org[key], dictionaries)
1216 
1217  return [[self.channel, dictionaries]]
1218  # end displayTreeView()
1219 
1220 
1221  def getVideos(self, dir_dict, dictionaries):
1222  '''Parse a list made of category lists and retrieve video meta data
1223  return a dictionary of directory names and categories video metadata
1224  '''
1225  for sets in dir_dict:
1226  if not isinstance(sets[1], list):
1227  if sets[0] != '': # Add the nested dictionaries display name
1228  try:
1229  dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
1230  except KeyError:
1231  dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
1232  else:
1233  dictionaries.append(['', u'']) # Add the nested dictionary indicator
1234  continue
1235  temp_dictionary = []
1236  for self.feed in sets[1]:
1237  if self.config[u'methods'][u'tree.view'][self.tree_key].has_key('__all__'):
1238  URL = self.config[u'methods'][u'tree.view'][self.tree_key]['__all__']
1239  else:
1240  URL = self.config[u'methods'][u'tree.view'][self.tree_key][self.feed]
1241  temp_dictionary = self.config['item_parser'][URL[1]](self.config[u'methods'][URL[0]], temp_dictionary)
1242  if len(temp_dictionary):
1243  if len(sets[0]): # Add the nested dictionaries display name
1244  try:
1245  dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
1246  except KeyError:
1247  dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
1248  for element in temp_dictionary:
1249  dictionaries.append(element)
1250  if len(sets[0]):
1251  dictionaries.append(['', u'']) # Add the nested dictionary indicator
1252  return dictionaries
1253  # end getVideos()
1254 
1255 
1256  def getVideosForChannels(self, method, dictionary):
1257  '''Process all channel related directory videos
1258  return dictionary of new video items
1259  '''
1260  self.next_page = 1
1261  self.max_page = self.channel_count[self.tree_key][self.feed][1]
1262  self.tree_list = False
1263  # Sometimes it is beter to see a list of videos rather than split them up by their channel names
1264  if self.max_page <= self.channel_list_max:
1265  self.tree_list = True
1266  tmp_dictionary = []
1267  for channel in self.channel_dict[self.tree_key][self.feed]:
1268  self.channel_id = channel[0]
1269  self.dir_name = channel[1]
1270 
1271  # Easier for debugging
1272  #tmp_dictionary = self.getTreeVideos(method, tmp_dictionary)
1273 
1274  try:
1275  tmp_dictionary = self.getTreeVideos(method, tmp_dictionary)
1276  except VimeoVideoNotFound, msg:
1277  sys.stderr.write(self.error_messages['VimeoVideoNotFound'] % msg)
1278  continue
1279  except VimeoVideosSearchError, msg:
1280  sys.stderr.write(self.error_messages['VimeoVideosSearchError'] % msg)
1281  sys.exit(1)
1282  except VimeoResponseError, msg:
1283  sys.stderr.write(self.error_messages['VimeoResponseError'] % msg)
1284  sys.exit(1)
1285  except VimeoException, msg:
1286  sys.stderr.write(self.error_messages['VimeoException'] % msg)
1287  sys.exit(1)
1288  except Exception, e:
1289  sys.stderr.write(u"! Error: Unknown error during while getting all Channels (%s)\nError(%s)\n" % (self.dir_name, e))
1290  sys.exit(1)
1291 
1292  if len(tmp_dictionary):
1293  dictionary.append([self.feed_names[self.tree_key][self.feed], self.setTreeViewIcon()])
1294  for element in tmp_dictionary:
1295  dictionary.append(element)
1296  dictionary.append(['', u''])
1297  return dictionary
1298  # end getVideosForChannels()
1299 
1300 
1301 
1302  def getTreeVideos(self, method, dictionaries):
1303  '''Get the video metadata for url search
1304  return the video dictionary of directories and their video mata data
1305  '''
1306  initial_length = len(dictionaries)
1307  try:
1308  xml_data = method(channel_id=self.channel_id, full_response=1,
1309  per_page=self.max_page,
1310  page=self.next_page)
1311  except Exception, msg:
1312  raise VimeoVideosSearchError(u'%s' % msg)
1313 
1314  if xml_data == None:
1315  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % self.dir_name)
1316 
1317  if not len(xml_data.keys()):
1318  raise VimeoVideoNotFound(self.error_messages['VimeoVideoNotFound'] % self.dir_name)
1319 
1320  if xml_data.tag == 'rsp':
1321  if not xml_data.get('stat') == 'ok':
1322  if __errmsgs__.has_key(xml_data.get('stat')):
1323  errmsg = __errmsg__[xml_data.get('stat')]
1324  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
1325  else:
1326  errmsg = u'Unknown error'
1327  raise VimeoResponseError(u"Error %s - %s" % (xml_data.get('stat'), errmsg))
1328 
1329  videos = xml_data.find(u"videos")
1330  if videos:
1331  if videos.get('total'):
1332  self.channel['channel_numresults'] = int(videos.get('total'))
1333 
1334  # Collect video meta data that matched the search value
1335  dictionary_first = False
1336  for video in xml_data.find(u"videos").getchildren():
1337  hd_flag = False
1338  embed_flag = False
1339  if video.tag == 'video':
1340  if video.get('embed_privacy') == "anywhere":
1341  embed_flag = True
1342  if video.get('is_hd') == "1":
1343  hd_flag = True
1344  v_details = {}
1345  for details in video.getchildren():
1346  if details.tag in ['tags', 'cast']:
1347  continue
1348  if details.tag == 'width':
1349  if details.text:
1350  v_details['width'] = details.text.strip()
1351  continue
1352  if details.tag == 'height':
1353  if details.text:
1354  v_details['height'] = details.text.strip()
1355  continue
1356  if details.tag == 'duration':
1357  if details.text:
1358  v_details['duration'] = details.text.strip()
1359  continue
1360  if details.tag == 'owner':
1361  if details.text:
1362  v_details['display_name'] = self.massageDescription(details.get('display_name').strip())
1363  else:
1364  v_details['display_name'] = u''
1365  continue
1366  if details.tag == 'description':
1367  if details.text:
1368  if self.tree_list:
1369  v_details[details.tag] = self.massageDescription(u'Channel "%s": %s' % (self.dir_name, details.text.strip()))
1370  else:
1371  v_details[details.tag] = self.massageDescription(details.text.strip())
1372  else:
1373  if self.tree_list:
1374  v_details[details.tag] = self.massageDescription(u'Channel "%s"' % self.dir_name)
1375  continue
1376  if details.tag == 'upload_date':
1377  if details.text:
1378  pub_time = time.strptime(details.text.strip(), "%Y-%m-%d %H:%M:%S")
1379  v_details[details.tag] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', pub_time)
1380  else:
1381  v_details[details.tag] = u''
1382  continue
1383  if details.tag == 'urls':
1384  for url in details.getchildren():
1385  if url.get('type') == 'video':
1386  if url.text: # Make the link fullscreen and auto play
1387  if embed_flag:
1388  v_details[url.tag] = self.processVideoUrl(url.text.strip())
1389  else:
1390  v_details[url.tag] = self.ampReplace(url.text.strip())
1391  else:
1392  v_details[url.tag] = u''
1393  continue
1394  if details.tag == 'thumbnails':
1395  largest = 0
1396  for image in details.getchildren():
1397  if image.tag == 'thumbnail':
1398  height = int(image.get('height'))
1399  width = int(image.get('width'))
1400  default = image.text.find('default')
1401  if largest < height * width and not default != -1:
1402  if image.text:
1403  v_details[image.tag] = self.ampReplace(image.text.strip())
1404  if width >= 200:
1405  break
1406  continue
1407  if details.text:
1408  v_details[details.tag] = self.massageDescription(details.text.strip())
1409  else:
1410  v_details[details.tag] = u''
1411 
1412  if hd_flag and not v_details.has_key('width'):
1413  v_details['width'] = 1280
1414  v_details['height'] = 720
1415 
1416  if not v_details.has_key('url'):
1417  continue
1418 
1419  if not dictionary_first and not self.tree_list: # Add the dictionaries display name
1420  dictionaries.append([self.dir_name, self.setTreeViewIcon()])
1421  dictionary_first = True
1422 
1423  final_item = {}
1424  for key in self.key_translation[1].keys():
1425  if key == 'url':
1426  final_item['item_link'] = v_details[key]
1427  final_item['item_url'] = v_details[key]
1428  continue
1429  if v_details.has_key(key):
1430  final_item[self.key_translation[1][key]] = v_details[key]
1431  else:
1432  final_item[self.key_translation[1][key]] = u''
1433  dictionaries.append(final_item)
1434 
1435  # Need to check if there was any items for this directory
1436  if initial_length < len(dictionaries) and not self.tree_list:
1437  dictionaries.append(['', u'']) # Add the nested dictionary indicator
1438  return dictionaries
1439  # end getTreeVideos()
1440 # end Videos() class
def user_groups(user, format="xml")
Definition: vimeo_api.py:564
def user_channels(user, format="xml")
Definition: vimeo_api.py:558
def __init__(self, apikey, mythtv=True, interactive=False, select_first=False, debug=False, custom_ui=None, language=None, search_all_languages=False)
Definition: vimeo_api.py:631
def getTreeVideos(self, method, dictionaries)
Definition: vimeo_api.py:1302
def searchForVideos(self, title, pagenumber)
Definition: vimeo_api.py:1025
def getVideos(self, dir_dict, dictionaries)
Definition: vimeo_api.py:1221
def __init__(self, outstream, encoding=None)
Definition: vimeo_api.py:596
def _user_request(user, info, format)
User related call from the "Simple API".
Definition: vimeo_api.py:511
def searchTitle(self, title, pagenumber, pagelen)
Definition: vimeo_api.py:897
def vimeo_test_echo(self, params={})
Contacts section.
Definition: vimeo_api.py:432
def user_all_videos(user, format="xml")
Definition: vimeo_api.py:540
def user_likes(user, format="xml")
Definition: vimeo_api.py:528
def vimeo_channels_getAll(self, sort=None, per_page=None, page=None)
Channel section.
Definition: vimeo_api.py:363
def initializeVimeo(self)
End of Utility functions.
Definition: vimeo_api.py:869
def user_info(user, format="xml")
Definition: vimeo_api.py:515
def do_post_call(self, url, args, use_progress=False)
Definition: vimeo_api.py:181
MythTV Netvideo specific classes start here.
Definition: vimeo_api.py:594
def vimeo_videos_search(self, query, sort=None, per_page=None, page=None)
Video section.
Definition: vimeo_api.py:338
def vimeo_oauth_checkAccessToken(self, auth_token)
Definition: vimeo_api.py:283
def setTreeViewIcon(self, dir_icon=None)
Definition: vimeo_api.py:846
def _simple_request(url, format)
Definition: vimeo_api.py:495
def _upload_progress(self, download_t, download_d, upload_t, upload_d)
Definition: vimeo_api.py:164
def getVideosForChannels(self, method, dictionary)
Definition: vimeo_api.py:1256
def user_appears_in(user, format="xml")
Definition: vimeo_api.py:534
def user_contacts_like(user, format="xml")
Definition: vimeo_api.py:576
def user_albums(user, format="xml")
Definition: vimeo_api.py:552
def user_videos(user, format="xml")
Definition: vimeo_api.py:522
def __init__(self, key, secret, server="vimeo.com", port=PORT, request_token_url=REQUEST_TOKEN_URL, access_token_url=ACCESS_TOKEN_URL, authorization_url=AUTHORIZATION_URL, token=None, token_secret=None)
Definition: vimeo_api.py:209
def video_request(video, format)
get a specific video
Definition: vimeo_api.py:586
def user_subscriptions(user, format="xml")
Definition: vimeo_api.py:546
def _do_vimeo_unauthenticated_call(self, method, parameters={})
Definition: vimeo_api.py:302
def vimeo_videos_upload_getQuota(self)
Videos section.
Definition: vimeo_api.py:478
def vimeo_albums_getAll(self, user_id, sort=None, per_page=None, page=None)
Album section.
Definition: vimeo_api.py:318
def user_contacts_videos(user, format="xml")
Definition: vimeo_api.py:570
def _do_vimeo_authenticated_call(self, method, parameters={})
Definition: vimeo_api.py:287
def massageDescription(self, text)
Start - Utility functions.
Definition: vimeo_api.py:773
def vimeo_channels_getVideos(self, channel_id=None, full_response=None, per_page=None, page=None)
Definition: vimeo_api.py:382