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