diff --git a/resources/lib/modules/player.py b/resources/lib/modules/player.py index 437e0a6..3d2e466 100644 --- a/resources/lib/modules/player.py +++ b/resources/lib/modules/player.py @@ -12,11 +12,6 @@ from resources.lib.viervijfzes.auth import AuthApi from resources.lib.viervijfzes.aws.cognito_idp import AuthenticationException, InvalidLoginException from resources.lib.viervijfzes.content import CACHE_PREVENT, ContentApi, GeoblockedException, UnavailableException -try: # Python 3 - from urllib.parse import quote, urlencode -except ImportError: # Python 2 - from urllib import quote, urlencode - _LOGGER = logging.getLogger(__name__) @@ -79,18 +74,9 @@ class Player: if resolved_stream: titleitem = Menu.generate_titleitem(episode) - if resolved_stream.license_url: - # Generate license key - license_key = self.create_license_key(resolved_stream.license_url, - key_headers=dict( - customdata=resolved_stream.auth, - )) - else: - license_key = None - kodiutils.play(resolved_stream.url, resolved_stream.stream_type, - license_key, + resolved_stream.license_key, info_dict=titleitem.info_dict, art_dict=titleitem.art_dict, prop_dict=titleitem.prop_dict) @@ -106,15 +92,7 @@ class Player: # Lookup the stream 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( - customdata=resolved_stream.auth, - )) - else: - license_key = None - - kodiutils.play(resolved_stream.url, resolved_stream.stream_type, license_key) + kodiutils.play(resolved_stream.url, resolved_stream.stream_type, resolved_stream.license_key) @staticmethod def _resolve_stream(uuid, islongform): @@ -153,26 +131,3 @@ class Player: except UnavailableException: kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable... return None - - @staticmethod - def create_license_key(key_url, key_type='R', key_headers=None, key_value=None): - """ Create a license key string that we need for inputstream.adaptive. - - :param str key_url: - :param str key_type: - :param dict[str, str] key_headers: - :param str key_value: - :rtype: str - """ - header = '' - if key_headers: - header = urlencode(key_headers) - - if key_type in ('A', 'R', 'B'): - key_value = key_type + '{SSM}' - elif key_type == 'D': - if 'D{SSM}' not in key_value: - raise ValueError('Missing D{SSM} placeholder') - key_value = quote(key_value) - - return '%s|%s|%s|' % (key_url, header, key_value) diff --git a/resources/lib/viervijfzes/__init__.py b/resources/lib/viervijfzes/__init__.py index a5dcb63..46cb626 100644 --- a/resources/lib/viervijfzes/__init__.py +++ b/resources/lib/viervijfzes/__init__.py @@ -79,19 +79,17 @@ STREAM_DICT = { class ResolvedStream: """ Defines a stream that we can play""" - def __init__(self, uuid=None, url=None, stream_type=None, license_url=None, auth=None): + def __init__(self, uuid=None, url=None, stream_type=None, license_key=None): """ :type uuid: str :type url: str :type stream_type: str - :type license_url: str - :type auth: str + :type license_key: str """ self.uuid = uuid self.url = url self.stream_type = stream_type - self.license_url = license_url - self.auth = auth + self.license_key = license_key def __repr__(self): return "%r" % self.__dict__ diff --git a/resources/lib/viervijfzes/content.py b/resources/lib/viervijfzes/content.py index 81e9753..097b2bf 100644 --- a/resources/lib/viervijfzes/content.py +++ b/resources/lib/viervijfzes/content.py @@ -351,10 +351,10 @@ class ContentApi: return None def get_stream_by_uuid(self, uuid, islongform): - """ Get the stream URL to use for this video. + """ Return a ResolvedStream for this video. :type uuid: str :type islongform: bool - :rtype str + :rtype: ResolvedStream """ 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()) @@ -363,34 +363,35 @@ class ContentApi: if not data: raise UnavailableException + # Get DRM license + license_key = None + if data.get('drmXml'): + # BuyDRM format + # See https://docs.unified-streaming.com/documentation/drm/buydrm.html#setting-up-the-client + + # Generate license key + license_key = self.create_license_key('https://wv-keyos.licensekeyserver.com/', key_headers=dict( + customdata=data['drmXml'], + )) + + # Get manifest url if data.get('manifestUrls'): - if data.get('drmXml'): - # DRM protected stream - # See https://docs.unified-streaming.com/documentation/drm/buydrm.html#setting-up-the-client - - # DRM protected DASH stream - return ResolvedStream( - uuid=uuid, - url=data['manifestUrls']['dash'], - stream_type=STREAM_DASH, - license_url='https://wv-keyos.licensekeyserver.com/', - auth=data['drmXml'], - ) - if data.get('manifestUrls').get('dash'): - # Unprotected DASH stream + # DASH stream return ResolvedStream( uuid=uuid, url=data['manifestUrls']['dash'], stream_type=STREAM_DASH, + license_key=license_key, ) - # Unprotected HLS stream + # HLS stream return ResolvedStream( uuid=uuid, url=data['manifestUrls']['hls'], stream_type=STREAM_HLS, + license_key=license_key, ) # No manifest url found, get manifest from Server-Side Ad Insertion service @@ -398,11 +399,12 @@ class ContentApi: 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 + # Server-Side Ad Insertion DASH stream return ResolvedStream( uuid=uuid, url=ad_data['stream_manifest'], stream_type=STREAM_DASH, + license_key=license_key, ) raise UnavailableException @@ -733,6 +735,34 @@ class ContentApi: ) return episode + @staticmethod + def create_license_key(key_url, key_type='R', key_headers=None, key_value='', response_value=''): + """ Create a license key string that we need for inputstream.adaptive. + :type key_url: str + :type key_type: str + :type key_headers: dict[str, str] + :type key_value: str + :type response_value: str + :rtype str + """ + try: # Python 3 + from urllib.parse import quote, urlencode + except ImportError: # Python 2 + from urllib import quote, urlencode + + header = '' + if key_headers: + header = urlencode(key_headers) + + if key_type in ('A', 'R', 'B'): + key_value = key_type + '{SSM}' + elif key_type == 'D': + if 'D{SSM}' not in key_value: + raise ValueError('Missing D{SSM} placeholder') + key_value = quote(key_value) + + return '%s|%s|%s|%s' % (key_url, header, key_value, response_value) + def _get_url(self, url, params=None, authentication=None): """ Makes a GET request for the specified URL. :type url: str