X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=resources%2Flib%2FMSL.py;h=db9d68b4b94d5dfab0ab35a446f10303d07a04ce;hb=a190d8141ee4d3a09c7fef3334fd6083ff9c354e;hp=71f1810a46ce4670732b46f1098688727531111b;hpb=465712e1d4368f223d522f178934f16e044fbb1a;p=plugin.video.netflix.git diff --git a/resources/lib/MSL.py b/resources/lib/MSL.py index 71f1810..db9d68b 100644 --- a/resources/lib/MSL.py +++ b/resources/lib/MSL.py @@ -13,7 +13,7 @@ from Cryptodome.PublicKey import RSA from Cryptodome.Cipher import PKCS1_OAEP from Cryptodome.Cipher import AES from Cryptodome.Random import get_random_bytes -from Crypto.Hash import HMAC, SHA256 +from Cryptodome.Hash import HMAC, SHA256 from Cryptodome.Util import Padding import xml.etree.ElementTree as ET @@ -36,6 +36,7 @@ class MSL: last_playback_context = '' #esn = "NFCDCH-LX-CQE0NU6PA5714R25VPLXVU2A193T36" esn = "WWW-BROWSE-D7GW1G4NPXGR1F0X1H3EQGY3V1F5WE" + #esn = "NFCDIE-02-DCH84Q2EK3N6VFVQJ0NLRQ27498N0F" current_message_id = 0 session = requests.session() rndm = random.SystemRandom() @@ -45,13 +46,11 @@ class MSL: 'license': 'http://www.netflix.com/api/msl/NFCDCH-LX/cadmium/license' } - def __init__(self, email, password, kodi_helper): + def __init__(self, kodi_helper): """ The Constructor checks for already existing crypto Keys. If they exist it will load the existing keys """ - self.email = email - self.password = password self.kodi_helper = kodi_helper try: os.mkdir(self.kodi_helper.msl_data_path) @@ -84,8 +83,69 @@ class MSL: 'lookupType': 'PREPARE', 'viewableIds': [viewable_id], 'profiles': [ - 'playready-h264mpl30-dash', - 'playready-h264mpl31-dash', + "playready-h264bpl30-dash", + "playready-h264mpl30-dash", + "playready-h264mpl31-dash", + "playready-h264mpl40-dash", + # "hevc-main-L30-dash-cenc", + # "hevc-main-L31-dash-cenc", + # "hevc-main-L40-dash-cenc", + # "hevc-main-L41-dash-cenc", + # "hevc-main-L50-dash-cenc", + # "hevc-main-L51-dash-cenc", + # "hevc-main10-L30-dash-cenc", + # "hevc-main10-L31-dash-cenc", + # "hevc-main10-L40-dash-cenc", + # "hevc-main10-L41-dash-cenc", + # "hevc-main10-L50-dash-cenc", + # "hevc-main10-L51-dash-cenc", + # "hevc-main10-L30-dash-cenc-prk", + # "hevc-main10-L31-dash-cenc-prk", + # "hevc-main10-L40-dash-cenc-prk", + # "hevc-main10-L41-dash-cenc-prk", + # "hevc-main-L30-L31-dash-cenc-tl", + # "hevc-main-L31-L40-dash-cenc-tl", + # "hevc-main-L40-L41-dash-cenc-tl", + # "hevc-main-L50-L51-dash-cenc-tl", + # "hevc-main10-L30-L31-dash-cenc-tl", + # "hevc-main10-L31-L40-dash-cenc-tl", + # "hevc-main10-L40-L41-dash-cenc-tl", + # "hevc-main10-L50-L51-dash-cenc-tl", + # "hevc-dv-main10-L30-dash-cenc", + # "hevc-dv-main10-L31-dash-cenc", + # "hevc-dv-main10-L40-dash-cenc", + # "hevc-dv-main10-L41-dash-cenc", + # "hevc-dv-main10-L50-dash-cenc", + # "hevc-dv-main10-L51-dash-cenc", + # "hevc-dv5-main10-L30-dash-cenc-prk", + # "hevc-dv5-main10-L31-dash-cenc-prk", + # "hevc-dv5-main10-L40-dash-cenc-prk", + # "hevc-dv5-main10-L41-dash-cenc-prk", + # "hevc-dv5-main10-L50-dash-cenc-prk", + # "hevc-dv5-main10-L51-dash-cenc-prk", + # "hevc-hdr-main10-L30-dash-cenc", + # "hevc-hdr-main10-L31-dash-cenc", + # "hevc-hdr-main10-L40-dash-cenc", + # "hevc-hdr-main10-L41-dash-cenc", + # "hevc-hdr-main10-L50-dash-cenc", + # "hevc-hdr-main10-L51-dash-cenc", + # "hevc-hdr-main10-L30-dash-cenc-prk", + # "hevc-hdr-main10-L31-dash-cenc-prk", + # "hevc-hdr-main10-L40-dash-cenc-prk", + # "hevc-hdr-main10-L41-dash-cenc-prk", + # "hevc-hdr-main10-L50-dash-cenc-prk", + # "hevc-hdr-main10-L51-dash-cenc-prk" + + # 'playready-h264mpl30-dash', + #'playready-h264mpl31-dash', + #'playready-h264mpl40-dash', + #'hevc-main10-L41-dash-cenc', + #'hevc-main10-L50-dash-cenc', + #'hevc-main10-L51-dash-cenc', + + + + # Audio 'heaac-2-dash', 'dfxp-ls-sdh', 'simplesdh', @@ -109,6 +169,12 @@ class MSL: 'clientVersion': '4.0004.899.011', 'uiVersion': 'akira' } + + # Check if dolby sound is enabled and add to profles + if self.kodi_helper.get_dolby_setting(): + manifest_request_data['profiles'].append('ddplus-2.0-dash') + manifest_request_data['profiles'].append('ddplus-5.1-dash') + request_data = self.__generate_msl_request_data(manifest_request_data) resp = self.session.post(self.endpoints['manifest'], request_data) @@ -203,6 +269,7 @@ class MSL: pssh = manifest['psshb64'][0] seconds = manifest['runtime']/1000 + init_length = seconds / 2 * 12 + 20*1000 duration = "PT"+str(seconds)+".00S" root = ET.Element('MPD') @@ -222,18 +289,30 @@ class MSL: ET.SubElement(protection, 'cenc:pssh').text = pssh for downloadable in video_track['downloadables']: + + codec = 'h264' + if 'hevc' in downloadable['contentProfile']: + codec = 'hevc' + + hdcp_versions = '0.0' + for hdcp in downloadable['hdcpVersions']: + if hdcp != 'none': + hdcp_versions = hdcp + rep = ET.SubElement(video_adaption_set, 'Representation', width=str(downloadable['width']), height=str(downloadable['height']), bandwidth=str(downloadable['bitrate']*1024), - codecs='h264', + hdcp=hdcp_versions, + nflxContentProfile=str(downloadable['contentProfile']), + codecs=codec, mimeType='video/mp4') #BaseURL ET.SubElement(rep, 'BaseURL').text = self.__get_base_url(downloadable['urls']) # Init an Segment block - segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-60000", indexRangeExact="true") - ET.SubElement(segment_base, 'Initialization', range='0-60000') + segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-"+str(init_length), indexRangeExact="true") + ET.SubElement(segment_base, 'Initialization', range='0-'+str(init_length)) @@ -244,8 +323,13 @@ class MSL: contentType='audio', mimeType='audio/mp4') for downloadable in audio_track['downloadables']: + codec = 'aac' + print downloadable + if downloadable['contentProfile'] == 'ddplus-2.0-dash' or downloadable['contentProfile'] == 'ddplus-5.1-dash': + codec = 'ec-3' + print "codec is: " + codec rep = ET.SubElement(audio_adaption_set, 'Representation', - codecs='aac', + codecs=codec, bandwidth=str(downloadable['bitrate']*1024), mimeType='audio/mp4') @@ -257,8 +341,8 @@ class MSL: #BaseURL ET.SubElement(rep, 'BaseURL').text = self.__get_base_url(downloadable['urls']) # Index range - segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-60000", indexRangeExact="true") - ET.SubElement(segment_base, 'Initialization', range='0-60000') + segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-"+str(init_length), indexRangeExact="true") + ET.SubElement(segment_base, 'Initialization', range='0-'+str(init_length)) xml = ET.tostring(root, encoding='utf-8', method='xml') @@ -306,7 +390,7 @@ class MSL: # Serialize the given Data serialized_data = json.dumps(data) serialized_data = serialized_data.replace('"', '\\"') - serialized_data = '[{},{"headers":{},"path":"/cbp/cadmium-11","payload":{"data":"' + serialized_data + '"},"query":""}]\n' + serialized_data = '[{},{"headers":{},"path":"/cbp/cadmium-13","payload":{"data":"' + serialized_data + '"},"query":""}]\n' compressed_data = self.__compress_data(serialized_data) @@ -377,12 +461,13 @@ class MSL: if 'usertoken' in self.tokens: pass else: + account = self.kodi_helper.get_credentials() # Auth via email and password header_data['userauthdata'] = { 'scheme': 'EMAIL_PASSWORD', 'authdata': { - 'email': self.email, - 'password': self.password + 'email': account['email'], + 'password': account['password'] } }