From d5bf6333ff77899a5a7ecf1f9a9d2b8d8e6ca1d8 Mon Sep 17 00:00:00 2001 From: Cas Date: Wed, 1 Jun 2022 20:14:14 +0200 Subject: [PATCH] Upgrade VTMGO REST API to version 12 (#325) * Upgrade to VTM GO API version 12 * Requirements installation fix * Annotate `get_config` as static method Co-authored-by: Cas van Dongen --- requirements.txt | 2 +- resources/lib/vtmgo/__init__.py | 8 +++--- resources/lib/vtmgo/util.py | 4 +-- resources/lib/vtmgo/vtmgo.py | 46 +++++++++++++++++++-------------- scripts/build.py | 2 +- tests/test_routing.py | 2 +- 6 files changed, 35 insertions(+), 29 deletions(-) mode change 100755 => 100644 scripts/build.py diff --git a/requirements.txt b/requirements.txt index c780ced..02b0f78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ pytest-timeout python-dateutil pysocks requests -git+git://github.com/dagwieers/kodi-plugin-routing.git@setup#egg=routing +git+https://github.com/tamland/kodi-plugin-routing@master#egg=routing mock sakee win-inet-pton; platform_system=="Windows" \ No newline at end of file diff --git a/resources/lib/vtmgo/__init__.py b/resources/lib/vtmgo/__init__.py index 8bfe5f5..3195793 100644 --- a/resources/lib/vtmgo/__init__.py +++ b/resources/lib/vtmgo/__init__.py @@ -7,10 +7,10 @@ API_ANDROID_ENDPOINT = 'https://lfvp-android-api.dpgmedia.net' # These seem to be hardcoded -STOREFRONT_MAIN = '9620cc0b-0f97-4d96-902a-827dcfd0b227' -STOREFRONT_MOVIES = 'e3fc0750-f110-4808-ae5f-246846ff940f' -STOREFRONT_SERIES = '1c683de4-3fb0-4cc4-9d9c-c365eba1b155' -STOREFRONT_KIDS = '73f34fbf-301c-4deb-b366-13ba39e25996' +STOREFRONT_MAIN = 'main' +STOREFRONT_MOVIES = 'movies' +STOREFRONT_SERIES = 'series' +STOREFRONT_KIDS = 'kids' class Profile: diff --git a/resources/lib/vtmgo/util.py b/resources/lib/vtmgo/util.py index cf2fbc7..4f8af81 100644 --- a/resources/lib/vtmgo/util.py +++ b/resources/lib/vtmgo/util.py @@ -16,8 +16,8 @@ # Setup a static session that can be reused for all calls SESSION = requests.Session() SESSION.headers = { - 'User-Agent': 'VTMGO/11.19 (be.vmma.vtm.zenderapp; build:14554; iOS 24) okhttp/4.9.1', - 'x-app-version': '11', + 'User-Agent': 'VTMGO/12.12 (be.vmma.vtm.zenderapp; build:16424; Android 24) okhttp/4.9.3', + 'x-app-version': '12', 'x-persgroep-mobile-app': 'true', 'x-persgroep-os': 'android', 'x-persgroep-os-version': '24', diff --git a/resources/lib/vtmgo/vtmgo.py b/resources/lib/vtmgo/vtmgo.py index 1daf912..ea31fed 100644 --- a/resources/lib/vtmgo/vtmgo.py +++ b/resources/lib/vtmgo/vtmgo.py @@ -26,7 +26,7 @@ class ApiUpdateRequired(Exception): - """ Is thrown when the an API update is required. """ + """ Is thrown when an API update is required. """ class VtmGo: @@ -42,10 +42,11 @@ def _mode(self): """ Return the mode that should be used for API calls """ return 'vtmgo-kids' if self.get_product() == 'VTM_GO_KIDS' else 'vtmgo' - def get_config(self): + @staticmethod + def get_config(): """ Returns the config for the app """ # This is currently not used - response = util.http_get(API_ANDROID_ENDPOINT + '/vtmgo/config', token=self._tokens.access_token) + response = util.http_get(API_ANDROID_ENDPOINT + '/vtmgo/config') info = json.loads(response.text) # This contains a player.updateIntervalSeconds that could be used to notify VTM GO about the playing progress @@ -106,7 +107,7 @@ def get_storefront_category(self, storefront, category): result = json.loads(response.text) items = [] - for item in result.get('row', {}).get('teasers'): + for item in result.get('teasers'): if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE: items.append(self._parse_movie_teaser(item)) @@ -222,7 +223,7 @@ def get_movie(self, movie_id, cache=CACHE_AUTO): thumb=movie.get('teaserImageUrl'), fanart=movie.get('bigPhotoUrl'), year=movie.get('productionYear'), - geoblocked=movie.get('geoBlocked'), + geoblocked=movie.get('blockedFor') == 'GEO', remaining=movie.get('remainingDaysAvailable'), legal=movie.get('legalIcons'), # aired=movie.get('broadcastTimestamp'), @@ -248,29 +249,34 @@ def get_program(self, program_id, cache=CACHE_AUTO): response = util.http_get(API_ENDPOINT + '/%s/programs/%s' % (self._mode(), program_id), token=self._tokens.access_token if self._tokens else None, profile=self._tokens.profile if self._tokens else None) - info = json.loads(response.text) - program = info.get('program', {}) + program = json.loads(response.text) kodiutils.set_cache(['program', program_id], program) channel = self._parse_channel(program.get('channelLogoUrl')) seasons = {} - for item_season in program.get('seasons', []): + for item_season in program.get('seasonIndices', []): episodes = {} - for item_episode in item_season.get('episodes', []): + # Fetch season + season_response = util.http_get(API_ENDPOINT + '/%s/programs/%s/seasons/%s' % (self._mode(), program_id, item_season), + token=self._tokens.access_token if self._tokens else None, + profile=self._tokens.profile if self._tokens else None) + season = json.loads(season_response.text) + + for item_episode in season.get('episodes', []): episodes[item_episode.get('index')] = Episode( episode_id=item_episode.get('id'), program_id=program_id, program_name=program.get('name'), number=item_episode.get('index'), - season=item_season.get('index'), + season=item_season, name=item_episode.get('name'), description=item_episode.get('description'), duration=item_episode.get('durationSeconds'), thumb=item_episode.get('bigPhotoUrl'), fanart=item_episode.get('bigPhotoUrl'), - geoblocked=program.get('geoBlocked'), + geoblocked=program.get('blockedFor') == 'GEO', remaining=item_episode.get('remainingDaysAvailable'), channel=channel, legal=program.get('legalIcons'), @@ -279,8 +285,8 @@ def get_program(self, program_id, cache=CACHE_AUTO): watched=item_episode.get('doneWatching', False), ) - seasons[item_season.get('index')] = Season( - number=item_season.get('index'), + seasons[item_season] = Season( + number=item_season, episodes=episodes, channel=channel, legal=program.get('legalIcons'), @@ -291,9 +297,9 @@ def get_program(self, program_id, cache=CACHE_AUTO): name=program.get('name'), description=program.get('description'), year=program.get('productionYear'), - thumb=program.get('teaserImageUrl'), - fanart=program.get('bigPhotoUrl'), - geoblocked=program.get('geoBlocked'), + thumb=program.get('landscapeTeaserImageUrl'), + fanart=program.get('backgroundImageUrl'), + geoblocked=program.get('blockedFor') == 'GEO', seasons=seasons, channel=channel, legal=program.get('legalIcons'), @@ -413,7 +419,7 @@ def _parse_movie_teaser(self, item, cache=CACHE_ONLY): movie_id=item.get('target', {}).get('id'), name=item.get('title'), thumb=item.get('imageUrl'), - geoblocked=item.get('geoBlocked'), + geoblocked=item.get('blockedFor') == 'GEO', ) def _parse_program_teaser(self, item, cache=CACHE_ONLY): @@ -429,8 +435,8 @@ def _parse_program_teaser(self, item, cache=CACHE_ONLY): return Program( program_id=item.get('target', {}).get('id'), name=item.get('title'), - thumb=item.get('imageUrl'), - geoblocked=item.get('geoBlocked'), + thumb=item.get('largeImageUrl'), + geoblocked=item.get('blockedFor') == 'GEO', ) def _parse_episode_teaser(self, item, cache=CACHE_ONLY): @@ -448,7 +454,7 @@ def _parse_episode_teaser(self, item, cache=CACHE_ONLY): program_name=item.get('title'), name=item.get('label'), description=episode.description if episode else None, - geoblocked=item.get('geoBlocked'), + geoblocked=item.get('blockedFor') == 'GEO', thumb=item.get('imageUrl'), progress=item.get('playerPositionSeconds'), watched=False, diff --git a/scripts/build.py b/scripts/build.py old mode 100755 new mode 100644 index 0eb268f..1a3ee2e --- a/scripts/build.py +++ b/scripts/build.py @@ -78,7 +78,7 @@ def modify_xml(file, version, news, python=None): if os.path.isfile(f): shutil.copy(f, dest) else: - shutil.copytree(f, os.path.join(dest, f), dirs_exist_ok=True) + shutil.copytree(f, os.path.join(dest, f)) # Update addon.xml for matrix and create zip modify_xml(os.path.join(dest, 'addon.xml'), addon_info['version'] + '+matrix.1', addon_info['news'], '3.0.0') diff --git a/tests/test_routing.py b/tests/test_routing.py index eda3c9d..dbeaf13 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -20,7 +20,7 @@ EXAMPLE_CHANNEL = 'ea826456-6b19-4612-8969-864d1c818347' # VTM2 EXAMPLE_MOVIE = '1c758fe2-fa19-4dc1-a9f6-fcd5eeb0a284' # Belgica -EXAMPLE_PROGRAM = '96a49148-59f6-420c-9b90-8b058760c467' # Familie +EXAMPLE_PROGRAM = '5d5e5976-6ca0-43a5-be96-1467ea25cfff' # Familie EXAMPLE_EPISODE = '03136212-d2f5-4c0f-abff-eac84ae8da42' # Instafamous S01E01