diff --git a/lib/srgssr.py b/lib/srgssr.py
index 671d01f..58569f9 100644
--- a/lib/srgssr.py
+++ b/lib/srgssr.py
@@ -83,7 +83,10 @@ def __init__(self, plugin_handle, bu='srf', addon_id=ADDON_ID):
self.host_url = f'https://www.{bu}.ch'
if bu == 'swi':
self.host_url = 'https://play.swissinfo.ch'
+ self.playtv_url = f'{self.host_url}/play/tv'
self.apiv3_url = f'{self.host_url}/play/v3/api/{bu}/production/'
+ self.data_regex = \
+ r''
self.data_uri = f'special://home/addons/{self.addon_id}/resources/data'
self.media_uri = \
f'special://home/addons/{self.addon_id}/resources/media'
@@ -142,10 +145,14 @@ def build_url(mode=None, name=None, url=None, page_hash=None, page=None):
page -- an integer used to indicate the current page in
the list of items
"""
- if mode:
+ try:
mode = str(mode)
- if page:
+ except Exception:
+ pass
+ try:
page = str(page)
+ except Exception:
+ pass
added = False
queries = (url, mode, name, page_hash, page)
query_names = ('url', 'mode', 'name', 'page_hash', 'page')
@@ -233,7 +240,7 @@ def build_main_menu(self, identifiers=[]):
'identifier': 'Topics',
'name': self.plugin_language(30058),
'mode': 13,
- 'displayItem': False, # not (yet) supported
+ 'displayItem': self.get_boolean_setting('Topics'),
'icon': self.icon,
}, {
# Most searched TV shows
@@ -271,6 +278,13 @@ def build_main_menu(self, identifiers=[]):
'mode': 27,
'displayItem': self.get_boolean_setting('Search'),
'icon': self.icon,
+ }, {
+ # Homepage
+ 'identifier': 'Homepage',
+ 'name': self.plugin_language(30060),
+ 'mode': 200,
+ 'displayItem': self.get_boolean_setting('Homepage'),
+ 'icon': self.icon,
}, {
# YouTube
'identifier': '%s_YouTube' % self.bu.upper(),
@@ -319,7 +333,8 @@ def build_menu_apiv3(self, queries, mode=1000, page=1, page_hash=None,
Keyword arguments:
queries -- the query string or a list of several queries
mode -- mode for the URL of the next folder
- page -- current page
+ page -- current page; if page is set to 0, do not build
+ a next page button
page_hash -- cursor for fetching the next items
is_show -- indicates if the menu contains only shows
whitelist_ids -- list of ids that should be displayed, if it is set
@@ -332,6 +347,7 @@ def build_menu_apiv3(self, queries, mode=1000, page=1, page_hash=None,
data = json.loads(self.open_url(self.apiv3_url + query))
if data:
data = utils.try_get(data, ['data', 'data'], list, []) or \
+ utils.try_get(data, ['data', 'medias'], list, []) or \
utils.try_get(data, ['data', 'results'], list, []) or \
utils.try_get(data, 'data', list, [])
for item in data:
@@ -349,8 +365,9 @@ def build_menu_apiv3(self, queries, mode=1000, page=1, page_hash=None,
cursor = None
if cursor:
- data = json.loads(self.open_url(self.apiv3_url + queries + (
- '&' if '?' in queries else '?') + 'next=' + cursor))
+ symb = '&' if '?' in queries else '?'
+ url = f'{self.apiv3_url}{queries}{symb}next={cursor}'
+ data = json.loads(self.open_url(url))
else:
data = json.loads(self.open_url(self.apiv3_url + queries))
cursor = utils.try_get(data, 'next') or utils.try_get(
@@ -363,6 +380,7 @@ def build_menu_apiv3(self, queries, mode=1000, page=1, page_hash=None,
return
items = utils.try_get(data, 'data', list, []) or \
+ utils.try_get(data, 'medias', list, []) or \
utils.try_get(data, 'results', list, []) or data
for item in items:
@@ -370,6 +388,16 @@ def build_menu_apiv3(self, queries, mode=1000, page=1, page_hash=None,
item, is_show=is_show, whitelist_ids=whitelist_ids)
if cursor:
+ if page == 0 or page == '0':
+ return
+
+ # Next page urls containing the string 'urns=' do not work
+ # properly. So in this case prevent the next page button from
+ # being created. Note that might lead to not having a next
+ # page butten where there should be one.
+ if 'urns=' in cursor:
+ return
+
if page:
url = self.build_url(
mode=mode, name=queries, page=int(page)+1,
@@ -443,37 +471,67 @@ def build_newest_favourite_menu(self, page=1):
queries.append('videos-by-show-id?showId=' + sid)
return self.build_menu_apiv3(queries)
- def extract_id_list(self, url, editor_picks=False):
+ def build_homepage_menu(self):
"""
- Opens a webpage and extracts video ids (of the form "id": "")
- from JavaScript snippets.
+ Builds the homepage menu.
+ """
+ self.build_menu_from_page(self.playtv_url, (
+ 'initialData', 'pacPageConfigs', 'videoHomeSections'))
- Keyword argmuents:
- url -- the URL of the webpage
- editor_picks -- if set, only extracts ids of editor picks
- (default: False)
+ def build_menu_from_page(self, url, path):
"""
- self.log(f'extract_id_list, url = {url}')
- response = self.open_url(url)
- string_response = utils.str_or_none(response, default='')
- if not string_response:
- self.log(f'No video ids found on {url}')
- return []
- readable_string_response = string_response.replace('"', '"')
- id_regex = r'''(?x)
- \"id\"
- \s*:\s*
- \"
- (?P
- %s
- )
- \"
- ''' % IDREGEX
- if editor_picks:
- id_regex += r'.+\"isEditorPick\"\s*:\s*true'
- id_list = [m.group('id') for m in re.finditer(
- id_regex, readable_string_response)]
- return id_list
+ Builds a menu by extracting some content directly from a website.
+
+ Keyword arguments:
+ url -- the url of the website
+ path -- the path to the relevant data in the json (as tuple
+ or list of strings)
+ """
+ html = self.open_url(url)
+ m = re.search(self.data_regex, html)
+ if not m:
+ self.log('build_menu_from_page: No data found in html')
+ return
+ content = m.groups()[0]
+ try:
+ js = json.loads(content)
+ except Exception:
+ self.log('build_menu_from_page: Invalid json')
+ return
+ data = utils.try_get(js, path, list, [])
+ if not data:
+ self.log('build_menu_from_page: Could not find any data in json')
+ return
+ for elem in data:
+ try:
+ id = elem['id']
+ section_type = elem['sectionType']
+ title = utils.try_get(elem, ('representation', 'title'))
+ if section_type in ('MediaSection', 'ShowSection',
+ 'MediaSectionWithShow'):
+ if section_type == 'MediaSection' and not title and \
+ utils.try_get(
+ elem, ('representation', 'name')
+ ) == 'HeroStage':
+ title = self.language(30053)
+ if not title:
+ continue
+ list_item = xbmcgui.ListItem(label=title)
+ list_item.setArt({
+ 'thumb': self.icon,
+ 'fanart': self.fanart,
+ })
+ if section_type == 'MediaSection':
+ name = f'media-section?sectionId={id}'
+ elif section_type == 'ShowSection':
+ name = f'show-section?sectionId={id}'
+ elif section_type == 'MediaSectionWithShow':
+ name = f'media-section-with-show?sectionId={id}'
+ url = self.build_url(mode=1000, name=name, page=1)
+ xbmcplugin.addDirectoryItem(
+ self.handle, url, list_item, isFolder=True)
+ except Exception:
+ pass
def build_episode_menu(self, video_id, include_segments=True,
segment_option=False, audio=False):
@@ -637,8 +695,21 @@ def build_entry_apiv3(self, data, is_show=False, whitelist_ids=None):
'banner': show_image_url or image_url,
})
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=True)
+ 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):
"""
@@ -652,7 +723,9 @@ def build_menu_by_urn(self, urn):
self.build_menu_apiv3(f'videos-by-show-id?showId={id}')
elif 'video' in urn:
self.build_episode_menu(id)
- # TODO: Add 'topic'
+ elif 'topic' in urn:
+ self.build_menu_from_page(self.playtv_url, (
+ 'initialData', 'pacPageConfigs', 'topicSections', urn))
def build_entry(self, json_entry, is_folder=False, audio=False,
fanart=None, urn=None, show_image_url=None,
diff --git a/resources/language/resource.language.de_de/strings.po b/resources/language/resource.language.de_de/strings.po
index 20cb149..784df96 100644
--- a/resources/language/resource.language.de_de/strings.po
+++ b/resources/language/resource.language.de_de/strings.po
@@ -15,6 +15,10 @@ msgstr ""
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+msgctxt "#30053"
+msgid "Recommendations"
+msgstr "Empfehlungen"
+
msgctxt "#30058"
msgid "Today"
msgstr "Heute"
@@ -102,3 +106,15 @@ 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
diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po
index 7e9af5f..6cbc454 100644
--- a/resources/language/resource.language.en_gb/strings.po
+++ b/resources/language/resource.language.en_gb/strings.po
@@ -15,6 +15,10 @@ msgstr ""
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+msgctxt "#30053"
+msgid "Recommendations"
+msgstr ""
+
msgctxt "#30058"
msgid "Today"
msgstr ""
@@ -102,3 +106,15 @@ 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 9fb5e83..6b52719 100644
--- a/resources/language/resource.language.fr_fr/strings.po
+++ b/resources/language/resource.language.fr_fr/strings.po
@@ -15,6 +15,10 @@ msgstr ""
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+msgctxt "#30053"
+msgid "Recommendations"
+msgstr "Recommandations"
+
msgctxt "#30058"
msgid "Today"
msgstr "Aujourd'hui"
@@ -102,3 +106,15 @@ 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
diff --git a/resources/language/resource.language.it_it/strings.po b/resources/language/resource.language.it_it/strings.po
index 78ef751..7f929aa 100644
--- a/resources/language/resource.language.it_it/strings.po
+++ b/resources/language/resource.language.it_it/strings.po
@@ -15,6 +15,10 @@ msgstr ""
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+msgctxt "#30053"
+msgid "Recommendations"
+msgstr "Consigli"
+
msgctxt "#30058"
msgid "Today"
msgstr "Oggi"
@@ -102,3 +106,15 @@ 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