MythTV  master
dailymotion_api.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 # ----------------------
4 # Name: dailymotion_api - Simple-to-use Python interface to the dailymotion API (http://www.dailymotion.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 # meta data, video and image URLs from dailymotion.
9 # These routines are based on the api. Specifications
10 # for this api are published at http://www.dailymotion.com/ca-en/doc/api/player
11 #
12 # License:Creative Commons GNU GPL v2
13 # (http://creativecommons.org/licenses/GPL/2.0/)
14 #-------------------------------------
15 __title__ ="dailymotion_api - Simple-to-use Python interface to the dailymotion API (http://www.dailymotion.com/ca-en/doc/api/player)"
16 __author__="R.D. Vaughan"
17 __purpose__='''
18 This python script is intended to perform a variety of utility functions to search and access text
19 meta data, video and image URLs from dailymotion. These routines are based on the api. Specifications
20 for this api are published at http://www.dailymotion.com/ca-en/doc/api/player
21 '''
22 
23 __version__="v0.2.4"
24 # 0.1.0 Initial development
25 # 0.1.1 Added getting local directory images
26 # 0.1.2 Documentation update
27 # 0.2.0 Public release
28 # 0.2.1 New python bindings conversion
29 # Better exception error reporting
30 # Better handling of invalid unicode data from source
31 # 0.2.2 Completed abort exception display message improvements
32 # Removed unused import of the feedparser library
33 # 0.2.3 Fixed an exception message output code error in two places
34 # 0.2.4 Removed the need for python MythTV bindings and added "%SHAREDIR%" to icon directory path
35 
36 
37 import os, struct, sys, re, time
38 import urllib, urllib2
39 import logging
40 from MythTV import MythXML
41 
42 try:
43  import xml.etree.cElementTree as ElementTree
44 except ImportError:
45  import xml.etree.ElementTree as ElementTree
46 
47 from dailymotion_exceptions import (DailymotionUrlError, DailymotionHttpError, DailymotionRssError, DailymotionVideoNotFound, DailymotionInvalidSearchType, DailymotionXmlError, DailymotionVideoDetailError, DailymotionCategoryNotFound)
48 
49 class OutStreamEncoder(object):
50  """Wraps a stream with an encoder"""
51  def __init__(self, outstream, encoding=None):
52  self.out = outstream
53  if not encoding:
54  self.encoding = sys.getfilesystemencoding()
55  else:
56  self.encoding = encoding
57 
58  def write(self, obj):
59  """Wraps the output stream, encoding Unicode strings with the specified encoding"""
60  if isinstance(obj, unicode):
61  try:
62  self.out.write(obj.encode(self.encoding))
63  except IOError:
64  pass
65  else:
66  try:
67  self.out.write(obj)
68  except IOError:
69  pass
70 
71  def __getattr__(self, attr):
72  """Delegate everything but write to the stream"""
73  return getattr(self.out, attr)
74 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
75 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
76 
77 
78 class XmlHandler:
79  """Deals with retrieval of XML files from API
80  """
81  def __init__(self, url):
82  self.url = url
83 
84  def _grabUrl(self, url):
85  try:
86  urlhandle = urllib.urlopen(url)
87  except IOError, errormsg:
88  raise DailymotionHttpError(errormsg)
89  return urlhandle.read()
90 
91  def getEt(self):
92  xml = self._grabUrl(self.url)
93  try:
94  et = ElementTree.fromstring(xml)
95  except SyntaxError, errormsg:
96  raise DailymotionXmlError(errormsg)
97  return et
98 
99 
100 class Videos(object):
101  """Main interface to http://www.dailymotion.com
102  This is done to support a common naming framework for all python Netvision plugins no matter their site
103  target.
104 
105  Supports search and tree view methods
106  The apikey is a not required to access http://www.dailymotion.com
107  """
108  def __init__(self,
109  apikey,
110  mythtv = True,
111  interactive = False,
112  select_first = False,
113  debug = False,
114  custom_ui = None,
115  language = None,
116  search_all_languages = False,
117  ):
118  """apikey (str/unicode):
119  Specify the target site API key. Applications need their own key in some cases
120 
121  mythtv (True/False):
122  When True, the returned meta data is being returned has the key and values massaged to match MythTV
123  When False, the returned meta data is being returned matches what target site returned
124 
125  interactive (True/False): (This option is not supported by all target site apis)
126  When True, uses built-in console UI is used to select the correct show.
127  When False, the first search result is used.
128 
129  select_first (True/False): (This option is not supported currently implemented in any grabbers)
130  Automatically selects the first series search result (rather
131  than showing the user a list of more than one series).
132  Is overridden by interactive = False, or specifying a custom_ui
133 
134  debug (True/False):
135  shows verbose debugging information
136 
137  custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers)
138  A callable subclass of interactive class (overrides interactive option)
139 
140  language (2 character language abbreviation): (This option is not supported by all target site apis)
141  The language of the returned data. Is also the language search
142  uses. Default is "en" (English). For full list, run..
143 
144  search_all_languages (True/False): (This option is not supported by all target site apis)
145  By default, a Netvision grabber will only search in the language specified using
146  the language option. When this is True, it will search for the
147  show in any language
148 
149  """
150  self.config = {}
151  self.mythxml = MythXML()
153  if apikey is not None:
154  self.config['apikey'] = apikey
155  else:
156  pass # Dailymotion does not require an apikey
157 
158  self.config['debug_enabled'] = debug # show debugging messages
159 
160  self.log_name = "Dailymotion"
161  self.log = self._initLogger() # Setups the logger (self.log.debug() etc)
163  self.config['custom_ui'] = custom_ui
164 
165  self.config['interactive'] = interactive # prompt for correct series?
166 
167  self.config['select_first'] = select_first
168 
169  self.config['search_all_languages'] = search_all_languages
170 
171  self.error_messages = {'DailymotionUrlError': u"! Error: The URL (%s) cause the exception error (%s)\n", 'DailymotionHttpError': u"! Error: An HTTP communicating error with Dailymotion was raised (%s)\n", 'DailymotionRssError': u"! Error: Invalid RSS meta data\nwas received from Dailymotion error (%s). Skipping item.\n", 'DailymotionVideoNotFound': u"! Error: Video search with Dailymotion did not return any results (%s)\n", 'DailymotionVideoDetailError': u"! Error: Invalid Video meta data detail\nwas received from Dailymotion error (%s). Skipping item.\n", }
172 
173  # This is an example that must be customized for each target site
174  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', 'author': 'item_author', 'published_parsed': 'item_pubdate', 'media_description': 'item_description', 'video': 'item_link', 'thumbnail': 'item_thumbnail', 'link': 'item_url', 'duration': 'item_duration', 'rating': 'item_rating', 'item_width': 'item_width', 'item_height': 'item_height', 'language': 'item_lang'}]
175 
176  # Defaulting to English 'en'
177  if language:
178  self.config['language'] = language
179  else:
180  self.config['language'] = u'en'
181 
182 
183  self.config[u'urls'] = {}
184 
185  # v2 api calls - An example that must be customized for each target site
186  self.config[u'urls'][u'video.search'] = 'http://www.dailymotion.com/rss/relevance/search/%s/%s'
187  self.config[u'urls'][u'group.search'] = 'http://www.dailymotion.com/rss/groups/relevance/search/%s/%s'
188  self.config[u'urls'][u'user.search'] = 'http://www.dailymotion.com/rss/users/relevance/search/%s/%s'
189 
190  # Functions that parse video data from RSS data
191  self.config['item_parser'] = {}
192  self.config['item_parser']['main'] = self.getVideosForURL
193  self.config['item_parser']['groups'] = self.getVideosForGroupURL
194 
195  # Tree view url and the function that parses that urls meta data
196  self.config[u'urls'][u'tree.view'] = {
197  'F_M_B_C': {
198  'featured': ['http://www.dailymotion.com/rss/us/relevance/%s/search/movie/1', 'main'],
199  'creative': ['http://www.dailymotion.com/rss/us/relevance/%s/search/movie/1', 'main'],
200  'official': ['http://www.dailymotion.com/rss/us/%s/search/movie/1', 'main'],
201  'hd': ['http://www.dailymotion.com/rss/relevance/%s/search/movie/1', 'main'],
202  'commented': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
203  'visited': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
204  'rated': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
205  'relevance-month': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
206  'relevance-week': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
207  'relevance-today': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'],
208  },
209  'categories': {
210  'movie': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'],
211  'comedy': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'],
212  'short+film': ['http://www.dailymotion.com/rss/creative/relevance/search/%s', 'main'],
213  'television': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'],
214  'documentary': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'],
215  'festival': ['http://www.dailymotion.com/rss/creative/relevance/search/%s', 'main'],
216  },
217  'channels': {
218  'animals_motionmaker': ['http://www.dailymotion.com/rss/creative/lang/en/channel/animals/1', 'main'],
219  'animals_most_recent': ['http://www.dailymotion.com/rss/lang/en/channel/animals/1', 'main'],
220  'animals_hd': ['http://www.dailymotion.com/rss/hd/channel/animals/1', 'main'],
221  'animals_official_users': ['http://www.dailymotion.com/rss/official/lang/en/channel/animals/1', 'main'],
222  'animals_most_viewed': ['http://www.dailymotion.com/rss/visited/lang/en/channel/animals/1', 'main'],
223  'animals_best_rated': ['http://www.dailymotion.com/rss/rated/lang/en/channel/animals/1', 'main'],
224 
225  'auto_most_recent': ['http://www.dailymotion.com/rss/lang/en/channel/auto/1', 'main'],
226  'auto_motionmaker': ['http://www.dailymotion.com/rss/creative/channel/auto/1', 'main'],
227  'auto_most_viewed': ['http://www.dailymotion.com/rss/visited/lang/en/channel/auto/1', 'main'],
228  'auto_official_users': ['http://www.dailymotion.com/rss/official/channel/auto/1', 'main'],
229 
230  'film_TV_movie': ['http://www.dailymotion.com/rss/us/relevance/official/search/movie', 'main'],
231  'film_TV_comedy': ['http://www.dailymotion.com/rss/us/relevance/official/search/comedy', 'main'],
232  'film_TV_short_film': ['http://www.dailymotion.com/rss/creative/relevance/search/short+film', 'main'],
233  'film_TV_television': ['http://www.dailymotion.com/rss/us/relevance/official/search/television', 'main'],
234  'film_TV_documentary': ['http://www.dailymotion.com/rss/us/relevance/official/search/documentary', 'main'],
235  'film_TV_festival': ['http://www.dailymotion.com/rss/official/relevance/search/festival', 'main'],
236 
237  'gaming_Trailer': ['http://www.dailymotion.com/rss/official/search/videogames+trailer/1', 'main'],
238  'gaming_Lego': ['http://www.dailymotion.com/rss/relevance/search/lego', 'main'],
239  'gaming_Machinima': ['http://www.dailymotion.com/rss/relevance/creative/search/machinima/1', 'main'],
240  'gaming_Motionmaker': ['http://www.dailymotion.com/rss/us/creative/channel/videogames/1', 'main'],
241  'gaming_Review': ['http://www.dailymotion.com/rss/official/search/videogames+review/1', 'main'],
242  'gaming_News': ['http://www.dailymotion.com/rss/official/search/videogames+news/1', 'main'],
243  'gaming_recent': ['http://www.dailymotion.com/rss/us/channel/videogames/lang/en/1', 'main'],
244  'gaming_users': ['http://www.dailymotion.com/rss/us/official/channel/videogames/1', 'main'],
245 
246  'lifestyle_best_rated': ['http://www.dailymotion.com/rss/rated/lang/en/channel/lifestyle/1', 'main'],
247  'lifestyle_most_commented': ['http://www.dailymotion.com/rss/commented/lang/en/channel/lifestyle/1', 'main'],
248  'lifestyle_most_viewed': ['http://www.dailymotion.com/rss/viewed/lang/en/channel/lifestyle/1', 'main'],
249  'lifestyle_HD': ['http://www.dailymotion.com/rss/hd/lang/en/channel/lifestyle/1', 'main'],
250 
251  'news_politics_Politics': ['http://www.dailymotion.com/rss/official/relevance/search/politics', 'main'],
252  'news_politics_Celebrity': ['http://www.dailymotion.com/rss/official/relevance/search/celeb+news', 'main'],
253  'news_politics_official_users': ['http://www.dailymotion.com/rss/official/search/news/1', 'main'],
254  'news_politics_International': ['http://www.dailymotion.com/rss/official/search/international+news/1', 'main'],
255  'news_politics_Entertainment': ['http://www.dailymotion.com/rss/official/search/entertainment+news/1', 'main'],
256  'news_politics_Motionmakers': ['http://www.dailymotion.com/rss/relevance/creative/search/news/1', 'main'],
257 
258  'sports_extreme_surf': ['http://www.dailymotion.com/rss/relevance/official/search/surf/1', 'main'],
259  'sports_extreme_baseball': ['http://www.dailymotion.com/rss/relevance/official/search/baseball', 'main'],
260  'sports_extreme_wrestling': ['http://www.dailymotion.com/rss/relevance/official/search/wrestling/1', 'main'],
261  'sports_extreme_BMX': ['http://www.dailymotion.com/rss/relevance/official/search/BMX/1', 'main'],
262 
263  'webcam_vlogs_Most_viewed': ['http://www.dailymotion.com/rss/visited/channel/webcam/lang/en/1', 'main'],
264  'webcam_vlogs_Featured_videos': ['http://www.dailymotion.com/rss/us/featured/channel/webcam/1', 'main'],
265  'webcam_vlogs_Best_rated': ['http://www.dailymotion.com/rss/rated/channel/webcam/lang/en/1', 'main'],
266  'webcam_vlogs_Most_Commented': ['http://www.dailymotion.com/rss/commented/channel/webcam/lang/en/1', 'main'],
267 
268  'arts_Animation': ['http://www.dailymotion.com/rss/relevance/creative-official/search/animation', 'main'],
269  'arts_Short_Film': ['http://www.dailymotion.com/rss/us/relevance/creative/search/shortfilm', 'main'],
270  'arts_Motionmaker': ['http://www.dailymotion.com/rss/creative-official/lang/en/1', 'main'],
271  'arts_Official_Users': ['http://www.dailymotion.com/rss/official/channel/creation/lang/en/1', 'main'],
272  'arts_Suede_swede': ['http://www.dailymotion.com/rss/relevance/creative/search/suede', 'main'],
273  'arts_Most_recent': ['http://www.dailymotion.com/rss/channel/creation/lang/en/1', 'main'],
274 
275  'college_Most_viewed': ['http://www.dailymotion.com/rss/visited/channel/school/lang/en/1', 'main'],
276  'college_HD_videos': ['http://www.dailymotion.com/rss/hd/channel/school/1', 'main'],
277  'college_Best_rated': ['http://www.dailymotion.com/rss/rated/channel/school/lang/en/1', 'main'],
278  'college_Most_commented': ['http://www.dailymotion.com/rss/channel/school/lang/en/1', 'main'],
279 
280  'funny_STAND UP': ['http://www.dailymotion.com/rss/official/relevance/search/standup', 'main'],
281  'funny_Hulu: NBC & Fox': ['http://www.dailymotion.com/rss/hulu/1', 'main'],
282  'funny_My Damn Channel': ['http://www.dailymotion.com/rss/mydamnchannel/1', 'main'],
283  'funny_Motionmakers': ['http://www.dailymotion.com/rss/us/creative/search/comedy/1', 'main'],
284  'funny_Sketch': ['http://www.dailymotion.com/rss/official/relevance/search/sketch', 'main'],
285  "funny_Nat'l Lampoon": ['http://www.dailymotion.com/rss/nationallampoon/1', 'main'],
286  'funny_Classic Sitcoms': ['http://www.dailymotion.com/rss/Classic_WB_TV/1', 'main'],
287  'funny_Official Users': ['http://www.dailymotion.com/rss/us/official/search/comedy/1', 'main'],
288 
289  'latino_Featured Videos': ['http://www.dailymotion.com/rss/featured/channel/latino/1', 'main'],
290  'latino_HD content': ['http://www.dailymotion.com/rss/hd/channel/latino/1', 'main'],
291  'latino_Official Content': ['http://www.dailymotion.com/rss/official/channel/latino/1', 'main'],
292  'latino_Creative Content': ['http://www.dailymotion.com/rss/creative/channel/latino/1', 'main'],
293  'latino_Most Commented': ['http://www.dailymotion.com/rss/commented-week/featured/channel/latino/1', 'main'],
294  'latino_Most Viewed': ['http://www.dailymotion.com/rss/visited-week/featured/channel/latino/1', 'main'],
295  'latino_Best Rated': ['http://www.dailymotion.com/rss/rated-week/featured/channel/latino/1', 'main'],
296 
297  'music_Pop': ['http://www.dailymotion.com/rss/official/relevance/search/pop', 'main'],
298  'music_Rock': ['http://www.dailymotion.com/rss/relevance/official/search/Rock+Music+Videos/1', 'main'],
299  'music_Jazz': ['http://www.dailymotion.com/rss/channel/music/official/relevance/search/jazz', 'main'],
300  'music_Covers': ['http://www.dailymotion.com/rss/channel/us/channel/music/relevance/creative/search/cover/1', 'main'],
301  'music_Rap': ['http://www.dailymotion.com/rss/official/relevance/search/rap', 'main'],
302  'music_R&B': ['http://www.dailymotion.com/rss/us/channel/music/relevance/search/rnb', 'main'],
303  'music_Metal': ['http://www.dailymotion.com/rss/channel/us/channel/music/official/relevance/search/metal', 'main'],
304  'music_Electro': ['http://www.dailymotion.com/rss/channel/music/official/relevance/search/electro', 'main'],
305 
306  'People_Family_Featured Videos': ['http://www.dailymotion.com/rss/featured/channel/people/1', 'main'],
307  'People_Family_HD content': ['http://www.dailymotion.com/rss/hd/channel/people/1', 'main'],
308  'People_Family_Official Content': ['http://www.dailymotion.com/rss/official/channel/people/1', 'main'],
309  'People_Family_Creative Content': ['http://www.dailymotion.com/rss/creative/channel/people/1', 'main'],
310  'People_Family_Most Commented': ['http://www.dailymotion.com/rss/commented-week/featured/channel/people/1', 'main'],
311  'People_Family_Most Viewed': ['http://www.dailymotion.com/rss/visited-week/featured/channel/people/1', 'main'],
312  'People_Family_Best Rated': ['http://www.dailymotion.com/rss/rated-week/featured/channel/people/1', 'main'],
313 
314  'Tech_Science_Most recent': ['http://www.dailymotion.com/rss/channel/tech/1', 'main'],
315  'Tech_Science_Most viewed': ['http://www.dailymotion.com/rss/visited/channel/tech/1', 'main'],
316  'Tech_Science_Most commented': ['http://www.dailymotion.com/rss/commented/channel/tech/1', 'main'],
317  'Tech_Science_Best rated': ['http://www.dailymotion.com/rss/rated/channel/tech/1', 'main'],
318 
319 # 'Travel_Most recent': ['', 'main'],
320 # 'Travel_Most commented': ['', 'main'],
321 # 'Travel_Best rated ': ['', 'main'],
322 
323  },
324 
325  'groups': {
326  'F_M_B_C_Featured': ['http://www.dailymotion.com/rss/groups/featured', 'groups'],
327  'F_M_B_C_Most Recent': ['http://www.dailymotion.com/rss/groups/1', 'groups'],
328  'F_M_B_C_Most Active': ['http://www.dailymotion.com/rss/groups/active', 'groups'],
329  'F_M_B_C_Month': ['http://www.dailymotion.com/rss/groups/active-month', 'groups'],
330  'F_M_B_C_Week': ['http://www.dailymotion.com/rss/groups/active-week', 'groups'],
331  'F_M_B_C_Today': ['http://www.dailymotion.com/rss/groups/active-today', 'groups'],
332  },
333 
334  'group': {
335  'group_Top rated': ['http://www.dailymotion.com/rss/rated/group', 'main'],
336  'group_Most viewed': ['http://www.dailymotion.com/rss/visited/group', 'main'],
337  'group_Most commented': ['http://www.dailymotion.com/rss/commented/group', 'main'],
338  },
339 
340  }
341 
342  self.config[u'image_extentions'] = ["png", "jpg", "bmp"] # Acceptable image extentions
343 
344 
345  self.tree_order = ['F_M_B_C', 'categories', 'channels',]
346  #self.tree_order = ['F_M_B_C', 'categories', 'channels', 'groups']
347 
348  self.tree_org = {
349  'F_M_B_C': [['Featured/Most/Best/Current ...', ['featured', 'creative', 'official', 'hd', 'commented', 'visited', 'rated', 'relevance-month', 'relevance-week', 'relevance-today']],
350  ],
351  'categories': [
352  ['Categories', ['movie', 'comedy', 'short+film', 'television', 'documentary', 'festival', ]],
353  ],
354  'channels': [
355  ['Video Channels', u''],
356 
357  ['Animals', ['animals_motionmaker', 'animals_most_recent', 'animals_hd', 'animals_official_users', 'animals_most_viewed', 'animals_best_rated', ]],
358 
359  ['Auto-Moto', ['auto_most_recent', 'auto_motionmaker', 'auto_most_viewed', 'auto_official_users', ]],
360 
361  ['Film & TV', ['film_TV_movie', 'film_TV_comedy', 'film_TV_short_film', 'film_TV_television', 'film_TV_documentary', 'film_TV_festival', ]],
362 
363  ['Gaming', ['gaming_Trailer', 'gaming_Lego', 'gaming_Machinima', 'gaming_Motionmaker', 'gaming_Review', 'gaming_News', 'gaming_recent', 'gaming_users', ]],
364 
365  ['Life & Style', ['lifestyle_best_rated', 'lifestyle_most_commented', 'lifestyle_most_viewed', 'lifestyle_HD', ]],
366 
367  ['News & Politics', ['news_politics_Politics', 'news_politics_Celebrity', 'news_politics_official_users', 'news_politics_International', 'news_politics_Entertainment', 'news_politics_Motionmakers', ]],
368 
369  ['Sports & Extreme', ['sports_extreme_surf', 'sports_extreme_baseball', 'sports_extreme_wrestling', 'sports_extreme_BMX', ]],
370 
371  ['Webcam & Vlogs', ['webcam_vlogs_Most_viewed', 'webcam_vlogs_Featured_videos', 'webcam_vlogs_Best_rated', 'webcam_vlogs_Most_Commented', ]],
372 
373  ['Arts', ['arts_Animation', 'arts_Short_Film', 'arts_Motionmaker', 'arts_Official_Users', 'arts_Suede_swede', 'arts_Most_recent', ]],
374 
375  ['College', ['college_Most_viewed', 'college_HD_videos', 'college_Best_rated', 'college_Most_commented', ]],
376 
377  ['Funny', [u'funny_STAND UP', u'funny_Hulu: NBC & Fox', u'funny_My Damn Channel', u'funny_Motionmakers', u'funny_Sketch', u"funny_Nat'l Lampoon", u'funny_Classic Sitcoms', u'funny_Official Users', ]],
378 
379  ['Latino', [u'latino_Featured Videos', u'latino_HD content', u'latino_Official Content', u'latino_Creative Content', u'latino_Most Commented', u'latino_Most Viewed', u'latino_Best Rated', ]],
380 
381  ['Music', [u'music_Pop', u'music_Rock', u'music_Jazz', u'music_Covers', u'music_Rap', u'music_R&B', u'music_Metal', u'music_Electro', ]],
382 
383  ['People & Family', [u'People_Family_Featured Videos', u'People_Family_HD content', u'People_Family_Official Content', u'People_Family_Creative Content', u'People_Family_Most Commented', u'People_Family_Most Viewed', u'People_Family_Best Rated', ]],
384 
385  ['Tech & Science', [u'Tech_Science_Most recent', u'Tech_Science_Most viewed', u'Tech_Science_Most commented', u'Tech_Science_Best rated', ]],
386 
387  [u'', u''],
388  ],
389 
390  'groups': [
391  ['Groups', u''],
392 
393  [u'Featured', ['F_M_B_C_Featured']],
394  [u'Most Recent', ['F_M_B_C_Most Recent']],
395  [u'Most Active', ['F_M_B_C_Most Active']],
396  [u'Month', ['F_M_B_C_Month']],
397  [u'Week', ['F_M_B_C_Week']],
398  [u'Today', ['F_M_B_C_Today']],
399 
400  [u'', u''],
401  ],
402 
403  'group': [
404  [u'', ['group_Top rated', 'group_Most viewed', 'group_Most commented', ], ],
405  ],
406 
407  }
408 
409  self.tree_customize = {
410  'F_M_B_C': {
411  '__default__': { },
412  #'cat name': {},
413  },
414  'categories': {
415  '__default__': { },
416  #'cat name': {},
417  },
418  'channels': {
419  '__default__': { },
420  #'cat name': {},
421  },
422  'groups': {
423  '__default__': { },
424  #'cat name': {},
425  },
426  'group': {
427  '__default__': {'add_': u'' },
428  #'cat name': {},
429  },
430  }
431 
432  self.feed_names = {
433  'F_M_B_C': {'featured': 'Featured Videos', 'creative': 'Creative Content', 'official': 'Most Recent', 'hd': 'HD content', 'commented': 'Most Comments', 'visited': 'Most Viewed', 'rated': 'Highest Rated', 'relevance-month': 'Month', 'relevance-week': 'Week', 'relevance-today': 'Today'
434  },
435  'categories': {'movie': 'Trailers', 'comedy': 'Comedy', 'short+film': 'Short Films', 'television': 'TV Clips', 'documentary': 'Documentaries', 'festival': 'Festivals',
436  },
437  'channels': {
438  'animals_motionmaker': 'Motionmaker', 'animals_most_recent': 'Most recent', 'animals_hd': 'HD videos', 'animals_official_users': 'Official users', 'animals_most_viewed': 'Most Viewed', 'animals_best_rated': 'Highest Rated',
439 
440  'auto_most_recent': 'Most recent', 'auto_motionmaker': 'Motionmaker', 'auto_most_viewed': 'Most Viewed', 'auto_official_users': 'Official users',
441 
442  'film_TV_movie': 'Trailers', 'film_TV_comedy': 'Comedy', 'film_TV_short_film': 'Short Films', 'film_TV_television': 'TV Clips', 'film_TV_documentary': 'Documentaries', 'film_TV_festival': 'Festivals',
443 
444  'gaming_Trailer': 'Trailer', 'gaming_Lego': 'Lego fan film', 'gaming_Machinima': 'Machinima', 'gaming_Motionmaker': 'Motionmaker', 'gaming_Review': 'Review', 'gaming_News': 'News', 'gaming_recent': 'Most recent', 'gaming_users': 'Official users',
445 
446  'lifestyle_best_rated': 'Highest Rated', 'lifestyle_most_commented': 'Most Comments', 'lifestyle_most_viewed': 'Most Viewed', 'lifestyle_HD': 'HD videos',
447 
448  'news_politics_Politics': 'Politics', 'news_politics_Celebrity': 'Celebrity news', 'news_politics_official_users': 'Official users', 'news_politics_International': 'International', 'news_politics_Entertainment': 'Entertainment', 'news_politics_Motionmakers': 'Motionmakers',
449 
450  'sports_extreme_surf': 'Surf', 'sports_extreme_baseball': 'Baseball', 'sports_extreme_wrestling': 'Wrestling', 'sports_extreme_BMX': 'BMX',
451 
452  'webcam_vlogs_Most_viewed': 'Most viewed', 'webcam_vlogs_Featured_videos': 'Featured videos', 'webcam_vlogs_Best_rated': 'Highest Rated', 'webcam_vlogs_Most_Commented': 'Most Comments',
453 
454  'arts_Animation': 'Animation', 'arts_Short_Film': 'Short Films', 'arts_Motionmaker': 'Motionmaker', 'arts_Official_Users': 'Official Users', 'arts_Suede_swede': 'Suede/Swede', 'arts_Most_recent': 'Most recent',
455 
456  'college_Most_viewed': 'Most viewed', 'college_HD_videos': 'HD videos', 'college_Best_rated': 'Highest Rated', 'college_Most_commented': 'Most Comments',
457 
458  u'funny_STAND UP': 'STAND UP', u'funny_Hulu: NBC & Fox': 'Hulu: NBC & Fox', u'funny_My Damn Channel': 'My Damn Channel', u'funny_Motionmakers': 'Motionmakers', u'funny_Sketch': 'Sketch', u"funny_Nat'l Lampoon": "Nat'l Lampoon", u'funny_Classic Sitcoms': 'Classic Sitcoms', u'funny_Official Users': 'Official Users',
459 
460  u'latino_Featured Videos': u'Featured Videos', u'latino_HD content': u'HD content', u'latino_Official Content': u'Official Content', u'latino_Creative Content': u'Creative Content', u'latino_Most Commented': u'Most Comments', u'latino_Most Viewed': u'Most Viewed', u'latino_Best Rated': u'Highest Rated',
461 
462  u'music_Pop': u'Pop', u'music_Rock': u'Rock', u'music_Jazz': u'Jazz', u'music_Covers': u'Covers', u'music_Rap': u'Rap', u'music_R&B': u'R&B', u'music_Metal': u'Metal', u'music_Electro': u'Electro',
463 
464  u'People_Family_Featured Videos': u'Featured Videos', u'People_Family_HD content': u'HD content', u'People_Family_Official Content': u'Official Content', u'People_Family_Creative Content': u'Creative Content', u'People_Family_Most Commented': u'Most Comments', u'People_Family_Most Viewed': u'Most Viewed', u'People_Family_Best Rated': u'Highest Rated',
465 
466  u'Tech_Science_Most recent': u'Most recent', u'Tech_Science_Most viewed': u'Most viewed', u'Tech_Science_Most commented': u'Most Comments', u'Tech_Science_Best rated': u'Highest Rated',
467 
468  },
469  'groups': {
470  'F_M_B_C_Featured': u'Featured', 'F_M_B_C_Most Recent': u'Most Recent', 'F_M_B_C_Most Active': u'Most Active', 'F_M_B_C_Month': u'Month', 'F_M_B_C_Week': u'Week', 'F_M_B_C_Today': u'Today',
471 
472  },
473  'group': {
474  u'group_Top rated': u'Top rated', u'group_Most viewed': u'Most viewed', u'group_Most commented': u'Most Comments',
475 
476  },
477  }
478 
479  self.feed_icons = {
480  'F_M_B_C': {'featured': 'directories/topics/featured', 'creative': '', 'official': 'directories/topics/most_recent', 'hd': 'directories/topics/hd', 'commented': 'directories/topics/most_comments', 'visited': 'directories/topics/most_viewed', 'rated': 'directories/topics/rated', 'relevance-month': 'directories/topics/month', 'relevance-week': 'directories/topics/week', 'relevance-today': 'directories/topics/today'
481  },
482  'categories': {'movie': 'directories/film_genres/trailers', 'comedy': 'directories/film_genres/comedy', 'short+film': 'directories/film_genres/short_film', 'television': 'directories/topics/tv', 'documentary': 'directories/film_genres/documentaries', 'festival': 'directories/film_genres/film_festivals',
483  },
484  'channels': {
485  'animals_motionmaker': 'directories/topics/animals', 'animals_most_recent': 'directories/topics/most_recent', 'animals_hd': 'directories/topics/hd', 'animals_official_users': 'directories/topics/animals', 'animals_most_viewed': 'directories/topics/most_viewed', 'animals_best_rated': 'directories/topics/rated',
486 
487  'auto_most_recent': 'directories/topics/most_recent', 'auto_motionmaker': 'directories/topics/automotive', 'auto_most_viewed': 'directories/topics/most_viewed', 'auto_official_users': 'directories/topics/most_subscribed',
488 
489  'film_TV_movie': 'directories/film_genres/trailers', 'film_TV_comedy': 'directories/film_genres/comedy', 'film_TV_short_film': 'directories/film_genres/short_film', 'film_TV_television': 'directories/topics/tv', 'film_TV_documentary': 'directories/film_genres/documentaries', 'film_TV_festival': 'directories/film_genres/film_festivals',
490 
491  'gaming_Trailer': 'directories/film_genres/trailers', 'gaming_Lego': 'directories/topics/games', 'gaming_Machinima': 'directories/topics/games', 'gaming_Motionmaker': 'directories/topics/games', 'gaming_Review': 'directories/topics/games', 'gaming_News': 'directories/topics/news', 'gaming_recent': 'directories/topics/most_recent', 'gaming_users': 'directories/topics/most_comments',
492 
493  'lifestyle_best_rated': 'directories/topics/rated', 'lifestyle_most_commented': 'directories/topics/most_comments', 'lifestyle_most_viewed': 'directories/topics/most_viewed', 'lifestyle_HD': 'directories/topics/hd',
494 
495  'news_politics_Politics': 'directories/topics/news', 'news_politics_Celebrity': 'directories/topics/news', 'news_politics_official_users': 'directories/topics/news', 'news_politics_International': 'directories/topics/news', 'news_politics_Entertainment': 'directories/topics/entertainment', 'news_politics_Motionmakers': 'directories/topics/news',
496 
497  'sports_extreme_surf': 'directories/topics/sports', 'sports_extreme_baseball': 'directories/topics/sports', 'sports_extreme_wrestling': 'directories/topics/sports', 'sports_extreme_BMX': 'directories/topics/sports',
498 
499  'webcam_vlogs_Most_viewed': 'directories/topics/most_viewed', 'webcam_vlogs_Featured_videos': 'directories/topics/featured', 'webcam_vlogs_Best_rated': 'directories/topics/rated', 'webcam_vlogs_Most_Commented': 'directories/topics/most_comments',
500 
501  'arts_Animation': 'directories/film_genres/animation', 'arts_Short_Film': 'directories/film_genres/short_film', 'arts_Motionmaker': '', 'arts_Official_Users': '', 'arts_Suede_swede': '', 'arts_Most_recent': 'directories/topics/most_recent',
502 
503  'college_Most_viewed': 'directories/topics/most_viewed', 'college_HD_videos': 'directories/topics/hd', 'college_Best_rated': 'directories/topics/rated', 'college_Most_commented': 'directories/topics/most_comments',
504 
505  u'funny_STAND UP': 'directories/film_genres/comedy', u'funny_Hulu: NBC & Fox': 'directories/film_genres/comedy', u'funny_My Damn Channel': 'directories/film_genres/comedy', u'funny_Motionmakers': 'directories/film_genres/comedy', u'funny_Sketch': 'directories/film_genres/comedy', u"funny_Nat'l Lampoon": "directories/film_genres/comedy", u'funny_Classic Sitcoms': 'directories/film_genres/comedy', u'funny_Official Users': 'directories/film_genres/comedy',
506 
507  u'latino_Featured Videos': u'directories/topics/featured', u'latino_HD content': u'directories/topics/hd', u'latino_Official Content': u'directories/music_genres/latino', u'latino_Creative Content': u'directories/music_genres/latino', u'latino_Most Commented': u'directories/topics/most_comments', u'latino_Most Viewed': u'directories/topics/most_viewed', u'latino_Best Rated': u'directories/topics/rated',
508 
509  u'music_Pop': u'directories/music_genres/pop', u'music_Rock': u'directories/music_genres/rock', u'music_Jazz': u'directories/music_genres/jazz', u'music_Covers': u'directories/topics/music', u'music_Rap': u'directories/music_genres/hiphop', u'music_R&B': u'directories/music_genres/rnb', u'music_Metal': u'directories/music_genres/metal', u'music_Electro': u'directories/music_genres/electronic_dance',
510 
511  u'People_Family_Featured Videos': u'directories/topics/featured', u'People_Family_HD content': u'directories/topics/hd', u'People_Family_Official Content': u'directories/topics/people', u'People_Family_Creative Content': u'directories/topics/people', u'People_Family_Most Commented': u'directories/topics/most_comments', u'People_Family_Most Viewed': u'directories/topics/most_viewed', u'People_Family_Best Rated': u'directories/topics/rated',
512 
513  u'Tech_Science_Most recent': u'directories/topics/recent', u'Tech_Science_Most viewed': u'directories/topics/most_viewed', u'Tech_Science_Most commented': u'directories/topics/most_comments', u'Tech_Science_Best rated': u'directories/topics/rated',
514 
515  'Animals': 'directories/topics/animals',
516  'Auto-Moto': 'directories/topics/automotive',
517  'Film & TV': 'directories/topics/movies',
518  'Gaming': 'directories/topics/games',
519  'Life & Style': 'directories/topics/????',
520  'News & Politics': 'directories/topics/news',
521  'Sports & Extreme': 'directories/topics/sports',
522  'Webcam & Vlogs': 'directories/topics/videoblog',
523  'Arts': 'directories/topics/arts',
524  'College': 'directories/topics/college',
525  'Funny': 'directories/film_genres/comedy',
526  'Latino': 'directories/music_genres/latino',
527  'Music': 'directories/topics/music',
528  'People & Family': 'directories/topics/people',
529  'Tech & Science': 'directories/topics/technology',
530  },
531  }
532 
533  # Switches specific to Group tree view
534  self.group_id = u''
535  self.groupview = False
536 
537  # Initialize the tree view flag so that the item parsing code can be used for multiple purposes
538  self.treeview = False
539  self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/dailymotion.png'
540  # end __init__()
541 
542 
547 
549  '''Get longitude and latitiude to find videos relative to your location. Up to three different
550  servers will be tried before giving up.
551  return a dictionary e.g.
552  {'Latitude': '43.6667', 'Country': 'Canada', 'Longitude': '-79.4167', 'City': 'Toronto'}
553  return an empty dictionary if there were any errors
554  Code found at: http://blog.suinova.com/2009/04/from-ip-to-geolocation-country-city.html
555  '''
556  def getExternalIP():
557  '''Find the external IP address of this computer.
558  '''
559  url = urllib.URLopener()
560  try:
561  resp = url.open('http://www.whatismyip.com/automation/n09230945.asp')
562  return resp.read()
563  except:
564  return None
565  # end getExternalIP()
566 
567  ip = getExternalIP()
568 
569  if ip == None:
570  return {}
571 
572  try:
573  gs = urllib.urlopen('http://blogama.org/ip_query.php?ip=%s&output=xml' % ip)
574  txt = gs.read()
575  except:
576  try:
577  gs = urllib.urlopen('http://www.seomoz.org/ip2location/look.php?ip=%s' % ip)
578  txt = gs.read()
579  except:
580  try:
581  gs = urllib.urlopen('http://api.hostip.info/?ip=%s' % ip)
582  txt = gs.read()
583  except:
584  logging.error('GeoIP servers not available')
585  return {}
586  try:
587  if txt.find('<Response>') > 0:
588  countrys = re.findall(r'<CountryName>([\w ]+)<',txt)[0]
589  citys = re.findall(r'<City>([\w ]+)<',txt)[0]
590  lats,lons = re.findall(r'<Latitude>([\d\-\.]+)</Latitude>\s*<Longitude>([\d\-\.]+)<',txt)[0]
591  elif txt.find('GLatLng') > 0:
592  citys,countrys = re.findall('<br />\s*([^<]+)<br />\s*([^<]+)<',txt)[0]
593  lats,lons = re.findall('LatLng\(([-\d\.]+),([-\d\.]+)',txt)[0]
594  elif txt.find('<gml:coordinates>') > 0:
595  citys = re.findall('<Hostip>\s*<gml:name>(\w+)</gml:name>',txt)[0]
596  countrys = re.findall('<countryName>([\w ,\.]+)</countryName>',txt)[0]
597  lats,lons = re.findall('gml:coordinates>([-\d\.]+),([-\d\.]+)<',txt)[0]
598  else:
599  logging.error('error parsing IP result %s'%txt)
600  return {}
601  return {'Country':countrys,'City':citys,'Latitude':lats,'Longitude':lons}
602  except:
603  logging.error('Error parsing IP result %s'%txt)
604  return {}
605  # end detectUserLocationByIP()
606 
607  def massageDescription(self, text):
608  '''Removes HTML markup from a text string.
609  @param text The HTML source.
610  @return The plain text. If the HTML source contains non-ASCII
611  entities or character references, this is a Unicode string.
612  '''
613  def fixup(m):
614  text = m.group(0)
615  if text[:1] == "<":
616  return "" # ignore tags
617  if text[:2] == "&#":
618  try:
619  if text[:3] == "&#x":
620  return unichr(int(text[3:-1], 16))
621  else:
622  return unichr(int(text[2:-1]))
623  except ValueError:
624  pass
625  elif text[:1] == "&":
626  import htmlentitydefs
627  entity = htmlentitydefs.entitydefs.get(text[1:-1])
628  if entity:
629  if entity[:2] == "&#":
630  try:
631  return unichr(int(entity[2:-1]))
632  except ValueError:
633  pass
634  else:
635  return unicode(entity, "iso-8859-1")
636  return text # leave as is
637  return self.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.textUtf8(text))).replace(u'\n',u' ')
638  # end massageDescription()
639 
640 
641  def _initLogger(self):
642  """Setups a logger using the logging module, returns a log object
643  """
644  logger = logging.getLogger(self.log_name)
645  formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
646 
647  hdlr = logging.StreamHandler(sys.stdout)
648 
649  hdlr.setFormatter(formatter)
650  logger.addHandler(hdlr)
651 
652  if self.config['debug_enabled']:
653  logger.setLevel(logging.DEBUG)
654  else:
655  logger.setLevel(logging.WARNING)
656  return logger
657  #end initLogger
658 
659 
660  def textUtf8(self, text):
661  if text == None:
662  return text
663  try:
664  return unicode(text, 'utf8')
665  except UnicodeDecodeError:
666  return u''
667  except (UnicodeEncodeError, TypeError):
668  return text
669  # end textUtf8()
670 
671 
672  def ampReplace(self, text):
673  '''Replace all "&" characters with "&amp;"
674  '''
675  text = self.textUtf8(text)
676  return text.replace(u'&amp;',u'~~~~~').replace(u'&',u'&amp;').replace(u'~~~~~', u'&amp;')
677  # end ampReplace()
678 
679 
680  def setTreeViewIcon(self, dir_icon=None):
681  '''Check if there is a specific generic tree view icon. If not default to the channel icon.
682  return self.tree_dir_icon
683  '''
685  if not dir_icon:
686  if not self.feed_icons.has_key(self.tree_key):
687  return self.tree_dir_icon
688  if not self.feed_icons[self.tree_key].has_key(self.feed):
689  return self.tree_dir_icon
690  dir_icon = self.feed_icons[self.tree_key][self.feed]
691  if not dir_icon:
692  return self.tree_dir_icon
693  self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, )
694  return self.tree_dir_icon
695  # end setTreeViewIcon()
696 
701 
702  def processVideoUrl(self, url):
703  playerUrl = self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/dailymotion.html", \
704  url.replace(u'http://www.dailymotion.com/swf/video/', ''))
705  return self.ampReplace(playerUrl)
706 
707  def searchTitle(self, title, pagenumber, pagelen):
708  '''Key word video search of the Dailymotion web site
709  return an array of matching item dictionaries
710  return
711  '''
712  url = self.config[u'urls'][u'video.search'] % (urllib.quote_plus(title.encode("utf-8")), pagenumber)
713  if self.config['debug_enabled']:
714  print url
715  print
716 
717  return self.config['item_parser']['main'](url, [])
718  # end searchTitle()
719 
720 
721  def searchForVideos(self, title, pagenumber):
722  """Common name for a video search. Used to interface with MythTV plugin NetVision
723  """
724  # Channel details and search results
725  self.channel = {'channel_title': u'Dailymotion', 'channel_link': u'http://www.dailymotion.com', 'channel_description': u"Dailymotion is about finding new ways to see, share and engage your world through the power of online video.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
726 
727  # Easier for debugging
728 # print self.searchTitle(title, pagenumber, self.page_limit)
729 # print
730 # sys.exit()
731 
732  try:
733  data = self.searchTitle(title, int(pagenumber), self.page_limit)
734  except DailymotionVideoNotFound, msg:
735  sys.stderr.write(u"%s\n" % msg)
736  return None
737  except DailymotionUrlError, msg:
738  sys.stderr.write(u'%s\n' % msg)
739  sys.exit(1)
740  except DailymotionHttpError, msg:
741  sys.stderr.write(self.error_messages['DailymotionHttpError'] % msg)
742  sys.exit(1)
743  except DailymotionRssError, msg:
744  sys.stderr.write(self.error_messages['DailymotionRssError'] % msg)
745  sys.exit(1)
746  except Exception, e:
747  sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e))
748  sys.exit(1)
749 
750  if data == None:
751  return None
752  if not len(data):
753  return None
754 
755  if self.next_page:
756  self.channel['channel_numresults'] = len(data) * int(pagenumber) + 1
757  else:
758  self.channel['channel_numresults'] = int(pagenumber) * len(data)
759 
760  self.channel['channel_startindex'] = int(pagenumber) * len(data)
761  self.channel['channel_returned'] = len(data)
762 
763  return [[self.channel, data]]
764  # end searchForVideos()
765 
766  def displayTreeView(self):
767  '''Gather the Dailymotion categories/feeds/...etc then get a max page of videos meta data in
768  each of them.
769  return array of directories and their video meta data
770  '''
771  # Channel details and search results
772  self.channel = {'channel_title': u'Dailymotion', 'channel_link': u'http://www.dailymotion.com', 'channel_description': u"Dailymotion is about finding new ways to see, share and engage your world through the power of online video.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
773 
774  if self.config['debug_enabled']:
775  print self.config[u'urls']
776  print
777 
778  # Get videos within each category
779  dictionaries = []
780 
781  self.treeview = True
782 
783  # Process the various video feeds/categories/... etc
784  for key in self.tree_order:
785  self.tree_key = key
786  dictionaries = self.getVideos(self.tree_org[key], dictionaries)
787 
788  return [[self.channel, dictionaries]]
789  # end displayTreeView()
790 
791  def makeURL(self, URL):
792  '''Form a URL to search for videos
793  return a URL
794  '''
795  additions = dict(self.tree_customize[self.tree_key]['__default__']) # Set defaults
796 
797  # Add customizations
798  if self.feed in self.tree_customize[self.tree_key].keys():
799  for element in self.tree_customize[self.tree_key][self.feed].keys():
800  additions[element] = self.tree_customize[self.tree_key][self.feed][element]
801 
802  # Make the search extension string that is added to the URL
803  addition = u''
804  for ky in additions.keys():
805  if ky.startswith('add_'):
806  addition+=u'/%s' % additions[ky]
807  else:
808  addition+=u'&%s=%s' % (ky, additions[ky])
809  index = URL.find('%')
810  if index == -1:
811  return (URL+addition)
812  else:
813  return (URL+addition) % self.feed
814  # end makeURL()
815 
816 
817  def getVideos(self, dir_dict, dictionaries):
818  '''Parse a list made of category lists and retrieve video meta data
819  return a dictionary of directory names and category's video meta data
820  '''
821  for sets in dir_dict:
822  if not isinstance(sets[1], list):
823  if sets[0] != '': # Add the nested dictionaries display name
824  try:
825  dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
826  except KeyError:
827  dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
828  else:
829  dictionaries.append(['', u'']) # Add the nested dictionary indicator
830  continue
831  temp_dictionary = []
832  for self.feed in sets[1]:
833  if self.config[u'urls'][u'tree.view'][self.tree_key].has_key('__all__'):
834  URL = self.config[u'urls'][u'tree.view'][self.tree_key]['__all__']
835  else:
836  URL = self.config[u'urls'][u'tree.view'][self.tree_key][self.feed]
837  temp_dictionary = self.config['item_parser'][URL[1]](self.makeURL(URL[0]), temp_dictionary)
838  if len(temp_dictionary):
839  if len(sets[0]): # Add the nested dictionaries display name
840  try:
841  dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])])
842  except KeyError:
843  dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
844  for element in temp_dictionary:
845  dictionaries.append(element)
846  if len(sets[0]):
847  dictionaries.append(['', u'']) # Add the nested dictionary indicator
848  return dictionaries
849  # end getVideos()
850 
851  def getVideosForURL(self, url, dictionaries):
852  '''Get the video meta data for url search
853  return the video dictionary of directories and their video mata data
854  '''
855  initial_length = len(dictionaries)
856 
857  if self.config['debug_enabled']:
858  print "Video URL:"
859  print url
860  print
861 
862  try:
863  etree = XmlHandler(url).getEt()
864  except Exception, errormsg:
865  sys.stderr.write(self.error_messages['DailymotionUrlError'] % (url, errormsg))
866  return dictionaries
867 
868  if etree is None:
869  sys.stderr.write(u'1-No Videos for (%s)\n' % self.feed)
870  return dictionaries
871 
872  dictionary_first = False
873  directory_image = u''
874  self.next_page = False
875  language = self.config['language']
876  for elements in etree.find('channel'):
877  if elements.tag.endswith(u'language'):
878  if elements.text:
879  language = elements.text[:2]
880  continue
881 
882  if elements.tag.endswith(u'link'):
883  if elements.get('rel') == "next":
884  self.next_page = True
885  continue
886 
887  if elements.tag.endswith(u'image'):
888  if elements.get('href'):
889  directory_image = self.ampReplace(elements.get(u'href').strip())
890  continue
891 
892  if not elements.tag.endswith(u'item'):
893  continue
894 
895  meta_data = {}
896  cur_size = True
897  flash = False
898  meta_data['language'] = language
899  for e in elements:
900  if e.tag.endswith(u'title'):
901  if e.text:
902  meta_data['title'] = self.massageDescription(e.text.strip())
903  continue
904  if e.tag.endswith(u'author'):
905  if e.text:
906  meta_data['author'] = self.massageDescription(e.text.strip())
907  continue
908  if e.tag.endswith(u'pubDate'): # Wed, 16 Dec 2009 21:15:57 +0100
909  if e.text:
910  meta_data['published_parsed'] = e.text.strip()
911  continue
912  if e.tag.endswith(u'description'):
913  if e.text:
914  index1 = e.text.find(u'<p>')
915  index2 = e.text.find(u'</p>')
916  if index1 != -1 and index2 != -1:
917  meta_data['media_description'] = self.massageDescription(e.text[index1+3:index2].strip())
918  continue
919  if e.tag.endswith(u'thumbnail'):
920  if e.get(u'url'):
921  meta_data['thumbnail'] = self.ampReplace(e.get(u'url').strip())
922  continue
923  if e.tag.endswith(u'player'):
924  if e.text:
925  meta_data['link'] = self.ampReplace(e.get(u'url').strip())
926  continue
927  if e.tag.endswith(u'videorating'):
928  if e.text:
929  meta_data['rating'] = e.text.strip()
930  continue
931  if not e.tag.endswith(u'group'):
932  continue
933  for elem in e:
934  if elem.tag.endswith('content') and elem.get('type') == 'application/x-shockwave-flash':
935  if elem.get('url'):
936  meta_data['video'] = self.processVideoUrl(elem.get('url'))
937  if elem.get('duration'):
938  meta_data['duration'] = elem.get('duration').strip()
939  if elem.get('width'):
940  meta_data['item_width'] = elem.get('width').strip()
941  if elem.get('height'):
942  meta_data['item_height'] = elem.get('height').strip()
943  break
944  continue
945 
946  if not meta_data.has_key('video') and not meta_data.has_key('link'):
947  continue
948 
949  if not meta_data.has_key('video'):
950  meta_data['video'] = meta_data['link']
951  else:
952  meta_data['link'] = meta_data['video']
953 
954  if self.treeview:
955  if not dictionary_first: # Add the dictionaries display name
956  if not self.groupview:
957  dictionaries.append([self.massageDescription(self.feed_names[self.tree_key][self.feed]), self.setTreeViewIcon()])
958  else:
959  dictionaries.append([self.massageDescription(self.feed_names[self.tree_key][self.feed]), self.groupview_image])
960  dictionary_first = True
961 
962  final_item = {}
963  for key in self.key_translation[1].keys():
964  if not meta_data.has_key(key):
965  final_item[self.key_translation[1][key]] = u''
966  else:
967  final_item[self.key_translation[1][key]] = meta_data[key]
968  dictionaries.append(final_item)
969 
970  if self.treeview:
971  if initial_length < len(dictionaries): # Need to check if there was any items for this Category
972  dictionaries.append(['', u'']) # Add the nested dictionary indicator
973  return dictionaries
974  # end getVideosForURL()
975 
976 
977  def getVideosForGroupURL(self, url, dictionaries):
978  '''Get the video meta data for a group url search
979  return the video dictionary of directories and their video mata data
980  '''
981  self.groupview = True
982  initial_length = len(dictionaries)
983  save_tree_key = self.tree_key
984 
985  if self.config['debug_enabled']:
986  print "Groups URL:"
987  print url
988  print
989 
990  try:
991  etree = XmlHandler(url).getEt()
992  except Exception, errormsg:
993  sys.stderr.write(self.error_messages['DailymotionUrlError'] % (url, errormsg))
994  return dictionaries
995 
996  if etree is None:
997  sys.stderr.write(u'1-No Groups for (%s)\n' % self.feed)
998  return dictionaries
999 
1000  for elements in etree.find('channel'):
1001  if not elements.tag.endswith(u'item'):
1002  continue
1003  self.group_id = u''
1004  group_name = u''
1005  group_image = u''
1006  for group in elements:
1007  if group.tag == u'title':
1008  if group.text:
1009  group_name = self.massageDescription(group.text.strip())
1010  if group.tag == u'link':
1011  if group.text:
1012  self.group_id = group.text.strip().replace(u'http://www.dailymotion.com/group/', u'')
1013  if group.tag.endswith(u'thumbnail'):
1014  if group.get(u'url'):
1015  group_image = self.ampReplace(group.get(u'url').strip())
1016  if group_name != u'' and self.group_id != u'' and group_image != u'':
1017 
1018  temp_dictionary = []
1019  self.tree_key = 'group'
1020  self.groupview_image = group_image
1021  self.tree_customize[self.tree_key]['__default__']['add_'] = self.group_id
1022  temp_dictionary = self.getVideos(self.tree_org[self.tree_key], temp_dictionary)
1023  if len(temp_dictionary):
1024  if self.treeview:
1025  dictionaries.append([group_name, group_image])
1026 
1027  for element in temp_dictionary:
1028  dictionaries.append(element)
1029 
1030  if self.treeview:
1031  dictionaries.append([u'',u''])
1032  break
1033 
1034  self.tree_key = save_tree_key
1035 
1036  return dictionaries
1037  # end getVideosForGroupURL()
1038 # end Videos() class
def processVideoUrl(self, url)
End of Utility functions.
def detectUserLocationByIP(self)
Start - Utility functions.
def getVideos(self, dir_dict, dictionaries)
def __init__(self, apikey, mythtv=True, interactive=False, select_first=False, debug=False, custom_ui=None, language=None, search_all_languages=False)
def searchTitle(self, title, pagenumber, pagelen)