Advertisement
HitcherUK

Untitled

Feb 4th, 2013
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 39.82 KB | None | 0 0
  1. #/bin/python
  2.  
  3. import sys, os, os.path, re, time
  4. import urllib, cgi
  5. from string import ascii_lowercase
  6. from socket import setdefaulttimeout
  7. import traceback
  8. import logging
  9. import operator
  10.  
  11. import xbmc, xbmcgui, xbmcplugin
  12. import utils
  13.  
  14. __scriptid__ = "plugin.video.iplayer"
  15. __addoninfo__ = utils.get_addoninfo(__scriptid__)
  16. __addon__ = __addoninfo__["addon"]
  17. __version__ = __addoninfo__["version"]
  18.  
  19. sys.path.insert(0, os.path.join(__addoninfo__['path'], 'lib'))
  20.  
  21. try:
  22.     import iplayer2 as iplayer
  23.     import live_tv
  24.     import iplayer_search
  25. except ImportError, error:
  26.     print error
  27.     print sys.path
  28.     d = xbmcgui.Dialog()
  29.     d.ok(str(error), 'Please check you installed this plugin correctly.')
  30.     raise
  31.  
  32. logging.basicConfig(
  33.     stream=sys.stdout,
  34.     level=logging.DEBUG,
  35.     format='iplayer2.py: %(levelname)4s %(message)s',
  36.     )
  37.  
  38. DIR_USERDATA   = xbmc.translatePath(__addoninfo__["profile"])
  39. HTTP_CACHE_DIR = os.path.join(DIR_USERDATA, 'iplayer_http_cache')
  40. SUBTITLES_DIR  = os.path.join(DIR_USERDATA, 'Subtitles')
  41. SEARCH_FILE    = os.path.join(DIR_USERDATA, 'search.txt')
  42. VERSION_FILE   = os.path.join(DIR_USERDATA, 'version.txt')
  43.  
  44. __plugin_handle__ = utils.__plugin_handle__
  45.  
  46. def file_read(filename):
  47.     text = ''
  48.     fh = open(filename, "r")
  49.     try:
  50.         text = fh.read()
  51.     finally:
  52.         fh.close()
  53.     return text
  54.  
  55. def file_write(filename, data):
  56.     fh = open(filename, "wb")
  57.     try:
  58.         fh.write(data)
  59.     finally:
  60.         fh.close()
  61.  
  62. def sort_by_attr(seq, attr):
  63.     intermed = map(None, map(getattr, seq, (attr,)*len(seq)), xrange(len(seq)), seq)
  64.     intermed.sort()
  65.     return map(operator.getitem, intermed, (-1,) * len(intermed))
  66.  
  67. def get_plugin_thumbnail(image):
  68.  
  69.     # support user supplied .png files
  70.     userpng = os.path.join(iplayer.get_thumb_dir(), xbmc.getSkinDir(), image + '.png')
  71.     if os.path.isfile(userpng):
  72.         return userpng
  73.     userpng = os.path.join(iplayer.get_thumb_dir(), image + '.png')
  74.     if os.path.isfile(userpng):
  75.         return userpng
  76.    
  77.     return None
  78.  
  79. def get_feed_thumbnail(feed):
  80.     thumbfn = ''
  81.     if not feed or not feed.channel: return ''
  82.  
  83.     # support user supplied .png files
  84.     userpng = get_plugin_thumbnail(feed.channel)
  85.     if userpng: return userpng
  86.    
  87.     # check for a preconfigured logo
  88.     if iplayer.stations.channels_logos.has_key(feed.channel):
  89.         url = iplayer.stations.channels_logos[feed.channel]
  90.         if url == None:
  91.             url = os.path.join(iplayer.get_thumb_dir(), 'bbc_local_radio.png')
  92.         return url
  93.        
  94.     # national TV and Radio stations have easy to find online logos
  95.     if feed.tvradio == 'radio':
  96.         url = "http://www.bbc.co.uk/iplayer/img/radio/%s.gif" % feed.channel
  97.     else:
  98.         url = "http://www.bbc.co.uk/iplayer/img/tv/%s.jpg" % feed.channel
  99.        
  100.     return url
  101.    
  102. def make_url(feed=None, listing=None, pid=None, tvradio=None, category=None, series=None, url=None, label=None, radio=None):
  103.     base = sys.argv[0]
  104.     d = {}
  105.     if series: d['series'] = series      
  106.     if feed:
  107.         if feed.channel:
  108.             d['feed_channel'] = feed.channel
  109.         if feed.atoz:
  110.             d['feed_atoz'] = feed.atoz
  111.     if category: d['category'] = category
  112.     if listing: d['listing'] = listing
  113.     if pid: d['pid'] = pid
  114.     if tvradio: d['tvradio'] = tvradio
  115.     if url: d['url'] = url
  116.     if label: d['label'] = label
  117.     if radio: d['radio'] = radio
  118.     params = urllib.urlencode(d, True)
  119.     return base + '?' + params
  120.  
  121. def read_url():
  122.     args = cgi.parse_qs(sys.argv[2][1:])
  123.     feed_channel = args.get('feed_channel', [None])[0]
  124.     feed_atoz    = args.get('feed_atoz', [None])[0]
  125.     listing      = args.get('listing', [None])[0]
  126.     pid          = args.get('pid', [None])[0]
  127.     tvradio      = args.get('tvradio', [None])[0]
  128.     category     = args.get('category', [None])[0]
  129.     series       = args.get('series', [None])[0]    
  130.     url          = args.get('url', [None])[0]
  131.     label        = args.get('label', [None])[0]
  132.     deletesearch = args.get('deletesearch', [None])[0]
  133.     radio        = args.get('radio', [None])[0]
  134.  
  135.     feed = None
  136.     if feed_channel:
  137.         feed = iplayer.feed('auto', channel=feed_channel, atoz=feed_atoz, radio=radio)
  138.     elif feed_atoz:
  139.         feed = iplayer.feed(tvradio or 'auto', atoz=feed_atoz, radio=radio)
  140.  
  141.     if not (feed or listing):
  142.         section = __addon__.getSetting('start_section')
  143.         if   section == '1': tvradio = 'tv'
  144.         elif section == '2': tvradio = 'radio'
  145.  
  146.     return (feed, listing, pid, tvradio, category, series, url, label, deletesearch, radio)
  147.    
  148. def list_feeds(feeds, tvradio='tv', radio=None):
  149.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_TRACKNUM )  
  150.  
  151.     folders = []
  152.     if tvradio == 'tv' or radio == 'national':
  153.         folders.append(('Categories', 'categories', make_url(listing='categories', tvradio=tvradio)))    
  154.         folders.append(('Highlights', 'highlights', make_url(listing='highlights', tvradio=tvradio)))
  155.     if tvradio == 'radio':
  156.         folders.append(('Listen Live', 'listenlive', make_url(listing='livefeeds', tvradio=tvradio, radio=radio)))
  157.     else:
  158.         folders.append(('Watch Live', 'tv', make_url(listing='livefeeds', tvradio=tvradio)))
  159.     if tvradio == 'tv' or radio == 'national':
  160.         folders.append(('Popular', 'popular', make_url(listing='popular', tvradio=tvradio)))
  161.         folders.append(('Search', 'search', make_url(listing='searchlist', tvradio=tvradio)))
  162.  
  163.     total = len(folders) + len(feeds) + 1
  164.  
  165.     i = 1        
  166.     for j, (label, tn, url) in enumerate(folders):
  167.         listitem = xbmcgui.ListItem(label=label)
  168.         listitem.setIconImage('defaultFolder.png')
  169.         listitem.setThumbnailImage(get_plugin_thumbnail(tn))
  170.         listitem.setProperty('tracknumber', str(i + j))            
  171.         ok = xbmcplugin.addDirectoryItem(
  172.             handle=__plugin_handle__,
  173.             url=url,
  174.             listitem=listitem,
  175.             isFolder=True,
  176.         )
  177.  
  178.     i = len(folders) + 1
  179.     for j, f in enumerate(feeds):
  180.         listitem = xbmcgui.ListItem(label=f.name)
  181.         listitem.setIconImage('defaultFolder.png')
  182.         listitem.setThumbnailImage(get_feed_thumbnail(f))
  183.         listitem.setProperty('tracknumber', str(i + j))
  184.         url = make_url(feed=f, listing='list')
  185.         ok = xbmcplugin.addDirectoryItem(
  186.             handle=__plugin_handle__,
  187.             url=url,
  188.             listitem=listitem,
  189.             isFolder=True,
  190.         )
  191.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  192.  
  193.  
  194. def list_live_feeds(feeds, tvradio='tv'):
  195.     #print 'list_live_feeds %s' % feeds
  196.     xbmcplugin.setContent(__plugin_handle__, 'songs')
  197.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_TRACKNUM)
  198.  
  199.     if tvradio == 'tv':
  200.         return
  201.        
  202.     i = 0        
  203.    
  204.     for j, f in enumerate(feeds):
  205.         if not iplayer.stations.live_radio_stations.has_key(f.name):
  206.             #print "no key for %s" % f.name
  207.             continue
  208.         listitem = xbmcgui.ListItem(label=f.name)
  209.         listitem.setIconImage('defaultFolder.png')
  210.         if iplayer.stations.live_webcams.has_key(f.name):
  211.             listitem.setThumbnailImage(iplayer.stations.live_webcams[f.name])
  212.         else:
  213.             listitem.setThumbnailImage(get_feed_thumbnail(f))
  214.         listitem.setProperty('tracknumber', str(i + j))
  215.        
  216.         # Real & ASX url's are just redirects that are not always well
  217.         # handled by XBMC so if present load and process redirect
  218.         radio_url   = iplayer.stations.live_radio_stations[f.name]
  219.         stream_asx  = re.compile('\.asx$', re.IGNORECASE)
  220.         stream_mms  = re.compile('href\s*\=\s*"(mms.*?)"', re.IGNORECASE)
  221.                
  222.         match_asx   = stream_asx.search(radio_url)
  223.        
  224.         if match_asx:
  225.             txt = iplayer.httpget(radio_url)
  226.             match_mms  = stream_mms.search(txt)
  227.             if  match_mms:
  228.                 stream_url = match_mms.group(1)
  229.             else:
  230.                 stream_url = radio_url
  231.         else:
  232.             stream_url = radio_url
  233.        
  234.         listitem.setPath(stream_url)
  235.                          
  236.         ok = xbmcplugin.addDirectoryItem(
  237.             handle=__plugin_handle__,
  238.             url=stream_url,
  239.             listitem=listitem,
  240.             isFolder=False,
  241.         )
  242.    
  243.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  244.  
  245.  
  246.  
  247.  
  248. def list_tvradio():
  249.     """
  250.    Lists five folders - one for TV and one for Radio, plus A-Z, highlights and popular
  251.    """
  252.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_TRACKNUM)
  253.        
  254.     folders = []
  255.     folders.append(('TV', 'tv', make_url(tvradio='tv')))
  256.     folders.append(('Radio', 'radio', make_url(tvradio='radio')))
  257.     folders.append(('Settings', 'settings', make_url(tvradio='Settings')))
  258.  
  259.     for i, (label, tn, url) in enumerate(folders):
  260.         listitem = xbmcgui.ListItem(label=label)
  261.         listitem.setIconImage('defaultFolder.png')
  262.         thumbnail = get_plugin_thumbnail(tn)
  263.         if thumbnail:
  264.             listitem.setThumbnailImage(get_plugin_thumbnail(tn))
  265.         folder=True
  266.         if label == 'Settings':
  267.             # fix for reported bug where loading dialog would overlay settings dialog
  268.             folder = False
  269.         ok = xbmcplugin.addDirectoryItem(
  270.             handle=__plugin_handle__,
  271.             url=url,
  272.             listitem=listitem,
  273.             isFolder=folder,
  274.         )
  275.    
  276.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  277.    
  278. def list_radio_types():
  279.     """
  280.    Lists folders - National, Regional & Local Radio + Search
  281.    """
  282.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_TRACKNUM)
  283.        
  284.     folders = []
  285.     folders.append(('National Radio Stations', 'national', make_url(tvradio='radio',radio='national')))
  286.     folders.append(('Regional Radio Stations', 'regional', make_url(tvradio='radio',radio='regional')))
  287.     folders.append(('Local Radio Stations',    'local',    make_url(tvradio='radio',radio='local')))
  288.        
  289.     for i, (label, tn, url) in enumerate(folders):
  290.         listitem = xbmcgui.ListItem(label=label)
  291.         listitem.setIconImage(get_plugin_thumbnail('bbc_radio'))
  292.         listitem.setThumbnailImage(get_plugin_thumbnail('bbc_radio'))
  293.         folder=True
  294.         ok = xbmcplugin.addDirectoryItem(
  295.             handle=__plugin_handle__,
  296.             url=url,
  297.             listitem=listitem,
  298.             isFolder=folder,
  299.         )
  300.    
  301.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  302.  
  303. def get_setting_videostream():  
  304.  
  305.     stream = 'h264 1500'
  306.  
  307.     stream_prefs = '0'
  308.     try:
  309.         stream_prefs = __addon__.getSetting('video_stream')
  310.     except:
  311.         pass
  312.        
  313.     # Auto|H.264 (480kb)|H.264 (800kb)|H.264 (1500kb)|H.264 (2800kb)
  314.     if stream_prefs == '0':
  315.         environment = os.environ.get( "OS" )
  316.         # check for xbox as we set a lower default for xbox (although it can do 1500kbit streams)
  317.         if environment == 'xbox':
  318.             stream = 'h264 800'
  319.         else:
  320.             # play full HD if the screen is large enough (not all programmes have this resolution)
  321.             Y = int(xbmc.getInfoLabel('System.ScreenHeight'))
  322.             X = int(xbmc.getInfoLabel('System.ScreenWidth'))
  323.             # if the screen is large enough for HD
  324.             if Y > 832 and X > 468:
  325.                 stream = 'h264 2800'
  326.     elif stream_prefs == '1':
  327.         stream = 'h264 480'
  328.     elif stream_prefs == '2':
  329.         stream = 'h264 800'
  330.     elif stream_prefs == '3':
  331.         stream = 'h264 1500'
  332.     elif stream_prefs == '4':
  333.         stream = 'h264 2800'
  334.  
  335.     logging.info("Video stream prefs %s - %s", stream_prefs, stream)
  336.     return stream
  337.  
  338. def get_setting_audiostream():
  339.     stream = 'wma'
  340.  
  341.     stream_prefs = '0'
  342.     try:
  343.         stream_prefs = __addon__.getSetting('audio_stream')
  344.     except:
  345.         pass
  346.  
  347.     # Auto|MP3|AAC|WMA
  348.     if stream_prefs == '1':
  349.         stream = 'mp3'
  350.     elif stream_prefs == '2':
  351.         stream = 'aac'        
  352.     elif stream_prefs == '3':
  353.         stream = 'wma'
  354.  
  355.     logging.info("Audio stream prefs %s - %s", stream_prefs, stream)
  356.     return stream
  357.  
  358.  
  359. def get_setting_thumbnail_size():
  360.     size = __addon__.getSetting('thumbnail_size')
  361.     #Biggest|Large|Small|Smallest|None
  362.     if size:
  363.         if size == '0':
  364.             return 'biggest'
  365.         elif size == '1':
  366.             return 'large'
  367.         elif size == '2':
  368.             return 'small'
  369.         elif size == '3':
  370.             return 'smallest'
  371.         elif size == '4':
  372.             return 'none'
  373.     # default
  374.     return 'large'
  375.  
  376. def get_setting_subtitles():
  377.     subtitles = __addon__.getSetting('subtitles_control')
  378.     #values="None|Download and Play|Download to File" default="None"
  379.     if subtitles:
  380.         if subtitles == 'None' or subtitles == '0':
  381.             return None
  382.         elif subtitles == 'Download and Play' or subtitles == '1':
  383.             return 'autoplay'
  384.         elif subtitles == 'Download to File' or subtitles == '2':
  385.             return 'download'
  386.     # default
  387.     return None
  388.  
  389. def add_programme(feed, programme, totalItems=None, tracknumber=None, thumbnail_size='large', tvradio='tv'):
  390.     title     = programme.title
  391.     thumbnail = programme.get_thumbnail(thumbnail_size, tvradio)
  392.     summary   = programme.summary
  393.    
  394.     listitem = xbmcgui.ListItem(label=title,
  395.                                 label2=summary,
  396.                                 iconImage='defaultVideo.png',
  397.                                 thumbnailImage=thumbnail)
  398.  
  399.     datestr = programme.updated[:10]
  400.     date=datestr[8:10] + '/' + datestr[5:7] + '/' +datestr[:4]#date ==dd/mm/yyyy
  401.     date2=datestr[:4] + '-' + datestr[5:7] + '-' + datestr[8:10]
  402.  
  403.     if programme.categories and len(programme.categories) > 0:
  404.         genre = ''
  405.         for cat in programme.categories:
  406.             genre += cat + ' / '
  407.         genre=genre[:-2]
  408.     else:
  409.         genre = ''
  410.  
  411.     listitem.setInfo('video', {
  412.         'Title': programme.title,
  413.         'Plot': programme.summary,
  414.         'PlotOutline': programme.summary,
  415.         'Genre': genre,
  416.         "Date": date,
  417.         'Premiered' : date2,
  418.         'Episode' : tracknumber + 1
  419.     })
  420.     listitem.setProperty('Title', str(title))
  421.     if tracknumber: listitem.setProperty('tracknumber', str(tracknumber))
  422.        
  423.     #print "Getting URL for %s ..." % (programme.title)
  424.  
  425.     # tv catchup url
  426.     url=make_url(feed=feed, pid=programme.pid)
  427.  
  428.     xbmcplugin.addDirectoryItem(
  429.         handle=__plugin_handle__,
  430.         url=url,
  431.         listitem=listitem,
  432.         totalItems=totalItems
  433.     )
  434.  
  435.     return True
  436.  
  437.  
  438. def list_categories(tvradio='tv', feed=None, channels=None, progcount=True):
  439.  
  440.     # list of categories within a channel
  441.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_NONE)
  442.     for label, category in feed.categories():
  443.         url = make_url(feed=feed, listing='list', category=category, tvradio=tvradio)
  444.         listitem = xbmcgui.ListItem(label=label)
  445.         if tvradio == 'tv':
  446.             listitem.setThumbnailImage(get_plugin_thumbnail('tv'))
  447.         else:
  448.             listitem.setThumbnailImage(get_plugin_thumbnail('radio'))
  449.         ok = xbmcplugin.addDirectoryItem(            
  450.             handle=__plugin_handle__,
  451.             url=url,
  452.             listitem=listitem,
  453.             isFolder=True,
  454.         )
  455.        
  456.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  457.    
  458. def series_match(name):
  459.     # match the series name part of a programme name
  460.     seriesmatch = []
  461.    
  462.     seriesmatch.append(re.compile('^(Late\s+Kick\s+Off\s+)'))
  463.     seriesmatch.append(re.compile('^(Inside\s+Out\s+)'))
  464.     seriesmatch.append(re.compile('^(.*?):'))  
  465.     match = None
  466.  
  467.     for s in seriesmatch:
  468.         match = s.match(name)
  469.         if match:
  470.             break
  471.        
  472.     return match
  473.  
  474. def list_series(feed, listing, category=None, progcount=True):
  475.  
  476.     c = 0
  477.     name = feed.name
  478.  
  479.     d = {}
  480.     d['list'] = feed.list
  481.     d['popular'] = feed.popular
  482.     d['highlights'] = feed.highlights
  483.     programmes = d[listing]()
  484.  
  485.     ## filter by category
  486.     if category:
  487.         temp_prog = []
  488.         # if a category filter has been specified then only parse programmes
  489.         # in that category
  490.         for p in programmes:
  491.             for cat in p.categories:
  492.                 if cat == category:
  493.                     temp_prog.append(p)
  494.                     continue
  495.         programmes = temp_prog
  496.  
  497.     ## extract the list of series names
  498.     series = {}
  499.     episodes = {}
  500.     categories = {}
  501.     dates = {}
  502.  
  503.     thumbnail_size = get_setting_thumbnail_size()
  504.     for p in programmes:
  505.  
  506.         match = series_match(p.title)            
  507.         thumb = p.get_thumbnail(thumbnail_size, feed.tvradio)
  508.  
  509.         if match:
  510.             seriesname = match.group(1)
  511.         else:
  512.             # the programme title doesn't have a series delimiter
  513.             seriesname = p.title
  514.            
  515.         series[seriesname] = thumb
  516.         datestr = p.updated[:10]
  517.         if not episodes.has_key(seriesname):
  518.             episodes[seriesname] = 0
  519.             dates[seriesname] = datestr
  520.  
  521.         episodes[seriesname] += 1
  522.         categories[seriesname] = p.categories
  523.        
  524.     serieslist = series.keys()
  525.     serieslist.sort()
  526.  
  527.     for s in serieslist:
  528.         url = make_url(feed=feed, listing='list', category=category, series=s )
  529.         if progcount:
  530.             label = "%s (%s)" % (s, episodes[s])
  531.         else:
  532.             label = s
  533.         listitem = xbmcgui.ListItem(label=label, label2=label)
  534.         listitem.setThumbnailImage(series[s])
  535.         date=dates[s][8:10] + '/' + dates[s][5:7] + '/' +dates[s][:4] #date ==dd/mm/yyyy
  536.         listitem.setInfo('video', {'Title': s, 'Date': date, 'Size': episodes[s], 'Genre': "/".join(categories[s])})
  537.         ok = xbmcplugin.addDirectoryItem(            
  538.             handle=__plugin_handle__,
  539.             url=url,
  540.             listitem=listitem,
  541.             isFolder=True,
  542.         )
  543.         c += 1        
  544.    
  545.     if c == 0:
  546.         # and yes it does happen once in a while
  547.         label = "(no programmes available - try again later)"
  548.         listitem = xbmcgui.ListItem(label=label)
  549.         ok = xbmcplugin.addDirectoryItem(
  550.             handle=__plugin_handle__,
  551.             url="",
  552.             listitem=listitem,
  553.         )
  554.  
  555.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  556.    
  557.    
  558. def search(tvradio, searchterm):
  559.    
  560.     if not searchterm:
  561.         searchterm = iplayer_search.prompt_for_search()
  562.         if searchterm != None and len(searchterm) >= 3:
  563.             iplayer_search.save_search(SEARCH_FILE, tvradio, searchterm)
  564.         else:
  565.             return
  566.  
  567.     logging.info("searchterm=" + searchterm)
  568.     feed = iplayer.feed(tvradio, searchterm=searchterm)
  569.    
  570.     list_feed_listings(feed, 'list')
  571.  
  572. def search_delete(tvradio, searchterm):
  573.     iplayer_search.delete_search(SEARCH_FILE, tvradio, searchterm)
  574.     xbmc.executebuiltin("Container.Refresh")
  575.    
  576. def search_list(tvradio):
  577.     # provide a list of saved search terms
  578.     xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_NONE)
  579.     searchimg = get_plugin_thumbnail('search')
  580.    
  581.     # First item allows a new search to be created
  582.     listitem = xbmcgui.ListItem(label='New Search...')
  583.     listitem.setThumbnailImage(searchimg)
  584.     url = make_url(listing='search', tvradio=tvradio)
  585.     ok = xbmcplugin.addDirectoryItem(            
  586.           handle=__plugin_handle__,
  587.           url=url,
  588.           listitem=listitem,
  589.           isFolder=True)
  590.    
  591.     # Now list all the saved searches
  592.     for searchterm in iplayer_search.load_search(SEARCH_FILE, tvradio):
  593.         listitem = xbmcgui.ListItem(label=searchterm)
  594.         listitem.setThumbnailImage(searchimg)
  595.         url = make_url(listing='search', tvradio=tvradio, label=searchterm)
  596.        
  597.         # change the context menu to an entry for deleting the search
  598.         cmd = "XBMC.RunPlugin(%s?deletesearch=%s&tvradio=%s)" % (sys.argv[0], urllib.quote_plus(searchterm), urllib.quote_plus(tvradio))
  599.         listitem.addContextMenuItems( [ ('Delete saved search', cmd) ] )
  600.        
  601.         ok = xbmcplugin.addDirectoryItem(            
  602.             handle=__plugin_handle__,
  603.             url=url,
  604.             listitem=listitem,
  605.             isFolder=True,
  606.         )        
  607.          
  608.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  609.        
  610. def list_feed_listings(feed, listing, category=None, series=None, channels=None):
  611.     if channels or listing == 'popular' or listing == 'highlights':
  612.         xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_NONE)
  613.     else:
  614.         xbmcplugin.addSortMethod(handle=__plugin_handle__, sortMethod=xbmcplugin.SORT_METHOD_NONE)
  615.      
  616.     d = {}
  617.     d['list'] = feed.list
  618.     d['popular'] = feed.popular
  619.     d['highlights'] = feed.highlights
  620.     programmes = d[listing]()
  621.  
  622.     ## filter by series
  623.     if series:
  624.         temp_prog = []
  625.         # if a series filter has been specified then only parse programmes
  626.         # in that series
  627.         i = len(series)
  628.  
  629.         for p in programmes:
  630.             matchagainst = p.title
  631.             match = series_match(p.title)
  632.             if match: matchagainst = match.group(1)
  633.             #print "matching %s,%s" % (p.title, matchagainst)
  634.             if series == matchagainst:
  635.                 temp_prog.append(p)
  636.         programmes = temp_prog
  637.    
  638.     programmes = sort_by_attr(programmes, 'title')
  639.     programmes = sort_by_attr(programmes, 'updated')
  640.    
  641.        
  642.     # add each programme
  643.     total = len(programmes)
  644.     if channels: total = total + len(channels)
  645.     count =  0
  646.     thumbnail_size = get_setting_thumbnail_size()
  647.     for p in programmes:
  648.         try:
  649.             if not add_programme(feed, p, total, count, thumbnail_size, feed.tvradio):
  650.                 total = total - 1
  651.         except:
  652.             traceback.print_exc()
  653.             total = total - 1
  654.         count = count + 1
  655.        
  656.     # normally from an empty search
  657.     if not programmes:
  658.         label = "(no programmes available - try again later)"
  659.         listitem = xbmcgui.ListItem(label=label)
  660.         ok = xbmcplugin.addDirectoryItem(
  661.             handle=__plugin_handle__,
  662.             url="",
  663.             listitem=listitem
  664.         )
  665.         count= count + 1
  666.  
  667.  
  668.     # add list of channels names - for top level Highlights and Popular
  669.     if channels:  
  670.         for j, f in enumerate(channels):
  671.             listitem = xbmcgui.ListItem(label=f.name)
  672.             listitem.setIconImage('defaultFolder.png')
  673.             listitem.setThumbnailImage(get_feed_thumbnail(f))
  674.             listitem.setProperty('tracknumber', str(count))
  675.             count = count + 1
  676.             url = make_url(feed=f, listing=listing, tvradio=feed.tvradio, category=category)
  677.             ok = xbmcplugin.addDirectoryItem(
  678.                 handle=__plugin_handle__,
  679.                 url=url,
  680.                 listitem=listitem,
  681.                 isFolder=True,
  682.             )
  683.  
  684.     xbmcplugin.setContent(handle=__plugin_handle__, content='episodes')
  685.     xbmcplugin.endOfDirectory(handle=__plugin_handle__, succeeded=True)
  686.  
  687.  
  688. def get_item(pid):
  689.     #print "Getting %s" % (pid)
  690.     p = iplayer.programme(pid)
  691.     #print "%s is %s" % (pid, p.title)
  692.      
  693.     #for i in p.items:
  694.     #    if i.kind in ['programme', 'radioProgrammme']:
  695.     #        return i
  696.     return p.programme
  697.  
  698. def download_subtitles(url):
  699.     # Download and Convert the TTAF format to srt
  700.     # SRT:
  701.     #1
  702.     #00:01:22,490 --> 00:01:26,494
  703.     #Next round!
  704.     #
  705.     #2
  706.     #00:01:33,710 --> 00:01:37,714
  707.     #Now that we've moved to paradise, there's nothing to eat.
  708.     #
  709.    
  710.     # TT:
  711.     #<p begin="0:01:12.400" end="0:01:13.880">Thinking.</p>
  712.    
  713.     logging.info('subtitles at =%s' % url)
  714.     outfile = os.path.join(SUBTITLES_DIR, 'iplayer.srt')
  715.     fw = open(outfile, 'w')
  716.    
  717.     if not url:
  718.         fw.write("1\n0:00:00,001 --> 0:01:00,001\nNo subtitles available\n\n")
  719.         fw.close()
  720.         return
  721.    
  722.     txt = iplayer.httpget(url)
  723.        
  724.     p= re.compile('^\s*<p.*?begin=\"(.*?)\.([0-9]+)\"\s+.*?end=\"(.*?)\.([0-9]+)\"\s*>(.*?)</p>')
  725.     i=0
  726.     prev = None
  727.  
  728.     # some of the subtitles are a bit rubbish in particular for live tv
  729.     # with lots of needless repeats. The follow code will collapse sequences
  730.     # of repeated subtitles into a single subtitles that covers the total time
  731.     # period. The downside of this is that it would mess up in the rare case
  732.     # where a subtitle actually needs to be repeated
  733.     for line in txt.split('\n'):
  734.         entry = None
  735.         m = p.match(line)
  736.         if m:
  737.             start_mil = "%s000" % m.group(2) # pad out to ensure 3 digits
  738.             end_mil   = "%s000" % m.group(4)
  739.            
  740.             ma = {'start'     : m.group(1),
  741.                   'start_mil' : start_mil[:3],
  742.                   'end'       : m.group(3),
  743.                   'end_mil'   : start_mil[:3],
  744.                   'text'      : m.group(5)}
  745.    
  746.             ma['text'] = ma['text'].replace('&amp;', '&')
  747.             ma['text'] = ma['text'].replace('&gt;', '>')
  748.             ma['text'] = ma['text'].replace('&lt;', '<')
  749.             ma['text'] = ma['text'].replace('<br />', '\n')
  750.             ma['text'] = ma['text'].replace('<br/>', '\n')
  751.             ma['text'] = re.sub('<.*?>', '', ma['text'])
  752.             ma['text'] = re.sub('&#[0-9]+;', '', ma['text'])
  753.             #ma['text'] = ma['text'].replace('<.*?>', '')
  754.    
  755.             if not prev:
  756.                 # first match - do nothing wait till next line
  757.                 prev = ma
  758.                 continue
  759.            
  760.             if prev['text'] == ma['text']:
  761.                 # current line = previous line then start a sequence to be collapsed
  762.                 prev['end'] = ma['end']
  763.                 prev['end_mil'] = ma['end_mil']
  764.             else:
  765.                 i += 1
  766.                 entry = "%d\n%s,%s --> %s,%s\n%s\n\n" % (i, prev['start'], prev['start_mil'], prev['end'], prev['end_mil'], prev['text'])
  767.                 prev = ma
  768.         elif prev:
  769.             i += 1
  770.             entry = "%d\n%s,%s --> %s,%s\n%s\n\n" % (i, prev['start'], prev['start_mil'], prev['end'], prev['end_mil'], prev['text'])
  771.            
  772.         if entry: fw.write(entry)
  773.    
  774.     fw.close()    
  775.     return outfile
  776.  
  777. def get_matching_stream(item, pref, streams):
  778.     """
  779.    tries to return a media object for requested stream,
  780.    falling back on a lower stream if requested one is not available. if there are no lower ones, it will
  781.    return the first stream it finds.
  782.    """
  783.     media = item.get_media_for(pref)
  784.  
  785.     for i, stream in enumerate(streams):
  786.         if pref == stream:
  787.             break
  788.  
  789.     while not media and i < len(streams)-1:
  790.         i += 1
  791.         logging.info('Stream %s not available, falling back to %s stream' % (pref, streams[i]) )
  792.         pref = streams[i]
  793.         media = item.get_media_for(pref)
  794.  
  795.     # problem - no media found for default or lower
  796.     if not media:
  797.         # find the first available stream in reverse order
  798.         for apref in reversed(streams):
  799.             media = item.get_media_for(apref)
  800.             if media:
  801.                 pref=apref
  802.                 break
  803.  
  804.     return (media, pref)
  805.  
  806. def watch(feed, pid, showDialog):
  807.  
  808.     times = []
  809.     times.append(['start',time.clock()])
  810.     if showDialog:
  811.         pDialog = xbmcgui.DialogProgress()
  812.         times.append(['xbmcgui.DialogProgress()',time.clock()])
  813.         pDialog.create('IPlayer', 'Loading catchup stream info')
  814.         times.append(['pDialog.create',time.clock()])
  815.  
  816.     subtitles_file = None
  817.     item      = get_item(pid)
  818.     times.append(['get_item',time.clock()])
  819.     thumbnail = item.programme.thumbnail
  820.     title     = item.programme.title
  821.     summary   = item.programme.summary
  822.     updated   = item.programme.updated
  823.     channel   = None
  824.     thumbfile = None
  825.     if feed and feed.name:
  826.         channel = feed.name
  827.     times.append(['setup variables',time.clock()])        
  828.     logging.info('watching channel=%s pid=%s' % (channel, pid))
  829.     times.append(['logging',time.clock()])
  830.     logging.info('thumb =%s   summary=%s' % (thumbnail, summary))
  831.     times.append(['logging',time.clock()])  
  832.     subtitles = get_setting_subtitles()
  833.     times.append(['get_setting_subtitles',time.clock()])
  834.  
  835.     if thumbnail:
  836.         # attempt to use the existing thumbnail file
  837.         thumbcache = xbmc.getCacheThumbName( sys.argv[ 0 ] + sys.argv[ 2 ] )
  838.         thumbfile  = os.path.join( xbmc.translatePath( "special://profile" ), "Thumbnails", "Video", thumbcache[ 0 ], thumbcache )
  839.         logging.info('Reusing existing thumbfile =%s for url %s%s' % (thumbfile, sys.argv[ 0 ], sys.argv[ 2 ]))
  840.        
  841.     if thumbnail and not os.path.isfile(thumbfile):
  842.         # thumbnail wasn't available locally so download    
  843.         try:
  844.             # The thumbnail needs to accessed via the local filesystem
  845.             # for "Media Info" to display it when playing a video
  846.             if showDialog:
  847.                 pDialog.update(20, 'Fetching thumbnail')
  848.                 if pDialog.iscanceled(): raise
  849.                 times.append(['update dialog',time.clock()])
  850.             iplayer.httpretrieve(thumbnail, thumbfile)
  851.             times.append(['retrieve thumbnail',time.clock()])
  852.         except:
  853.             pass
  854.  
  855.     if item.is_tv:
  856.         # TV Stream
  857.         iconimage = 'DefaultVideo.png'
  858.  
  859.         if showDialog:
  860.             pDialog.update(50, 'Fetching video stream info')
  861.             if pDialog.iscanceled(): raise
  862.             times.append(['update dialog',time.clock()])
  863.         pref = get_setting_videostream()        
  864.         times.append(['get_setting_videostream',time.clock()])
  865.         opref = pref
  866.         if showDialog:
  867.             pDialog.update(70, 'Selecting video stream')
  868.             if pDialog.iscanceled(): raise
  869.             times.append(['update dialog',time.clock()])
  870.  
  871.         streams = ['h264 2800', 'h264 1500', 'h264 800', 'h264 480', 'h264 400']
  872.         (media, pref) = get_matching_stream(item, pref, streams)
  873.  
  874.         # A potentially usable stream was found (higher bitrate than the default) offer it to the user
  875.         if not media:
  876.             # Nothing usable was found
  877.             d = xbmcgui.Dialog()
  878.             d.ok('Stream Error', 'Can\'t locate any usable TV streams.')            
  879.             return False
  880.  
  881.         if streams.index(opref) > streams.index(pref):
  882.             d = xbmcgui.Dialog()
  883.             if d.yesno('Default %s Stream Not Available' % opref, 'Play higher bitrate %s stream ?' % pref ) == False:
  884.                 return False
  885.  
  886.         times.append(['media 2',time.clock()])    
  887.         url = media.url
  888.         times.append(['media.url',time.clock()])
  889.         logging.info('watching url=%s' % url)
  890.         times.append(['logging',time.clock()])
  891.  
  892.         if showDialog:
  893.             pDialog.update(90, 'Selecting subtitles')
  894.             if pDialog.iscanceled(): raise
  895.             times.append(['update dialog',time.clock()])
  896.         if subtitles:
  897.             subtitles_media = item.get_media_for('captions')
  898.             times.append(['subtitles_media',time.clock()])
  899.             if subtitles_media:
  900.                 subtitles_file = download_subtitles(subtitles_media.url)
  901.                 times.append(['subtitles download',time.clock()])
  902.  
  903.         listitem = xbmcgui.ListItem(title)
  904.         times.append(['create listitem',time.clock()])
  905.         #listitem.setIconImage(iconimage)
  906.         listitem.setInfo('video', {
  907.                                    "TVShowTitle": title,
  908.                                    'Plot': summary + ' ' + updated,
  909.                                    'PlotOutline': summary,
  910.                                    "Date": updated,})
  911.         times.append(['listitem setinfo',time.clock()])
  912.         play=xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
  913.         times.append(['xbmc.PlayList',time.clock()])
  914.        
  915.     else:
  916.         # Radio stream        
  917.         if showDialog:
  918.             pDialog.update(30, 'Fetching radio stream info')
  919.             if pDialog.iscanceled(): raise
  920.             times.append(['update dialog',time.clock()])
  921.         pref = get_setting_audiostream()
  922.         if showDialog:
  923.             pDialog.update(50, 'Selecting radio stream')
  924.             if pDialog.iscanceled(): raise
  925.             times.append(['update dialog',time.clock()])
  926.  
  927.         (media, pref) = get_matching_stream(item, pref, ['wma', 'mp3', 'aac'])
  928.  
  929.         if not media:            
  930.             d = xbmcgui.Dialog()
  931.             d.ok('Stream Error', 'Error: can\'t locate radio stream')            
  932.             return False
  933.         url = media.url
  934.            
  935.         logging.info('Listening to url=%s' % url)
  936.  
  937.         listitem = xbmcgui.ListItem(title)
  938.         times.append(['listitem create',time.clock()])
  939.         listitem.setIconImage('defaultAudio.png')
  940.         times.append(['listitem.setIconImage',time.clock()])
  941.         play=xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
  942.         times.append(['xbmc.PlayList',time.clock()])
  943.  
  944.     logging.info('Playing preference %s' % pref)
  945.     times.append(['logging.info',time.clock()])
  946.     times.append(['listitem.setproperty x 3',time.clock()])
  947.  
  948.     if thumbfile:
  949.         listitem.setIconImage(thumbfile)
  950.         times.append(['listitem.setIconImage(thumbfile)',time.clock()])
  951.         listitem.setThumbnailImage(thumbfile)
  952.         times.append(['listitem.setThumbnailImage(thumbfile)',time.clock()])
  953.    
  954.     del item
  955.     del media
  956.    
  957.     if showDialog:
  958.         pDialog.update(80, 'Playing')
  959.         if pDialog.iscanceled(): raise
  960.         times.append(['update dialog',time.clock()])
  961.     play.clear()
  962.     times.append(['play.clear()',time.clock()])
  963.     play.add(url,listitem)
  964.     times.append(['play.add',time.clock()])
  965.     player = xbmc.Player(xbmc.PLAYER_CORE_AUTO)
  966.     times.append(['xbmc.Player()',time.clock()])
  967.     player.play(play)
  968.     times.append(['player.play',time.clock()])
  969.     # Auto play subtitles if they have downloaded
  970.     logging.info("subtitles: %s   - subtitles_file %s " % (subtitles,subtitles_file))
  971.     times.append(['logging.info',time.clock()])
  972.     if subtitles == 'autoplay' and subtitles_file:
  973.         player.setSubtitles(subtitles_file)
  974.         times.append(['player.setSubtitles',time.clock()])
  975.    
  976.     if showDialog: pDialog.close()
  977.     times.append(['pDialog.close()',time.clock()])
  978.    
  979.     if __addon__.getSetting('enhanceddebug') == 'true':
  980.         pt = times[0][1]
  981.         for t in times:
  982.             logging.info('Took %2.2f sec for %s' % (t[1] - pt, t[0]))
  983.             pt = t[1]
  984.  
  985.  
  986. def listen_live(label='', url=None):
  987.    
  988.     if not url:
  989.         return
  990.    
  991.     txt = iplayer.httpget(url)
  992.    
  993.     # some of the the urls passed in are .asx. These are text files with multiple mss stream hrefs
  994.     stream = re.compile('href\="(mms.*?)"', re.IGNORECASE)
  995.     match  = stream.search(txt)
  996.     stream_url = None
  997.     if match:
  998.         stream_url = match.group(1)
  999.     else:
  1000.         # pass it to xbmc and see if it is directly supported
  1001.         stream_url = url
  1002.        
  1003.     listitem = xbmcgui.ListItem(label=label, label2=label)
  1004.     if thumbnail: listitem.setThumbnailImage(thumbnail)
  1005.    
  1006.     play=xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
  1007.  
  1008.     play.clear()
  1009.     play.add(stream_url,listitem)
  1010.        
  1011.     player = xbmc.Player(xbmc.PLAYER_CORE_AUTO)
  1012.  
  1013.     player.play(play)
  1014.  
  1015.  
  1016. logging.info("IPlayer: version: %s" % __version__)
  1017. logging.info("IPlayer: Subtitles dir: %s" % SUBTITLES_DIR)
  1018.  
  1019. old_version = ''
  1020.  
  1021. DIR_USERDATA
  1022.  
  1023. for d in [DIR_USERDATA, HTTP_CACHE_DIR, SUBTITLES_DIR]:
  1024.     if not os.path.isdir(d):
  1025.         try:
  1026.             logging.info("%s doesn't exist, creating" % d)
  1027.             os.makedirs(d)
  1028.         except IOError, e:
  1029.             logging.info("Couldn't create %s, %s" % (d, str(e)))
  1030.             raise
  1031.  
  1032. if not os.path.isfile(SEARCH_FILE):
  1033.     try:
  1034.         open(SEARCH_FILE, 'wb').close()
  1035.     except IOError, e:
  1036.         logging.error("Couldn't create %s, %s" % (d, str(e)))
  1037.         raise
  1038.  
  1039. if os.path.isfile(VERSION_FILE):
  1040.     old_version = file_read(VERSION_FILE)
  1041.    
  1042. if old_version != __version__:
  1043.     file_write(VERSION_FILE, __version__)
  1044.     d = xbmcgui.Dialog()
  1045.     d.ok('Welcome to the BBC IPlayer addon', 'Please be aware this addon only works in the UK.', 'The IPlayer service checks to ensure UK IP addresses.')
  1046.  
  1047. if __name__ == "__main__":
  1048.     try:
  1049.  
  1050.         # setup and check script environment
  1051.         if __addon__.getSetting('http_cache_disable') == 'false': iplayer.set_http_cache(HTTP_CACHE_DIR)
  1052.    
  1053.         environment = os.environ.get( "OS", "xbox" )
  1054.         try:
  1055.             timeout = int(__addon__.getSetting('socket_timeout'))
  1056.         except:
  1057.             timeout = 5
  1058.         if environment in ['Linux', 'xbox'] and timeout > 0:
  1059.             setdefaulttimeout(timeout)
  1060.    
  1061.         progcount = True
  1062.         if __addon__.getSetting('progcount') == 'false':  progcount = False  
  1063.      
  1064.         # get current state parameters
  1065.         (feed, listing, pid, tvradio, category, series, url, label, deletesearch, radio) = read_url()
  1066.         logging.info( (feed, listing, pid, tvradio, category, series, url, label, deletesearch, radio) )
  1067.        
  1068.         # update feed category
  1069.         if feed and category:
  1070.             feed.category = category
  1071.    
  1072.         # state engine
  1073.         if pid:
  1074.             showDialog = __addon__.getSetting('displaydialog') == 'true'
  1075.             if not label:
  1076.                 watch(feed, pid, showDialog)
  1077.             else:
  1078.                 pref = get_setting_videostream()
  1079.                 bitrate = pref.split(' ')[1]
  1080.                 live_tv.play_stream(label, bitrate, showDialog)
  1081.         elif url:
  1082.             listen_live(label, url)
  1083.         elif deletesearch:
  1084.             search_delete(tvradio or 'tv', deletesearch)        
  1085.         elif not (feed or listing):
  1086.             if not tvradio:
  1087.                 list_tvradio()
  1088.             elif tvradio == 'Settings':
  1089.                 __addon__.openSettings()
  1090.             elif (tvradio == 'radio' and radio == None):
  1091.                 list_radio_types()
  1092.             elif tvradio:
  1093.                 feed = iplayer.feed(tvradio, radio=radio).channels_feed()
  1094.                 list_feeds(feed, tvradio, radio)
  1095.         elif listing == 'categories':
  1096.             channels = None
  1097.             feed = feed or iplayer.feed(tvradio or 'tv',  searchcategory=True, category=category, radio=radio)
  1098.             list_categories(tvradio, feed)
  1099.         elif listing == 'searchlist':
  1100.             search_list(tvradio or 'tv')
  1101.         elif listing == 'search':
  1102.             search(tvradio or 'tv', label)  
  1103.         elif listing == 'livefeeds':
  1104.             tvradio = tvradio or 'tv'
  1105.             if tvradio == 'radio':
  1106.                 channels = iplayer.feed(tvradio or 'tv', radio=radio).channels_feed()
  1107.                 list_live_feeds(channels, tvradio)
  1108.             else:
  1109.                 live_tv.list_channels()
  1110.         elif listing == 'list' and not series and not category:
  1111.             feed = feed or iplayer.feed(tvradio or 'tv', category=category, radio=radio)
  1112.             list_series(feed, listing, category=category, progcount=progcount)
  1113.         elif listing:
  1114.             channels=None
  1115.             if not feed:
  1116.                 feed = feed or iplayer.feed(tvradio or 'tv', category=category, radio=radio)
  1117.                 channels=feed.channels_feed()
  1118.             list_feed_listings(feed, listing, category=category, series=series, channels=channels)
  1119.  
  1120.     except:
  1121.         # Make sure the text from any script errors are logged
  1122.         traceback.print_exc(file=sys.stdout)
  1123.         raise
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement