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