Fix empty My List due to unknown items (#102)
* Ignore unavailable items on My List * Rework My List API
This commit is contained in:
parent
21f877fb8d
commit
02b2d4dbb1
@ -4,9 +4,6 @@
|
|||||||
from __future__ import absolute_import, division, unicode_literals
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import dateutil.tz
|
|
||||||
|
|
||||||
from resources.lib import kodiutils
|
from resources.lib import kodiutils
|
||||||
from resources.lib.kodiutils import TitleItem
|
from resources.lib.kodiutils import TitleItem
|
||||||
@ -253,22 +250,10 @@ class Catalog:
|
|||||||
kodiutils.show_listing(listing, 30005, content='tvshows')
|
kodiutils.show_listing(listing, 30005, content='tvshows')
|
||||||
|
|
||||||
def show_mylist(self):
|
def show_mylist(self):
|
||||||
""" Show all the programs of all channels """
|
""" Show the programs of My List """
|
||||||
try:
|
mylist = self._api.get_mylist()
|
||||||
mylist, _ = self._auth.get_dataset('myList', 'myList')
|
|
||||||
except Exception as ex:
|
|
||||||
kodiutils.notification(message=str(ex))
|
|
||||||
raise
|
|
||||||
|
|
||||||
items = []
|
listing = [Menu.generate_titleitem(item) for item in mylist]
|
||||||
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]
|
|
||||||
|
|
||||||
# Sort items by title
|
# Sort items by title
|
||||||
# Used for A-Z listing or when movies and episodes are mixed.
|
# Used for A-Z listing or when movies and episodes are mixed.
|
||||||
@ -280,23 +265,7 @@ class Catalog:
|
|||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
return
|
return
|
||||||
|
|
||||||
mylist, sync_info = self._auth.get_dataset('myList', 'myList')
|
self._api.mylist_add(uuid)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
|
|
||||||
@ -306,12 +275,6 @@ class Catalog:
|
|||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
return
|
return
|
||||||
|
|
||||||
mylist, sync_info = self._auth.get_dataset('myList', 'myList')
|
self._api.mylist_del(uuid)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
|
@ -354,7 +354,7 @@ class ContentApi:
|
|||||||
:type uuid: str
|
:type uuid: str
|
||||||
:rtype 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)
|
data = json.loads(response)
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
@ -366,7 +366,7 @@ class ContentApi:
|
|||||||
drm_key = data['drmKey']['S']
|
drm_key = data['drmKey']['S']
|
||||||
|
|
||||||
_LOGGER.debug('Fetching Authentication XML with drm_key %s', drm_key)
|
_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)
|
data_drm = json.loads(response_drm)
|
||||||
|
|
||||||
return ResolvedStream(
|
return ResolvedStream(
|
||||||
@ -484,6 +484,33 @@ class ContentApi:
|
|||||||
|
|
||||||
return categories
|
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
|
@staticmethod
|
||||||
def _extract_programs(html):
|
def _extract_programs(html):
|
||||||
""" Extract Programs from HTML code
|
""" Extract Programs from HTML code
|
||||||
@ -669,16 +696,15 @@ class ContentApi:
|
|||||||
)
|
)
|
||||||
return episode
|
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.
|
""" Makes a GET request for the specified URL.
|
||||||
:type url: str
|
:type url: str
|
||||||
|
:type authentication: str
|
||||||
:rtype str
|
:rtype str
|
||||||
"""
|
"""
|
||||||
if authentication:
|
if authentication:
|
||||||
if not self._auth:
|
|
||||||
raise Exception('Requested to authenticate, but not auth object passed')
|
|
||||||
response = self._session.get(url, params=params, headers={
|
response = self._session.get(url, params=params, headers={
|
||||||
'authorization': self._auth.get_token(),
|
'authorization': authentication,
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
response = self._session.get(url, params=params)
|
response = self._session.get(url, params=params)
|
||||||
@ -689,6 +715,44 @@ class ContentApi:
|
|||||||
|
|
||||||
return response.text
|
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):
|
def _handle_cache(self, key, cache_mode, update, ttl=30 * 24 * 60 * 60):
|
||||||
""" Fetch something from the cache, and update if needed """
|
""" Fetch something from the cache, and update if needed """
|
||||||
if cache_mode in [CACHE_AUTO, CACHE_ONLY]:
|
if cache_mode in [CACHE_AUTO, CACHE_ONLY]:
|
||||||
|
Loading…
Reference in New Issue
Block a user