Update api (#114)
This commit is contained in:
parent
89f4b457df
commit
9cdebb6c7f
@ -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>')
|
||||
|
@ -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=''))
|
||||
|
@ -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:
|
||||
|
@ -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,50 +351,63 @@ 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['manifestUrls']['dash'],
|
||||
stream_type=STREAM_DASH,
|
||||
)
|
||||
|
||||
# Unprotected HLS stream
|
||||
return ResolvedStream(
|
||||
uuid=uuid,
|
||||
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=data['videoDash']['S'],
|
||||
url=ad_data['stream_manifest'],
|
||||
stream_type=STREAM_DASH,
|
||||
)
|
||||
|
||||
# Unprotected HLS stream
|
||||
return ResolvedStream(
|
||||
uuid=uuid,
|
||||
url=data['video']['S'],
|
||||
stream_type=STREAM_HLS,
|
||||
)
|
||||
raise UnavailableException
|
||||
|
||||
|
||||
def get_program_tree(self, cache=CACHE_AUTO):
|
||||
""" Get a content tree with information about all the programs.
|
||||
@ -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')
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user