MythTV  0.26-pre
dailymotion_api.py
Go to the documentation of this file.
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 "&amp;"
00674         '''
00675         text = self.textUtf8(text)
00676         return text.replace(u'&amp;',u'~~~~~').replace(u'&',u'&amp;').replace(u'~~~~~', u'&amp;')
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends