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__='''
18This python script is intended to perform a variety of utility functions to search and access text
19meta data, video and image URLs from dailymotion. These routines are based on the api. Specifications
20for 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
37import os, struct, sys, re, time
38import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse
39import logging
40from MythTV import MythXML
41
42try:
43 import xml.etree.cElementTree as ElementTree
44except ImportError:
45 import xml.etree.ElementTree as ElementTree
46
47from .dailymotion_exceptions import (DailymotionUrlError, DailymotionHttpError, DailymotionRssError, DailymotionVideoNotFound, DailymotionInvalidSearchType, DailymotionXmlError, DailymotionVideoDetailError, DailymotionCategoryNotFound)
48import io
49
50class 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
69if isinstance(sys.stdout, io.TextIOWrapper):
70 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
71 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
72
73
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
96class 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
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
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
def detectUserLocationByIP(self)
Start - Utility functions.
def searchTitle(self, title, pagenumber, pagelen)
def processVideoUrl(self, url)
End of Utility functions.
def __init__(self, apikey, mythtv=True, interactive=False, select_first=False, debug=False, custom_ui=None, language=None, search_all_languages=False)
def getVideos(self, dir_dict, dictionaries)
static void print(const QList< uint > &raw_minimas, const QList< uint > &raw_maximas, const QList< float > &minimas, const QList< float > &maximas)