Skip to content

Commit

Permalink
Add our own kodiutils library
Browse files Browse the repository at this point in the history
In order to wrap some Kodi functionality, this PR introduces a library
with generic Kodi utilities.
  • Loading branch information
dagwieers committed Sep 16, 2019
1 parent ea25ede commit fd2e0a6
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 123 deletions.
133 changes: 24 additions & 109 deletions lib/inputstreamhelper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@
import xbmcaddon
import xbmcgui
import xbmcvfs
from .unicodehelper import to_unicode, from_unicode

ADDON = xbmcaddon.Addon('script.module.inputstreamhelper')
ADDON_PROFILE = to_unicode(xbmc.translatePath(ADDON.getAddonInfo('profile')))
ADDON_ID = to_unicode(ADDON.getAddonInfo('id'))
ADDON_VERSION = to_unicode(ADDON.getAddonInfo('version'))
from .kodiutils import get_addon_info, get_proxies, get_setting, localize, log, set_setting
from .unicodehelper import to_unicode

# NOTE: Work around issue caused by platform still using os.popen()
# This helps to survive 'IOError: [Errno 10] No child processes'
Expand All @@ -43,43 +39,6 @@ class InputStreamException(Exception):
''' Stub Exception '''


class SafeDict(dict):
''' A safe dictionary implementation that does not break down on missing keys '''
def __missing__(self, key):
''' Replace missing keys with the original placeholder '''
return '{' + key + '}'


def log(msg, **kwargs):
''' InputStream Helper log method '''
xbmc.log(msg=from_unicode('[{addon}-{version}]: {msg}'.format(addon=ADDON_ID, version=ADDON_VERSION, msg=msg.format(**kwargs))), level=xbmc.LOGDEBUG)


def localize(string_id, **kwargs):
''' Return the translated string from the .po language files, optionally translating variables '''
if kwargs:
import string
return string.Formatter().vformat(ADDON.getLocalizedString(string_id), (), SafeDict(**kwargs))

return ADDON.getLocalizedString(string_id)


def has_socks():
''' Test if socks is installed, and remember this information '''

# If it wasn't stored before, check if socks is installed
if not hasattr(has_socks, 'installed'):
try:
import socks # noqa: F401; pylint: disable=unused-variable,unused-import
has_socks.installed = True
except ImportError:
has_socks.installed = False
return None # Detect if this is the first run

# Return the stored value
return has_socks.installed


def system_os():
''' Get system platform, and remember this information '''

Expand Down Expand Up @@ -121,7 +80,7 @@ def __init__(self, protocol, drm=None):
self.drm = config.DRM_SCHEMES[drm]

# Add proxy support to HTTP requests
install_opener(build_opener(ProxyHandler(self._get_proxies())))
install_opener(build_opener(ProxyHandler(get_proxies())))

def __repr__(self):
''' String representation of Helper class '''
Expand All @@ -136,7 +95,7 @@ def _diskspace(cls):
@classmethod
def _temp_path(cls):
''' Return temporary path, usually ~/.kodi/userdata/addon_data/script.module.inputstreamhelper/temp '''
temp_path = xbmc.translatePath(os.path.join(ADDON.getSetting('temp_path'), 'temp'))
temp_path = xbmc.translatePath(os.path.join(get_setting('temp_path'), 'temp'))
if not xbmcvfs.exists(temp_path):
xbmcvfs.mkdir(temp_path)

Expand Down Expand Up @@ -233,12 +192,12 @@ def _update_temp_path(self, new_temp_path):
""""Updates temp_path and merges files."""
old_temp_path = self._temp_path()

ADDON.setSetting('temp_path', new_temp_path)
set_setting('temp_path', new_temp_path)
shutil.move(old_temp_path, new_temp_path)

def _helper_disabled(self):
"""Return if inputstreamhelper has been disabled in settings.xml."""
disabled = ADDON.getSetting('disabled')
disabled = get_setting('disabled', 'false')
if disabled is None:
self.disable() # Create default entry
disabled = 'true'
Expand All @@ -252,14 +211,14 @@ def _helper_disabled(self):
@staticmethod
def disable():
''' Disable plugin '''
if ADDON.getSetting('disabled') == 'false':
ADDON.setSetting('disabled', 'true')
if get_setting('disabled') == 'false':
set_setting('disabled', 'true')

@staticmethod
def enable():
''' Enable plugin '''
if ADDON.getSetting('disabled') == 'true':
ADDON.setSetting('disabled', 'false')
if get_setting('disabled', 'false') == 'true':
set_setting('disabled', 'false')

def _inputstream_version(self):
''' Return the requested inputstream version '''
Expand Down Expand Up @@ -562,7 +521,7 @@ def _latest_widevine_version(self, eula=False):
versions = self._http_get(url)
return versions.split()[-1]

ADDON.setSetting('last_update', str(time.mktime(datetime.utcnow().timetuple())))
set_setting('last_update', str(time.mktime(datetime.utcnow().timetuple())))
if 'x86' in self._arch():
url = config.WIDEVINE_VERSIONS_URL
versions = self._http_get(url)
Expand Down Expand Up @@ -698,7 +657,7 @@ def _install_widevine_arm(self): # pylint: disable=too-many-statements
progress_dialog.update(97, line1=localize(30050)) # Finishing
self._cleanup()
if self._has_widevine():
ADDON.setSetting('chromeos_version', arm_device['version'])
set_setting('chromeos_version', arm_device['version'])
with open(self._widevine_config_path(), 'w') as config_file:
config_file.write(json.dumps(devices, indent=4))
wv_check = self._check_widevine()
Expand Down Expand Up @@ -742,24 +701,23 @@ def _first_run():
"""Check if this add-on version is running for the first time"""

# Get versions
settings_version = ADDON.getSetting('version')
if settings_version == '':
settings_version = '0.3.4' # settings_version didn't exist in version 0.3.4 and older
settings_version = get_setting('version', '0.3.4') # settings_version didn't exist in version 0.3.4 and older
addon_version = get_addon_info('version')

# Compare versions
if LooseVersion(ADDON_VERSION) > LooseVersion(settings_version):
if LooseVersion(addon_version) > LooseVersion(settings_version):
# New version found, save addon_version to settings
ADDON.setSetting('version', ADDON_VERSION)
log('inputstreamhelper version {version} is running for the first time', version=ADDON_VERSION)
set_setting('version', addon_version)
log('inputstreamhelper version {version} is running for the first time', version=addon_version)
return True
return False

def _update_widevine(self):
"""Prompts user to upgrade Widevine CDM when a newer version is available."""
last_update = ADDON.getSetting('last_update')
last_update = get_setting('last_update')
if last_update and not self._first_run():
last_update_dt = datetime.fromtimestamp(float(ADDON.getSetting('last_update')))
if last_update_dt + timedelta(days=int(ADDON.getSetting('update_frequency'))) >= datetime.utcnow():
last_update_dt = datetime.fromtimestamp(float(get_setting('last_update')))
if last_update_dt + timedelta(days=int(get_setting('update_frequency'))) >= datetime.utcnow():
log('Widevine update check was made on {date}', date=last_update_dt.isoformat())
return

Expand Down Expand Up @@ -984,66 +942,23 @@ def check_inputstream(self):

return self._check_drm()

@staticmethod
def _get_global_setting(setting):
json_result = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Settings.GetSettingValue", "params": {"setting": "%s"}, "id": 1}' % setting)
return json.loads(json_result)['result']['value']

def _get_proxies(self):
usehttpproxy = self._get_global_setting('network.usehttpproxy')
if usehttpproxy is False:
return None

httpproxytype = self._get_global_setting('network.httpproxytype')

socks_supported = has_socks()
if httpproxytype != 0 and not socks_supported:
# Only open the dialog the first time (to avoid multiple popups)
if socks_supported is None:
xbmcgui.Dialog().ok('', localize(30042)) # Requires PySocks
return None

proxy_types = ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']
if 0 <= httpproxytype <= 5:
httpproxyscheme = proxy_types[httpproxytype]
else:
httpproxyscheme = 'http'

httpproxyserver = self._get_global_setting('network.httpproxyserver')
httpproxyport = self._get_global_setting('network.httpproxyport')
httpproxyusername = self._get_global_setting('network.httpproxyusername')
httpproxypassword = self._get_global_setting('network.httpproxypassword')

if httpproxyserver and httpproxyport and httpproxyusername and httpproxypassword:
proxy_address = '%s://%s:%s@%s:%s' % (httpproxyscheme, httpproxyusername, httpproxypassword, httpproxyserver, httpproxyport)
elif httpproxyserver and httpproxyport and httpproxyusername:
proxy_address = '%s://%s@%s:%s' % (httpproxyscheme, httpproxyusername, httpproxyserver, httpproxyport)
elif httpproxyserver and httpproxyport:
proxy_address = '%s://%s:%s' % (httpproxyscheme, httpproxyserver, httpproxyport)
elif httpproxyserver:
proxy_address = '%s://%s' % (httpproxyscheme, httpproxyserver)
else:
return None

return dict(http=proxy_address, https=proxy_address)

def info_dialog(self):
""" Show an Info box with useful info e.g. for bug reports"""
disabled_str = ' ({disabled}'.format(disabled=localize(30054))

kodi_info = [localize(30801, version=self._kodi_version()),
localize(30802, platform=system_os(), arch=self._arch())]

ishelper_state = disabled_str if not ADDON.getSetting('disabled') == 'false' else ''
ishelper_state = disabled_str if get_setting('disabled', 'false') != 'false' else ''
istream_state = disabled_str if not self._inputstream_enabled() else ''
is_info = [localize(30811, version=ADDON_VERSION, state=ishelper_state),
is_info = [localize(30811, version=get_addon_info('version'), state=ishelper_state),
localize(30812, version=self._inputstream_version(), state=istream_state)]

wv_updated = datetime.fromtimestamp(float(ADDON.getSetting('last_update'))).strftime("%Y-%m-%d %H:%M") if ADDON.getSetting('last_update') else 'Never'
wv_updated = datetime.fromtimestamp(float(get_setting('last_update'))).strftime("%Y-%m-%d %H:%M") if get_setting('last_update') else 'Never'
wv_info = [localize(30821, version=self._get_lib_version(self._widevine_path()), date=wv_updated),
localize(30822, path=self._ia_cdm_path())]
if platform == 'arm':
wv_info.append(localize(30823, version=ADDON.getSetting('chromeos_version')))
wv_info.append(localize(30823, version=get_setting('chromeos_version')))

text = (localize(30800) + "\n - "
+ "\n - ".join(kodi_info) + "\n\n"
Expand Down
3 changes: 2 additions & 1 deletion lib/inputstreamhelper/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
''' This is the actual InputStream Helper API script '''

from __future__ import absolute_import, division, unicode_literals
from inputstreamhelper import ADDON, Helper, log
from inputstreamhelper import Helper
from .kodiutils import ADDON, log


def run(params):
Expand Down
29 changes: 20 additions & 9 deletions lib/inputstreamhelper/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,26 +80,37 @@

# Last updated: 2019-08-20 (version 12239.67.0)
CHROMEOS_RECOVERY_ARM_HWIDS = [
'BOB',
'WHITETIP',
'SKATE',
'SPRING',
'SNOW',
'ELM',
'HANA',
'ARKHAM',
'BIG',
'BLAZE',
'RELM',
'BOB',
'DAISY',
'DRUWL',
'DUMO',
'SCARLET',
'ELM',
'EXPRESSO',
'FIEVEL',
'HANA',
'JAQ',
'JERRY',
'KEVIN',
'KITTY',
'MICKEY',
'MIGHTY',
'MINNIE',
'PHASER',
'PHASER360',
'PI',
'PIT',
'RELM',
'SCARLET',
'SKATE',
'SNOW',
'SPEEDY',
'SPRING',
'TIGER',
'WHIRLWIND',
'WHITETIP',
]

CHROMEOS_BLOCK_SIZE = 512
Expand Down
Loading

0 comments on commit fd2e0a6

Please sign in to comment.