# Module: default
# Created on: 13.01.2017
-# import local classes
-
import sys
from resources.lib.NetflixSession import NetflixSession
from resources.lib.KodiHelper import KodiHelper
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.netflix" name="Netflix" version="0.9.10" provider-name="libdev + jojo + asciidisco">
+<addon id="plugin.video.netflix" name="Netflix" version="0.9.11" provider-name="libdev + jojo + asciidisco">
<requires>
<import addon="xbmc.python" version="2.24.0"/>
<import addon="script.module.beautifulsoup4" version="4.3.2"/>
<import addon="script.module.requests" version="2.12.4"/>
<import addon="script.module.pycryptodome" version="3.4.3"/>
- <import addon="script.module.simplejson" version="3.3.0"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon.py">
<provides>video</provides>
# Kodi Media Center language file
# Addon Name: Netflix
# Addon id: plugin.video.netflix
-# Addon version: 0.9.10
+# Addon version: 0.9.11
# Addon Provider: libdev + jojo + asciidisco
msgid ""
msgstr ""
# Kodi Media Center language file
# Addon Name: Netflix
# Addon id: plugin.video.netflix
-# Addon version: 0.9.10
+# Addon version: 0.9.11
# Addon Provider: libdev + jojo + asciidisco
msgid ""
msgstr ""
# Module: KodiHelper
# Created on: 13.01.2017
-import os
-import urllib
import xbmcplugin
import xbmcgui
-import xbmcaddon
import xbmc
import json
-import uuid
+from os.path import join
+from urllib import urlencode
+from xbmcaddon import Addon
+from uuid import uuid4
from UniversalAnalytics import Tracker
try:
import cPickle as pickle
"""
self.plugin_handle = plugin_handle
self.base_url = base_url
- self.addon = xbmcaddon.Addon()
+ self.addon = Addon()
self.plugin = self.addon.getAddonInfo('name')
self.base_data_path = xbmc.translatePath(self.addon.getAddonInfo('profile'))
self.home_path = xbmc.translatePath('special://home')
self.plugin_path = self.addon.getAddonInfo('path')
self.cookie_path = self.base_data_path + 'COOKIE'
self.data_path = self.base_data_path + 'DATA'
- self.config_path = os.path.join(self.base_data_path, 'config')
+ self.config_path = join(self.base_data_path, 'config')
self.msl_data_path = xbmc.translatePath('special://profile/addon_data/service.msl').decode('utf-8') + '/'
self.verb_log = self.addon.getSetting('logging') == 'true'
self.default_fanart = self.addon.getAddonInfo('fanart')
entry_keys = entry.keys()
# action item templates
- encoded_title = urllib.urlencode({'title': entry['title'].encode('utf-8')}) if 'title' in entry else ''
+ encoded_title = urlencode({'title': entry['title'].encode('utf-8')}) if 'title' in entry else ''
url_tmpl = 'XBMC.RunPlugin(' + self.base_url + '?action=%action%&id=' + str(entry['id']) + '&' + encoded_title + ')'
actions = [
['export_to_library', self.get_local_string(30018), 'export'],
#Get or Create Tracking id
tracking_id = self.addon.getSetting('tracking_id')
if tracking_id is '':
- tracking_id = str(uuid.uuid4())
+ tracking_id = str(uuid4())
self.addon.setSetting('tracking_id', tracking_id)
# Send the tracking event
tracker = Tracker.create('UA-46081640-5', client_id=tracking_id)
# Created on: 13.01.2017
import os
-import shutil
+from shutil import rmtree
+from utils import noop
try:
import cPickle as pickle
except:
import pickle
-from utils import noop
class Library:
"""Exports Netflix shows & movies to a local library folder"""
self._update_local_db(filename=self.db_filepath, db=self.db)
dirname = os.path.join(self.movie_path, folder)
if os.path.exists(dirname):
- shutil.rmtree(dirname)
+ rmtree(dirname)
return True
return False
self._update_local_db(filename=self.db_filepath, db=self.db)
show_dir = os.path.join(self.tvshow_path, folder)
if os.path.exists(show_dir):
- shutil.rmtree(show_dir)
+ rmtree(show_dir)
return True
return False
# Module: Navigation
# Created on: 13.01.2017
-import urllib
-import time
+from urllib import urlencode, unquote
from urlparse import parse_qsl
-from utils import noop
-from utils import log
+from utils import noop, log
class Navigation:
"""Routes to the correct subfolder, dispatches actions & acts as a controller for the Kodi view & the Netflix model"""
return self.add_to_list(video_id=params['id'])
elif params['action'] == 'export':
# adds a title to the users list on Netflix
- alt_title = self.kodi_helper.show_add_to_library_title_dialog(original_title=urllib.unquote(params['title']).decode('utf8'))
+ alt_title = self.kodi_helper.show_add_to_library_title_dialog(original_title=unquote(params['title']).decode('utf8'))
return self.export_to_library(video_id=params['id'], alt_title=alt_title)
elif params['action'] == 'remove':
# adds a title to the users list on Netflix
str
Url + querystring based on the param
"""
- return self.base_url + '?' + urllib.urlencode(query)
+ return self.base_url + '?' + urlencode(query)
# Created on: 13.01.2017
import os
-import base64
-import time
-import urllib
import json
-import requests
+from requests import session, cookies
+from urllib import quote
+from time import time
+from base64 import urlsafe_b64encode
+from bs4 import BeautifulSoup, SoupStrainer
+from utils import noop
try:
import cPickle as pickle
except:
import pickle
-from bs4 import BeautifulSoup, SoupStrainer
-from utils import noop
class NetflixSession:
"""Helps with login/session management of Netflix users & API data fetching"""
self.log = log_fn
# start session, fake chrome on the current platform (so that we get a proper widevine esn) & enable gzip
- self.session = requests.session()
+ self.session = session()
self.session.headers.update({
'User-Agent': self._get_user_agent_for_current_platform(),
'Accept-Encoding': 'gzip'
"""
payload = {
'switchProfileGuid': profile_id,
- '_': int(time.time()),
+ '_': int(time()),
'authURL': self.user_data['authURL']
}
'toRow': list_to,
'opaqueImageExtension': 'jpg',
'transparentImageExtension': 'png',
- '_': int(time.time()),
+ '_': int(time()),
'authURL': self.user_data['authURL']
}
response = self._session_get(component='video_list_ids', params=payload, type='api')
Raw Netflix API call response or api call error
"""
# properly encode the search string
- encoded_search_string = urllib.quote(search_str)
+ encoded_search_string = quote(search_str)
paths = [
['search', encoded_search_string, 'titles', {'from': list_from, 'to': list_to}, ['summary', 'title']],
payload = {
'movieid': id,
'imageformat': 'jpg',
- '_': int(time.time())
+ '_': int(time())
}
response = self._session_get(component='metadata', params=payload, type='api')
return self._process_response(response=response, component=self._get_api_url_for(component='metadata'))
return False
with open(filename) as f:
- cookies = pickle.load(f)
- if cookies:
- jar = requests.cookies.RequestsCookieJar()
- jar._cookies = cookies
+ _cookies = pickle.load(f)
+ if _cookies:
+ jar = cookies.RequestsCookieJar()
+ jar._cookies = _cookies
self.session.cookies = jar
else:
return False
:obj:`str`
Account data hash
"""
- return base64.urlsafe_b64encode(account['email'])
+ return urlsafe_b64encode(account['email'])
def _get_user_agent_for_current_platform (self):
"""Determines the user agent string for the current platform (to retrieve a valid ESN)
Contents of the field to match
"""
url = self._get_document_url_for(component=component) if type == 'document' else self._get_api_url_for(component=component)
- start = time.time()
+ start = time()
response = self.session.post(url=url, data=data, params=params, headers=headers, verify=self.verify_ssl)
- end = time.time()
+ end = time()
self.log('[POST] Request for "' + url + '" took ' + str(end - start) + ' seconds')
return response
Contents of the field to match
"""
url = self._get_document_url_for(component=component) if type == 'document' else self._get_api_url_for(component=component)
- start = time.time()
+ start = time()
response = self.session.get(url=url, verify=self.verify_ssl, params=params)
- end = time.time()
+ end = time()
self.log('[GET] Request for "' + url + '" took ' + str(end - start) + ' seconds')
return response
base_url=None
)
-
def select_unused_port():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 0))