|
MythTV
0.26-pre
|
00001 #!/usr/bin/env python 00002 # -*- coding: UTF-8 -*- 00003 # ---------------------- 00004 # Name: dailymotion_api - Simple-to-use Python interface to the dailymotion API (http://www.dailymotion.com) 00005 # Python Script 00006 # Author: R.D. Vaughan 00007 # Purpose: This python script is intended to perform a variety of utility functions to search and access text 00008 # meta data, video and image URLs from dailymotion. 00009 # These routines are based on the api. Specifications 00010 # for this api are published at http://www.dailymotion.com/ca-en/doc/api/player 00011 # 00012 # License:Creative Commons GNU GPL v2 00013 # (http://creativecommons.org/licenses/GPL/2.0/) 00014 #------------------------------------- 00015 __title__ ="dailymotion_api - Simple-to-use Python interface to the dailymotion API (http://www.dailymotion.com/ca-en/doc/api/player)" 00016 __author__="R.D. Vaughan" 00017 __purpose__=''' 00018 This python script is intended to perform a variety of utility functions to search and access text 00019 meta data, video and image URLs from dailymotion. These routines are based on the api. Specifications 00020 for this api are published at http://www.dailymotion.com/ca-en/doc/api/player 00021 ''' 00022 00023 __version__="v0.2.4" 00024 # 0.1.0 Initial development 00025 # 0.1.1 Added getting local directory images 00026 # 0.1.2 Documentation update 00027 # 0.2.0 Public release 00028 # 0.2.1 New python bindings conversion 00029 # Better exception error reporting 00030 # Better handling of invalid unicode data from source 00031 # 0.2.2 Completed abort exception display message improvements 00032 # Removed unused import of the feedparser library 00033 # 0.2.3 Fixed an exception message output code error in two places 00034 # 0.2.4 Removed the need for python MythTV bindings and added "%SHAREDIR%" to icon directory path 00035 00036 00037 import os, struct, sys, re, time 00038 import urllib, urllib2 00039 import logging 00040 from MythTV import MythXML 00041 00042 try: 00043 import xml.etree.cElementTree as ElementTree 00044 except ImportError: 00045 import xml.etree.ElementTree as ElementTree 00046 00047 from dailymotion_exceptions import (DailymotionUrlError, DailymotionHttpError, DailymotionRssError, DailymotionVideoNotFound, DailymotionInvalidSearchType, DailymotionXmlError, DailymotionVideoDetailError, DailymotionCategoryNotFound) 00048 00049 class OutStreamEncoder(object): 00050 """Wraps a stream with an encoder""" 00051 def __init__(self, outstream, encoding=None): 00052 self.out = outstream 00053 if not encoding: 00054 self.encoding = sys.getfilesystemencoding() 00055 else: 00056 self.encoding = encoding 00057 00058 def write(self, obj): 00059 """Wraps the output stream, encoding Unicode strings with the specified encoding""" 00060 if isinstance(obj, unicode): 00061 try: 00062 self.out.write(obj.encode(self.encoding)) 00063 except IOError: 00064 pass 00065 else: 00066 try: 00067 self.out.write(obj) 00068 except IOError: 00069 pass 00070 00071 def __getattr__(self, attr): 00072 """Delegate everything but write to the stream""" 00073 return getattr(self.out, attr) 00074 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8') 00075 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8') 00076 00077 00078 class XmlHandler: 00079 """Deals with retrieval of XML files from API 00080 """ 00081 def __init__(self, url): 00082 self.url = url 00083 00084 def _grabUrl(self, url): 00085 try: 00086 urlhandle = urllib.urlopen(url) 00087 except IOError, errormsg: 00088 raise DailymotionHttpError(errormsg) 00089 return urlhandle.read() 00090 00091 def getEt(self): 00092 xml = self._grabUrl(self.url) 00093 try: 00094 et = ElementTree.fromstring(xml) 00095 except SyntaxError, errormsg: 00096 raise DailymotionXmlError(errormsg) 00097 return et 00098 00099 00100 class Videos(object): 00101 """Main interface to http://www.dailymotion.com 00102 This is done to support a common naming framework for all python Netvision plugins no matter their site 00103 target. 00104 00105 Supports search and tree view methods 00106 The apikey is a not required to access http://www.dailymotion.com 00107 """ 00108 def __init__(self, 00109 apikey, 00110 mythtv = True, 00111 interactive = False, 00112 select_first = False, 00113 debug = False, 00114 custom_ui = None, 00115 language = None, 00116 search_all_languages = False, 00117 ): 00118 """apikey (str/unicode): 00119 Specify the target site API key. Applications need their own key in some cases 00120 00121 mythtv (True/False): 00122 When True, the returned meta data is being returned has the key and values massaged to match MythTV 00123 When False, the returned meta data is being returned matches what target site returned 00124 00125 interactive (True/False): (This option is not supported by all target site apis) 00126 When True, uses built-in console UI is used to select the correct show. 00127 When False, the first search result is used. 00128 00129 select_first (True/False): (This option is not supported currently implemented in any grabbers) 00130 Automatically selects the first series search result (rather 00131 than showing the user a list of more than one series). 00132 Is overridden by interactive = False, or specifying a custom_ui 00133 00134 debug (True/False): 00135 shows verbose debugging information 00136 00137 custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers) 00138 A callable subclass of interactive class (overrides interactive option) 00139 00140 language (2 character language abbreviation): (This option is not supported by all target site apis) 00141 The language of the returned data. Is also the language search 00142 uses. Default is "en" (English). For full list, run.. 00143 00144 search_all_languages (True/False): (This option is not supported by all target site apis) 00145 By default, a Netvision grabber will only search in the language specified using 00146 the language option. When this is True, it will search for the 00147 show in any language 00148 00149 """ 00150 self.config = {} 00151 self.mythxml = MythXML() 00152 00153 if apikey is not None: 00154 self.config['apikey'] = apikey 00155 else: 00156 pass # Dailymotion does not require an apikey 00157 00158 self.config['debug_enabled'] = debug # show debugging messages 00159 00160 self.log_name = "Dailymotion" 00161 self.log = self._initLogger() # Setups the logger (self.log.debug() etc) 00162 00163 self.config['custom_ui'] = custom_ui 00164 00165 self.config['interactive'] = interactive # prompt for correct series? 00166 00167 self.config['select_first'] = select_first 00168 00169 self.config['search_all_languages'] = search_all_languages 00170 00171 self.error_messages = {'DailymotionUrlError': u"! Error: The URL (%s) cause the exception error (%s)\n", 'DailymotionHttpError': u"! Error: An HTTP communicating error with Dailymotion was raised (%s)\n", 'DailymotionRssError': u"! Error: Invalid RSS meta data\nwas received from Dailymotion error (%s). Skipping item.\n", 'DailymotionVideoNotFound': u"! Error: Video search with Dailymotion did not return any results (%s)\n", 'DailymotionVideoDetailError': u"! Error: Invalid Video meta data detail\nwas received from Dailymotion error (%s). Skipping item.\n", } 00172 00173 # This is an example that must be customized for each target site 00174 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'}] 00175 00176 # Defaulting to English 'en' 00177 if language: 00178 self.config['language'] = language 00179 else: 00180 self.config['language'] = u'en' 00181 00182 00183 self.config[u'urls'] = {} 00184 00185 # v2 api calls - An example that must be customized for each target site 00186 self.config[u'urls'][u'video.search'] = 'http://www.dailymotion.com/rss/relevance/search/%s/%s' 00187 self.config[u'urls'][u'group.search'] = 'http://www.dailymotion.com/rss/groups/relevance/search/%s/%s' 00188 self.config[u'urls'][u'user.search'] = 'http://www.dailymotion.com/rss/users/relevance/search/%s/%s' 00189 00190 # Functions that parse video data from RSS data 00191 self.config['item_parser'] = {} 00192 self.config['item_parser']['main'] = self.getVideosForURL 00193 self.config['item_parser']['groups'] = self.getVideosForGroupURL 00194 00195 # Tree view url and the function that parses that urls meta data 00196 self.config[u'urls'][u'tree.view'] = { 00197 'F_M_B_C': { 00198 'featured': ['http://www.dailymotion.com/rss/us/relevance/%s/search/movie/1', 'main'], 00199 'creative': ['http://www.dailymotion.com/rss/us/relevance/%s/search/movie/1', 'main'], 00200 'official': ['http://www.dailymotion.com/rss/us/%s/search/movie/1', 'main'], 00201 'hd': ['http://www.dailymotion.com/rss/relevance/%s/search/movie/1', 'main'], 00202 'commented': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00203 'visited': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00204 'rated': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00205 'relevance-month': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00206 'relevance-week': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00207 'relevance-today': ['http://www.dailymotion.com/rss/us/%s/official/search/movie/1', 'main'], 00208 }, 00209 'categories': { 00210 'movie': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'], 00211 'comedy': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'], 00212 'short+film': ['http://www.dailymotion.com/rss/creative/relevance/search/%s', 'main'], 00213 'television': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'], 00214 'documentary': ['http://www.dailymotion.com/rss/us/relevance/official/search/%s', 'main'], 00215 'festival': ['http://www.dailymotion.com/rss/creative/relevance/search/%s', 'main'], 00216 }, 00217 'channels': { 00218 'animals_motionmaker': ['http://www.dailymotion.com/rss/creative/lang/en/channel/animals/1', 'main'], 00219 'animals_most_recent': ['http://www.dailymotion.com/rss/lang/en/channel/animals/1', 'main'], 00220 'animals_hd': ['http://www.dailymotion.com/rss/hd/channel/animals/1', 'main'], 00221 'animals_official_users': ['http://www.dailymotion.com/rss/official/lang/en/channel/animals/1', 'main'], 00222 'animals_most_viewed': ['http://www.dailymotion.com/rss/visited/lang/en/channel/animals/1', 'main'], 00223 'animals_best_rated': ['http://www.dailymotion.com/rss/rated/lang/en/channel/animals/1', 'main'], 00224 00225 'auto_most_recent': ['http://www.dailymotion.com/rss/lang/en/channel/auto/1', 'main'], 00226 'auto_motionmaker': ['http://www.dailymotion.com/rss/creative/channel/auto/1', 'main'], 00227 'auto_most_viewed': ['http://www.dailymotion.com/rss/visited/lang/en/channel/auto/1', 'main'], 00228 'auto_official_users': ['http://www.dailymotion.com/rss/official/channel/auto/1', 'main'], 00229 00230 'film_TV_movie': ['http://www.dailymotion.com/rss/us/relevance/official/search/movie', 'main'], 00231 'film_TV_comedy': ['http://www.dailymotion.com/rss/us/relevance/official/search/comedy', 'main'], 00232 'film_TV_short_film': ['http://www.dailymotion.com/rss/creative/relevance/search/short+film', 'main'], 00233 'film_TV_television': ['http://www.dailymotion.com/rss/us/relevance/official/search/television', 'main'], 00234 'film_TV_documentary': ['http://www.dailymotion.com/rss/us/relevance/official/search/documentary', 'main'], 00235 'film_TV_festival': ['http://www.dailymotion.com/rss/official/relevance/search/festival', 'main'], 00236 00237 'gaming_Trailer': ['http://www.dailymotion.com/rss/official/search/videogames+trailer/1', 'main'], 00238 'gaming_Lego': ['http://www.dailymotion.com/rss/relevance/search/lego', 'main'], 00239 'gaming_Machinima': ['http://www.dailymotion.com/rss/relevance/creative/search/machinima/1', 'main'], 00240 'gaming_Motionmaker': ['http://www.dailymotion.com/rss/us/creative/channel/videogames/1', 'main'], 00241 'gaming_Review': ['http://www.dailymotion.com/rss/official/search/videogames+review/1', 'main'], 00242 'gaming_News': ['http://www.dailymotion.com/rss/official/search/videogames+news/1', 'main'], 00243 'gaming_recent': ['http://www.dailymotion.com/rss/us/channel/videogames/lang/en/1', 'main'], 00244 'gaming_users': ['http://www.dailymotion.com/rss/us/official/channel/videogames/1', 'main'], 00245 00246 'lifestyle_best_rated': ['http://www.dailymotion.com/rss/rated/lang/en/channel/lifestyle/1', 'main'], 00247 'lifestyle_most_commented': ['http://www.dailymotion.com/rss/commented/lang/en/channel/lifestyle/1', 'main'], 00248 'lifestyle_most_viewed': ['http://www.dailymotion.com/rss/viewed/lang/en/channel/lifestyle/1', 'main'], 00249 'lifestyle_HD': ['http://www.dailymotion.com/rss/hd/lang/en/channel/lifestyle/1', 'main'], 00250 00251 'news_politics_Politics': ['http://www.dailymotion.com/rss/official/relevance/search/politics', 'main'], 00252 'news_politics_Celebrity': ['http://www.dailymotion.com/rss/official/relevance/search/celeb+news', 'main'], 00253 'news_politics_official_users': ['http://www.dailymotion.com/rss/official/search/news/1', 'main'], 00254 'news_politics_International': ['http://www.dailymotion.com/rss/official/search/international+news/1', 'main'], 00255 'news_politics_Entertainment': ['http://www.dailymotion.com/rss/official/search/entertainment+news/1', 'main'], 00256 'news_politics_Motionmakers': ['http://www.dailymotion.com/rss/relevance/creative/search/news/1', 'main'], 00257 00258 'sports_extreme_surf': ['http://www.dailymotion.com/rss/relevance/official/search/surf/1', 'main'], 00259 'sports_extreme_baseball': ['http://www.dailymotion.com/rss/relevance/official/search/baseball', 'main'], 00260 'sports_extreme_wrestling': ['http://www.dailymotion.com/rss/relevance/official/search/wrestling/1', 'main'], 00261 'sports_extreme_BMX': ['http://www.dailymotion.com/rss/relevance/official/search/BMX/1', 'main'], 00262 00263 'webcam_vlogs_Most_viewed': ['http://www.dailymotion.com/rss/visited/channel/webcam/lang/en/1', 'main'], 00264 'webcam_vlogs_Featured_videos': ['http://www.dailymotion.com/rss/us/featured/channel/webcam/1', 'main'], 00265 'webcam_vlogs_Best_rated': ['http://www.dailymotion.com/rss/rated/channel/webcam/lang/en/1', 'main'], 00266 'webcam_vlogs_Most_Commented': ['http://www.dailymotion.com/rss/commented/channel/webcam/lang/en/1', 'main'], 00267 00268 'arts_Animation': ['http://www.dailymotion.com/rss/relevance/creative-official/search/animation', 'main'], 00269 'arts_Short_Film': ['http://www.dailymotion.com/rss/us/relevance/creative/search/shortfilm', 'main'], 00270 'arts_Motionmaker': ['http://www.dailymotion.com/rss/creative-official/lang/en/1', 'main'], 00271 'arts_Official_Users': ['http://www.dailymotion.com/rss/official/channel/creation/lang/en/1', 'main'], 00272 'arts_Suede_swede': ['http://www.dailymotion.com/rss/relevance/creative/search/suede', 'main'], 00273 'arts_Most_recent': ['http://www.dailymotion.com/rss/channel/creation/lang/en/1', 'main'], 00274 00275 'college_Most_viewed': ['http://www.dailymotion.com/rss/visited/channel/school/lang/en/1', 'main'], 00276 'college_HD_videos': ['http://www.dailymotion.com/rss/hd/channel/school/1', 'main'], 00277 'college_Best_rated': ['http://www.dailymotion.com/rss/rated/channel/school/lang/en/1', 'main'], 00278 'college_Most_commented': ['http://www.dailymotion.com/rss/channel/school/lang/en/1', 'main'], 00279 00280 'funny_STAND UP': ['http://www.dailymotion.com/rss/official/relevance/search/standup', 'main'], 00281 'funny_Hulu: NBC & Fox': ['http://www.dailymotion.com/rss/hulu/1', 'main'], 00282 'funny_My Damn Channel': ['http://www.dailymotion.com/rss/mydamnchannel/1', 'main'], 00283 'funny_Motionmakers': ['http://www.dailymotion.com/rss/us/creative/search/comedy/1', 'main'], 00284 'funny_Sketch': ['http://www.dailymotion.com/rss/official/relevance/search/sketch', 'main'], 00285 "funny_Nat'l Lampoon": ['http://www.dailymotion.com/rss/nationallampoon/1', 'main'], 00286 'funny_Classic Sitcoms': ['http://www.dailymotion.com/rss/Classic_WB_TV/1', 'main'], 00287 'funny_Official Users': ['http://www.dailymotion.com/rss/us/official/search/comedy/1', 'main'], 00288 00289 'latino_Featured Videos': ['http://www.dailymotion.com/rss/featured/channel/latino/1', 'main'], 00290 'latino_HD content': ['http://www.dailymotion.com/rss/hd/channel/latino/1', 'main'], 00291 'latino_Official Content': ['http://www.dailymotion.com/rss/official/channel/latino/1', 'main'], 00292 'latino_Creative Content': ['http://www.dailymotion.com/rss/creative/channel/latino/1', 'main'], 00293 'latino_Most Commented': ['http://www.dailymotion.com/rss/commented-week/featured/channel/latino/1', 'main'], 00294 'latino_Most Viewed': ['http://www.dailymotion.com/rss/visited-week/featured/channel/latino/1', 'main'], 00295 'latino_Best Rated': ['http://www.dailymotion.com/rss/rated-week/featured/channel/latino/1', 'main'], 00296 00297 'music_Pop': ['http://www.dailymotion.com/rss/official/relevance/search/pop', 'main'], 00298 'music_Rock': ['http://www.dailymotion.com/rss/relevance/official/search/Rock+Music+Videos/1', 'main'], 00299 'music_Jazz': ['http://www.dailymotion.com/rss/channel/music/official/relevance/search/jazz', 'main'], 00300 'music_Covers': ['http://www.dailymotion.com/rss/channel/us/channel/music/relevance/creative/search/cover/1', 'main'], 00301 'music_Rap': ['http://www.dailymotion.com/rss/official/relevance/search/rap', 'main'], 00302 'music_R&B': ['http://www.dailymotion.com/rss/us/channel/music/relevance/search/rnb', 'main'], 00303 'music_Metal': ['http://www.dailymotion.com/rss/channel/us/channel/music/official/relevance/search/metal', 'main'], 00304 'music_Electro': ['http://www.dailymotion.com/rss/channel/music/official/relevance/search/electro', 'main'], 00305 00306 'People_Family_Featured Videos': ['http://www.dailymotion.com/rss/featured/channel/people/1', 'main'], 00307 'People_Family_HD content': ['http://www.dailymotion.com/rss/hd/channel/people/1', 'main'], 00308 'People_Family_Official Content': ['http://www.dailymotion.com/rss/official/channel/people/1', 'main'], 00309 'People_Family_Creative Content': ['http://www.dailymotion.com/rss/creative/channel/people/1', 'main'], 00310 'People_Family_Most Commented': ['http://www.dailymotion.com/rss/commented-week/featured/channel/people/1', 'main'], 00311 'People_Family_Most Viewed': ['http://www.dailymotion.com/rss/visited-week/featured/channel/people/1', 'main'], 00312 'People_Family_Best Rated': ['http://www.dailymotion.com/rss/rated-week/featured/channel/people/1', 'main'], 00313 00314 'Tech_Science_Most recent': ['http://www.dailymotion.com/rss/channel/tech/1', 'main'], 00315 'Tech_Science_Most viewed': ['http://www.dailymotion.com/rss/visited/channel/tech/1', 'main'], 00316 'Tech_Science_Most commented': ['http://www.dailymotion.com/rss/commented/channel/tech/1', 'main'], 00317 'Tech_Science_Best rated': ['http://www.dailymotion.com/rss/rated/channel/tech/1', 'main'], 00318 00319 # 'Travel_Most recent': ['', 'main'], 00320 # 'Travel_Most commented': ['', 'main'], 00321 # 'Travel_Best rated ': ['', 'main'], 00322 00323 }, 00324 00325 'groups': { 00326 'F_M_B_C_Featured': ['http://www.dailymotion.com/rss/groups/featured', 'groups'], 00327 'F_M_B_C_Most Recent': ['http://www.dailymotion.com/rss/groups/1', 'groups'], 00328 'F_M_B_C_Most Active': ['http://www.dailymotion.com/rss/groups/active', 'groups'], 00329 'F_M_B_C_Month': ['http://www.dailymotion.com/rss/groups/active-month', 'groups'], 00330 'F_M_B_C_Week': ['http://www.dailymotion.com/rss/groups/active-week', 'groups'], 00331 'F_M_B_C_Today': ['http://www.dailymotion.com/rss/groups/active-today', 'groups'], 00332 }, 00333 00334 'group': { 00335 'group_Top rated': ['http://www.dailymotion.com/rss/rated/group', 'main'], 00336 'group_Most viewed': ['http://www.dailymotion.com/rss/visited/group', 'main'], 00337 'group_Most commented': ['http://www.dailymotion.com/rss/commented/group', 'main'], 00338 }, 00339 00340 } 00341 00342 self.config[u'image_extentions'] = ["png", "jpg", "bmp"] # Acceptable image extentions 00343 00344 ###CHANGE 00345 self.tree_order = ['F_M_B_C', 'categories', 'channels',] 00346 #self.tree_order = ['F_M_B_C', 'categories', 'channels', 'groups'] 00347 00348 self.tree_org = { 00349 'F_M_B_C': [['Featured/Most/Best/Current ...', ['featured', 'creative', 'official', 'hd', 'commented', 'visited', 'rated', 'relevance-month', 'relevance-week', 'relevance-today']], 00350 ], 00351 'categories': [ 00352 ['Categories', ['movie', 'comedy', 'short+film', 'television', 'documentary', 'festival', ]], 00353 ], 00354 'channels': [ 00355 ['Video Channels', u''], 00356 00357 ['Animals', ['animals_motionmaker', 'animals_most_recent', 'animals_hd', 'animals_official_users', 'animals_most_viewed', 'animals_best_rated', ]], 00358 00359 ['Auto-Moto', ['auto_most_recent', 'auto_motionmaker', 'auto_most_viewed', 'auto_official_users', ]], 00360 00361 ['Film & TV', ['film_TV_movie', 'film_TV_comedy', 'film_TV_short_film', 'film_TV_television', 'film_TV_documentary', 'film_TV_festival', ]], 00362 00363 ['Gaming', ['gaming_Trailer', 'gaming_Lego', 'gaming_Machinima', 'gaming_Motionmaker', 'gaming_Review', 'gaming_News', 'gaming_recent', 'gaming_users', ]], 00364 00365 ['Life & Style', ['lifestyle_best_rated', 'lifestyle_most_commented', 'lifestyle_most_viewed', 'lifestyle_HD', ]], 00366 00367 ['News & Politics', ['news_politics_Politics', 'news_politics_Celebrity', 'news_politics_official_users', 'news_politics_International', 'news_politics_Entertainment', 'news_politics_Motionmakers', ]], 00368 00369 ['Sports & Extreme', ['sports_extreme_surf', 'sports_extreme_baseball', 'sports_extreme_wrestling', 'sports_extreme_BMX', ]], 00370 00371 ['Webcam & Vlogs', ['webcam_vlogs_Most_viewed', 'webcam_vlogs_Featured_videos', 'webcam_vlogs_Best_rated', 'webcam_vlogs_Most_Commented', ]], 00372 00373 ['Arts', ['arts_Animation', 'arts_Short_Film', 'arts_Motionmaker', 'arts_Official_Users', 'arts_Suede_swede', 'arts_Most_recent', ]], 00374 00375 ['College', ['college_Most_viewed', 'college_HD_videos', 'college_Best_rated', 'college_Most_commented', ]], 00376 00377 ['Funny', [u'funny_STAND UP', u'funny_Hulu: NBC & Fox', u'funny_My Damn Channel', u'funny_Motionmakers', u'funny_Sketch', u"funny_Nat'l Lampoon", u'funny_Classic Sitcoms', u'funny_Official Users', ]], 00378 00379 ['Latino', [u'latino_Featured Videos', u'latino_HD content', u'latino_Official Content', u'latino_Creative Content', u'latino_Most Commented', u'latino_Most Viewed', u'latino_Best Rated', ]], 00380 00381 ['Music', [u'music_Pop', u'music_Rock', u'music_Jazz', u'music_Covers', u'music_Rap', u'music_R&B', u'music_Metal', u'music_Electro', ]], 00382 00383 ['People & Family', [u'People_Family_Featured Videos', u'People_Family_HD content', u'People_Family_Official Content', u'People_Family_Creative Content', u'People_Family_Most Commented', u'People_Family_Most Viewed', u'People_Family_Best Rated', ]], 00384 00385 ['Tech & Science', [u'Tech_Science_Most recent', u'Tech_Science_Most viewed', u'Tech_Science_Most commented', u'Tech_Science_Best rated', ]], 00386 00387 [u'', u''], 00388 ], 00389 00390 'groups': [ 00391 ['Groups', u''], 00392 00393 [u'Featured', ['F_M_B_C_Featured']], 00394 [u'Most Recent', ['F_M_B_C_Most Recent']], 00395 [u'Most Active', ['F_M_B_C_Most Active']], 00396 [u'Month', ['F_M_B_C_Month']], 00397 [u'Week', ['F_M_B_C_Week']], 00398 [u'Today', ['F_M_B_C_Today']], 00399 00400 [u'', u''], 00401 ], 00402 00403 'group': [ 00404 [u'', ['group_Top rated', 'group_Most viewed', 'group_Most commented', ], ], 00405 ], 00406 00407 } 00408 00409 self.tree_customize = { 00410 'F_M_B_C': { 00411 '__default__': { }, 00412 #'cat name': {}, 00413 }, 00414 'categories': { 00415 '__default__': { }, 00416 #'cat name': {}, 00417 }, 00418 'channels': { 00419 '__default__': { }, 00420 #'cat name': {}, 00421 }, 00422 'groups': { 00423 '__default__': { }, 00424 #'cat name': {}, 00425 }, 00426 'group': { 00427 '__default__': {'add_': u'' }, 00428 #'cat name': {}, 00429 }, 00430 } 00431 00432 self.feed_names = { 00433 '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' 00434 }, 00435 'categories': {'movie': 'Trailers', 'comedy': 'Comedy', 'short+film': 'Short Films', 'television': 'TV Clips', 'documentary': 'Documentaries', 'festival': 'Festivals', 00436 }, 00437 'channels': { 00438 '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', 00439 00440 'auto_most_recent': 'Most recent', 'auto_motionmaker': 'Motionmaker', 'auto_most_viewed': 'Most Viewed', 'auto_official_users': 'Official users', 00441 00442 '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', 00443 00444 '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', 00445 00446 'lifestyle_best_rated': 'Highest Rated', 'lifestyle_most_commented': 'Most Comments', 'lifestyle_most_viewed': 'Most Viewed', 'lifestyle_HD': 'HD videos', 00447 00448 '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', 00449 00450 'sports_extreme_surf': 'Surf', 'sports_extreme_baseball': 'Baseball', 'sports_extreme_wrestling': 'Wrestling', 'sports_extreme_BMX': 'BMX', 00451 00452 'webcam_vlogs_Most_viewed': 'Most viewed', 'webcam_vlogs_Featured_videos': 'Featured videos', 'webcam_vlogs_Best_rated': 'Highest Rated', 'webcam_vlogs_Most_Commented': 'Most Comments', 00453 00454 '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', 00455 00456 'college_Most_viewed': 'Most viewed', 'college_HD_videos': 'HD videos', 'college_Best_rated': 'Highest Rated', 'college_Most_commented': 'Most Comments', 00457 00458 u'funny_STAND UP': 'STAND UP', u'funny_Hulu: NBC & Fox': 'Hulu: NBC & Fox', u'funny_My Damn Channel': 'My Damn Channel', u'funny_Motionmakers': 'Motionmakers', u'funny_Sketch': 'Sketch', u"funny_Nat'l Lampoon": "Nat'l Lampoon", u'funny_Classic Sitcoms': 'Classic Sitcoms', u'funny_Official Users': 'Official Users', 00459 00460 u'latino_Featured Videos': u'Featured Videos', u'latino_HD content': u'HD content', u'latino_Official Content': u'Official Content', u'latino_Creative Content': u'Creative Content', u'latino_Most Commented': u'Most Comments', u'latino_Most Viewed': u'Most Viewed', u'latino_Best Rated': u'Highest Rated', 00461 00462 u'music_Pop': u'Pop', u'music_Rock': u'Rock', u'music_Jazz': u'Jazz', u'music_Covers': u'Covers', u'music_Rap': u'Rap', u'music_R&B': u'R&B', u'music_Metal': u'Metal', u'music_Electro': u'Electro', 00463 00464 u'People_Family_Featured Videos': u'Featured Videos', u'People_Family_HD content': u'HD content', u'People_Family_Official Content': u'Official Content', u'People_Family_Creative Content': u'Creative Content', u'People_Family_Most Commented': u'Most Comments', u'People_Family_Most Viewed': u'Most Viewed', u'People_Family_Best Rated': u'Highest Rated', 00465 00466 u'Tech_Science_Most recent': u'Most recent', u'Tech_Science_Most viewed': u'Most viewed', u'Tech_Science_Most commented': u'Most Comments', u'Tech_Science_Best rated': u'Highest Rated', 00467 00468 }, 00469 'groups': { 00470 'F_M_B_C_Featured': u'Featured', 'F_M_B_C_Most Recent': u'Most Recent', 'F_M_B_C_Most Active': u'Most Active', 'F_M_B_C_Month': u'Month', 'F_M_B_C_Week': u'Week', 'F_M_B_C_Today': u'Today', 00471 00472 }, 00473 'group': { 00474 u'group_Top rated': u'Top rated', u'group_Most viewed': u'Most viewed', u'group_Most commented': u'Most Comments', 00475 00476 }, 00477 } 00478 00479 self.feed_icons = { 00480 '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' 00481 }, 00482 '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', 00483 }, 00484 'channels': { 00485 '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', 00486 00487 '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', 00488 00489 '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', 00490 00491 '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', 00492 00493 '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', 00494 00495 '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', 00496 00497 'sports_extreme_surf': 'directories/topics/sports', 'sports_extreme_baseball': 'directories/topics/sports', 'sports_extreme_wrestling': 'directories/topics/sports', 'sports_extreme_BMX': 'directories/topics/sports', 00498 00499 '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', 00500 00501 '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', 00502 00503 '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', 00504 00505 u'funny_STAND UP': 'directories/film_genres/comedy', u'funny_Hulu: NBC & Fox': 'directories/film_genres/comedy', u'funny_My Damn Channel': 'directories/film_genres/comedy', u'funny_Motionmakers': 'directories/film_genres/comedy', u'funny_Sketch': 'directories/film_genres/comedy', u"funny_Nat'l Lampoon": "directories/film_genres/comedy", u'funny_Classic Sitcoms': 'directories/film_genres/comedy', u'funny_Official Users': 'directories/film_genres/comedy', 00506 00507 u'latino_Featured Videos': u'directories/topics/featured', u'latino_HD content': u'directories/topics/hd', u'latino_Official Content': u'directories/music_genres/latino', u'latino_Creative Content': u'directories/music_genres/latino', u'latino_Most Commented': u'directories/topics/most_comments', u'latino_Most Viewed': u'directories/topics/most_viewed', u'latino_Best Rated': u'directories/topics/rated', 00508 00509 u'music_Pop': u'directories/music_genres/pop', u'music_Rock': u'directories/music_genres/rock', u'music_Jazz': u'directories/music_genres/jazz', u'music_Covers': u'directories/topics/music', u'music_Rap': u'directories/music_genres/hiphop', u'music_R&B': u'directories/music_genres/rnb', u'music_Metal': u'directories/music_genres/metal', u'music_Electro': u'directories/music_genres/electronic_dance', 00510 00511 u'People_Family_Featured Videos': u'directories/topics/featured', u'People_Family_HD content': u'directories/topics/hd', u'People_Family_Official Content': u'directories/topics/people', u'People_Family_Creative Content': u'directories/topics/people', u'People_Family_Most Commented': u'directories/topics/most_comments', u'People_Family_Most Viewed': u'directories/topics/most_viewed', u'People_Family_Best Rated': u'directories/topics/rated', 00512 00513 u'Tech_Science_Most recent': u'directories/topics/recent', u'Tech_Science_Most viewed': u'directories/topics/most_viewed', u'Tech_Science_Most commented': u'directories/topics/most_comments', u'Tech_Science_Best rated': u'directories/topics/rated', 00514 00515 'Animals': 'directories/topics/animals', 00516 'Auto-Moto': 'directories/topics/automotive', 00517 'Film & TV': 'directories/topics/movies', 00518 'Gaming': 'directories/topics/games', 00519 'Life & Style': 'directories/topics/????', 00520 'News & Politics': 'directories/topics/news', 00521 'Sports & Extreme': 'directories/topics/sports', 00522 'Webcam & Vlogs': 'directories/topics/videoblog', 00523 'Arts': 'directories/topics/arts', 00524 'College': 'directories/topics/college', 00525 'Funny': 'directories/film_genres/comedy', 00526 'Latino': 'directories/music_genres/latino', 00527 'Music': 'directories/topics/music', 00528 'People & Family': 'directories/topics/people', 00529 'Tech & Science': 'directories/topics/technology', 00530 }, 00531 } 00532 00533 # Switches specific to Group tree view 00534 self.group_id = u'' 00535 self.groupview = False 00536 00537 # Initialize the tree view flag so that the item parsing code can be used for multiple purposes 00538 self.treeview = False 00539 self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/dailymotion.png' 00540 # end __init__() 00541 00542 ########################################################################################################### 00543 # 00544 # Start - Utility functions 00545 # 00546 ########################################################################################################### 00547 00548 def detectUserLocationByIP(self): 00549 '''Get longitude and latitiude to find videos relative to your location. Up to three different 00550 servers will be tried before giving up. 00551 return a dictionary e.g. 00552 {'Latitude': '43.6667', 'Country': 'Canada', 'Longitude': '-79.4167', 'City': 'Toronto'} 00553 return an empty dictionary if there were any errors 00554 Code found at: http://blog.suinova.com/2009/04/from-ip-to-geolocation-country-city.html 00555 ''' 00556 def getExternalIP(): 00557 '''Find the external IP address of this computer. 00558 ''' 00559 url = urllib.URLopener() 00560 try: 00561 resp = url.open('http://www.whatismyip.com/automation/n09230945.asp') 00562 return resp.read() 00563 except: 00564 return None 00565 # end getExternalIP() 00566 00567 ip = getExternalIP() 00568 00569 if ip == None: 00570 return {} 00571 00572 try: 00573 gs = urllib.urlopen('http://blogama.org/ip_query.php?ip=%s&output=xml' % ip) 00574 txt = gs.read() 00575 except: 00576 try: 00577 gs = urllib.urlopen('http://www.seomoz.org/ip2location/look.php?ip=%s' % ip) 00578 txt = gs.read() 00579 except: 00580 try: 00581 gs = urllib.urlopen('http://api.hostip.info/?ip=%s' % ip) 00582 txt = gs.read() 00583 except: 00584 logging.error('GeoIP servers not available') 00585 return {} 00586 try: 00587 if txt.find('<Response>') > 0: 00588 countrys = re.findall(r'<CountryName>([\w ]+)<',txt)[0] 00589 citys = re.findall(r'<City>([\w ]+)<',txt)[0] 00590 lats,lons = re.findall(r'<Latitude>([\d\-\.]+)</Latitude>\s*<Longitude>([\d\-\.]+)<',txt)[0] 00591 elif txt.find('GLatLng') > 0: 00592 citys,countrys = re.findall('<br />\s*([^<]+)<br />\s*([^<]+)<',txt)[0] 00593 lats,lons = re.findall('LatLng\(([-\d\.]+),([-\d\.]+)',txt)[0] 00594 elif txt.find('<gml:coordinates>') > 0: 00595 citys = re.findall('<Hostip>\s*<gml:name>(\w+)</gml:name>',txt)[0] 00596 countrys = re.findall('<countryName>([\w ,\.]+)</countryName>',txt)[0] 00597 lats,lons = re.findall('gml:coordinates>([-\d\.]+),([-\d\.]+)<',txt)[0] 00598 else: 00599 logging.error('error parsing IP result %s'%txt) 00600 return {} 00601 return {'Country':countrys,'City':citys,'Latitude':lats,'Longitude':lons} 00602 except: 00603 logging.error('Error parsing IP result %s'%txt) 00604 return {} 00605 # end detectUserLocationByIP() 00606 00607 def massageDescription(self, text): 00608 '''Removes HTML markup from a text string. 00609 @param text The HTML source. 00610 @return The plain text. If the HTML source contains non-ASCII 00611 entities or character references, this is a Unicode string. 00612 ''' 00613 def fixup(m): 00614 text = m.group(0) 00615 if text[:1] == "<": 00616 return "" # ignore tags 00617 if text[:2] == "&#": 00618 try: 00619 if text[:3] == "&#x": 00620 return unichr(int(text[3:-1], 16)) 00621 else: 00622 return unichr(int(text[2:-1])) 00623 except ValueError: 00624 pass 00625 elif text[:1] == "&": 00626 import htmlentitydefs 00627 entity = htmlentitydefs.entitydefs.get(text[1:-1]) 00628 if entity: 00629 if entity[:2] == "&#": 00630 try: 00631 return unichr(int(entity[2:-1])) 00632 except ValueError: 00633 pass 00634 else: 00635 return unicode(entity, "iso-8859-1") 00636 return text # leave as is 00637 return self.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.textUtf8(text))).replace(u'\n',u' ') 00638 # end massageDescription() 00639 00640 00641 def _initLogger(self): 00642 """Setups a logger using the logging module, returns a log object 00643 """ 00644 logger = logging.getLogger(self.log_name) 00645 formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s') 00646 00647 hdlr = logging.StreamHandler(sys.stdout) 00648 00649 hdlr.setFormatter(formatter) 00650 logger.addHandler(hdlr) 00651 00652 if self.config['debug_enabled']: 00653 logger.setLevel(logging.DEBUG) 00654 else: 00655 logger.setLevel(logging.WARNING) 00656 return logger 00657 #end initLogger 00658 00659 00660 def textUtf8(self, text): 00661 if text == None: 00662 return text 00663 try: 00664 return unicode(text, 'utf8') 00665 except UnicodeDecodeError: 00666 return u'' 00667 except (UnicodeEncodeError, TypeError): 00668 return text 00669 # end textUtf8() 00670 00671 00672 def ampReplace(self, text): 00673 '''Replace all "&" characters with "&" 00674 ''' 00675 text = self.textUtf8(text) 00676 return text.replace(u'&',u'~~~~~').replace(u'&',u'&').replace(u'~~~~~', u'&') 00677 # end ampReplace() 00678 00679 00680 def setTreeViewIcon(self, dir_icon=None): 00681 '''Check if there is a specific generic tree view icon. If not default to the channel icon. 00682 return self.tree_dir_icon 00683 ''' 00684 self.tree_dir_icon = self.channel_icon 00685 if not dir_icon: 00686 if not self.feed_icons.has_key(self.tree_key): 00687 return self.tree_dir_icon 00688 if not self.feed_icons[self.tree_key].has_key(self.feed): 00689 return self.tree_dir_icon 00690 dir_icon = self.feed_icons[self.tree_key][self.feed] 00691 if not dir_icon: 00692 return self.tree_dir_icon 00693 self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, ) 00694 return self.tree_dir_icon 00695 # end setTreeViewIcon() 00696 ########################################################################################################### 00697 # 00698 # End of Utility functions 00699 # 00700 ########################################################################################################### 00701 00702 def processVideoUrl(self, url): 00703 playerUrl = self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/dailymotion.html", \ 00704 url.replace(u'http://www.dailymotion.com/swf/video/', '')) 00705 return self.ampReplace(playerUrl) 00706 00707 def searchTitle(self, title, pagenumber, pagelen): 00708 '''Key word video search of the Dailymotion web site 00709 return an array of matching item dictionaries 00710 return 00711 ''' 00712 url = self.config[u'urls'][u'video.search'] % (urllib.quote_plus(title.encode("utf-8")), pagenumber) 00713 if self.config['debug_enabled']: 00714 print url 00715 print 00716 00717 return self.config['item_parser']['main'](url, []) 00718 # end searchTitle() 00719 00720 00721 def searchForVideos(self, title, pagenumber): 00722 """Common name for a video search. Used to interface with MythTV plugin NetVision 00723 """ 00724 # Channel details and search results 00725 self.channel = {'channel_title': u'Dailymotion', 'channel_link': u'http://www.dailymotion.com', 'channel_description': u"Dailymotion is about finding new ways to see, share and engage your world through the power of online video.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0} 00726 00727 # Easier for debugging 00728 # print self.searchTitle(title, pagenumber, self.page_limit) 00729 # print 00730 # sys.exit() 00731 00732 try: 00733 data = self.searchTitle(title, int(pagenumber), self.page_limit) 00734 except DailymotionVideoNotFound, msg: 00735 sys.stderr.write(u"%s\n" % msg) 00736 return None 00737 except DailymotionUrlError, msg: 00738 sys.stderr.write(u'%s\n' % msg) 00739 sys.exit(1) 00740 except DailymotionHttpError, msg: 00741 sys.stderr.write(self.error_messages['DailymotionHttpError'] % msg) 00742 sys.exit(1) 00743 except DailymotionRssError, msg: 00744 sys.stderr.write(self.error_messages['DailymotionRssError'] % msg) 00745 sys.exit(1) 00746 except Exception, e: 00747 sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e)) 00748 sys.exit(1) 00749 00750 if data == None: 00751 return None 00752 if not len(data): 00753 return None 00754 00755 if self.next_page: 00756 self.channel['channel_numresults'] = len(data) * int(pagenumber) + 1 00757 else: 00758 self.channel['channel_numresults'] = int(pagenumber) * len(data) 00759 00760 self.channel['channel_startindex'] = int(pagenumber) * len(data) 00761 self.channel['channel_returned'] = len(data) 00762 00763 return [[self.channel, data]] 00764 # end searchForVideos() 00765 00766 def displayTreeView(self): 00767 '''Gather the Dailymotion categories/feeds/...etc then get a max page of videos meta data in 00768 each of them. 00769 return array of directories and their video meta data 00770 ''' 00771 # Channel details and search results 00772 self.channel = {'channel_title': u'Dailymotion', 'channel_link': u'http://www.dailymotion.com', 'channel_description': u"Dailymotion is about finding new ways to see, share and engage your world through the power of online video.", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0} 00773 00774 if self.config['debug_enabled']: 00775 print self.config[u'urls'] 00776 print 00777 00778 # Get videos within each category 00779 dictionaries = [] 00780 00781 self.treeview = True 00782 00783 # Process the various video feeds/categories/... etc 00784 for key in self.tree_order: 00785 self.tree_key = key 00786 dictionaries = self.getVideos(self.tree_org[key], dictionaries) 00787 00788 return [[self.channel, dictionaries]] 00789 # end displayTreeView() 00790 00791 def makeURL(self, URL): 00792 '''Form a URL to search for videos 00793 return a URL 00794 ''' 00795 additions = dict(self.tree_customize[self.tree_key]['__default__']) # Set defaults 00796 00797 # Add customizations 00798 if self.feed in self.tree_customize[self.tree_key].keys(): 00799 for element in self.tree_customize[self.tree_key][self.feed].keys(): 00800 additions[element] = self.tree_customize[self.tree_key][self.feed][element] 00801 00802 # Make the search extension string that is added to the URL 00803 addition = u'' 00804 for ky in additions.keys(): 00805 if ky.startswith('add_'): 00806 addition+=u'/%s' % additions[ky] 00807 else: 00808 addition+=u'&%s=%s' % (ky, additions[ky]) 00809 index = URL.find('%') 00810 if index == -1: 00811 return (URL+addition) 00812 else: 00813 return (URL+addition) % self.feed 00814 # end makeURL() 00815 00816 00817 def getVideos(self, dir_dict, dictionaries): 00818 '''Parse a list made of category lists and retrieve video meta data 00819 return a dictionary of directory names and category's video meta data 00820 ''' 00821 for sets in dir_dict: 00822 if not isinstance(sets[1], list): 00823 if sets[0] != '': # Add the nested dictionaries display name 00824 try: 00825 dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])]) 00826 except KeyError: 00827 dictionaries.append([self.massageDescription(sets[0]), self.channel_icon]) 00828 else: 00829 dictionaries.append(['', u'']) # Add the nested dictionary indicator 00830 continue 00831 temp_dictionary = [] 00832 for self.feed in sets[1]: 00833 if self.config[u'urls'][u'tree.view'][self.tree_key].has_key('__all__'): 00834 URL = self.config[u'urls'][u'tree.view'][self.tree_key]['__all__'] 00835 else: 00836 URL = self.config[u'urls'][u'tree.view'][self.tree_key][self.feed] 00837 temp_dictionary = self.config['item_parser'][URL[1]](self.makeURL(URL[0]), temp_dictionary) 00838 if len(temp_dictionary): 00839 if len(sets[0]): # Add the nested dictionaries display name 00840 try: 00841 dictionaries.append([self.massageDescription(sets[0]), self.setTreeViewIcon(self.feed_icons[self.tree_key][sets[0]])]) 00842 except KeyError: 00843 dictionaries.append([self.massageDescription(sets[0]), self.channel_icon]) 00844 for element in temp_dictionary: 00845 dictionaries.append(element) 00846 if len(sets[0]): 00847 dictionaries.append(['', u'']) # Add the nested dictionary indicator 00848 return dictionaries 00849 # end getVideos() 00850 00851 def getVideosForURL(self, url, dictionaries): 00852 '''Get the video meta data for url search 00853 return the video dictionary of directories and their video mata data 00854 ''' 00855 initial_length = len(dictionaries) 00856 00857 if self.config['debug_enabled']: 00858 print "Video URL:" 00859 print url 00860 print 00861 00862 try: 00863 etree = XmlHandler(url).getEt() 00864 except Exception, errormsg: 00865 sys.stderr.write(self.error_messages['DailymotionUrlError'] % (url, errormsg)) 00866 return dictionaries 00867 00868 if etree is None: 00869 sys.stderr.write(u'1-No Videos for (%s)\n' % self.feed) 00870 return dictionaries 00871 00872 dictionary_first = False 00873 directory_image = u'' 00874 self.next_page = False 00875 language = self.config['language'] 00876 for elements in etree.find('channel'): 00877 if elements.tag.endswith(u'language'): 00878 if elements.text: 00879 language = elements.text[:2] 00880 continue 00881 00882 if elements.tag.endswith(u'link'): 00883 if elements.get('rel') == "next": 00884 self.next_page = True 00885 continue 00886 00887 if elements.tag.endswith(u'image'): 00888 if elements.get('href'): 00889 directory_image = self.ampReplace(elements.get(u'href').strip()) 00890 continue 00891 00892 if not elements.tag.endswith(u'item'): 00893 continue 00894 00895 meta_data = {} 00896 cur_size = True 00897 flash = False 00898 meta_data['language'] = language 00899 for e in elements: 00900 if e.tag.endswith(u'title'): 00901 if e.text: 00902 meta_data['title'] = self.massageDescription(e.text.strip()) 00903 continue 00904 if e.tag.endswith(u'author'): 00905 if e.text: 00906 meta_data['author'] = self.massageDescription(e.text.strip()) 00907 continue 00908 if e.tag.endswith(u'pubDate'): # Wed, 16 Dec 2009 21:15:57 +0100 00909 if e.text: 00910 meta_data['published_parsed'] = e.text.strip() 00911 continue 00912 if e.tag.endswith(u'description'): 00913 if e.text: 00914 index1 = e.text.find(u'<p>') 00915 index2 = e.text.find(u'</p>') 00916 if index1 != -1 and index2 != -1: 00917 meta_data['media_description'] = self.massageDescription(e.text[index1+3:index2].strip()) 00918 continue 00919 if e.tag.endswith(u'thumbnail'): 00920 if e.get(u'url'): 00921 meta_data['thumbnail'] = self.ampReplace(e.get(u'url').strip()) 00922 continue 00923 if e.tag.endswith(u'player'): 00924 if e.text: 00925 meta_data['link'] = self.ampReplace(e.get(u'url').strip()) 00926 continue 00927 if e.tag.endswith(u'videorating'): 00928 if e.text: 00929 meta_data['rating'] = e.text.strip() 00930 continue 00931 if not e.tag.endswith(u'group'): 00932 continue 00933 for elem in e: 00934 if elem.tag.endswith('content') and elem.get('type') == 'application/x-shockwave-flash': 00935 if elem.get('url'): 00936 meta_data['video'] = self.processVideoUrl(elem.get('url')) 00937 if elem.get('duration'): 00938 meta_data['duration'] = elem.get('duration').strip() 00939 if elem.get('width'): 00940 meta_data['item_width'] = elem.get('width').strip() 00941 if elem.get('height'): 00942 meta_data['item_height'] = elem.get('height').strip() 00943 break 00944 continue 00945 00946 if not meta_data.has_key('video') and not meta_data.has_key('link'): 00947 continue 00948 00949 if not meta_data.has_key('video'): 00950 meta_data['video'] = meta_data['link'] 00951 else: 00952 meta_data['link'] = meta_data['video'] 00953 00954 if self.treeview: 00955 if not dictionary_first: # Add the dictionaries display name 00956 if not self.groupview: 00957 dictionaries.append([self.massageDescription(self.feed_names[self.tree_key][self.feed]), self.setTreeViewIcon()]) 00958 else: 00959 dictionaries.append([self.massageDescription(self.feed_names[self.tree_key][self.feed]), self.groupview_image]) 00960 dictionary_first = True 00961 00962 final_item = {} 00963 for key in self.key_translation[1].keys(): 00964 if not meta_data.has_key(key): 00965 final_item[self.key_translation[1][key]] = u'' 00966 else: 00967 final_item[self.key_translation[1][key]] = meta_data[key] 00968 dictionaries.append(final_item) 00969 00970 if self.treeview: 00971 if initial_length < len(dictionaries): # Need to check if there was any items for this Category 00972 dictionaries.append(['', u'']) # Add the nested dictionary indicator 00973 return dictionaries 00974 # end getVideosForURL() 00975 00976 00977 def getVideosForGroupURL(self, url, dictionaries): 00978 '''Get the video meta data for a group url search 00979 return the video dictionary of directories and their video mata data 00980 ''' 00981 self.groupview = True 00982 initial_length = len(dictionaries) 00983 save_tree_key = self.tree_key 00984 00985 if self.config['debug_enabled']: 00986 print "Groups URL:" 00987 print url 00988 print 00989 00990 try: 00991 etree = XmlHandler(url).getEt() 00992 except Exception, errormsg: 00993 sys.stderr.write(self.error_messages['DailymotionUrlError'] % (url, errormsg)) 00994 return dictionaries 00995 00996 if etree is None: 00997 sys.stderr.write(u'1-No Groups for (%s)\n' % self.feed) 00998 return dictionaries 00999 01000 for elements in etree.find('channel'): 01001 if not elements.tag.endswith(u'item'): 01002 continue 01003 self.group_id = u'' 01004 group_name = u'' 01005 group_image = u'' 01006 for group in elements: 01007 if group.tag == u'title': 01008 if group.text: 01009 group_name = self.massageDescription(group.text.strip()) 01010 if group.tag == u'link': 01011 if group.text: 01012 self.group_id = group.text.strip().replace(u'http://www.dailymotion.com/group/', u'') 01013 if group.tag.endswith(u'thumbnail'): 01014 if group.get(u'url'): 01015 group_image = self.ampReplace(group.get(u'url').strip()) 01016 if group_name != u'' and self.group_id != u'' and group_image != u'': 01017 01018 temp_dictionary = [] 01019 self.tree_key = 'group' 01020 self.groupview_image = group_image 01021 self.tree_customize[self.tree_key]['__default__']['add_'] = self.group_id 01022 temp_dictionary = self.getVideos(self.tree_org[self.tree_key], temp_dictionary) 01023 if len(temp_dictionary): 01024 if self.treeview: 01025 dictionaries.append([group_name, group_image]) 01026 01027 for element in temp_dictionary: 01028 dictionaries.append(element) 01029 01030 if self.treeview: 01031 dictionaries.append([u'',u'']) 01032 break 01033 01034 self.tree_key = save_tree_key 01035 01036 return dictionaries 01037 # end getVideosForGroupURL() 01038 # end Videos() class
1.7.6.1