88import re
99import sys
1010import zlib
11- import gzip
1211import json
1312import time
1413import 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