diff options
author | CaptainTK <CaptainTK@users.noreply.github.com> | 2017-03-22 03:37:02 +0100 |
---|---|---|
committer | enen92 <enen92@users.noreply.github.com> | 2017-03-22 02:37:02 +0000 |
commit | b89a149740c83b53d73a07042015498044bfe0a1 (patch) | |
tree | 38fd727b0ba2478361da831fdc91d5d82c914819 /plugin.video.iplayerwww | |
parent | aefa7d3d72e3a461ec6db79fe305023395118cf1 (diff) |
[plugin.video.iplayerwww] 3.0.1 (#1071)
Diffstat (limited to 'plugin.video.iplayerwww')
-rw-r--r-- | plugin.video.iplayerwww/addon.xml | 9 | ||||
-rw-r--r-- | plugin.video.iplayerwww/default.py | 3 | ||||
-rw-r--r-- | plugin.video.iplayerwww/resources/lib/ipwww_video.py | 237 | ||||
-rw-r--r-- | plugin.video.iplayerwww/resources/settings.xml | 2 |
4 files changed, 241 insertions, 10 deletions
diff --git a/plugin.video.iplayerwww/addon.xml b/plugin.video.iplayerwww/addon.xml index c5ac661..d96d770 100644 --- a/plugin.video.iplayerwww/addon.xml +++ b/plugin.video.iplayerwww/addon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<addon id="plugin.video.iplayerwww" name="iPlayer WWW" version="3.0.0" provider-name="CaptainT, Cas, ihurst, primaeval"> +<addon id="plugin.video.iplayerwww" name="iPlayer WWW" version="3.0.1" provider-name="CaptainT, Cas, ihurst, primaeval"> <requires> <import addon="xbmc.python" version="2.25.0"/> <import addon="script.module.requests" version="2.7.0"/> @@ -23,6 +23,13 @@ <fanart>resources/fanart.jpg</fanart> </assets> <news> +v3.0.1 +Optimized selection of catchup CDN internally. +COMPATIBILITY NOTE: Users need to set catchup source to "Any" when Autoplay is switched off +to get a choice of all CDNs. +Additional programme properties for better shortcut handling within Kodi. +Fixed Channel A-Z. + v3.0.0 Initial release for Kodi Krypton. Support for DASH streams if inputstream.adaptive add-on is available. diff --git a/plugin.video.iplayerwww/default.py b/plugin.video.iplayerwww/default.py index 47d3eb9..95264a8 100644 --- a/plugin.video.iplayerwww/default.py +++ b/plugin.video.iplayerwww/default.py @@ -196,6 +196,9 @@ elif mode == 132: elif mode == 133: Radio.AddAvailableLiveStreamsDirectory(name, url, iconimage) +elif mode == 134: + Video.ScrapeAtoZEpisodes(url) + elif mode == 136: Radio.GetPage(url) diff --git a/plugin.video.iplayerwww/resources/lib/ipwww_video.py b/plugin.video.iplayerwww/resources/lib/ipwww_video.py index b6dc3ac..31274c4 100644 --- a/plugin.video.iplayerwww/resources/lib/ipwww_video.py +++ b/plugin.video.iplayerwww/resources/lib/ipwww_video.py @@ -82,7 +82,7 @@ def ListRedButton(): ('sport_stream_21b', 'BBC Red Button 21b'), ('sport_stream_22b', 'BBC Red Button 22b'), ('sport_stream_23b', 'BBC Red Button 23b'), - ('sport_stream_24b', 'BBC Red Button 24b'), + ('sport_stream_24b', 'BBC Red Button 24b'), ] iconimage = xbmc.translatePath('special://home/addons/plugin.video.iplayerwww/media/red_button.png') for id, name in channel_list: @@ -184,7 +184,7 @@ def ListChannelAtoZ(): iconimage = xbmc.translatePath( os.path.join('special://home/addons/plugin.video.iplayerwww/media', img + '.png')) url = "http://www.bbc.co.uk/%s/a-z" % id - AddMenuEntry(name, url, 128, iconimage, '', '') + AddMenuEntry(name, url, 134, iconimage, '', '') def GetAtoZPage(url): @@ -444,6 +444,195 @@ def ScrapeEpisodes(page_url): pDialog.close() +def ScrapeAtoZEpisodes(page_url): + """Creates a list of programmes on one standard HTML page. + + ScrapeEpisodes contains a number of special treatments, which are only needed for + specific pages, e.g. Search, but allows to use a single function for all kinds + of pages. + """ + + pDialog = xbmcgui.DialogProgressBG() + pDialog.create(translation(30319)) + + html = OpenURL(page_url) + + total_pages = 1 + current_page = 1 + page_range = range(1) + paginate = re.search(r'<ul class="pagination.*?</ul>', html, re.DOTALL) + next_page = 1 + if paginate: + page_base_url_match = re.search(r'(.+?)page=', page_url) + if page_base_url_match: + page_base_url = page_base_url_match.group(0) + else: + page_base_url = page_url+"?page=" + if int(ADDON.getSetting('paginate_episodes')) == 0: + current_page_match = re.search(r'page=(\d*)', page_url) + if current_page_match: + current_page = int(current_page_match.group(1)) + page_base_url_match = re.search(r'(.+?)page=', page_url) + if page_base_url_match: + page_base_url = page_base_url_match.group(0) + else: + page_base_url = page_url+"?page=" + page_range = range(current_page, current_page+1) + next_page_match = re.search(r'pagination__item--next">\n.+?<a href="\?page=(.*?)"', + paginate.group(0), + re.DOTALL) + if next_page_match: + next_page = int(next_page_match.group(1)) + else: + next_page = current_page + page_range = range(current_page, current_page+1) + else: + pages = re.findall(r'pagination__item--page">.+?<a href=".+?"',paginate.group(0),re.DOTALL) + if pages: + last = pages[-1] + last_page = re.search(r'<a href="\?page=(.*?)"',last) + total_pages = int(last_page.group(1)) + page_range = range(1, total_pages+1) + + for page in page_range: + + if page > current_page: + page_url = page_base_url + str(page) + html = OpenURL(page_url) + + # NOTE remove inner li to match outer li + + # <li data-version-type="hd"> + html = re.compile(r'<li data-version-type.*?</li>', + flags=(re.DOTALL | re.MULTILINE)).sub('', html) + + # <li class="list-item programme" data-ip-id="p026f2t4"> + list_items = re.findall(r'<li class="list-item.*?</li>', html, flags=(re.DOTALL | re.MULTILINE)) + + list_item_num = 1 + + for li in list_items: + + search_group = False + + main_url = None + # <a href="/iplayer/episode/b08jny1j/antiques-road-trip-series-13-reversions-episode-10" + # title="Antiques Road Trip, Series 13 Reversions: Episode 10" class="list-item__main-link"> + url_match = re.search( + r'<a.*?href="(.*?)".*?list-item__main-link.*?>', + li, flags=(re.DOTALL | re.MULTILINE)) + if url_match: + url = url_match.group(1) + if url: + main_url = 'http://www.bbc.co.uk' + url + + name = '' + title = '' + #<h1 class="list-item__title typo typo--bold typo--goose">Antiques Road Trip</h1> + title_match = re.search( + r'<h1 class="list-item__title.+?">\s*(.*?)\s*</h1>', + li, flags=(re.DOTALL | re.MULTILINE)) + if title_match: + title = title_match.group(1) + name = title + + subtitle = None + # <h2 class="list-item__programme-info__subtitle typo typo--skylark"> + # Series 39: 14. Burton Constable 2</h2> + subtitle_match = re.search( + r'<h2 class="list-item__programme-info__subtitle.+?">\s*(.*?)\s*</h2>', + li, flags=(re.DOTALL | re.MULTILINE)) + if subtitle_match: + subtitle = subtitle_match.group(1) + if subtitle: + name = name + " - " + subtitle + + icon = '' + # <source srcset="http://ichef.bbci.co.uk/images/ic/336x189/p04cd999.jpg" + icon_match = re.search( + r'<source.*?srcset="https://ichef.bbci.co.uk/images/ic/.*?/(.*?)\.jpg', + li, flags=(re.DOTALL | re.MULTILINE)) + if icon_match: + image = icon_match.group(1) + if image: + icon = "https://ichef.bbci.co.uk/images/ic/832x468/" + image + ".jpg" + + + type = None + synopsis = '' + # <p class="list-item__programme-info__synopsis"> + # Take an exclusive first look at this year’s candidates. + # </p> + synopsis_match = re.search( + r'<p class="list-item__programme-info__synopsis">\s*(.*?)\s*</p>', + li, flags=(re.DOTALL | re.MULTILINE)) + if synopsis_match: + synopsis = synopsis_match.group(1) + + aired = '' + # <p class="metadata__item typo typo--bullfinch">First shown: 10 Jun 2016</p> + release_match = re.search( + r'<p class="metadata__item.*?>First shown:\s*(.*?)</p>', + li, flags=(re.DOTALL | re.MULTILINE)) + if release_match: + release = release_match.group(1) + if release: + aired = FirstShownToAired(release) + + episodes = None + # <div class="list-item__episodes-button + # list-item__episodes-button--only-bp3 gel-layout__item"> + # <a href="/iplayer/episodes/b07gx71q" + # class="button button--with-link button--left-align button--full-width "> + episodes_match = re.search( + r'<div class="list-item__episodes-button.+?href="(.*?)"', + li, flags=(re.DOTALL | re.MULTILINE)) + if episodes_match: + episodes = episodes_match.group(1) + + more = None + # <span class="button__text typo typo--bullfinch typo--bold">12 available episodes</span> + more_match = re.search( + r'<span class="button__text.+?">(.*?) available episodes</span>', + li, flags=(re.DOTALL | re.MULTILINE)) + if more_match: + more = more_match.group(1) + + if episodes: + episodes_url = 'http://www.bbc.co.uk' + episodes + if search_group: + AddMenuEntry('[B]%s[/B] - %s' % (title, translation(30318)), + episodes_url, 128, icon, '', '') + else: + AddMenuEntry('[B]%s[/B] - %s %s' % (title, more, translation(30313)), + episodes_url, 128, icon, '', '') + elif more: + AddMenuEntry('[B]%s[/B] - %s %s' % (title, more, translation(30313)), + main_url, 128, icon, '', '') + + if type != "group": + CheckAutoplay(name , main_url, icon, synopsis, aired) + + percent = int(100*(page+list_item_num/len(list_items))/total_pages) + pDialog.update(percent,translation(30319),name) + + list_item_num += 1 + + percent = int(100*page/total_pages) + pDialog.update(percent,translation(30319)) + + if int(ADDON.getSetting('paginate_episodes')) == 0: + if current_page < next_page: + page_url = page_base_url + str(next_page) + AddMenuEntry(" [COLOR ffffa500]%s >>[/COLOR]" % translation(30320), page_url, 134, '', '', '') + + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE) + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE) + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_UNSORTED) + + pDialog.close() + + def ScrapeMarkup(markup): """Creates a list of programmes of a markup response. @@ -866,6 +1055,12 @@ def ListMostPopular(): def AddAvailableStreamItem(name, url, iconimage, description): """Play a streamm based on settings for preferred catchup source and bitrate.""" stream_ids = ScrapeAvailableStreams(url) + if stream_ids['name']: + name = stream_ids['name'] + if not iconimage or iconimage == u"DefaultVideo.png" and stream_ids['image']: + iconimage = stream_ids['image'] + if stream_ids['description']: + description = stream_ids['description'] if stream_ids['stream_id_ad']: streams_all = ParseStreamsHLSDASH(stream_ids['stream_id_ad']) elif stream_ids['stream_id_sl']: @@ -927,6 +1122,12 @@ def GetAvailableStreams(name, url, iconimage, description): """Calls AddAvailableStreamsDirectory based on user settings""" #print url stream_ids = ScrapeAvailableStreams(url) + if stream_ids['name']: + name = stream_ids['name'] + if stream_ids['image']: + iconimage = stream_ids['image'] + if stream_ids['description']: + description = stream_ids['description'] AddAvailableStreamsDirectory(name, stream_ids['stream_id_st'], iconimage, description) # If we searched for Audio Described programmes and they have been found, append them to the list. if stream_ids['stream_id_ad']: @@ -1095,6 +1296,9 @@ def PlayStream(name, url, iconimage, description, subtitles_url): liz.setInfo(type='Video', infoLabels={'Title': name}) liz.setProperty("IsPlayable", "true") liz.setPath(url) + if ADDON.getSetting('stream_protocol') == '0': + liz.setProperty('inputstreamaddon', 'inputstream.adaptive') + liz.setProperty('inputstream.adaptive.manifest_type', 'mpd') if subtitles_url and ADDON.getSetting('subtitles') == 'true': subtitles_file = download_subtitles(subtitles_url) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz) @@ -1155,16 +1359,19 @@ def ParseStreams(stream_id): match = re.compile( 'connection authExpires=".+?href="(.+?)".+?supplier="mf_(.+?)".+?transferFormat="(.+?)"' ).findall(html) + source = int(ADDON.getSetting('catchup_source')) for m3u8_url, supplier, transfer_format in match: tmp_sup = 0 tmp_br = 0 if transfer_format == 'hls': - if supplier == 'akamai_uk_hls': + if supplier == 'akamai_uk_hls' and source in [0,1]: tmp_sup = 1 - elif supplier == 'limelight_uk_hls': + elif supplier == 'limelight_uk_hls' and source in [0,2]: tmp_sup = 2 - elif supplier == 'bidi_uk_hls': + elif supplier == 'bidi_uk_hls' and source in [0,3]: tmp_sup = 3 + else: + continue m3u8_breakdown = re.compile('(.+?)iptv.+?m3u8(.+?)$').findall(m3u8_url) #print m3u8_breakdown # print m3u8_url @@ -1197,10 +1404,12 @@ def ParseStreams(stream_id): tmp_sup = 0 tmp_br = 0 if transfer_format == 'hls': - if supplier == 'akamai_hls_open': + if supplier == 'akamai_hls_open' and source in [0,1]: tmp_sup = 1 - elif supplier == 'limelight_hls_open': + elif supplier == 'limelight_hls_open' and source in [0,2]: tmp_sup = 2 + else: + continue m3u8_breakdown = re.compile('.+?master.m3u8(.+?)$').findall(m3u8_url) # print m3u8_url # print m3u8_breakdown @@ -1376,6 +1585,18 @@ def ParseLiveDASHStreams(channelname): def ScrapeAvailableStreams(url): # Open page and retrieve the stream ID html = OpenURL(url) + name = None + match = re.search(r'<meta property="og:title" content="(.*?)"', html, re.DOTALL) + if match: + name = match.group(1) + image = None + match = re.search(r'<meta property="og:image" content="(.*?)"', html, re.DOTALL) + if match: + image = match.group(1) + description = None + match = re.search(r'<meta property="og:description" content="(.*?)"', html, re.DOTALL) + if match: + description = match.group(1) # Search for standard programmes. stream_id_st = re.compile('"vpid":"(.+?)"').findall(html) # Optionally, Signed programmes can be searched for. These have a different ID. @@ -1392,7 +1613,7 @@ def ScrapeAvailableStreams(url): # print stream_id_ad else: stream_id_ad = [] - return {'stream_id_st': stream_id_st, 'stream_id_sl': stream_id_sl, 'stream_id_ad': stream_id_ad} + return {'stream_id_st': stream_id_st, 'stream_id_sl': stream_id_sl, 'stream_id_ad': stream_id_ad, 'name': name, 'image':image, 'description': description} def CheckAutoplay(name, url, iconimage, plot, aired=None): diff --git a/plugin.video.iplayerwww/resources/settings.xml b/plugin.video.iplayerwww/resources/settings.xml index af3ed8b..7f2b970 100644 --- a/plugin.video.iplayerwww/resources/settings.xml +++ b/plugin.video.iplayerwww/resources/settings.xml @@ -44,7 +44,7 @@ <setting id="streams_autoplay" label="30205" type="bool" default="true" /> <setting label="30101" type="lsep" /> <setting id="stream_protocol" label="30212" type="enum" values="DASH|HLS" default="0" /> - <setting id="catchup_source" label="30210" type="enum" values="Any|Akamai|Limelight|Bidi" default="0" enable="eq(-3,true)" /> + <setting id="catchup_source" label="30210" type="enum" values="Any|Akamai|Limelight|Bidi" default="0" enable="true" /> <setting id="catchup_bitrate" label="30211" type="enum" values="Highest|0.8 Mbps|1.0 Mbps|1.5 Mbps|1.8 Mbps|2.4 Mbps|3.1 Mbps|5.5 Mbps" default="0" enable="eq(-4,true) + eq(-2,1)" /> <setting id="live_source" label="30220" type="enum" values="Any|Akamai|Limelight" default="0" enable="eq(-5,true)" /> <setting id="live_bitrate" label="30230" type="enum" values="Highest|0.1 Mbps|0.2 Mbps|0.3 Mbps|0.6 Mbps|1.0 Mbps|1.8 Mbps|3.1 Mbps|5.5 Mbps" default="0" enable="eq(-6,true) + eq(-4,1)" /> |