Skip to content

Commit c2d1135

Browse files
v2 license request / Add h264 profileLevel40 streams
1 parent fe53bce commit c2d1135

File tree

1 file changed

+27
-55
lines changed

1 file changed

+27
-55
lines changed

resources/lib/MSLv2.py

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import re
99
import sys
1010
import zlib
11-
import gzip
1211
import json
1312
import time
1413
import base64
@@ -48,8 +47,7 @@ class MSL(object):
4847
base_url = 'https://www.netflix.com/nq/msl_v1/cadmium/'
4948
endpoints = {
5049
'manifest': base_url + 'pbo_manifests/%5E1.0.0/router',
51-
#'license': base_url + 'pbo_licenses/%5E1.0.0/router'
52-
'license': 'http://www.netflix.com/api/msl/NFCDCH-LX/cadmium/license'
50+
'license': base_url + 'pbo_licenses/%5E1.0.0/router'
5351
}
5452

5553
def __init__(self, nx_common):
@@ -80,14 +78,19 @@ def load_manifest(self, viewable_id, dolby, hevc, hdr, dolbyvision, vp9):
8078
:param viewable_id: The id of of the viewable
8179
:return: MPD XML Manifest or False if no success
8280
"""
81+
82+
ia_addon = xbmcaddon.Addon('inputstream.adaptive')
83+
hdcp = ia_addon is not None and ia_addon.getSetting('HDCPOVERRIDE') == 'true'
84+
8385
esn = self.nx_common.get_esn()
86+
id = int(time.time() * 10000)
8487
manifest_request_data = {
8588
'version': 2,
8689
'url': '/manifest',
87-
'id': 15423166626396,
90+
'id': id,
8891
'esn': esn,
8992
'languages': self.locale_id,
90-
'uiVersion': 'shakti-vb45817f4',
93+
'uiVersion': 'shakti-v25d2fa21',
9194
'clientVersion': '6.0011.474.011',
9295
'params': {
9396
'type': 'standard',
@@ -97,10 +100,10 @@ def load_manifest(self, viewable_id, dolby, hevc, hdr, dolbyvision, vp9):
97100
'drmVersion': 25,
98101
'usePsshBox': True,
99102
'isBranching': False,
100-
'useHttpsStreams': True,
103+
'useHttpsStreams': False,
101104
'imageSubtitleHeight': 1080,
102105
'uiVersion': 'shakti-vb45817f4',
103-
'clientVersion': '6.0011.474.011',
106+
'clientVersion': '6.0011.511.011',
104107
'supportsPreReleasePin': True,
105108
'supportsWatermark': True,
106109
'showAllSubDubTracks': False,
@@ -109,19 +112,18 @@ def load_manifest(self, viewable_id, dolby, hevc, hdr, dolbyvision, vp9):
109112
'type': 'DigitalVideoOutputDescriptor',
110113
'outputType': 'unknown',
111114
'supportedHdcpVersions': [],
112-
'isHdcpEngaged': False
115+
'isHdcpEngaged': hdcp
113116
}],
114117
'preferAssistiveAudio': False,
115118
'isNonMember': False
116119
}
117120
}
118121
manifest_request_data['params']['titleSpecificData'][viewable_id] = { 'unletterboxed': False }
119122

120-
profiles = ['playready-h264mpl30-dash', 'playready-h264mpl31-dash', 'playready-h264hpl30-dash', 'playready-h264hpl31-dash', 'heaac-2-dash', 'BIF240', 'BIF320']
123+
profiles = ['playready-h264mpl30-dash', 'playready-h264mpl31-dash', 'playready-h264mpl40-dash', 'playready-h264hpl30-dash', 'playready-h264hpl31-dash', 'playready-h264hpl40-dash', 'heaac-2-dash', 'BIF240', 'BIF320']
121124

122125
# subtitles
123-
addon = xbmcaddon.Addon('inputstream.adaptive')
124-
if addon and self.nx_common.compare_versions(map(int, addon.getAddonInfo('version').split('.')), [2, 3, 8]) >= 0:
126+
if ia_addon and self.nx_common.compare_versions(map(int, ia_addon.getAddonInfo('version').split('.')), [2, 3, 8]) >= 0:
125127
profiles.append('webvtt-lssdh-ios8')
126128
else:
127129
profiles.append('simplesdh')
@@ -212,7 +214,7 @@ def load_manifest(self, viewable_id, dolby, hevc, hdr, dolbyvision, vp9):
212214
profiles.append('ddplus-5.1-dash')
213215

214216
manifest_request_data["params"]["profiles"] = profiles
215-
print manifest_request_data
217+
#print manifest_request_data
216218

217219
request_data = self.__generate_msl_request_data(manifest_request_data)
218220

@@ -252,7 +254,7 @@ def get_license(self, challenge, sid):
252254
"""
253255
esn = self.nx_common.get_esn()
254256
id = int(time.time() * 10000)
255-
'''license_request_data = {
257+
license_request_data = {
256258
'version': 2,
257259
'url': self.last_license_url,
258260
'id': id,
@@ -267,24 +269,7 @@ def get_license(self, challenge, sid):
267269
'xid': str(id + 1610)
268270
}],
269271
'echo': 'sessionId'
270-
}'''
271-
272-
license_request_data = {
273-
'method': 'license',
274-
'licenseType': 'STANDARD',
275-
'clientVersion': '4.0004.899.011',
276-
'uiVersion': 'akira',
277-
'languages': self.locale_id,
278-
'playbackContextId': self.last_playback_context,
279-
'drmContextIds': [self.last_drm_context],
280-
'challenges': [{
281-
'dataBase64': challenge,
282-
'sessionId': sid
283-
}],
284-
'clientTime': int(id / 10000),
285-
'xid': id + 1610
286272
}
287-
288273
#print license_request_data
289274

290275
request_data = self.__generate_msl_request_data(license_request_data)
@@ -309,8 +294,8 @@ def get_license(self, challenge, sid):
309294
# json() failed so we have a chunked json response
310295
resp = self.__parse_chunked_msl_response(resp.text)
311296
data = self.__decrypt_payload_chunks(resp['payloads'])
312-
if data['success'] is True:
313-
return data['result']['licenses'][0]['data']
297+
if 'licenseResponseBase64' in data[0]:
298+
return data[0]['licenseResponseBase64']
314299
else:
315300
self.nx_common.log(
316301
msg='Error getting license: ' + json.dumps(data))
@@ -339,7 +324,12 @@ def __decrypt_payload_chunks(self, payloadchunks):
339324
data = base64.standard_b64decode(data)
340325
decrypted_payload += data
341326

342-
decrypted_payload = json.JSONDecoder().decode(decrypted_payload)[1]['payload']
327+
decrypted_payload = json.JSONDecoder().decode(decrypted_payload)
328+
329+
if 'result' in decrypted_payload:
330+
return decrypted_payload['result']
331+
332+
decrypted_payload = decrypted_payload[1]['payload']
343333
if 'json' in decrypted_payload:
344334
return decrypted_payload['json']['result']
345335
else:
@@ -354,7 +344,7 @@ def __tranform_to_dash(self, manifest):
354344
filename='manifest.json',
355345
content=json.dumps(manifest))
356346

357-
self.last_license_url = manifest['links']['ldl']['href']
347+
self.last_license_url = manifest['links']['license']['href']
358348
self.last_playback_context = manifest['playbackContextId']
359349
self.last_drm_context = manifest['drmContextId']
360350

@@ -562,21 +552,10 @@ def __generate_msl_request_data(self, data):
562552
'mastertoken': self.mastertoken,
563553
}
564554

565-
# Serialize the given Data
566-
raw_marshalled_data = json.dumps(data)
567-
marshalled_data = raw_marshalled_data.replace('"', '\\"')
568-
serialized_data = '[{},{"headers":{},"path":"/cbp/cadmium-13"'
569-
serialized_data += ',"payload":{"data":"'
570-
serialized_data += marshalled_data
571-
serialized_data += '"},"query":""}]\n'
572-
573-
compressed_data = self.__compress_data(serialized_data)
574-
575555
# Create FIRST Payload Chunks
576556
first_payload = {
577557
'messageid': self.current_message_id,
578-
'data': compressed_data,
579-
'compressionalgo': 'GZIP',
558+
'data': base64.standard_b64encode(json.dumps(data)),
580559
'sequencenumber': 1,
581560
'endofmsg': True
582561
}
@@ -590,13 +569,6 @@ def __generate_msl_request_data(self, data):
590569
request_data = json.dumps(header) + json.dumps(first_payload_chunk)
591570
return request_data
592571

593-
def __compress_data(self, data):
594-
# GZIP THE DATA
595-
out = StringIO()
596-
with gzip.GzipFile(fileobj=out, mode="w") as f:
597-
f.write(data)
598-
return base64.standard_b64encode(out.getvalue())
599-
600572
def __generate_msl_header(
601573
self,
602574
is_handshake=False,
@@ -618,13 +590,13 @@ def __generate_msl_header(
618590
'handshake': is_handshake,
619591
'nonreplayable': False,
620592
'capabilities': {
621-
'languages': ['en-US'],
593+
'languages': self.locale_id,
622594
'compressionalgos': compression_algos
623595
},
624596
'recipient': 'Netflix',
625597
'renewable': True,
626598
'messageid': self.current_message_id,
627-
'timestamp': 1467733923
599+
'timestamp': time.time()
628600
}
629601

630602
# If this is a keyrequest act diffrent then other requests

0 commit comments

Comments
 (0)