00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 __title__ ="bliptv_api - Simple-to-use Python interface to the bliptv API (http://blip.tv/about/api/)"
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 blip.tv. These routines are based on the v2.0 api. Specifications
00020 for this api are published at http://blip.tv/about/api/
00021 '''
00022
00023 __version__="v0.2.5"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 import os, struct, sys, re, time
00041 import urllib, urllib2
00042 import logging
00043 from MythTV import MythXML
00044
00045 try:
00046 import xml.etree.cElementTree as ElementTree
00047 except ImportError:
00048 import xml.etree.ElementTree as ElementTree
00049
00050 from bliptv_exceptions import (BliptvUrlError, BliptvHttpError, BliptvRssError, BliptvVideoNotFound, BliptvXmlError)
00051
00052 class OutStreamEncoder(object):
00053 """Wraps a stream with an encoder"""
00054 def __init__(self, outstream, encoding=None):
00055 self.out = outstream
00056 if not encoding:
00057 self.encoding = sys.getfilesystemencoding()
00058 else:
00059 self.encoding = encoding
00060
00061 def write(self, obj):
00062 """Wraps the output stream, encoding Unicode strings with the specified encoding"""
00063 if isinstance(obj, unicode):
00064 try:
00065 self.out.write(obj.encode(self.encoding))
00066 except IOError:
00067 pass
00068 else:
00069 try:
00070 self.out.write(obj)
00071 except IOError:
00072 pass
00073
00074 def __getattr__(self, attr):
00075 """Delegate everything but write to the stream"""
00076 return getattr(self.out, attr)
00077 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
00078 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
00079
00080
00081 class XmlHandler:
00082 """Deals with retrieval of XML files from API
00083 """
00084 def __init__(self, url):
00085 self.url = url
00086
00087 def _grabUrl(self, url):
00088 try:
00089 urlhandle = urllib.urlopen(url)
00090 except IOError, errormsg:
00091 raise BliptvHttpError(errormsg)
00092 return urlhandle.read()
00093
00094 def getEt(self):
00095 xml = self._grabUrl(self.url)
00096 try:
00097 et = ElementTree.fromstring(xml)
00098 except SyntaxError, errormsg:
00099 raise BliptvXmlError(errormsg)
00100 return et
00101
00102
00103 class Videos(object):
00104 """Main interface to http://blip.tv/
00105 This is done to support a common naming framework for all python Netvision plugins no matter their site
00106 target.
00107
00108 Supports search and tree view methods
00109 The apikey is a not required to access http://blip.tv/
00110 """
00111 def __init__(self,
00112 apikey,
00113 mythtv = True,
00114 interactive = False,
00115 select_first = False,
00116 debug = False,
00117 custom_ui = None,
00118 language = None,
00119 search_all_languages = False,
00120 ):
00121 """apikey (str/unicode):
00122 Specify the target site API key. Applications need their own key in some cases
00123
00124 mythtv (True/False):
00125 When True, the returned meta data is being returned has the key and values massaged to match MythTV
00126 When False, the returned meta data is being returned matches what target site returned
00127
00128 interactive (True/False): (This option is not supported by all target site apis)
00129 When True, uses built-in console UI is used to select the correct show.
00130 When False, the first search result is used.
00131
00132 select_first (True/False): (This option is not supported currently implemented in any grabbers)
00133 Automatically selects the first series search result (rather
00134 than showing the user a list of more than one series).
00135 Is overridden by interactive = False, or specifying a custom_ui
00136
00137 debug (True/False):
00138 shows verbose debugging information
00139
00140 custom_ui (xx_ui.BaseUI subclass): (This option is not supported currently implemented in any grabbers)
00141 A callable subclass of interactive class (overrides interactive option)
00142
00143 language (2 character language abbreviation): (This option is not supported by all target site apis)
00144 The language of the returned data. Is also the language search
00145 uses. Default is "en" (English). For full list, run..
00146
00147 search_all_languages (True/False): (This option is not supported by all target site apis)
00148 By default, a Netvision grabber will only search in the language specified using
00149 the language option. When this is True, it will search for the
00150 show in any language
00151
00152 """
00153 self.config = {}
00154 self.mythxml = MythXML()
00155
00156 if apikey is not None:
00157 self.config['apikey'] = apikey
00158 else:
00159 pass
00160
00161 self.config['debug_enabled'] = debug
00162
00163 self.log_name = "Bliptv"
00164 self.log = self._initLogger()
00165
00166 self.config['custom_ui'] = custom_ui
00167
00168 self.config['interactive'] = interactive
00169
00170 self.config['select_first'] = select_first
00171
00172 self.config['search_all_languages'] = search_all_languages
00173
00174
00175 self.config['language'] = "en"
00176
00177 self.error_messages = {'BliptvUrlError': u"! Error: The URL (%s) cause the exception error (%s)\n", 'BliptvHttpError': u"! Error: An HTTP communicating error with blip.tv was raised (%s)\n", 'BliptvRssError': u"! Error: Invalid RSS meta data\nwas received from blip.tv error (%s). Skipping item.\n", 'BliptvVideoNotFound': u"! Error: Video search with blip.tv did not return any results (%s)\n", }
00178
00179
00180 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', 'blip_safeusername': 'item_author', 'updated': 'item_pubdate', 'blip_puredescription': 'item_description', 'link': 'item_link', 'blip_picture': 'item_thumbnail', 'video': 'item_url', 'blip_runtime': 'item_duration', 'blip_rating': 'item_rating', 'width': 'item_width', 'height': 'item_height', 'language': 'item_lang'}]
00181
00182
00183
00184 self.config['base_url'] = "http://www.blip.tv%s"
00185 self.config['thumb_url'] = u"http://a.images.blip.tv%s"
00186
00187 self.config[u'urls'] = {}
00188
00189
00190 self.config[u'urls'][u'video.search'] = "http://www.blip.tv/?search=%s;&page=%s;&pagelen=%s;&language_code=%s;&skin=rss"
00191 self.config[u'urls'][u'categories'] = "http://www.blip.tv/?section=categories&cmd=view&skin=api"
00192
00193 self.config[u'image_extentions'] = ["png", "jpg", "bmp"]
00194
00195
00196 self.config['item_parser'] = {}
00197 self.config['item_parser']['main'] = self.getVideosForURL
00198
00199
00200 self.config[u'urls'][u'tree.view'] = {
00201 'P_R_R_F': {
00202 '__all__': ['http://www.blip.tv/%s/?skin=rss', 'main'],
00203 },
00204 'categories': {
00205 '__all__': ['http://www.blip.tv/rss/', 'main'],
00206 },
00207 }
00208
00209
00210
00211 self.tree_order = ['P_R_R_F']
00212
00213 self.tree_org = {
00214
00215 'P_R_R_F': [['', ['popular', 'recent', 'random', 'featured',]],
00216 ],
00217
00218 'categories': [
00219 ['Categories', u''],
00220 ],
00221 }
00222
00223 self.tree_customize = {
00224 'P_R_R_F': {
00225 '__default__': { },
00226
00227 },
00228 'categories': {
00229 '__default__': {'categories_id': u'', 'sort': u'', },
00230
00231 },
00232 }
00233
00234 self.feed_names = {
00235 'P_R_R_F': {'popular': 'Most Comments', 'recent': 'Most Recent', 'random': 'Random selection',
00236 },
00237 'categories': {'featured': 'Featured Videos', 'popular': 'Most Comments', 'recent': 'Most Recent', 'random': 'Random selection',
00238 },
00239 }
00240
00241 self.feed_icons = {
00242 'P_R_R_F': {'popular': 'directories/topics/most_comments', 'recent': 'directories/topics/most_recent', 'random': 'directories/topics/random',
00243 },
00244 'categories': {'featured': 'directories/topics/featured', 'popular': 'directories/topics/most_comments', 'recent': 'directories/topics/most_recent', 'random': 'directories/topics/random',
00245 },
00246 }
00247
00248
00249 self.categories = False
00250 self.treeview = False
00251 self.channel_icon = u'%SHAREDIR%/mythnetvision/icons/bliptv.png'
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 def detectUserLocationByIP(self):
00262 '''Get longitude and latitiude to find videos relative to your location. Up to three different
00263 servers will be tried before giving up.
00264 return a dictionary e.g.
00265 {'Latitude': '43.6667', 'Country': 'Canada', 'Longitude': '-79.4167', 'City': 'Toronto'}
00266 return an empty dictionary if there were any errors
00267 Code found at: http://blog.suinova.com/2009/04/from-ip-to-geolocation-country-city.html
00268 '''
00269 def getExternalIP():
00270 '''Find the external IP address of this computer.
00271 '''
00272 url = urllib.URLopener()
00273 try:
00274 resp = url.open('http://www.whatismyip.com/automation/n09230945.asp')
00275 return resp.read()
00276 except:
00277 return None
00278
00279
00280 ip = getExternalIP()
00281
00282 if ip == None:
00283 return {}
00284
00285 try:
00286 gs = urllib.urlopen('http://blogama.org/ip_query.php?ip=%s&output=xml' % ip)
00287 txt = gs.read()
00288 except:
00289 try:
00290 gs = urllib.urlopen('http://www.seomoz.org/ip2location/look.php?ip=%s' % ip)
00291 txt = gs.read()
00292 except:
00293 try:
00294 gs = urllib.urlopen('http://api.hostip.info/?ip=%s' % ip)
00295 txt = gs.read()
00296 except:
00297 logging.error('GeoIP servers not available')
00298 return {}
00299 try:
00300 if txt.find('<Response>') > 0:
00301 countrys = re.findall(r'<CountryName>([\w ]+)<',txt)[0]
00302 citys = re.findall(r'<City>([\w ]+)<',txt)[0]
00303 lats,lons = re.findall(r'<Latitude>([\d\-\.]+)</Latitude>\s*<Longitude>([\d\-\.]+)<',txt)[0]
00304 elif txt.find('GLatLng') > 0:
00305 citys,countrys = re.findall('<br />\s*([^<]+)<br />\s*([^<]+)<',txt)[0]
00306 lats,lons = re.findall('LatLng\(([-\d\.]+),([-\d\.]+)',txt)[0]
00307 elif txt.find('<gml:coordinates>') > 0:
00308 citys = re.findall('<Hostip>\s*<gml:name>(\w+)</gml:name>',txt)[0]
00309 countrys = re.findall('<countryName>([\w ,\.]+)</countryName>',txt)[0]
00310 lats,lons = re.findall('gml:coordinates>([-\d\.]+),([-\d\.]+)<',txt)[0]
00311 else:
00312 logging.error('error parsing IP result %s'%txt)
00313 return {}
00314 return {'Country':countrys,'City':citys,'Latitude':lats,'Longitude':lons}
00315 except:
00316 logging.error('Error parsing IP result %s'%txt)
00317 return {}
00318
00319
00320 def massageDescription(self, text):
00321 '''Removes HTML markup from a text string.
00322 @param text The HTML source.
00323 @return The plain text. If the HTML source contains non-ASCII
00324 entities or character references, this is a Unicode string.
00325 '''
00326 def fixup(m):
00327 text = m.group(0)
00328 if text[:1] == "<":
00329 return ""
00330 if text[:2] == "&#":
00331 try:
00332 if text[:3] == "&#x":
00333 return unichr(int(text[3:-1], 16))
00334 else:
00335 return unichr(int(text[2:-1]))
00336 except ValueError:
00337 pass
00338 elif text[:1] == "&":
00339 import htmlentitydefs
00340 entity = htmlentitydefs.entitydefs.get(text[1:-1])
00341 if entity:
00342 if entity[:2] == "&#":
00343 try:
00344 return unichr(int(entity[2:-1]))
00345 except ValueError:
00346 pass
00347 else:
00348 return unicode(entity, "iso-8859-1")
00349 return text
00350 return self.ampReplace(re.sub(u"(?s)<[^>]*>|&#?\w+;", fixup, self.textUtf8(text))).replace(u'\n',u' ')
00351
00352
00353
00354 def _initLogger(self):
00355 """Setups a logger using the logging module, returns a log object
00356 """
00357 logger = logging.getLogger(self.log_name)
00358 formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
00359
00360 hdlr = logging.StreamHandler(sys.stdout)
00361
00362 hdlr.setFormatter(formatter)
00363 logger.addHandler(hdlr)
00364
00365 if self.config['debug_enabled']:
00366 logger.setLevel(logging.DEBUG)
00367 else:
00368 logger.setLevel(logging.WARNING)
00369 return logger
00370
00371
00372
00373 def textUtf8(self, text):
00374 if text == None:
00375 return text
00376 try:
00377 return unicode(text, 'utf8')
00378 except UnicodeDecodeError:
00379 return u''
00380 except (UnicodeEncodeError, TypeError):
00381 return text
00382
00383
00384
00385 def ampReplace(self, text):
00386 '''Replace all "&" characters with "&"
00387 '''
00388 text = self.textUtf8(text)
00389 return text.replace(u'&',u'~~~~~').replace(u'&',u'&').replace(u'~~~~~', u'&')
00390
00391
00392 def setTreeViewIcon(self, dir_icon=None):
00393 '''Check if there is a specific generic tree view icon. If not default to the channel icon.
00394 return self.tree_dir_icon
00395 '''
00396 self.tree_dir_icon = self.channel_icon
00397 if not dir_icon:
00398 if not self.feed_icons.has_key(self.tree_key):
00399 return self.tree_dir_icon
00400 if not self.feed_icons[self.tree_key].has_key(self.feed):
00401 return self.tree_dir_icon
00402 dir_icon = self.feed_icons[self.tree_key][self.feed]
00403 if not dir_icon:
00404 return self.tree_dir_icon
00405 self.tree_dir_icon = u'%%SHAREDIR%%/mythnetvision/icons/%s.png' % (dir_icon, )
00406 return self.tree_dir_icon
00407
00408
00409
00410
00411
00412
00413
00414
00415 def processVideoUrl(self, url):
00416 playerUrl = self.mythxml.getInternetContentUrl("nv_python_libs/configs/HTML/bliptv.html", \
00417 url.replace(u'http://blip.tv/play/', ''))
00418 return self.ampReplace(playerUrl)
00419
00420 def searchTitle(self, title, pagenumber, pagelen):
00421 '''Key word video search of the blip.tv web site
00422 return an array of matching item dictionaries
00423 return
00424 '''
00425 url = self.config[u'urls'][u'video.search'] % (urllib.quote_plus(title.encode("utf-8")), pagenumber, pagelen, self.config['language'])
00426
00427 if self.config['debug_enabled']:
00428 print "Search URL:"
00429 print url
00430 print
00431
00432 try:
00433 etree = XmlHandler(url).getEt()
00434 except Exception, errormsg:
00435 raise BliptvUrlError(self.error_messages['BliptvUrlError'] % (url, errormsg))
00436
00437 if etree is None:
00438 raise BliptvVideoNotFound(u"1-No blip.tv Video matches found for search value (%s)" % title)
00439
00440
00441 elements_final = []
00442 dictionary_first = False
00443 directory_image = u''
00444 self.next_page = False
00445 language = self.config['language']
00446 for elements in etree.find('channel'):
00447 if elements.tag == 'language':
00448 if elements.text:
00449 language = elements.text[:2]
00450 continue
00451 if not elements.tag == 'item':
00452 continue
00453 item = {}
00454 item['language'] = language
00455 embedURL = u''
00456 for elem in elements:
00457 if elem.tag == 'title':
00458 if elem.text:
00459 item['title'] = self.massageDescription(elem.text.strip())
00460 continue
00461 if elem.tag.endswith('safeusername'):
00462 if elem.text:
00463 item['blip_safeusername'] = self.massageDescription(elem.text.strip())
00464 continue
00465 if elem.tag.endswith('pubDate'):
00466 if elem.text:
00467 item['updated'] = self.massageDescription(elem.text.strip())
00468 continue
00469 if elem.tag.endswith('puredescription'):
00470 if elem.text:
00471 item['blip_puredescription'] = self.massageDescription(elem.text.strip())
00472 continue
00473 if elem.tag.endswith('link'):
00474 if elem.text:
00475 item['link'] = self.ampReplace(elem.text.strip())
00476 continue
00477 if elem.tag.endswith('embedUrl'):
00478 if elem.text:
00479 embedURL = self.ampReplace(elem.text.strip())
00480 continue
00481 if elem.tag.endswith('thumbnail'):
00482 if elem.get('url'):
00483 item['blip_picture'] = self.ampReplace(elem.get('url').strip())
00484 continue
00485 if elem.tag.endswith('group'):
00486 file_size = 0
00487 for e in elem:
00488 if e.tag.endswith('content'):
00489 if e.get('fileSize'):
00490 try:
00491 if int(e.get('fileSize')) > file_size:
00492 item['video'] = self.ampReplace(e.get('url').strip())
00493 file_size = int(e.get('fileSize'))
00494 except:
00495 pass
00496 continue
00497 continue
00498 if elem.tag.endswith('runtime'):
00499 if elem.text:
00500 item['blip_runtime'] = self.massageDescription(elem.text.strip())
00501 continue
00502 if elem.tag.endswith('rating'):
00503 if elem.text:
00504 item['blip_rating'] = self.massageDescription(elem.text.strip())
00505 continue
00506 if not item.has_key('video') and not item.has_key('link') and not embedURL:
00507 continue
00508 if embedURL:
00509 item['link'] = self.processVideoUrl(embedURL)
00510 if item.has_key('link') and not item.has_key('video'):
00511 continue
00512 if item.has_key('video') and not item.has_key('link'):
00513 item['link'] = item['video']
00514 elements_final.append(item)
00515
00516 if not len(elements_final):
00517 raise BliptvVideoNotFound(u"2-No blip.tv Video matches found for search value (%s)" % title)
00518
00519 return elements_final
00520
00521
00522
00523 def searchForVideos(self, title, pagenumber):
00524 """Common name for a video search. Used to interface with MythTV plugin NetVision
00525 """
00526 try:
00527 data = self.searchTitle(title, pagenumber, self.page_limit)
00528 except BliptvVideoNotFound, msg:
00529 sys.stderr.write(u"%s\n" % msg)
00530 return None
00531 except BliptvUrlError, msg:
00532 sys.stderr.write(u'%s' % msg)
00533 sys.exit(1)
00534 except BliptvHttpError, msg:
00535 sys.stderr.write(self.error_messages['BliptvHttpError'] % msg)
00536 sys.exit(1)
00537 except BliptvRssError, msg:
00538 sys.stderr.write(self.error_messages['BliptvRssError'] % msg)
00539 sys.exit(1)
00540 except Exception, e:
00541 sys.stderr.write(u"! Error: Unknown error during a Video search (%s)\nError(%s)\n" % (title, e))
00542 sys.exit(1)
00543
00544 if data == None:
00545 return None
00546 if not len(data):
00547 return None
00548
00549 items = []
00550 for match in data:
00551 item_data = {}
00552 for key in self.key_translation[1].keys():
00553 if key in match.keys():
00554 item_data[self.key_translation[1][key]] = match[key]
00555 else:
00556 item_data[self.key_translation[1][key]] = u''
00557 items.append(item_data)
00558
00559
00560 channel = {'channel_title': u'blip.tv', 'channel_link': u'http://blip.tv', 'channel_description': u"We're the next generation television network", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
00561
00562 if len(items) == self.page_limit:
00563 channel['channel_numresults'] = self.page_limit * int(pagenumber) + 1
00564 else:
00565 channel['channel_numresults'] = self.page_limit * int(pagenumber)
00566 channel['channel_startindex'] = self.page_limit * int(pagenumber)
00567 channel['channel_returned'] = len(items)
00568
00569 if len(items):
00570 return [[channel, items]]
00571 return None
00572
00573
00574
00575 def getCategories(self):
00576 '''Get the list of valid category ids and their name and update the proper dictionaries
00577 return nothing
00578 '''
00579 url = self.config[u'urls'][u'categories']
00580 if self.config['debug_enabled']:
00581 print "Category list URL:"
00582 print url
00583 print
00584
00585 try:
00586 etree = XmlHandler(url).getEt()
00587 except Exception, errormsg:
00588 sys.stderr.write(self.error_messages['BliptvUrlError'] % (url, errormsg))
00589 self.tree_order.remove('categories')
00590 return
00591
00592 if etree is None:
00593 sys.stderr.write(u'1-No Categories found at (%s)\n' % url)
00594 self.tree_order.remove('categories')
00595 return
00596
00597 if not etree.find('payload'):
00598 sys.stderr.write(u'2-No Categories found at (%s)\n' % url)
00599 self.tree_order.remove('categories')
00600 return
00601
00602 category = False
00603 for element in etree.find('payload'):
00604 if element.tag == 'category':
00605 tmp_name = u''
00606 tmp_id = u''
00607 for e in element:
00608 if e.tag == 'id':
00609 if e.text == '-1':
00610 break
00611 if e.text:
00612 tmp_id = self.massageDescription(e.text.strip())
00613 if e.tag == 'name':
00614 if e.text:
00615 tmp_name = self.massageDescription(e.text.strip())
00616 if tmp_id and tmp_name:
00617 category = True
00618 self.tree_org['categories'].append([tmp_name, ['popular', 'recent', 'random', 'featured',]])
00619 self.feed_names['categories'][tmp_name] = tmp_id
00620
00621 if not category:
00622 sys.stderr.write(u'3-No Categories found at (%s)\n' % url)
00623 self.tree_order.remove('categories')
00624 return
00625
00626 self.tree_org['categories'].append([u'', u''])
00627
00628 return
00629
00630
00631 def displayTreeView(self):
00632 '''Gather the categories/feeds/...etc then retrieve a max page of videos meta data in each of them
00633 return array of directories and their video meta data
00634 '''
00635
00636 self.channel = {'channel_title': u'blip.tv', 'channel_link': u'http://blip.tv', 'channel_description': u"We're the next generation television network", 'channel_numresults': 0, 'channel_returned': 1, u'channel_startindex': 0}
00637
00638 if self.config['debug_enabled']:
00639 print self.config[u'urls']
00640 print
00641
00642
00643 self.getCategories()
00644
00645
00646 self.treeview = True
00647 dictionaries = []
00648 for key in self.tree_order:
00649 if key == 'categories':
00650 self.categories = True
00651 else:
00652 self.categories = False
00653 self.tree_key = key
00654 dictionaries = self.getVideos(self.tree_org[key], dictionaries)
00655
00656 return [[self.channel, dictionaries]]
00657
00658
00659 def makeURL(self, URL):
00660 '''Form a URL to search for videos
00661 return a URL
00662 '''
00663 additions = dict(self.tree_customize[self.tree_key]['__default__'])
00664
00665
00666 if self.feed in self.tree_customize[self.tree_key].keys():
00667 for element in self.tree_customize[self.tree_key][self.feed].keys():
00668 additions[element] = self.tree_customize[self.tree_key][self.feed][element]
00669
00670
00671 addition = u''
00672 for ky in additions.keys():
00673 if ky.startswith('add_'):
00674 addition+=u'/%s' % additions[ky]
00675 else:
00676 addition+=u'?%s=%s' % (ky, additions[ky])
00677 index = URL.find('%')
00678 if index == -1:
00679 return (URL+addition)
00680 else:
00681 return (URL+addition) % self.feed
00682
00683
00684
00685 def getVideos(self, dir_dict, dictionaries):
00686 '''Parse a list made of categories and retrieve video meta data
00687 return a dictionary of directory names and categories video meta data
00688 '''
00689 for sets in dir_dict:
00690 if not isinstance(sets[1], list):
00691 if sets[0] != '':
00692 dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
00693 else:
00694 dictionaries.append(['', u''])
00695 continue
00696 temp_dictionary = []
00697 for self.feed in sets[1]:
00698 if self.categories:
00699 self.tree_customize[self.tree_key]['__default__']['categories_id'] = self.feed_names['categories'][sets[0]]
00700 self.tree_customize[self.tree_key]['__default__']['sort'] = self.feed
00701 if self.config[u'urls'][u'tree.view'][self.tree_key].has_key('__all__'):
00702 URL = self.config[u'urls'][u'tree.view'][self.tree_key]['__all__']
00703 else:
00704 URL = self.config[u'urls'][u'tree.view'][self.tree_key][self.feed]
00705 temp_dictionary = self.config['item_parser'][URL[1]](self.makeURL(URL[0]), temp_dictionary)
00706 if len(temp_dictionary):
00707 if len(sets[0]):
00708 dictionaries.append([self.massageDescription(sets[0]), self.channel_icon])
00709 for element in temp_dictionary:
00710 dictionaries.append(element)
00711 if len(sets[0]):
00712 dictionaries.append(['', u''])
00713 return dictionaries
00714
00715
00716 def getVideosForURL(self, url, dictionaries):
00717 '''Get the video meta data for url search
00718 return the video dictionary of directories and their video mata data
00719 '''
00720 initial_length = len(dictionaries)
00721
00722 if self.config['debug_enabled']:
00723 print "Video URL:"
00724 print url
00725 print
00726
00727 try:
00728 etree = XmlHandler(url).getEt()
00729 except Exception, errormsg:
00730 sys.stderr.write(self.error_messages['BliptvUrlError'] % (url, errormsg))
00731 return dictionaries
00732
00733 if etree is None:
00734 sys.stderr.write(u'1-No Videos for (%s)\n' % self.feed)
00735 return dictionaries
00736
00737 dictionary_first = False
00738 self.next_page = False
00739 language = self.config['language']
00740 for elements in etree.find('channel'):
00741 if elements.tag.endswith(u'language'):
00742 if elements.text:
00743 language = elements.text[:2]
00744 continue
00745
00746 if not elements.tag.endswith(u'item'):
00747 continue
00748
00749 item = {}
00750 item['language'] = language
00751 embedURL = u''
00752 for elem in elements:
00753 if elem.tag == 'title':
00754 if elem.text:
00755 item['title'] = self.massageDescription(elem.text.strip())
00756 continue
00757 if elem.tag.endswith('safeusername'):
00758 if elem.text:
00759 item['blip_safeusername'] = self.massageDescription(elem.text.strip())
00760 continue
00761 if elem.tag.endswith('pubDate'):
00762 if elem.text:
00763 item['updated'] = self.massageDescription(elem.text.strip())
00764 continue
00765 if elem.tag.endswith('puredescription'):
00766 if elem.text:
00767 item['blip_puredescription'] = self.massageDescription(elem.text.strip())
00768 continue
00769 if elem.tag == 'link':
00770 if elem.text:
00771 item['link'] = self.ampReplace(elem.text.strip())
00772 continue
00773 if elem.tag.endswith('embedUrl'):
00774 if elem.text:
00775 embedURL = self.ampReplace(elem.text.strip())
00776 continue
00777 if elem.tag.endswith('thumbnail'):
00778 if elem.get('url'):
00779 item['blip_picture'] = self.ampReplace(elem.get('url').strip())
00780 continue
00781 if elem.tag.endswith('group'):
00782 file_size = 0
00783 for e in elem:
00784 if e.tag.endswith('content'):
00785 for key in e.keys():
00786 if key.endswith('vcodec'):
00787 break
00788 else:
00789 continue
00790 if e.get('fileSize'):
00791 try:
00792 if int(e.get('fileSize')) > file_size:
00793 item['video'] = self.ampReplace(e.get('url').strip())
00794 file_size = int(e.get('fileSize'))
00795 except:
00796 pass
00797 if e.get('height'):
00798 item['height'] = e.get('height').strip()
00799 if e.get('width'):
00800 item['width'] = e.get('width').strip()
00801 continue
00802 continue
00803 if elem.tag.endswith('runtime'):
00804 if elem.text:
00805 item['blip_runtime'] = self.massageDescription(elem.text.strip())
00806 continue
00807 if elem.tag.endswith('rating'):
00808 if elem.text:
00809 item['blip_rating'] = self.massageDescription(elem.text.strip())
00810 continue
00811 if not item.has_key('video') and not item.has_key('link'):
00812 continue
00813 if embedURL:
00814 item['link'] = embedURL
00815 if item.has_key('link') and not item.has_key('video'):
00816 continue
00817 if item.has_key('video') and not item.has_key('link'):
00818 item['link'] = item['video']
00819
00820 if self.treeview:
00821 if not dictionary_first:
00822 dictionaries.append([self.massageDescription(self.feed_names[self.tree_key][self.feed]), self.setTreeViewIcon()])
00823 dictionary_first = True
00824
00825 final_item = {}
00826 for key in self.key_translation[1].keys():
00827 if not item.has_key(key):
00828 final_item[self.key_translation[1][key]] = u''
00829 else:
00830 final_item[self.key_translation[1][key]] = item[key]
00831 dictionaries.append(final_item)
00832
00833 if self.treeview:
00834 if initial_length < len(dictionaries):
00835 dictionaries.append(['', u''])
00836 return dictionaries
00837
00838