Skip to content

Commit 9562406

Browse files
committed
Move imports to where they are being used
May be controversial, but if we want to keep inputstreamhelper's footprint as small as possible to add-ons using it, this may help.
1 parent 9deb312 commit 9562406

File tree

1 file changed

+58
-34
lines changed

1 file changed

+58
-34
lines changed

lib/inputstreamhelper/__init__.py

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,10 @@
11
# -*- coding: utf-8 -*-
22
''' Implements the main InputStream Helper class '''
33
from __future__ import absolute_import, division, unicode_literals
4-
54
import os
6-
import platform
7-
import json
8-
import subprocess
9-
import shutil
10-
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
11-
from datetime import datetime, timedelta
12-
13-
try: # Python 3
14-
from urllib.error import HTTPError
15-
from urllib.request import build_opener, install_opener, ProxyHandler, urlopen
16-
except ImportError: # Python 2
17-
from urllib2 import build_opener, HTTPError, install_opener, ProxyHandler, urlopen
18-
195
from inputstreamhelper import config
20-
21-
import xbmc
22-
from xbmcaddon import Addon
23-
import xbmcvfs
246
from .kodiutils import (browsesingle, execute_jsonrpc, get_addon_info, get_proxies, get_setting, kodi_to_ascii, localize, log,
257
notification, ok_dialog, progress_dialog, set_setting, textviewer, translate_path, yesno_dialog)
26-
from .unicodehelper import to_unicode
278

289
# NOTE: Work around issue caused by platform still using os.popen()
2910
# This helps to survive 'IOError: [Errno 10] No child processes'
@@ -40,9 +21,11 @@ def system_os():
4021

4122
# If it wasn't stored before, get the correct value
4223
if not hasattr(system_os, 'name'):
43-
if xbmc.getCondVisibility('system.platform.android'):
24+
from xbmc import getCondVisibility
25+
if getCondVisibility('system.platform.android'):
4426
system_os.name = 'Android'
4527
else:
28+
import platform
4629
system_os.name = platform.system()
4730

4831
# Return the stored value
@@ -62,6 +45,7 @@ def __init__(self, protocol, drm=None):
6245
self.protocol = protocol
6346
self.drm = drm
6447

48+
import platform
6549
log('Platform information: {platform}', platform=platform.uname())
6650

6751
if self.protocol not in config.INPUTSTREAM_PROTOCOLS:
@@ -76,7 +60,13 @@ def __init__(self, protocol, drm=None):
7660
self.drm = config.DRM_SCHEMES[drm]
7761

7862
# Add proxy support to HTTP requests
79-
install_opener(build_opener(ProxyHandler(get_proxies())))
63+
proxies = get_proxies()
64+
if proxies:
65+
try: # Python 3
66+
from urllib.request import build_opener, install_opener, ProxyHandler
67+
except ImportError: # Python 2
68+
from urllib2 import build_opener, install_opener, ProxyHandler
69+
install_opener(build_opener(ProxyHandler(proxies)))
8070

8171
def __repr__(self):
8272
''' String representation of Helper class '''
@@ -91,31 +81,36 @@ def _diskspace(cls):
9181
@classmethod
9282
def _temp_path(cls):
9383
''' Return temporary path, usually ~/.kodi/userdata/addon_data/script.module.inputstreamhelper/temp '''
84+
from xbmcvfs import exists, mkdirs
9485
temp_path = translate_path(os.path.join(get_setting('temp_path', 'special://masterprofile/addon_data/script.module.inputstreamhelper'), 'temp'))
95-
if not xbmcvfs.exists(temp_path):
96-
xbmcvfs.mkdirs(temp_path)
86+
if not exists(temp_path):
87+
mkdirs(temp_path)
9788

9889
return temp_path
9990

10091
@classmethod
10192
def _mnt_path(cls):
10293
''' Return mount path, usually ~/.kodi/userdata/addon_data/script.module.inputstreamhelper/temp/mnt '''
94+
from xbmcvfs import exists, mkdir
10395
mnt_path = os.path.join(cls._temp_path(), 'mnt')
104-
if not xbmcvfs.exists(mnt_path):
105-
xbmcvfs.mkdir(mnt_path)
96+
if not exists(mnt_path):
97+
mkdir(mnt_path)
10698

10799
return mnt_path
108100

109101
@classmethod
110102
def _ia_cdm_path(cls):
111103
''' Return the specified CDM path for inputstream.adaptive, usually ~/.kodi/cdm '''
104+
from xbmcaddon import Addon
112105
try:
113106
addon = Addon('inputstream.adaptive')
114107
except RuntimeError:
115108
return None
109+
116110
cdm_path = translate_path(addon.getSetting('DECRYPTERPATH'))
117-
if not xbmcvfs.exists(cdm_path):
118-
xbmcvfs.mkdir(cdm_path)
111+
from xbmcvfs import exists, mkdir
112+
if not exists(cdm_path):
113+
mkdir(cdm_path)
119114

120115
return cdm_path
121116

@@ -129,6 +124,7 @@ def _widevine_config_path(cls):
129124
@classmethod
130125
def _load_widevine_config(cls):
131126
''' Load the widevine or recovery config in JSON format '''
127+
import json
132128
with open(cls._widevine_config_path(), 'r') as config_file:
133129
return json.loads(config_file.read())
134130

@@ -141,20 +137,23 @@ def _widevine_path(cls):
141137

142138
if cls._ia_cdm_path():
143139
widevine_path = os.path.join(cls._ia_cdm_path(), widevine_cdm_filename)
144-
if xbmcvfs.exists(widevine_path):
140+
from xbmcvfs import exists
141+
if exists(widevine_path):
145142
return widevine_path
146143

147144
return False
148145

149146
@classmethod
150147
def _kodi_version(cls):
151148
''' Return the current Kodi version '''
152-
version = xbmc.getInfoLabel('System.BuildVersion')
149+
from xbmc import getInfoLabel
150+
version = getInfoLabel('System.BuildVersion')
153151
return version.split(' ')[0]
154152

155153
@classmethod
156154
def _arch(cls):
157155
"""Map together and return the system architecture."""
156+
import platform
158157
arch = platform.machine()
159158
if arch == 'aarch64':
160159
import struct
@@ -189,6 +188,7 @@ def _sizeof_fmt(num, suffix='B'):
189188
def _cmd_exists(cmd):
190189
"""Check whether cmd exists on system."""
191190
# https://stackoverflow.com/questions/377017/test-if-executable-exists-in-python
191+
import subprocess
192192
return subprocess.call('type ' + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
193193

194194
def _update_temp_path(self, new_temp_path):
@@ -197,6 +197,7 @@ def _update_temp_path(self, new_temp_path):
197197

198198
set_setting('temp_path', new_temp_path)
199199
if old_temp_path != self._temp_path():
200+
import shutil
200201
shutil.move(old_temp_path, self._temp_path())
201202

202203
def _helper_disabled(self):
@@ -226,11 +227,13 @@ def enable():
226227

227228
def _inputstream_version(self):
228229
''' Return the requested inputstream version '''
230+
from xbmcaddon import Addon
229231
try:
230232
addon = Addon(self.inputstream_addon)
231233
except RuntimeError:
232234
return None
233235

236+
from .unicodehelper import to_unicode
234237
return to_unicode(addon.getAddonInfo('version'))
235238

236239
@staticmethod
@@ -265,6 +268,7 @@ def _chromeos_offset(self, bin_path):
265268

266269
def _run_cmd(self, cmd, sudo=False, shell=False):
267270
''' Run subprocess command and return if it succeeds as a bool '''
271+
import subprocess
268272
output = ''
269273
success = False
270274
if sudo and os.getuid() != 0 and self._cmd_exists('sudo'):
@@ -345,6 +349,13 @@ def _has_widevine(self):
345349
@staticmethod
346350
def _http_request(url):
347351
''' Perform an HTTP request and return request '''
352+
353+
try: # Python 3
354+
from urllib.error import HTTPError
355+
from urllib.request import urlopen
356+
except ImportError: # Python 2
357+
from urllib2 import HTTPError, urlopen
358+
348359
log('Request URL: {url}', url=url)
349360
filename = url.split('/')[-1]
350361

@@ -442,6 +453,7 @@ def _supports_widevine(self):
442453
ok_dialog(localize(30004), localize(30011, os=system_os())) # Operating system not supported by Widevine
443454
return False
444455

456+
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
445457
if LooseVersion(config.WIDEVINE_MINIMUM_KODI_VERSION[system_os()]) > LooseVersion(self._kodi_version()):
446458
log('Unsupported Kodi version for Widevine: {version}', version=self._kodi_version())
447459
ok_dialog(localize(30004), localize(30010, version=config.WIDEVINE_MINIMUM_KODI_VERSION[system_os()])) # Kodi too old
@@ -480,6 +492,7 @@ def _select_best_chromeos_image(devices):
480492
continue
481493

482494
# Select the newest version
495+
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
483496
if LooseVersion(device['version']) > LooseVersion(best['version']):
484497
log('{device[hwid]} ({device[version]}) is newer than {best[hwid]} ({best[version]})', # pylint: disable=invalid-format-index
485498
device=device,
@@ -505,6 +518,7 @@ def _latest_widevine_version(self, eula=False):
505518
versions = self._http_get(url)
506519
return versions.split()[-1]
507520

521+
from datetime import datetime
508522
import time
509523
set_setting('last_update', str(time.mktime(datetime.utcnow().timetuple())))
510524
if 'x86' in self._arch():
@@ -643,6 +657,7 @@ def _install_widevine_arm(self): # pylint: disable=too-many-statements
643657
progress.update(97, line1=localize(30050)) # Finishing
644658
self._cleanup()
645659
if self._has_widevine():
660+
import json
646661
set_setting('chromeos_version', arm_device['version'])
647662
with open(self._widevine_config_path(), 'w') as config_file:
648663
config_file.write(json.dumps(devices, indent=4))
@@ -673,10 +688,11 @@ def install_widevine(self):
673688

674689
def remove_widevine(self):
675690
"""Removes Widevine CDM"""
691+
from xbmcvfs import delete, exists
676692
widevinecdm = self._widevine_path()
677-
if widevinecdm and xbmcvfs.exists(widevinecdm):
693+
if widevinecdm and exists(widevinecdm):
678694
log('Remove Widevine CDM at {path}', path=widevinecdm)
679-
xbmcvfs.delete(widevinecdm)
695+
delete(widevinecdm)
680696
notification(localize(30037), localize(30052)) # Success! Widevine successfully removed.
681697
return True
682698
notification(localize(30004), localize(30053)) # Error. Widevine CDM not found.
@@ -691,6 +707,7 @@ def _first_run():
691707
addon_version = get_addon_info('version')
692708

693709
# Compare versions
710+
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
694711
if LooseVersion(addon_version) > LooseVersion(settings_version):
695712
# New version found, save addon_version to settings
696713
set_setting('version', addon_version)
@@ -702,6 +719,7 @@ def _update_widevine(self):
702719
"""Prompts user to upgrade Widevine CDM when a newer version is available."""
703720
last_update = get_setting('last_update')
704721
if last_update and not self._first_run():
722+
from datetime import datetime, timedelta
705723
last_update_dt = datetime.fromtimestamp(float(get_setting('last_update')))
706724
if last_update_dt + timedelta(days=int(get_setting('update_frequency', '14'))) >= datetime.utcnow():
707725
log('Widevine update check was made on {date}', date=last_update_dt.isoformat())
@@ -718,6 +736,7 @@ def _update_widevine(self):
718736
log('Latest {component} version is {version}', component=component, version=latest_version)
719737
log('Current {component} version installed is {version}', component=component, version=current_version)
720738

739+
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
721740
if LooseVersion(latest_version) > LooseVersion(current_version):
722741
log('There is an update available for {component}', component=component)
723742
if yesno_dialog(localize(30040), localize(30033), nolabel=localize(30028), yeslabel=localize(30034)):
@@ -749,6 +768,7 @@ def _widevine_eula(self):
749768

750769
def _extract_widevine_from_img(self):
751770
''' Extract the Widevine CDM binary from the mounted Chrome OS image '''
771+
import shutil
752772
for root, dirs, files in os.walk(str(self._mnt_path())): # pylint: disable=unused-variable
753773
if str('libwidevinecdm.so') not in files:
754774
continue
@@ -854,6 +874,7 @@ def _unmount(self):
854874

855875
def _cleanup(self):
856876
''' Clean up function after Widevine CDM installation '''
877+
import shutil
857878
self._unmount()
858879
if self._attached_loop_dev:
859880
cmd = ['losetup', '-d', self._loop_dev]
@@ -870,6 +891,7 @@ def _cleanup(self):
870891

871892
def _supports_hls(self):
872893
"""Return if HLS support is available in inputstream.adaptive."""
894+
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module
873895
if LooseVersion(self._inputstream_version()) >= LooseVersion(config.HLS_MINIMUM_IA_VERSION):
874896
return True
875897

@@ -894,9 +916,11 @@ def _check_drm(self):
894916

895917
def _install_inputstream(self):
896918
"""Install inputstream addon."""
919+
from xbmc import executebuiltin
920+
from xbmcaddon import Addon
897921
try:
898922
# See if there's an installed repo that has it
899-
xbmc.executebuiltin('InstallAddon({})'.format(self.inputstream_addon), wait=True)
923+
executebuiltin('InstallAddon({})'.format(self.inputstream_addon), wait=True)
900924

901925
# Check if InputStream add-on exists!
902926
Addon('{}'.format(self.inputstream_addon))
@@ -934,7 +958,6 @@ def check_inputstream(self):
934958

935959
def info_dialog(self):
936960
""" Show an Info box with useful info e.g. for bug reports"""
937-
938961
text = localize(30800) + '\n' # Kodi information
939962
text += ' - ' + localize(30801, version=self._kodi_version()) + '\n'
940963
text += ' - ' + localize(30802, platform=system_os(), arch=self._arch()) + '\n'
@@ -950,6 +973,7 @@ def info_dialog(self):
950973

951974
if system_os() != 'Android':
952975
text += ' - ' + localize(30820) + '\n' # Widevine information
976+
from datetime import datetime
953977
wv_updated = datetime.fromtimestamp(float(get_setting('last_update'))).strftime("%Y-%m-%d %H:%M") if get_setting('last_update') else 'Never'
954978
text += ' - ' + localize(30821, version=self._get_lib_version(self._widevine_path()), date=wv_updated) + '\n'
955979
text += ' - ' + localize(30822, path=self._ia_cdm_path()) + '\n'
@@ -961,5 +985,5 @@ def info_dialog(self):
961985

962986
text += localize(30830, url=config.ISSUE_URL) # Report issues
963987

964-
log('\n{info}'.format(info=kodi_to_ascii(text)), level=xbmc.LOGNOTICE)
988+
log('\n{info}'.format(info=kodi_to_ascii(text)), level=2)
965989
textviewer(localize(30901), text)

0 commit comments

Comments
 (0)