From 0c52481998def0c436fec55f71cd5056d2f7663f Mon Sep 17 00:00:00 2001 From: Alexander Seiler Date: Wed, 25 May 2022 14:32:20 +0200 Subject: [PATCH 1/4] Add livestream support --- lib/srgssr.py | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/srgssr.py b/lib/srgssr.py index f0c29c7..1b3c434 100644 --- a/lib/srgssr.py +++ b/lib/srgssr.py @@ -533,7 +533,7 @@ def build_menu_from_page(self, url, path): except Exception: pass - def build_episode_menu(self, video_id, include_segments=True, + def build_episode_menu(self, video_id_or_urn, include_segments=True, segment_option=False, audio=False): """ Builds a list entry for a episode by a given video id. @@ -542,7 +542,7 @@ def build_episode_menu(self, video_id, include_segments=True, entry for the segment will be created. Keyword arguments: - video_id -- the id of the video + video_id_or_urn -- the video id or the urn include_segments -- indicates if the segments (if available) of the video should be included in the list (default: True) @@ -551,25 +551,30 @@ def build_episode_menu(self, video_id, include_segments=True, audio -- boolean value to indicate if the episode is a radio show (default: False) """ - self.log(f'build_episode_menu, video_id = {video_id}') + self.log(f'build_episode_menu, video_id_or_urn = {video_id_or_urn}') content_type = 'audio' if audio else 'video' - json_url = f'https://il.srgssr.ch/integrationlayer/2.0/{self.bu}/' \ - f'mediaComposition/{content_type}/{video_id}.json' + if ':' in video_id_or_urn: + json_url = 'https://il.srgssr.ch/integrationlayer/2.0/' \ + f'mediaComposition/byUrn/{video_id_or_urn}.json' + video_id = video_id_or_urn.split(':')[-1] + else: + json_url = f'https://il.srgssr.ch/integrationlayer/2.0/{self.bu}' \ + f'/mediaComposition/{content_type}/{video_id_or_urn}' \ + '.json' + video_id = video_id_or_urn self.log(f'build_episode_menu. Open URL {json_url}') try: json_response = json.loads(self.open_url(json_url)) except Exception: - self.log(f'build_episode_menu: Cannot open json for {video_id}.') + self.log( + f'build_episode_menu: Cannot open json for {video_id_or_urn}.') return chapter_urn = utils.try_get(json_response, 'chapterUrn') segment_urn = utils.try_get(json_response, 'segmentUrn') - id_regex = r'[a-z]+:[a-z]+:[a-z]+:(?P.+)' - match_chapter_id = re.match(id_regex, chapter_urn) - match_segment_id = re.match(id_regex, segment_urn) - chapter_id = match_chapter_id.group('id') if match_chapter_id else None - segment_id = match_segment_id.group('id') if match_segment_id else None + chapter_id = chapter_urn.split(':')[-1] if chapter_urn else None + segment_id = segment_urn.split(':')[-1] if segment_urn else None if not chapter_id: self.log(f'build_episode_menu: No valid chapter URN \ @@ -594,6 +599,7 @@ def build_episode_menu(self, video_id, include_segments=True, for video_id {video_id}') return + # TODO: Simplify json_segment_list = utils.try_get( json_chapter, 'segmentList', data_type=list, default=[]) if video_id == chapter_id: @@ -697,9 +703,9 @@ def build_entry_apiv3(self, data, is_show=False, whitelist_ids=None): is_folder = True # Prevent upcoming live events from being played: - if 'swisstxt' in urn: - url = self.build_url(mode=500, name=urn) - is_folder = False + # if 'swisstxt' in urn: + # url = self.build_url(mode=500, name=urn) + # is_folder = False xbmcplugin.addDirectoryItem( self.handle, url, list_item, isFolder=is_folder) @@ -720,6 +726,9 @@ def build_menu_by_urn(self, urn): id = urn.split(':')[-1] if 'show' in urn: self.build_menu_apiv3(f'videos-by-show-id?showId={id}') + elif 'swisstxt' in urn: + # self.build_menu_apiv3(f'video?urn={urn}') + self.build_episode_menu(urn) elif 'video' in urn: self.build_episode_menu(id) elif 'topic' in urn: @@ -817,7 +826,11 @@ def build_entry(self, json_entry, is_folder=False, audio=False, url = self.build_url(mode=21, name=name) else: list_item.setProperty('IsPlayable', 'true') - url = self.build_url(mode=50, name=name) + # TODO: Simplify this, use URN instead of video id everywhere + if 'swisstxt' in urn: + url = self.build_url(mode=50, name=urn) + else: + url = self.build_url(mode=50, name=name) xbmcplugin.addDirectoryItem( self.handle, url, list_item, isFolder=is_folder) From 3fbec4af3254dfb1797ef2862c18f27540a1d422 Mon Sep 17 00:00:00 2001 From: Alexander Seiler Date: Tue, 31 May 2022 19:43:18 +0200 Subject: [PATCH 2/4] Do not include segments for livestreams --- lib/srgssr.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/srgssr.py b/lib/srgssr.py index 1b3c434..9514bff 100644 --- a/lib/srgssr.py +++ b/lib/srgssr.py @@ -727,8 +727,9 @@ def build_menu_by_urn(self, urn): if 'show' in urn: self.build_menu_apiv3(f'videos-by-show-id?showId={id}') elif 'swisstxt' in urn: - # self.build_menu_apiv3(f'video?urn={urn}') - self.build_episode_menu(urn) + # Do not include segments for livestreams, + # they fail to play. + self.build_episode_menu(urn, include_segments=False) elif 'video' in urn: self.build_episode_menu(id) elif 'topic' in urn: From 71b1ec5b5b07df21d364353d91a6358a32ecbacd Mon Sep 17 00:00:00 2001 From: Alexander Seiler Date: Tue, 31 May 2022 19:47:51 +0200 Subject: [PATCH 3/4] Revert playback not supported --- lib/srgssr.py | 11 ----------- .../language/resource.language.de_de/strings.po | 14 +------------- .../language/resource.language.en_gb/strings.po | 12 ------------ .../language/resource.language.fr_fr/strings.po | 14 +------------- .../language/resource.language.it_it/strings.po | 14 +------------- 5 files changed, 3 insertions(+), 62 deletions(-) diff --git a/lib/srgssr.py b/lib/srgssr.py index 9514bff..f8baada 100644 --- a/lib/srgssr.py +++ b/lib/srgssr.py @@ -702,20 +702,9 @@ def build_entry_apiv3(self, data, is_show=False, whitelist_ids=None): url = self.build_url(mode=100, name=urn) is_folder = True - # Prevent upcoming live events from being played: - # if 'swisstxt' in urn: - # url = self.build_url(mode=500, name=urn) - # is_folder = False - xbmcplugin.addDirectoryItem( self.handle, url, list_item, isFolder=is_folder) - def playback_not_supported_dialog(self, urn): - heading = self.language(30500) - message = self.language(30501) + f' {urn} ' + self.language(30502) - dialog = xbmcgui.Dialog() - dialog.notification(heading, message) - def build_menu_by_urn(self, urn): """ Builds a menu from an urn. diff --git a/resources/language/resource.language.de_de/strings.po b/resources/language/resource.language.de_de/strings.po index 784df96..e591952 100644 --- a/resources/language/resource.language.de_de/strings.po +++ b/resources/language/resource.language.de_de/strings.po @@ -105,16 +105,4 @@ msgstr "Kürzlich gesuchte Audios" msgctxt "#30118" msgid "Recently searched shows" -msgstr "Kürzlich gesuchte Sendungen" - -msgctxt "#30500" -msgid "Playback not supported" -msgstr "Wiedergabe wird nicht unterstützt" - -msgctxt "#30501" -msgid "Playback for item" -msgstr "Wiedergabe für das Medium" - -msgctxt "#30502" -msgid "not supported" -msgstr "wird nicht unterstützt" \ No newline at end of file +msgstr "Kürzlich gesuchte Sendungen" \ No newline at end of file diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 6cbc454..e81a1cc 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -105,16 +105,4 @@ msgstr "" msgctxt "#30118" msgid "Recently searched shows" -msgstr "" - -msgctxt "#30500" -msgid "Playback not supported" -msgstr "" - -msgctxt "#30501" -msgid "Playback for item" -msgstr "" - -msgctxt "#30502" -msgid "not supported" msgstr "" \ No newline at end of file diff --git a/resources/language/resource.language.fr_fr/strings.po b/resources/language/resource.language.fr_fr/strings.po index 6b52719..5130d7d 100644 --- a/resources/language/resource.language.fr_fr/strings.po +++ b/resources/language/resource.language.fr_fr/strings.po @@ -105,16 +105,4 @@ msgstr "Audios récemment recherchées" msgctxt "#30118" msgid "Recently searched shows" -msgstr "Émissions récemment recherchées" - -msgctxt "#30500" -msgid "Playback not supported" -msgstr "La lecture n'est pas prise en charge" - -msgctxt "#30501" -msgid "Playback for item" -msgstr "La lecture de l'élément" - -msgctxt "#30502" -msgid "not supported" -msgstr "n'est pas prise en charge" \ No newline at end of file +msgstr "Émissions récemment recherchées" \ No newline at end of file diff --git a/resources/language/resource.language.it_it/strings.po b/resources/language/resource.language.it_it/strings.po index 7f929aa..f1c8937 100644 --- a/resources/language/resource.language.it_it/strings.po +++ b/resources/language/resource.language.it_it/strings.po @@ -105,16 +105,4 @@ msgstr "Audios cercato di recente" msgctxt "#30118" msgid "Recently searched shows" -msgstr "Show cercato di recente" - -msgctxt "#30500" -msgid "Playback not supported" -msgstr "Riproduzione non supportata" - -msgctxt "#30501" -msgid "Playback for item" -msgstr "Riproduzione per l'elemento" - -msgctxt "#30502" -msgid "not supported" -msgstr "non supportata" \ No newline at end of file +msgstr "Show cercato di recente" \ No newline at end of file From 22f43e01eb9c1fdd450d7189d518ab2d2ba162b3 Mon Sep 17 00:00:00 2001 From: Alexander Seiler Date: Tue, 31 May 2022 19:49:02 +0200 Subject: [PATCH 4/4] Remove old code for livestreams --- lib/srgssr.py | 68 --------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/lib/srgssr.py b/lib/srgssr.py index f8baada..de04d71 100644 --- a/lib/srgssr.py +++ b/lib/srgssr.py @@ -1338,74 +1338,6 @@ def write_search(self, filename, name, max_entries=10): # continue # self.build_entry(json_entry) - def build_live_menu(self, extract_srf3=False): - """ - Builds the menu listing the currently available livestreams. - """ - def get_live_ids(): - """ - Downloads the main webpage and scrapes it for - possible livestreams. If some live events were found, a list - of live ids will be returned, otherwise an empty list. - """ - live_ids = [] - webpage = self.open_url(self.host_url, use_cache=False) - event_id_regex = r'(?:data-sport-id=\"|eventId=)(?P\d+)' - try: - for match in re.finditer(event_id_regex, webpage): - live_ids.append(match.group('live_id')) - except StopIteration: - pass - return live_ids - - def get_srf3_live_ids(): - """ - Returns a list of Radio SRF 3 video streams. - """ - url = 'https://www.srf.ch/radio-srf-3' - webpage = self.open_url(url, use_cache=False) - video_id_regex = r'''(?x) - popupvideoplayer\?id= - (?P - [a-f0-9]{8}- - [a-f0-9]{4}- - [a-f0-9]{4}- - [a-f0-9]{4}- - [a-f0-9]{12} - ) - ''' - live_ids = [] - try: - for match in re.finditer(video_id_regex, webpage): - live_ids.append(match.group('video_id')) - except StopIteration: - pass - return live_ids - live_ids = get_live_ids() - for lid in live_ids: - api_url = ('https://event.api.swisstxt.ch/v1/events/' - f'{self.bu}/byEventItemId/?eids={lid}') - live_json = json.loads(self.open_url(api_url)) - entry = utils.try_get(live_json, 0, data_type=dict, default={}) - if not entry: - self.log('build_live_menu: No entry found for live id {lid}.') - continue - if utils.try_get(entry, 'streamType') == 'noStream': - continue - title = utils.try_get(entry, 'title') - stream_url = utils.try_get(entry, 'hls') - image = utils.try_get(entry, 'imageUrl') - item = xbmcgui.ListItem(label=title) - item.setProperty('IsPlayable', 'true') - item.setArt({'thumb': image}) - purl = self.build_url(mode=51, name=stream_url) - xbmcplugin.addDirectoryItem( - self.handle, purl, item, isFolder=False) - if extract_srf3: - srf3_ids = get_srf3_live_ids() - for vid in srf3_ids: - self.build_episode_menu(vid, include_segments=False) - def _read_youtube_channels(self, fname): """ Reads YouTube channel IDs from a specified file and returns a list