Merge pull request #29 from joaosagrath/patch-1
[plugin.video.netflix.git] / resources / lib / MSL.py
index 7f813d470b33acda3ea7c102751a9f4af4c44cde..ef7e93be5a6c20ba6ab7ce85881eb09bfa009dc3 100644 (file)
@@ -1,3 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Module: MSL
+# Created on: 26.01.2017
+
 import base64
 import gzip
 import json
@@ -5,6 +10,8 @@ import os
 import pprint
 import random
 from StringIO import StringIO
+
+from datetime import datetime
 import requests
 import zlib
 
@@ -46,13 +53,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)
@@ -149,11 +154,13 @@ class MSL:
 
                 # Audio
                 'heaac-2-dash',
-                'ddplus-2.0-dash',
-                'ddplus-5.1-dash',
+
+                #subtiltes
                 'dfxp-ls-sdh',
-                'simplesdh',
-                'nflx-cmisc',
+                #'simplesdh',
+                #'nflx-cmisc',
+
+                #unkown
                 'BIF240',
                 'BIF320'
             ],
@@ -173,6 +180,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)
 
@@ -342,6 +355,21 @@ class MSL:
                 segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-"+str(init_length), indexRangeExact="true")
                 ET.SubElement(segment_base, 'Initialization', range='0-'+str(init_length))
 
+        # Multiple Adaption Sets for subtiles
+        for text_track in manifest['textTracks']:
+            if 'downloadables' not in text_track or text_track['downloadables'] is None:
+                continue
+            subtiles_adaption_set = ET.SubElement(period, 'AdaptationSet',
+                                                  lang=text_track['bcp47'],
+                                                  codecs='stpp',
+                                                  contentType='text',
+                                                  mimeType='application/ttml+xml')
+            for downloadable in text_track['downloadables']:
+                rep = ET.SubElement(subtiles_adaption_set, 'Representation',
+                                    nflxProfile=downloadable['contentProfile']
+                                    )
+                ET.SubElement(rep, 'BaseURL').text = self.__get_base_url(downloadable['urls'])
+
 
         xml = ET.tostring(root, encoding='utf-8', method='xml')
         xml = xml.replace('\n', '').replace('\r', '')
@@ -459,12 +487,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']
                     }
                 }
 
@@ -551,6 +580,18 @@ class MSL:
 
     def __load_msl_data(self):
         msl_data = json.JSONDecoder().decode(self.load_file(self.kodi_helper.msl_data_path, 'msl_data.json'))
+        #Check expire date of the token
+        master_token = json.JSONDecoder().decode(base64.standard_b64decode(msl_data['tokens']['mastertoken']['tokendata']))
+        valid_until = datetime.utcfromtimestamp(int(master_token['expiration']))
+        present = datetime.now()
+        difference = valid_until - present
+        difference = difference.total_seconds() / 60 / 60
+        # If token expires in less then 10 hours or is expires renew it
+        if difference < 10:
+            self.__load_rsa_keys()
+            self.__perform_key_handshake()
+            return
+
         self.__set_master_token(msl_data['tokens']['mastertoken'])
         self.encryption_key = base64.standard_b64decode(msl_data['encryption_key'])
         self.sign_key = base64.standard_b64decode(msl_data['sign_key'])