Add DRM support for all streams (#121)
This commit is contained in:
parent
dc446332ab
commit
c9ae78f83b
@ -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)
|
||||
|
@ -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__
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user