From 02b2d4dbb17b6f4c8ab93bdb4bbba2e411c3f8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Thu, 3 Feb 2022 18:38:34 +0100 Subject: [PATCH] Fix empty My List due to unknown items (#102) * Ignore unavailable items on My List * Rework My List API --- resources/lib/modules/catalog.py | 47 ++--------------- resources/lib/viervijfzes/content.py | 76 +++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 48 deletions(-) diff --git a/resources/lib/modules/catalog.py b/resources/lib/modules/catalog.py index 46bb5f4..92a0515 100644 --- a/resources/lib/modules/catalog.py +++ b/resources/lib/modules/catalog.py @@ -4,9 +4,6 @@ from __future__ import absolute_import, division, unicode_literals import logging -from datetime import datetime - -import dateutil.tz from resources.lib import kodiutils from resources.lib.kodiutils import TitleItem @@ -253,22 +250,10 @@ class Catalog: kodiutils.show_listing(listing, 30005, content='tvshows') def show_mylist(self): - """ Show all the programs of all channels """ - try: - mylist, _ = self._auth.get_dataset('myList', 'myList') - except Exception as ex: - kodiutils.notification(message=str(ex)) - raise + """ Show the programs of My List """ + mylist = self._api.get_mylist() - items = [] - if mylist: - for item in mylist: - program = self._api.get_program_by_uuid(item.get('id')) - if program: - program.my_list = True - items.append(program) - - listing = [Menu.generate_titleitem(item) for item in items] + listing = [Menu.generate_titleitem(item) for item in mylist] # Sort items by title # Used for A-Z listing or when movies and episodes are mixed. @@ -280,23 +265,7 @@ class Catalog: kodiutils.end_of_directory() return - mylist, sync_info = self._auth.get_dataset('myList', 'myList') - - if not mylist: - mylist = [] - - if uuid not in [item.get('id') for item in mylist]: - # Python 2.7 doesn't support .timestamp(), and windows doesn't do '%s', so we need to calculate it ourself - epoch = datetime(1970, 1, 1, tzinfo=dateutil.tz.gettz('UTC')) - now = datetime.now(tz=dateutil.tz.gettz('UTC')) - timestamp = int((now - epoch).total_seconds()) * 1000 - - mylist.append({ - 'id': uuid, - 'timestamp': timestamp, - }) - - self._auth.put_dataset('myList', 'myList', mylist, sync_info) + self._api.mylist_add(uuid) kodiutils.end_of_directory() @@ -306,12 +275,6 @@ class Catalog: kodiutils.end_of_directory() return - mylist, sync_info = self._auth.get_dataset('myList', 'myList') - - if not mylist: - mylist = [] - - new_mylist = [item for item in mylist if item.get('id') != uuid] - self._auth.put_dataset('myList', 'myList', new_mylist, sync_info) + self._api.mylist_del(uuid) kodiutils.end_of_directory() diff --git a/resources/lib/viervijfzes/content.py b/resources/lib/viervijfzes/content.py index e4e12be..225b14c 100644 --- a/resources/lib/viervijfzes/content.py +++ b/resources/lib/viervijfzes/content.py @@ -354,7 +354,7 @@ class ContentApi: :type uuid: str :rtype str """ - response = self._get_url(self.API_VIERVIJFZES + '/content/%s' % uuid, authentication=True) + response = self._get_url(self.API_VIERVIJFZES + '/content/%s' % uuid, authentication=self._auth.get_token()) data = json.loads(response) if not data: @@ -366,7 +366,7 @@ class ContentApi: drm_key = data['drmKey']['S'] _LOGGER.debug('Fetching Authentication XML with drm_key %s', drm_key) - response_drm = self._get_url(self.API_GOPLAY + '/video/xml/%s' % drm_key, authentication=True) + response_drm = self._get_url(self.API_GOPLAY + '/video/xml/%s' % drm_key, authentication=self._auth.get_token()) data_drm = json.loads(response_drm) return ResolvedStream( @@ -484,6 +484,33 @@ class ContentApi: return categories + def get_mylist(self): + """ Get the content of My List + :rtype list[Program] + """ + data = self._get_url(self.API_GOPLAY + '/my-list', authentication='Bearer %s' % self._auth.get_token()) + result = json.loads(data) + + items = [] + for item in result: + try: + program = self.get_program_by_uuid(item.get('programId')) + if program: + program.my_list = True + items.append(program) + except Exception as exc: # pylint: disable=broad-except + _LOGGER.warning(exc) + + return items + + def mylist_add(self, program_id): + """ Add a program on My List """ + self._post_url(self.API_GOPLAY + '/my-list', data={'programId': program_id}, authentication='Bearer %s' % self._auth.get_token()) + + def mylist_del(self, program_id): + """ Remove a program on My List """ + self._delete_url(self.API_GOPLAY + '/my-list-item', params={'programId': program_id}, authentication='Bearer %s' % self._auth.get_token()) + @staticmethod def _extract_programs(html): """ Extract Programs from HTML code @@ -669,16 +696,15 @@ class ContentApi: ) return episode - def _get_url(self, url, params=None, authentication=False): + def _get_url(self, url, params=None, authentication=None): """ Makes a GET request for the specified URL. :type url: str + :type authentication: str :rtype str """ if authentication: - if not self._auth: - raise Exception('Requested to authenticate, but not auth object passed') response = self._session.get(url, params=params, headers={ - 'authorization': self._auth.get_token(), + 'authorization': authentication, }) else: response = self._session.get(url, params=params) @@ -689,6 +715,44 @@ class ContentApi: return response.text + def _post_url(self, url, params=None, data=None, authentication=None): + """ Makes a POST request for the specified URL. + :type url: str + :type authentication: str + :rtype str + """ + if authentication: + response = self._session.post(url, params=params, json=data, headers={ + 'authorization': authentication, + }) + else: + response = self._session.post(url, params=params, json=data) + + if response.status_code != 200: + _LOGGER.error(response.text) + raise Exception('Could not fetch data') + + return response.text + + def _delete_url(self, url, params=None, authentication=None): + """ Makes a DELETE request for the specified URL. + :type url: str + :type authentication: str + :rtype str + """ + if authentication: + response = self._session.delete(url, params=params, headers={ + 'authorization': authentication, + }) + else: + response = self._session.delete(url, params=params) + + if response.status_code != 200: + _LOGGER.error(response.text) + raise Exception('Could not fetch data') + + return response.text + def _handle_cache(self, key, cache_mode, update, ttl=30 * 24 * 60 * 60): """ Fetch something from the cache, and update if needed """ if cache_mode in [CACHE_AUTO, CACHE_ONLY]: