MythTV  master
youtube_api.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 # ----------------------
4 # Name: youtube_api - Simple-to-use Python interface to the youtube API (http://www.youtube.com/)
5 # Python Script
6 # Author: R.D. Vaughan
7 # Purpose: This python script is intended to perform a variety of utility functions to search and access text
8 # metadata, video and image URLs from youtube. These routines are based on the api. Specifications
9 # for this api are published at http://developer.youtubenservices.com/docs
10 #
11 # License:Creative Commons GNU GPL v2
12 # (http://creativecommons.org/licenses/GPL/2.0/)
13 #-------------------------------------
14 __title__ ="youtube_api - Simple-to-use Python interface to the youtube API (http://developer.youtubenservices.com/docs)"
15 __author__="R.D. Vaughan"
16 __purpose__='''
17 This python script is intended to perform a variety of utility functions to search and access text
18 meta data, video and image URLs from youtube. These routines are based on the api. Specifications
19 for this api are published at http://developer.youtubenservices.com/docs
20 '''
21 
22 __version__="v0.3.0"
23 # 0.1.0 Initial development
24 # 0.1.1 Added Tree view display option
25 # 0.1.2 Modified Tree view internals to be consistent in approach and structure.
26 # 0.1.3 Added images for directories
27 # 0.1.4 Documentation review
28 # 0.2.0 Public release
29 # 0.2.1 New python bindings conversion
30 # Better exception error reporting
31 # Better handling of invalid unicode data from source
32 # 0.2.2 Completed exception error reporting improvements
33 # Removed the use of the feedparser library
34 # 0.2.3 Fixed an exception message output code error in two places
35 # 0.2.4 Removed the need for python MythTV bindings and added "%SHAREDIR%" to icon directory path
36 # 0.2.5 Fixed the Foreign Film icon file name
37 # 0.3.0 Adapted to the v3 API
38 
39 import os, struct, sys, re, time, shutil
40 import urllib, urllib2
41 import json
42 import logging
43 from MythTV import MythXML
44 from ..common import common_api
45 
46 from youtube_exceptions import (YouTubeUrlError, YouTubeHttpError, YouTubeRssError, YouTubeVideoNotFound, YouTubeInvalidSearchType, YouTubeXmlError, YouTubeVideoDetailError, YouTubeCategoryNotFound)
47 from youtube_data import getData
48 
49 try:
50  import aniso8601
51 except:
52  sys.stderr.write("The module aniso8601 could not be imported, duration "
53  "parsing will be disabled\n")
54  pass
55 
57  """Deals with retrieval of JSON data from API
58  """
59  def __init__(self, url):
60  self.url = url
61 
62  def getJson(self):
63  try:
64  urlhandle = urllib.urlopen(self.url)
65  return json.load(urlhandle)
66  except IOError, errormsg:
67  raise YouTubeHttpError(errormsg)
68 
69 
70 class Videos(object):
71  """Main interface to http://www.youtube.com/
72  This is done to support a common naming framework for all python Netvision plugins no matter their site
73  target.
74 
75  Supports search methods
76  """
77  def __init__(self,
78  apikey,
79  mythtv = True,
80  interactive = False,
81  select_first = False,
82  debug = False,
83  custom_ui = None,
84  language = None,
85  search_all_languages = False,
86  ):
87  """apikey (str/unicode):
88  Specify the target site API key. Applications need their own key in some cases
89 
90  mythtv (True/False):
91  When True, the returned meta data is being returned has the key and values massaged to match MythTV
92  When False, the returned meta data is being returned matches what target site returned
93 
94  interactive (True/False): (This option is not supported by all target site apis)
95  When True, uses built-in console UI is used to select the correct show.
96  When False, the first search result is used.
97 
98  select_first (True/False): (This option is not supported currently implemented in any grabbers)
99  Automatically selects the first series search result (rather
100  than showing the user a list of more than one series).
101  Is overridden by interactive = False, or specifying a custom_ui
102 
103  debug (True/False):
104  shows verbose debugging information
105 
106  custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers)
107  A callable subclass of interactive class (overrides interactive option)
108 
109  language (2 character language abbreviation): (This option is not supported by all target site apis)
110  The language of the returned data. Is also the language search
111  uses. Default is "en" (English). For full list, run..
112 
113  search_all_languages (True/False): (This option is not supported by all target site apis)
114  By default, a Netvision grabber will only search in the language specified using
115  the language option. When this is True, it will search for the
116  show in any language
117 
118  """
119  self.config = {}
120  self.common = common_api.Common()
121  self.mythxml = MythXML()
122 
123  self.config['debug_enabled'] = debug # show debugging messages
124 
125  self.log_name = "youtube"
126  self.log = self._initLogger() # Setups the logger (self.log.debug() etc)
127 
128  self.config['custom_ui'] = custom_ui
129 
130  self.config['interactive'] = interactive # prompt for correct series?
131 
132  self.config['select_first'] = select_first
133 
134  self.config['search_all_languages'] = search_all_languages
135 
136  self.error_messages = \
137  {'YouTubeUrlError': u"! Error: The URL (%s) cause the exception error (%s)\n",
138  'YouTubeHttpError': u"! Error: An HTTP communications error with YouTube was raised (%s)\n",
139  'YouTubeRssError': u"! Error: Invalid RSS meta data\nwas received from YouTube error (%s). Skipping item.\n",
140  'YouTubeVideoNotFound': u"! Error: Video search with YouTube did not return any results (%s)\n",
141  'YouTubeVideoDetailError': u"! Error: Invalid Video meta data detail\nwas received from YouTube error (%s). Skipping item.\n", }
142 
143  # This is an example that must be customized for each target site
144  self.key_translation = \
145  [{'channel_title': 'channel_title',
146  'channel_link': 'channel_link',
147  'channel_description': 'channel_description',
148  'channel_numresults': 'channel_numresults',
149  'channel_returned': 'channel_returned',
150  'channel_startindex': 'channel_startindex'},
151  {'title': 'item_title',
152  'author': 'item_author',
153  'published_parsed': 'item_pubdate',
154  'media_description': 'item_description',
155  'video': 'item_link',
156  'thumbnail': 'item_thumbnail',
157  'link': 'item_url',
158  'duration': 'item_duration',
159  'rating': 'item_rating',
160  'item_width': 'item_width',
161  'item_height': 'item_height',
162  'language': 'item_lang'}]
163 
164  # Defaulting to no language specified. The YouTube apis does support specifying a language
165  if language:
166  self.config['language'] = language
167  else:
168  self.config['language'] = u''
169 
170  self.getUserPreferences("~/.mythtv/MythNetvision/userGrabberPrefs/youtube.xml")
171 
172  # Read region code from user preferences, used by tree view
173  region = self.userPrefs.find("region")
174  if region is not None and region.text:
175  self.config['region'] = region.text
176  else:
177  self.config['region'] = u'us'
178 
179  self.apikey = getData().update(getData().a)
180 
181  apikey = self.userPrefs.find("apikey")
182  if apikey is not None and apikey.text:
183  self.apikey = apikey.text
184 
185  self.feed_icons = {
186  'Film & Animation': 'directories/topics/movies',
187  'Movies': 'directories/topics/movies',
188  'Trailers': 'directories/topics/movies',
189  'Sports': 'directories/topics/sports',
190  'News & Politics': 'directories/topics/news',
191  'Science & Technology': 'directories/topics/technology',
192  'Education': 'directories/topics/education',
193  'Howto & Style': 'directories/topics/howto',
194  'Music': 'directories/topics/music',
195  'Gaming': 'directories/topics/games',
196  'Entertainment': 'directories/topics/entertainment',
197  'Autos & Vehicles': 'directories/topics/automotive',
198  'Pets & Animals': 'directories/topics/animals',
199  'Travel & Events': 'directories/topics/travel',
200  'People & Blogs': 'directories/topics/people',
201  }
202 
203  self.treeview = False
204  self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/youtube.png'
205  # end __init__()
206 
207  def getUserPreferences(self, userPreferenceFilePath):
208  userPreferenceFilePath = os.path.expanduser(userPreferenceFilePath)
209 
210  # If the user config file does not exists then copy one the default
211  if not os.path.isfile(userPreferenceFilePath):
212  # Make the necessary directories if they do not already exist
213  prefDir = os.path.dirname(userPreferenceFilePath)
214  if not os.path.isdir(prefDir):
215  os.makedirs(prefDir)
216 
217  fileName = os.path.basename(userPreferenceFilePath)
218  defaultConfig = u'%s/nv_python_libs/configs/XML/defaultUserPrefs/%s' \
219  % (baseProcessingDir, fileName)
220  shutil.copy2(defaultConfig, userPreferenceFilePath)
221 
222  # Read the grabber hulu_config.xml configuration file
223  url = u'file://%s' % userPreferenceFilePath
224  if self.config['debug_enabled']:
225  print(url)
226  print
227  try:
228  self.userPrefs = self.common.etree.parse(url)
229  except Exception as e:
230  raise Exception(url, e)
231 
232 
237 
239  '''Get longitude and latitiude to find videos relative to your location. Up to three different
240  servers will be tried before giving up.
241  return a dictionary e.g.
242  {'Latitude': '43.6667', 'Country': 'Canada', 'Longitude': '-79.4167', 'City': 'Toronto'}
243  return an empty dictionary if there were any errors
244  Code found at: http://blog.suinova.com/2009/04/from-ip-to-geolocation-country-city.html
245  '''
246  def getExternalIP():
247  '''Find the external IP address of this computer.
248  '''
249  url = urllib.URLopener()
250  try:
251  resp = url.open('http://www.whatismyip.com/automation/n09230945.asp')
252  return resp.read()
253  except:
254  return None
255  # end getExternalIP()
256 
257  ip = getExternalIP()
258 
259  if ip is None:
260  return {}
261 
262  try:
263  gs = urllib.urlopen('http://blogama.org/ip_query.php?ip=%s&output=xml' % ip)
264  txt = gs.read()
265  except:
266  try:
267  gs = urllib.urlopen('http://www.seomoz.org/ip2location/look.php?ip=%s' % ip)
268  txt = gs.read()
269  except:
270  try:
271  gs = urllib.urlopen('http://api.hostip.info/?ip=%s' % ip)
272  txt = gs.read()
273  except:
274  logging.error('GeoIP servers not available')
275  return {}
276  try:
277  if txt.find('<Response>') > 0:
278  countrys = re.findall(r'<CountryName>([\w ]+)<',txt)[0]
279  citys = re.findall(r'<City>([\w ]+)<',txt)[0]
280  lats,lons = re.findall(r'<Latitude>([\d\-\.]+)</Latitude>\s*<Longitude>([\d\-\.]+)<',txt)[0]
281  elif txt.find('GLatLng') > 0:
282  citys,countrys = re.findall('<br />\s*([^<]+)<br />\s*([^<]+)<',txt)[0]
283  lats,lons = re.findall('LatLng\‍(([-\d\.]+),([-\d\.]+)',txt)[0]
284  elif txt.find('<gml:coordinates>') > 0:
285  citys = re.findall('<Hostip>\s*<gml:name>(\w+)</gml:name>',txt)[0]
286  countrys = re.findall('<countryName>([\w ,\.]+)</countryName>',txt)[0]
287  lats,lons = re.findall('gml:coordinates>([-\d\.]+),([-\d\.]+)<',txt)[0]
288  else:
289  logging.error('error parsing IP result %s'%txt)
290  return {}
291  return {'Country':countrys,'City':citys,'Latitude':lats,'Longitude':lons}
292  except:
293  logging.error('Error parsing IP result %s'%txt)
294  return {}
295  # end detectUserLocationByIP()
296 
297 
298  def massageDescription(self, text):
299  '''Removes HTML markup from a text string.
300  @param text The HTML source.
301  @return The plain text. If the HTML source contains non-ASCII
302  entities or character references, this is a Unicode string.
303  '''
304  def fixup(m):
305  text = m.group(0)
306  if text[:1] == "<":
307  return "" # ignore tags
308  if text[:2] == "&#":
309  try:
310  if text[:3] == "&#x":
311  return unichr(int(text[3:-1], 16))
312  else:
313  return unichr(int(text[2:-1]))
314  except ValueError:
315  pass
316  elif text[:1] == "&":
317  import htmlentitydefs
318  entity = htmlentitydefs.entitydefs.get(text[1:-1])
319  if entity:
320  if entity[:2] == "&#":
321  try:
322  return unichr(int(entity[2:-1]))
323  except ValueError:
324  pass
325  else:
326  return unicode(entity, "iso-8859-1")
327  return text # leave as is
328  return self.common.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.common.textUtf8(text)))
329  # end massageDescription()
330 
331  def _initLogger(self):
332  """Setups a logger using the logging module, returns a log object
333  """
334  logger = logging.getLogger(self.log_name)
335  formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
336 
337  hdlr = logging.StreamHandler(sys.stdout)
338 
339  hdlr.setFormatter(formatter)
340  logger.addHandler(hdlr)
341 
342  if self.config['debug_enabled']:
343  logger.setLevel(logging.DEBUG)
344  else:
345  logger.setLevel(logging.WARNING)
346  return logger
347  #end initLogger
348 
349  def setTreeViewIcon(self, dir_icon=None):
350  '''Check if there is a specific generic tree view icon. If not default to the channel icon.
351  return self.tree_dir_icon
352  '''
354  if not dir_icon:
355  if not self.feed_icons.has_key(self.tree_key):
356  return self.tree_dir_icon
357  dir_icon = self.feed_icons[self.tree_key]
358  if not dir_icon:
359  return self.tree_dir_icon
360  self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, )
361  return self.tree_dir_icon
362  # end setTreeViewIcon()
363 
364 
369 
370 
371  def searchTitle(self, title, pagenumber, pagelen):
372  '''Key word video search of the YouTube web site
373  return an array of matching item dictionaries
374  return
375  '''
376  # Special case where the grabber has been executed without any page
377  # argument
378  if 1 == pagenumber:
379  pagenumber = ""
380 
381  result = self.getSearchResults(title, pagenumber, pagelen)
382  if not result:
383  raise YouTubeVideoNotFound(u"No YouTube Video matches found for search value (%s)" % title)
384 
385  self.channel['channel_numresults'] = int(result['pageInfo']['totalResults'])
386  if 'nextPageToken' in result:
387  self.channel['nextpagetoken'] = result['nextPageToken']
388  if 'prevPageToken' in result:
389  self.channel['prevpagetoken'] = result['prevPageToken']
390 
391  ids = map(lambda entry: entry['id']['videoId'], result['items'])
392 
393  result = self.getVideoDetails(ids)
394  data = map(lambda entry: self.parseDetails(entry), result['items'])
395 
396  if not len(data):
397  raise YouTubeVideoNotFound(u"No YouTube Video matches found for search value (%s)" % title)
398 
399  return data
400  # end searchTitle()
401 
402  def getSearchResults(self, title, pagenumber, pagelen):
403  url = ('https://www.googleapis.com/youtube/v3/search?part=snippet&' + \
404  'type=video&q=%s&maxResults=%s&order=relevance&' + \
405  'videoEmbeddable=true&key=%s&pageToken=%s') % \
406  (urllib.quote_plus(title.encode("utf-8")), pagelen, self.apikey,
407  pagenumber)
408  if self.config['debug_enabled']:
409  print url
410  print
411 
412  try:
413  return JsonHandler(url).getJson()
414  except Exception, errormsg:
415  raise YouTubeUrlError(self.error_messages['YouTubeUrlError'] % (url, errormsg))
416 
417  def getVideoDetails(self, ids):
418  url = 'https://www.googleapis.com/youtube/v3/videos?part=id,snippet,' + \
419  'contentDetails&key=%s&id=%s' % (self.apikey, ",".join(ids))
420  try:
421  return JsonHandler(url).getJson()
422  except Exception as errormsg:
423  raise YouTubeUrlError(self.error_messages['YouTubeUrlError'] % (url, errormsg))
424 
425  def parseDetails(self, entry):
426  item = {}
427  try:
428  item['id'] = entry['id']
429  item['video'] = \
430  self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/youtube.html", \
431  item['id'])
432  item['link'] = item['video']
433  snippet = entry['snippet']
434  item['title'] = snippet['title']
435  item['media_description'] = snippet['description']
436  item['thumbnail'] = snippet['thumbnails']['high']['url']
437  item['author'] = snippet['channelTitle']
438  item['published_parsed'] = snippet['publishedAt']
439 
440  try:
441  duration = aniso8601.parse_duration(entry['contentDetails']['duration'])
442  item['duration'] = duration.days * 24 * 3600 + duration.seconds
443  except Exception:
444  pass
445 
446  for key in item.keys():
447  # Make sure there are no item elements that are None
448  if item[key] is None:
449  item[key] = u''
450  elif key == 'published_parsed': # 2010-01-23T08:38:39.000Z
451  if item[key]:
452  pub_time = time.strptime(item[key].strip(), "%Y-%m-%dT%H:%M:%S.%fZ")
453  item[key] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', pub_time)
454  elif key == 'media_description' or key == 'title':
455  # Strip the HTML tags
456  if item[key]:
457  item[key] = self.massageDescription(item[key].strip())
458  item[key] = item[key].replace(u'|', u'-')
459  elif type(item[key]) == type(u''):
460  if item[key]:
461  item[key] = self.common.ampReplace(item[key].replace('"\n',' ').strip())
462  except KeyError:
463  pass
464 
465  return item
466 
467  def searchForVideos(self, title, pagenumber):
468  """Common name for a video search. Used to interface with MythTV plugin NetVision
469  """
470  # Channel details and search results
471  self.channel = {
472  'channel_title': u'YouTube',
473  'channel_link': u'http://www.youtube.com/',
474  'channel_description': u"Share your videos with friends, family, and the world.",
475  'channel_numresults': 0,
476  'channel_returned': 1,
477  'channel_startindex': 0}
478 
479  # Easier for debugging
480 # print self.searchTitle(title, pagenumber, self.page_limit)
481 # print
482 # sys.exit()
483 
484  try:
485  data = self.searchTitle(title, pagenumber, self.page_limit)
486  except YouTubeVideoNotFound, msg:
487  sys.stderr.write(u"%s\n" % msg)
488  return None
489  except YouTubeUrlError, msg:
490  sys.stderr.write(u'%s\n' % msg)
491  sys.exit(1)
492  except YouTubeHttpError, msg:
493  sys.stderr.write(self.error_messages['YouTubeHttpError'] % msg)
494  sys.exit(1)
495  except YouTubeRssError, msg:
496  sys.stderr.write(self.error_messages['YouTubeRssError'] % msg)
497  sys.exit(1)
498  except Exception, e:
499  sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e))
500  sys.exit(1)
501 
502  if data is None:
503  return None
504  if not len(data):
505  return None
506 
507  items = map(lambda match: self.translateItem(match), data)
508  self.channel['channel_returned'] = len(items)
509 
510  if len(items):
511  return [[self.channel, items]]
512  return None
513  # end searchForVideos()
514 
515  def translateItem(self, item):
516  item_data = {}
517  for key in self.key_translation[1].keys():
518  if key in item.keys():
519  item_data[self.key_translation[1][key]] = item[key]
520  else:
521  item_data[self.key_translation[1][key]] = u''
522  return item_data
523 
524  def displayTreeView(self):
525  '''Gather the Youtube categories/feeds/...etc then get a max page of videos meta data in each of them
526  return array of directories and their video metadata
527  '''
528  # Channel details and search results
529  self.channel = {
530  'channel_title': u'YouTube',
531  'channel_link': u'http://www.youtube.com/',
532  'channel_description': u"Share your videos with friends, family, and the world.",
533  'channel_numresults': 0,
534  'channel_returned': 1,
535  'channel_startindex': 0}
536 
537  etree = self.getVideoCategories()
538  if etree is None:
539  raise YouTubeCategoryNotFound(u"No YouTube Categories found for Tree view")
540 
541  feed_names = {}
542  for category in etree['items']:
543  snippet = category['snippet']
544  feed_names[snippet['title']] = self.common.ampReplace(category['id'])
545 
546  # Get videos within each category
547  dictionaries = []
548 
549  # Process the various video feeds/categories/... etc
550  for category in feed_names:
551  self.tree_key = category
552  dictionaries = self.getVideosForCategory(feed_names[category], dictionaries)
553 
554  return [[self.channel, dictionaries]]
555  # end displayTreeView()
556 
558  try:
559  url = 'https://www.googleapis.com/youtube/v3/videoCategories?' + \
560  'part=snippet&regionCode=%s&key=%s' % \
561  (self.config['region'], self.apikey)
562  return JsonHandler(url).getJson()
563  except Exception as errormsg:
564  raise YouTubeUrlError(self.error_messages['YouTubeUrlError'] % (url, errormsg))
565 
566  def getVideosForCategory(self, categoryId, dictionaries):
567  '''Parse a list made of category lists and retrieve video meta data
568  return a dictionary of directory names and categories video metadata
569  '''
570  url = 'https://www.googleapis.com/youtube/v3/videos?part=snippet&' + \
571  'chart=mostPopular&videoCategoryId=%s&maxResults=%s&key=%s' % \
572  (categoryId, self.page_limit, self.apikey)
573  temp_dictionary = []
574  temp_dictionary = self.getVideosForURL(url, temp_dictionary)
575  for element in temp_dictionary:
576  dictionaries.append(element)
577  return dictionaries
578  # end getVideosForCategory()
579 
580  def getVideosForURL(self, url, dictionaries):
581  '''Get the video metadata for url search
582  return the video dictionary of directories and their video mata data
583  '''
584  initial_length = len(dictionaries)
585 
586  if self.config['debug_enabled']:
587  print "Category URL:"
588  print url
589  print
590 
591  try:
592  result = JsonHandler(url).getJson()
593  except Exception, errormsg:
594  sys.stderr.write(self.error_messages['YouTubeUrlError'] % (url, errormsg))
595  return dictionaries
596 
597  if result is None:
598  sys.stderr.write(u'1-No Videos for (%s)\n' % self.feed)
599  return dictionaries
600 
601  if 'pageInfo' not in result or 'items' not in result:
602  return dictionaries
603 
604  dictionary_first = False
605  self.channel['channel_numresults'] += int(result['pageInfo']['totalResults'])
606  self.channel['channel_startindex'] = self.page_limit
607  self.channel['channel_returned'] = len(result['items'])
608  for entry in result['items']:
609  item = self.parseDetails(entry)
610 
611  if not dictionary_first: # Add the dictionaries display name
612  dictionaries.append([self.massageDescription(self.tree_key),
613  self.setTreeViewIcon()])
614  dictionary_first = True
615 
616  dictionaries.append(self.translateItem(item))
617 
618  if initial_length < len(dictionaries): # Need to check if there was any items for this Category
619  dictionaries.append(['', u'']) # Add the nested dictionary indicator
620  return dictionaries
621  # end getVideosForURL()
622 # end Videos() class
nv_python_libs.youtube.youtube_api.Videos.displayTreeView
def displayTreeView(self)
Definition: youtube_api.py:524
nv_python_libs.youtube.youtube_exceptions.YouTubeHttpError
Definition: youtube_exceptions.py:30
nv_python_libs.youtube.youtube_api.Videos.searchTitle
def searchTitle(self, title, pagenumber, pagelen)
End of Utility functions.
Definition: youtube_api.py:371
nv_python_libs.youtube.youtube_api.Videos.mythxml
mythxml
Definition: youtube_api.py:112
nv_python_libs.youtube.youtube_api.Videos.translateItem
def translateItem(self, item)
Definition: youtube_api.py:515
nv_python_libs.youtube.youtube_api.Videos.massageDescription
def massageDescription(self, text)
Definition: youtube_api.py:298
nv_python_libs.youtube.youtube_api.Videos.apikey
apikey
Definition: youtube_api.py:170
nv_python_libs.youtube.youtube_api.Videos._initLogger
def _initLogger(self)
Definition: youtube_api.py:331
nv_python_libs.youtube.youtube_api.Videos.common
common
Definition: youtube_api.py:111
nv_python_libs.youtube.youtube_api.JsonHandler.url
url
Definition: youtube_api.py:60
nv_python_libs.youtube.youtube_api.Videos.getVideoDetails
def getVideoDetails(self, ids)
Definition: youtube_api.py:417
nv_python_libs.youtube.youtube_api.Videos.tree_dir_icon
tree_dir_icon
Definition: youtube_api.py:353
nv_python_libs.youtube.youtube_api.Videos.userPrefs
userPrefs
Definition: youtube_api.py:228
nv_python_libs.youtube.youtube_api.Videos.getSearchResults
def getSearchResults(self, title, pagenumber, pagelen)
Definition: youtube_api.py:402
nv_python_libs.youtube.youtube_api.Videos.feed_icons
feed_icons
Definition: youtube_api.py:176
nv_python_libs.youtube.youtube_api.JsonHandler.__init__
def __init__(self, url)
Definition: youtube_api.py:59
nv_python_libs.youtube.youtube_api.Videos.getUserPreferences
def getUserPreferences(self, userPreferenceFilePath)
Definition: youtube_api.py:207
nv_python_libs.youtube.youtube_api.Videos.setTreeViewIcon
def setTreeViewIcon(self, dir_icon=None)
Definition: youtube_api.py:349
nv_python_libs.youtube.youtube_data.getData
Definition: youtube_data.py:5
nv_python_libs.youtube.youtube_api.Videos.error_messages
error_messages
Definition: youtube_api.py:127
nv_python_libs.youtube.youtube_api.Videos.config
config
Definition: youtube_api.py:110
nv_python_libs.youtube.youtube_exceptions.YouTubeUrlError
Definition: youtube_exceptions.py:25
nv_python_libs.youtube.youtube_api.Videos.parseDetails
def parseDetails(self, entry)
Definition: youtube_api.py:425
nv_python_libs.youtube.youtube_api.Videos.searchForVideos
def searchForVideos(self, title, pagenumber)
Definition: youtube_api.py:467
nv_python_libs.youtube.youtube_exceptions.YouTubeVideoNotFound
Definition: youtube_exceptions.py:40
nv_python_libs.youtube.youtube_api.Videos.channel
channel
Definition: youtube_api.py:471
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.youtube.youtube_api.Videos.channel_icon
channel_icon
Definition: youtube_api.py:195
nv_python_libs.youtube.youtube_api.Videos.log
log
Definition: youtube_api.py:117
musicbrainzngs.compat.unicode
unicode
Definition: compat.py:50
nv_python_libs.youtube.youtube_api.JsonHandler.getJson
def getJson(self)
Definition: youtube_api.py:62
nv_python_libs.youtube.youtube_api.Videos.treeview
treeview
Definition: youtube_api.py:194
nv_python_libs.youtube.youtube_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: youtube_api.py:77
nv_python_libs.youtube.youtube_api.Videos.detectUserLocationByIP
def detectUserLocationByIP(self)
Start - Utility functions.
Definition: youtube_api.py:238
nv_python_libs.youtube.youtube_api.JsonHandler
Definition: youtube_api.py:56
nv_python_libs.youtube.youtube_api.Videos.tree_key
tree_key
Definition: youtube_api.py:551
nv_python_libs.youtube.youtube_api.Videos.getVideosForCategory
def getVideosForCategory(self, categoryId, dictionaries)
Definition: youtube_api.py:566
nv_python_libs.youtube.youtube_api.Videos.log_name
log_name
Definition: youtube_api.py:116
nv_python_libs.youtube.youtube_api.Videos.getVideoCategories
def getVideoCategories(self)
Definition: youtube_api.py:557
nv_python_libs.youtube.youtube_api.Videos.getVideosForURL
def getVideosForURL(self, url, dictionaries)
Definition: youtube_api.py:580
nv_python_libs.youtube.youtube_api.Videos.key_translation
key_translation
Definition: youtube_api.py:135
nv_python_libs.youtube.youtube_exceptions.YouTubeCategoryNotFound
Definition: youtube_exceptions.py:60
nv_python_libs.youtube.youtube_api.Videos
Definition: youtube_api.py:70
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:356