Update api (#114)

This commit is contained in:
mediaminister 2023-01-16 17:59:29 +01:00 committed by GitHub
parent 89f4b457df
commit 9cdebb6c7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 31 deletions

View File

@ -161,10 +161,13 @@ def play_epg(channel, timestamp):
@routing.route('/play/catalog')
@routing.route('/play/catalog/<uuid>')
def play_catalog(uuid=None):
@routing.route('/play/catalog/<uuid>/<islongform>')
def play_catalog(uuid=None, islongform=False):
""" Play the requested item """
from ast import literal_eval
from resources.lib.modules.player import Player
Player().play(uuid)
# Convert string to bool using literal_eval
Player().play(uuid, literal_eval(islongform))
@routing.route('/play/page/<page>')

View File

@ -183,7 +183,7 @@ class Menu:
if item.uuid:
# We have an UUID and can play this item directly
path = kodiutils.url_for('play_catalog', uuid=item.uuid)
path = kodiutils.url_for('play_catalog', uuid=item.uuid, islongform=item.islongform)
else:
# We don't have an UUID, and first need to fetch the video information from the page
path = kodiutils.url_for('play_from_page', page=quote(item.path, safe=''))

View File

@ -74,7 +74,7 @@ class Player:
if episode.uuid:
# Lookup the stream
resolved_stream = self._resolve_stream(episode.uuid)
resolved_stream = self._resolve_stream(episode.uuid, episode.islongform)
_LOGGER.debug('Resolved stream: %s', resolved_stream)
if resolved_stream:
@ -95,16 +95,17 @@ class Player:
art_dict=titleitem.art_dict,
prop_dict=titleitem.prop_dict)
def play(self, uuid):
def play(self, uuid, islongform):
""" Play the requested item.
:type uuid: string
:type islongform: bool
"""
if not uuid:
kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable...
return
# Lookup the stream
resolved_stream = self._resolve_stream(uuid)
resolved_stream = self._resolve_stream(uuid, islongform)
if resolved_stream.license_url:
# Generate license key
license_key = self.create_license_key(resolved_stream.license_url, key_headers=dict(
@ -116,9 +117,10 @@ class Player:
kodiutils.play(resolved_stream.url, resolved_stream.stream_type, license_key)
@staticmethod
def _resolve_stream(uuid):
def _resolve_stream(uuid, islongform):
""" Resolve the stream for the requested item
:type uuid: string
:type islongform: bool
"""
try:
# Check if we have credentials
@ -135,7 +137,7 @@ class Player:
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path())
# Get stream information
resolved_stream = ContentApi(auth).get_stream_by_uuid(uuid)
resolved_stream = ContentApi(auth).get_stream_by_uuid(uuid, islongform)
return resolved_stream
except (InvalidLoginException, AuthenticationException) as ex:

View File

@ -109,7 +109,7 @@ class Episode:
""" Defines an Episode. """
def __init__(self, uuid=None, nodeid=None, path=None, channel=None, program_title=None, title=None, description=None, thumb=None, duration=None,
season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None):
season=None, season_uuid=None, number=None, rating=None, aired=None, expiry=None, stream=None, islongform=False):
"""
:type uuid: str
:type nodeid: str
@ -127,6 +127,7 @@ class Episode:
:type aired: datetime
:type expiry: datetime
:type stream: string
:type islongform: bool
"""
self.uuid = uuid
self.nodeid = nodeid
@ -144,6 +145,7 @@ class Episode:
self.aired = aired
self.expiry = expiry
self.stream = stream
self.islongform = islongform
def __repr__(self):
return "%r" % self.__dict__
@ -349,51 +351,64 @@ class ContentApi:
return None
def get_stream_by_uuid(self, uuid):
def get_stream_by_uuid(self, uuid, islongform):
""" Get the stream URL to use for this video.
:type uuid: str
:type islongform: bool
:rtype str
"""
response = self._get_url(self.API_VIERVIJFZES + '/content/%s' % uuid, authentication=self._auth.get_token())
mode = 'long-form' if islongform else 'short-form'
response = self._get_url(self.API_GOPLAY + '/web/v1/videos/%s/%s' % (mode, uuid), authentication='Bearer %s' % self._auth.get_token())
data = json.loads(response)
if not data:
raise UnavailableException
if 'videoDash' in data:
if data.get('manifestUrls'):
if 'drmKey' in data:
if data.get('drmXml'):
# DRM protected stream
# See https://docs.unified-streaming.com/documentation/drm/buydrm.html#setting-up-the-client
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=self._auth.get_token())
data_drm = json.loads(response_drm)
# DRM protected DASH stream
return ResolvedStream(
uuid=uuid,
url=data['videoDash']['S'],
url=data['manifestUrls']['dash'],
stream_type=STREAM_DASH,
license_url='https://wv-keyos.licensekeyserver.com/',
auth=data_drm.get('auth'),
auth=data['drmXml'],
)
if data.get('manifestUrls').get('dash'):
# Unprotected DASH stream
return ResolvedStream(
uuid=uuid,
url=data['videoDash']['S'],
url=data['manifestUrls']['dash'],
stream_type=STREAM_DASH,
)
# Unprotected HLS stream
return ResolvedStream(
uuid=uuid,
url=data['video']['S'],
url=data['manifestUrls']['hls'],
stream_type=STREAM_HLS,
)
# No manifest url found, get manifest from Server-Side Ad Insertion service
if data.get('adType') == 'SSAI' and data.get('ssai'):
url = 'https://pubads.g.doubleclick.net/ondemand/dash/content/%s/vid/%s/streams' % (data.get('ssai').get('contentSourceID'), data.get('ssai').get('videoID'))
ad_data = json.loads(self._post_url(url, data=''))
# Unprotected DASH stream
return ResolvedStream(
uuid=uuid,
url=ad_data['stream_manifest'],
stream_type=STREAM_DASH,
)
raise UnavailableException
def get_program_tree(self, cache=CACHE_AUTO):
""" Get a content tree with information about all the programs.
:type cache: str
@ -675,7 +690,6 @@ class ContentApi:
:type season_uuid: str
:rtype Episode
"""
if data.get('episodeNumber'):
episode_number = data.get('episodeNumber')
else:
@ -703,6 +717,7 @@ class ContentApi:
expiry=datetime.fromtimestamp(int(data.get('unpublishDate'))) if data.get('unpublishDate') else None,
rating=data.get('parentalRating'),
stream=data.get('path'),
islongform=data.get('isLongForm'),
)
return episode
@ -751,7 +766,7 @@ class ContentApi:
else:
response = self._session.post(url, params=params, json=data)
if response.status_code != 200:
if response.status_code not in (200, 201):
_LOGGER.error(response.text)
raise Exception('Could not fetch data')

View File

@ -70,12 +70,12 @@ class TestApi(unittest.TestCase):
self.assertIsInstance(program, Program)
episode = program.episodes[0]
resolved_stream = self._api.get_stream_by_uuid(episode.uuid)
resolved_stream = self._api.get_stream_by_uuid(episode.uuid, episode.islongform)
self.assertIsInstance(resolved_stream, ResolvedStream)
@unittest.skipUnless(kodiutils.get_setting('username') and kodiutils.get_setting('password'), 'Skipping since we have no credentials.')
def test_get_drm_stream(self):
resolved_stream = self._api.get_stream_by_uuid('e7faa457-5768-4abd-bf4f-5a0e1055bbd3') # https://www.goplay.be/video/ncis-los-angeles/ncis-los-angeles-s13/ncis-los-angeles-s13-aflevering-1
resolved_stream = self._api.get_stream_by_uuid('e7faa457-5768-4abd-bf4f-5a0e1055bbd3', True) # https://www.goplay.be/video/ncis-los-angeles/ncis-los-angeles-s13/ncis-los-angeles-s13-aflevering-1
self.assertIsInstance(resolved_stream, ResolvedStream)