Skip to content

Commit b359b3e

Browse files
committed
Autoinstall Widevine updates
This adds a feature to enable automatic installation of Widevine.
1 parent bda852e commit b359b3e

File tree

6 files changed

+121
-67
lines changed

6 files changed

+121
-67
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ __pycache__/
55
*.py[cod]
66
test/cdm/
77
test/userdata/addon_settings.json
8+
test/userdata/addon_data/
89
test/userdata/cdm/
910
test/userdata/tmp/
1011

.pylintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ disable=
55
import-outside-toplevel,
66
line-too-long,
77
old-style-class,
8+
too-many-arguments,
89
too-many-branches,
910
too-many-lines,
1011
too-many-return-statements,

lib/inputstreamhelper/__init__.py

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
import xbmc
2222
from xbmcaddon import Addon
23-
from xbmcgui import Dialog, DialogProgress
2423
import xbmcvfs
25-
from .kodiutils import execute_jsonrpc, get_addon_info, get_proxies, get_setting, kodi_to_ascii, localize, log, set_setting, translate_path
24+
from .kodiutils import (browsesingle, execute_jsonrpc, get_addon_info, get_proxies, get_setting, kodi_to_ascii, localize, log,
25+
notification, ok_dialog, progress_dialog, set_setting, textviewer, translate_path, yesno_dialog)
2626
from .unicodehelper import to_unicode
2727

2828
# NOTE: Work around issue caused by platform still using os.popen()
@@ -354,7 +354,7 @@ def _http_request(url):
354354
if 400 <= req.getcode() < 600:
355355
raise HTTPError('HTTP %s Error for url: %s' % (req.getcode(), url), response=req)
356356
except HTTPError:
357-
Dialog().ok(localize(30004), localize(30013, filename=filename)) # Failed to retrieve file
357+
ok_dialog(localize(30004), localize(30013, filename=filename)) # Failed to retrieve file
358358
return None
359359
return req
360360

@@ -381,8 +381,8 @@ def _http_download(self, url, message=None):
381381

382382
self._download_path = os.path.join(self._temp_path(), filename)
383383
total_length = float(req.info().get('content-length'))
384-
progress_dialog = DialogProgress()
385-
progress_dialog.create(localize(30014), message) # Download in progress
384+
progress = progress_dialog()
385+
progress.create(localize(30014), message) # Download in progress
386386

387387
chunk_size = 32 * 1024
388388
with open(self._download_path, 'wb') as image:
@@ -394,13 +394,13 @@ def _http_download(self, url, message=None):
394394
image.write(chunk)
395395
size += len(chunk)
396396
percent = int(size * 100 / total_length)
397-
if progress_dialog.iscanceled():
398-
progress_dialog.close()
397+
if progress.iscanceled():
398+
progress.close()
399399
req.close()
400400
return False
401-
progress_dialog.update(percent)
401+
progress.update(percent)
402402

403-
progress_dialog.close()
403+
progress.close()
404404
return True
405405

406406
def _has_inputstream(self):
@@ -434,22 +434,22 @@ def _supports_widevine(self):
434434
"""Checks if Widevine is supported on the architecture/operating system/Kodi version."""
435435
if self._arch() not in config.WIDEVINE_SUPPORTED_ARCHS:
436436
log('Unsupported Widevine architecture found: {arch}', arch=self._arch())
437-
Dialog().ok(localize(30004), localize(30007)) # Widevine not available on this architecture
437+
ok_dialog(localize(30004), localize(30007)) # Widevine not available on this architecture
438438
return False
439439

440440
if system_os() not in config.WIDEVINE_SUPPORTED_OS:
441441
log('Unsupported Widevine OS found: {os}', os=system_os())
442-
Dialog().ok(localize(30004), localize(30011, os=system_os())) # Operating system not supported by Widevine
442+
ok_dialog(localize(30004), localize(30011, os=system_os())) # Operating system not supported by Widevine
443443
return False
444444

445445
if LooseVersion(config.WIDEVINE_MINIMUM_KODI_VERSION[system_os()]) > LooseVersion(self._kodi_version()):
446446
log('Unsupported Kodi version for Widevine: {version}', version=self._kodi_version())
447-
Dialog().ok(localize(30004), localize(30010, version=config.WIDEVINE_MINIMUM_KODI_VERSION[system_os()])) # Kodi too old
447+
ok_dialog(localize(30004), localize(30010, version=config.WIDEVINE_MINIMUM_KODI_VERSION[system_os()])) # Kodi too old
448448
return False
449449

450450
if 'WindowsApps' in translate_path('special://xbmcbin/'): # uwp is not supported
451451
log('Unsupported UWP Kodi version detected.')
452-
Dialog().ok(localize(30004), localize(30012)) # Windows Store Kodi falls short
452+
ok_dialog(localize(30004), localize(30012)) # Windows Store Kodi falls short
453453
return False
454454

455455
return True
@@ -516,7 +516,7 @@ def _latest_widevine_version(self, eula=False):
516516
arm_device = self._select_best_chromeos_image(devices)
517517
if arm_device is None:
518518
log('We could not find an ARM device in recovery.conf')
519-
Dialog().ok(localize(30004), localize(30005))
519+
ok_dialog(localize(30004), localize(30005))
520520
return ''
521521
return arm_device['version']
522522

@@ -549,12 +549,12 @@ def _install_widevine_x86(self):
549549

550550
downloaded = self._http_download(url)
551551
if downloaded:
552-
progress_dialog = DialogProgress()
553-
progress_dialog.create(heading=localize(30043), line1=localize(30044)) # Extracting Widevine CDM
554-
progress_dialog.update(94, line1=localize(30049)) # Installing Widevine CDM
552+
progress = progress_dialog()
553+
progress.create(heading=localize(30043), line1=localize(30044)) # Extracting Widevine CDM
554+
progress.update(94, line1=localize(30049)) # Installing Widevine CDM
555555
self._unzip(self._ia_cdm_path())
556556

557-
progress_dialog.update(97, line1=localize(30050)) # Finishing
557+
progress.update(97, line1=localize(30050)) # Finishing
558558
self._cleanup()
559559
if not self._widevine_eula():
560560
return False
@@ -565,13 +565,13 @@ def _install_widevine_x86(self):
565565
os.rename(os.path.join(self._ia_cdm_path(), config.WIDEVINE_MANIFEST_FILE), self._widevine_config_path())
566566
wv_check = self._check_widevine()
567567
if wv_check:
568-
progress_dialog.update(100, line1=localize(30051)) # Widevine CDM successfully installed.
569-
Dialog().notification(localize(30037), localize(30051)) # Success! Widevine successfully installed.
570-
progress_dialog.close()
568+
progress.update(100, line1=localize(30051)) # Widevine CDM successfully installed.
569+
notification(localize(30037), localize(30051)) # Success! Widevine successfully installed.
570+
progress.close()
571571
return wv_check
572572

573-
progress_dialog.close()
574-
Dialog().ok(localize(30004), localize(30005)) # An error occurred
573+
progress.close()
574+
ok_dialog(localize(30004), localize(30005)) # An error occurred
575575

576576
return False
577577

@@ -582,52 +582,54 @@ def _install_widevine_arm(self): # pylint: disable=too-many-statements
582582
arm_device = self._select_best_chromeos_image(devices)
583583
if arm_device is None:
584584
log('We could not find an ARM device in recovery.conf')
585-
Dialog().ok(localize(30004), localize(30005))
585+
ok_dialog(localize(30004), localize(30005))
586586
return ''
587587
required_diskspace = int(arm_device['filesize']) + int(arm_device['zipfilesize'])
588-
if Dialog().yesno(localize(30001), # Due to distributing issues, this takes a long time
589-
localize(30006, diskspace=self._sizeof_fmt(required_diskspace))) and self._widevine_eula():
588+
if yesno_dialog(localize(30001), # Due to distributing issues, this takes a long time
589+
localize(30006, diskspace=self._sizeof_fmt(required_diskspace)),
590+
autoanswer=True) and self._widevine_eula():
590591
if system_os() != 'Linux':
591-
Dialog().ok(localize(30004), localize(30019, os=system_os()))
592+
ok_dialog(localize(30004), localize(30019, os=system_os()))
592593
return False
593594

594595
while required_diskspace >= self._diskspace():
595-
if Dialog().yesno(localize(30004), localize(30055)): # Not enough space, alternative path?
596-
self._update_temp_path(Dialog().browseSingle(3, localize(30909), 'files')) # Temporary path
596+
if yesno_dialog(localize(30004), localize(30055)): # Not enough space, alternative path?
597+
self._update_temp_path(browsesingle(3, localize(30909), 'files')) # Temporary path
597598
continue
598599

599-
Dialog().ok(localize(30004), # Not enough free disk space
600-
localize(30018, diskspace=self._sizeof_fmt(required_diskspace)))
600+
ok_dialog(localize(30004), # Not enough free disk space
601+
localize(30018, diskspace=self._sizeof_fmt(required_diskspace)))
601602
return False
602603

603604
if not self._cmd_exists('fdisk') and not self._cmd_exists('parted'):
604-
Dialog().ok(localize(30004), localize(30020, command1='fdisk', command2='parted')) # Commands are missing
605+
ok_dialog(localize(30004), localize(30020, command1='fdisk', command2='parted')) # Commands are missing
605606
return False
606607

607608
if not self._cmd_exists('mount'):
608-
Dialog().ok(localize(30004), localize(30021, command='mount')) # Mount command is missing
609+
ok_dialog(localize(30004), localize(30021, command='mount')) # Mount command is missing
609610
return False
610611

611612
if not self._cmd_exists('losetup'):
612-
Dialog().ok(localize(30004), localize(30021, command='losetup')) # Losetup command is missing
613+
ok_dialog(localize(30004), localize(30021, command='losetup')) # Losetup command is missing
613614
return False
614615

615-
if os.getuid() != 0: # ask for permissions to run cmds as root
616-
if not Dialog().yesno(localize(30001), localize(30030, cmds=', '.join(root_cmds)), yeslabel=localize(30027), nolabel=localize(30028)):
617-
return False
616+
if os.getuid() != 0 and not yesno_dialog(localize(30001), # Ask for permission to run cmds as root
617+
localize(30030, cmds=', '.join(root_cmds)),
618+
nolabel=localize(30028), yeslabel=localize(30027), autoanswer=True):
619+
return False
618620

619621
# Clean up any remaining mounts
620622
self._unmount()
621623

622624
url = arm_device['url']
623625
downloaded = self._http_download(url, message=localize(30022)) # Downloading the recovery image
624626
if downloaded:
625-
progress_dialog = DialogProgress()
626-
progress_dialog.create(heading=localize(30043), line1=localize(30044)) # Extracting Widevine CDM
627+
progress = progress_dialog()
628+
progress.create(heading=localize(30043), line1=localize(30044)) # Extracting Widevine CDM
627629
bin_filename = url.split('/')[-1].replace('.zip', '')
628630
bin_path = os.path.join(self._temp_path(), bin_filename)
629631

630-
progress_dialog.update(5, line1=localize(30045), line2=localize(30046), line3=localize(30047)) # Uncompressing image
632+
progress.update(5, line1=localize(30045), line2=localize(30046), line3=localize(30047)) # Uncompressing image
631633
success = [
632634
self._unzip(self._temp_path(), bin_filename),
633635
self._check_loop(),
@@ -636,27 +638,27 @@ def _install_widevine_arm(self): # pylint: disable=too-many-statements
636638
self._mnt_loop_dev(),
637639
]
638640
if all(success):
639-
progress_dialog.update(91, line1=localize(30048)) # Extracting Widevine CDM
641+
progress.update(91, line1=localize(30048)) # Extracting Widevine CDM
640642
self._extract_widevine_from_img()
641-
progress_dialog.update(94, line1=localize(30049)) # Installing Widevine CDM
642-
progress_dialog.update(97, line1=localize(30050)) # Finishing
643+
progress.update(94, line1=localize(30049)) # Installing Widevine CDM
644+
progress.update(97, line1=localize(30050)) # Finishing
643645
self._cleanup()
644646
if self._has_widevine():
645647
set_setting('chromeos_version', arm_device['version'])
646648
with open(self._widevine_config_path(), 'w') as config_file:
647649
config_file.write(json.dumps(devices, indent=4))
648650
wv_check = self._check_widevine()
649651
if wv_check:
650-
progress_dialog.update(100, line1=localize(30051)) # Widevine CDM successfully installed.
651-
Dialog().notification(localize(30037), localize(30051)) # Success! Widevine CDM successfully installed.
652-
progress_dialog.close()
652+
progress.update(100, line1=localize(30051)) # Widevine CDM successfully installed.
653+
notification(localize(30037), localize(30051)) # Success! Widevine CDM successfully installed.
654+
progress.close()
653655
return wv_check
654656
else:
655-
progress_dialog.update(100, line1=localize(30050)) # Finishing
657+
progress.update(100, line1=localize(30050)) # Finishing
656658
self._cleanup()
657659

658-
progress_dialog.close()
659-
Dialog().ok(localize(30004), localize(30005)) # An error occurred
660+
progress.close()
661+
ok_dialog(localize(30004), localize(30005)) # An error occurred
660662

661663
return False
662664

@@ -676,9 +678,9 @@ def remove_widevine(self):
676678
if widevinecdm and xbmcvfs.exists(widevinecdm):
677679
log('Remove Widevine CDM at {path}', path=widevinecdm)
678680
xbmcvfs.delete(widevinecdm)
679-
Dialog().notification(localize(30037), localize(30052)) # Success! Widevine successfully removed.
681+
notification(localize(30037), localize(30052)) # Success! Widevine successfully removed.
680682
return True
681-
Dialog().notification(localize(30004), localize(30053)) # Error. Widevine CDM not found.
683+
notification(localize(30004), localize(30053)) # Error. Widevine CDM not found.
682684
return False
683685

684686
@staticmethod
@@ -719,7 +721,7 @@ def _update_widevine(self):
719721

720722
if LooseVersion(latest_version) > LooseVersion(current_version):
721723
log('There is an update available for {component}', component=component)
722-
if Dialog().yesno(localize(30040), localize(30033), yeslabel=localize(30034), nolabel=localize(30028)):
724+
if yesno_dialog(localize(30040), localize(30033), nolabel=localize(30028), yeslabel=localize(30034), autoanswer=True):
723725
self.install_widevine()
724726
else:
725727
log('User declined to update {component}.', component=component)
@@ -744,7 +746,7 @@ def _widevine_eula(self):
744746
with archive.open(config.WIDEVINE_LICENSE_FILE) as file_obj:
745747
eula = file_obj.read().decode().strip().replace('\n', ' ')
746748

747-
return Dialog().yesno(localize(30026), eula, yeslabel=localize(30027), nolabel=localize(30028)) # Widevine CDM EULA
749+
return yesno_dialog(localize(30026), eula, nolabel=localize(30028), yeslabel=localize(30027), autoanswer=True) # Widevine CDM EULA
748750

749751
def _extract_widevine_from_img(self):
750752
''' Extract the Widevine CDM binary from the mounted Chrome OS image '''
@@ -793,7 +795,7 @@ def _missing_widevine_libs(self):
793795
import struct
794796
if struct.calcsize('P') * 8 == 64:
795797
log('ARM64 ldd check failed. User needs 32-bit userspace.')
796-
Dialog().ok(localize(30004), localize(30039)) # Widevine not available on ARM64
798+
ok_dialog(localize(30004), localize(30039)) # Widevine not available on ARM64
797799

798800
log('Failed to check for missing Widevine libraries.')
799801
return None
@@ -805,18 +807,18 @@ def _check_widevine(self):
805807

806808
if not os.path.exists(self._widevine_config_path()):
807809
log('Widevine or recovery config is missing. Reinstall is required.')
808-
Dialog().ok(localize(30001), localize(30031)) # An update of Widevine is required
810+
ok_dialog(localize(30001), localize(30031)) # An update of Widevine is required
809811
return self.install_widevine()
810812

811813
if 'x86' in self._arch(): # check that widevine arch matches system arch
812814
wv_config = self._load_widevine_config()
813815
if config.WIDEVINE_ARCH_MAP_X86[self._arch()] != wv_config['arch']:
814816
log('Widevine/system arch mismatch. Reinstall is required.')
815-
Dialog().ok(localize(30001), localize(30031)) # An update of Widevine is required
817+
ok_dialog(localize(30001), localize(30031)) # An update of Widevine is required
816818
return self.install_widevine()
817819

818820
if self._missing_widevine_libs():
819-
Dialog().ok(localize(30004), localize(30032, libs=', '.join(self._missing_widevine_libs()))) # Missing libraries
821+
ok_dialog(localize(30004), localize(30032, libs=', '.join(self._missing_widevine_libs()))) # Missing libraries
820822
return False
821823

822824
self._update_widevine()
@@ -860,7 +862,7 @@ def _cleanup(self):
860862
if unattach_output['success']:
861863
self._loop_dev = False
862864
if self._modprobe_loop:
863-
Dialog().notification(localize(30035), localize(30036)) # Unload by hand in CLI
865+
notification(localize(30035), localize(30036)) # Unload by hand in CLI
864866
if not self._has_widevine():
865867
shutil.rmtree(self._ia_cdm_path())
866868

@@ -886,7 +888,7 @@ def _check_drm(self):
886888
if self._has_widevine():
887889
return self._check_widevine()
888890

889-
if Dialog().yesno(localize(30041), localize(30002), yeslabel=localize(30038), nolabel=localize(30028)): # Widevine required
891+
if yesno_dialog(localize(30041), localize(30002), nolabel=localize(30028), yeslabel=localize(30038), autoanswer=True): # Widevine required
890892
return self.install_widevine()
891893

892894
return False
@@ -915,18 +917,18 @@ def check_inputstream(self):
915917
if not self._has_inputstream():
916918
# Try to install InputStream add-on
917919
if not self._install_inputstream():
918-
Dialog().ok(localize(30004), localize(30008, addon=self.inputstream_addon)) # inputstream is missing on system
920+
ok_dialog(localize(30004), localize(30008, addon=self.inputstream_addon)) # inputstream is missing on system
919921
return False
920922
elif not self._inputstream_enabled():
921-
ret = Dialog().yesno(localize(30001), localize(30009, addon=self.inputstream_addon)) # inputstream is disabled
923+
ret = yesno_dialog(localize(30001), localize(30009, addon=self.inputstream_addon)) # inputstream is disabled
922924
if ret:
923925
self._enable_inputstream()
924926
return False
925927
log('{addon} {version} is installed and enabled.', addon=self.inputstream_addon, version=self._inputstream_version())
926928

927929
if self.protocol == 'hls' and not self._supports_hls():
928-
Dialog().ok(localize(30004), # HLS Minimum version is needed
929-
localize(30017, addon=self.inputstream_addon, version=config.HLS_MINIMUM_IA_VERSION))
930+
ok_dialog(localize(30004), # HLS Minimum version is needed
931+
localize(30017, addon=self.inputstream_addon, version=config.HLS_MINIMUM_IA_VERSION))
930932
return False
931933

932934
return self._check_drm()
@@ -961,4 +963,4 @@ def info_dialog(self):
961963
text += localize(30830, url=config.ISSUE_URL) # Report issues
962964

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

0 commit comments

Comments
 (0)