Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion script.module.inputstreamhelper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
```python
# -*- coding: utf-8 -*-
"""InputStream Helper Demo"""
from __future__ import absolute_import, division, unicode_literals
import sys
import inputstreamhelper
import xbmc
Expand Down Expand Up @@ -91,6 +90,10 @@ Please report any issues or bug reports on the [GitHub Issues](https://github.co
This module is licensed under the **The MIT License**. Please see the [LICENSE.txt](LICENSE.txt) file for details.

## Releases
### v0.8.0 (2025-09-19)
- Fix Widevine CDM installation on Windows, Linux and Macintosh (@mediaminister)
- Add support for LG webOS (@Uukrull)

### v0.7.0 (2024-09-24)
- Get rid of distutils dependency (@horstle, @emilsvennesson)
- Option to get Widevine from lacros image (@horstle)
Expand Down
6 changes: 5 additions & 1 deletion script.module.inputstreamhelper/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.module.inputstreamhelper" name="InputStream Helper" version="0.7.0" provider-name="emilsvennesson, dagwieers, mediaminister, horstle">
<addon id="script.module.inputstreamhelper" name="InputStream Helper" version="0.8.0" provider-name="emilsvennesson, dagwieers, mediaminister, horstle">
<requires>
<!--py3 compliant-->
<import addon="xbmc.python" version="3.0.0"/>
Expand All @@ -25,6 +25,10 @@
<description lang="hr_HR">Jednostavan Kodi modul koji olakšava razvijanje dodataka koji se temelje na InputStream dodatku i reprodukciji DRM zaštićenog sadržaja.</description>
<description lang="ru_RU">Простой модуль для Kodi, который облегчает жизнь разработчикам дополнений, с использованием InputStream дополнений и воспроизведения DRM контента.</description>
<news>
v0.8.0 (2025-09-19)
- Fix Widevine CDM installation on Windows, Linux and Macintosh
- Add support for LG webOS

v0.7.0 (2024-09-24)
- Get rid of distutils dependency
- Option to get Widevine from lacros image
Expand Down
1 change: 0 additions & 1 deletion script.module.inputstreamhelper/default.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
''' This is the actual InputStream Helper API script entry point '''

from __future__ import absolute_import, division, unicode_literals
import sys
from lib.inputstreamhelper.api import run

Expand Down
32 changes: 13 additions & 19 deletions script.module.inputstreamhelper/lib/inputstreamhelper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
"""Implements the main InputStream Helper class"""

from __future__ import absolute_import, division, unicode_literals
import os
import json

from . import config
from .kodiutils import (addon_version, browsesingle, delete, exists, get_proxies, get_setting, get_setting_bool, get_setting_float, get_setting_int, jsonrpc,
kodi_to_ascii, kodi_version, listdir, localize, log, notification, ok_dialog, progress_dialog, select_dialog,
set_setting, set_setting_bool, textviewer, translate_path, yesno_dialog)
from .utils import arch, download_path, http_download, parse_version, remove_tree, system_os, temp_path, unzip, userspace64
from .widevine.arm import dl_extract_widevine_chromeos, extract_widevine_chromeos, install_widevine_arm
from .widevine.arm_lacros import cdm_from_lacros, latest_lacros
from .widevine.arm_lacros import cdm_from_lacros
from .widevine.widevine import (backup_path, has_widevinecdm, ia_cdm_path,
install_cdm_from_backup, latest_widevine_version,
load_widevine_config, missing_widevine_libs, widevine_config_path,
widevine_eula, widevinecdm_path)
from .widevine.repo import cdm_from_repo, choose_widevine_from_repo, latest_widevine_available_from_repo
from .widevine.repo import cdm_from_repo, latest_widevine_available_from_repo
from .unicodes import compat_path

# NOTE: Work around issue caused by platform still using os.popen()
Expand All @@ -33,8 +31,7 @@ class InputStreamException(Exception):
def cleanup_decorator(func):
"""Decorator which runs cleanup before and after a function"""

def clean_before_after(self, *args, **kwargs): # pylint: disable=missing-docstring
# pylint only complains about a missing docstring on py2.7?
def clean_before_after(self, *args, **kwargs):
self.cleanup()
result = func(self, *args, **kwargs)
self.cleanup()
Expand Down Expand Up @@ -68,10 +65,7 @@ def __init__(self, protocol, drm=None):
# Add proxy support to HTTP requests
proxies = get_proxies()
if proxies:
try: # Python 3
from urllib.request import build_opener, install_opener, ProxyHandler
except ImportError: # Python 2
from urllib2 import build_opener, install_opener, ProxyHandler
from urllib.request import build_opener, install_opener, ProxyHandler
install_opener(build_opener(ProxyHandler(proxies)))

def __repr__(self):
Expand Down Expand Up @@ -178,12 +172,9 @@ def _supports_widevine(self):
return True

@staticmethod
def _install_widevine_from_repo(bpath, choose_version=False):
def _install_widevine_from_repo(bpath):
"""Install Widevine CDM from Google's library CDM repository"""
if choose_version:
cdm = choose_widevine_from_repo()
else:
cdm = latest_widevine_available_from_repo()
cdm = latest_widevine_available_from_repo(config.WIDEVINE_OS_MAP[system_os()], config.WIDEVINE_ARCH_MAP_REPO[arch()])

if not cdm:
return cdm
Expand All @@ -197,7 +188,8 @@ def _install_widevine_from_repo(bpath, choose_version=False):
if dl_path:
progress = progress_dialog()
progress.create(heading=localize(30043), message=localize(30044)) # Extracting Widevine CDM
unzip(dl_path, os.path.join(bpath, cdm_version, ''))
unzip(dl_path, os.path.join(bpath, cdm_version, ''), file_to_unzip=[config.WIDEVINE_LICENSE_FILE,
config.WIDEVINE_MANIFEST_FILE, config.WIDEVINE_CDM_FILENAME[system_os()]])

return (progress, cdm_version)

Expand Down Expand Up @@ -231,7 +223,7 @@ def install_widevine(self, choose_version=False):
return False

if cdm_from_repo():
result = self._install_widevine_from_repo(backup_path(), choose_version=choose_version)
result = self._install_widevine_from_repo(backup_path())
else:
if choose_version:
log(1, "Choosing a version to install is only implemented if the lib is found in googles repo.")
Expand Down Expand Up @@ -359,7 +351,7 @@ def _update_widevine(self):

def _check_widevine(self):
"""Checks that all Widevine components are installed and available."""
if system_os() == 'Android': # no checks needed for Android
if system_os() == 'Android' or system_os() == 'webOS': # no checks needed for Android or webOS
return True

if not exists(widevine_config_path()):
Expand All @@ -369,7 +361,7 @@ def _check_widevine(self):

if cdm_from_repo(): # check that widevine arch matches system arch
wv_config = load_widevine_config()
if config.WIDEVINE_ARCH_MAP_REPO[arch()] != wv_config['arch']:
if config.WIDEVINE_ARCH_MAP_REPO[arch()] != wv_config['platforms'][0]['arch']:
log(4, 'Widevine/system arch mismatch. Reinstall is required.')
ok_dialog(localize(30001), localize(30031)) # An update of Widevine is required
return self.install_widevine()
Expand Down Expand Up @@ -471,6 +463,8 @@ def info_dialog(self):

if system_os() == 'Android':
text += localize(30820) + '\n'
elif system_os() == 'webOS':
text += localize(30826) + '\n'
else:
from time import localtime, strftime
if get_setting_float('last_modified', 0.0):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
"""This is the actual InputStream Helper API script"""

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

Expand Down
37 changes: 20 additions & 17 deletions script.module.inputstreamhelper/lib/inputstreamhelper/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
"""Configuration variables for inpustreamhelper"""
from __future__ import absolute_import, division, unicode_literals


INPUTSTREAM_PROTOCOLS = {
Expand All @@ -20,7 +19,8 @@
'Android': None,
'Linux': 'libwidevinecdm.so',
'Windows': 'widevinecdm.dll',
'Darwin': 'libwidevinecdm.dylib'
'Darwin': 'libwidevinecdm.dylib',
'webOS': None
}

ARCH_MAP = {
Expand All @@ -44,12 +44,12 @@

WIDEVINE_ARCH_MAP_REPO = {
'x86_64': 'x64',
'x86': 'ia32',
'x86': 'x86',
'arm64': 'arm64'
}

WIDEVINE_OS_MAP = {
'Linux': 'linux',
'Linux': 'Linux',
'Windows': 'win',
'Darwin': 'mac'
}
Expand All @@ -58,21 +58,23 @@
'Android',
'Linux',
'Windows',
'Darwin'
'Darwin',
'webOS'
]

WIDEVINE_MINIMUM_KODI_VERSION = {
'Android': '18.0',
'Windows': '18.0',
'Linux': '18.0',
'Darwin': '18.0'
'Darwin': '18.0',
'webOS': '22.0'
}

WIDEVINE_VERSIONS_URL = 'https://dl.google.com/widevine-cdm/versions.txt'

WIDEVINE_DOWNLOAD_URL = 'https://dl.google.com/widevine-cdm/{version}-{os}-{arch}.zip'

WIDEVINE_LICENSE_FILE = 'LICENSE.txt'
WIDEVINE_LICENSE_FILE = 'LICENSE'

WIDEVINE_MANIFEST_FILE = 'manifest.json'

Expand All @@ -83,22 +85,23 @@
# To keep the Chrome OS ARM(64) hardware ID list up to date, the following resources can be used:
# https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices
# https://chromiumdash.appspot.com/serving-builds?deviceCategory=Chrome%20OS
# Last updated: 2023-03-24
# Last updated: 2024-10-13
# current Chrome OS version: 16002.44.0, Widevine version: 4.10.2662.3
CHROMEOS_RECOVERY_ARM_BNAMES = [
'bob', # no longer updated, still latest wv. last: https://dl.google.com/dl/edgedl/chromeos/recovery/chromeos_15509.81.0_bob_recovery_stable-channel_mp-v2.bin.zip
'elm', # probably 64bit soon. current: https://dl.google.com/dl/edgedl/chromeos/recovery/chromeos_15886.44.0_elm_recovery_stable-channel_mp-v6.bin.zip
'hana', # probably 64bit soon. current: https://dl.google.com/dl/edgedl/chromeos/recovery/chromeos_15964.59.0_hana_recovery_stable-channel_mp-v11.bin.zip
'kevin', # no longer updated, still latest wv. last: https://dl.google.com/dl/edgedl/chromeos/recovery/chromeos_15509.81.0_kevin_recovery_stable-channel_mp-v2.bin.zip
'scarlet', # no longer updated, still latest wv. last: https://dl.google.com/dl/edgedl/chromeos/recovery/chromeos_15509.81.0_scarlet_recovery_stable-channel_mp-v8.bin.zip
]

CHROMEOS_RECOVERY_ARM64_BNAMES = [
'asurada',
'bob',
'cherry',
'elm',
'hana',
'corsola',
'jacuzzi',
'kevin',
'kukui',
'scarlet',
'strongbad',
]

CHROMEOS_RECOVERY_ARM64_BNAMES = [
'corsola',
'trogdor',
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
"""Implements Kodi Helper functions"""

from __future__ import absolute_import, division, unicode_literals
from contextlib import contextmanager
import xbmc
import xbmcaddon
Expand All @@ -11,7 +10,6 @@
try: # Kodi v19 or newer
from xbmcvfs import translatePath
except ImportError: # Kodi v18 and older
# pylint: disable=ungrouped-imports
from xbmc import translatePath

from .unicodes import from_unicode, to_unicode
Expand Down Expand Up @@ -105,7 +103,7 @@ def addon_version(addon_name=None):
return get_addon_info('version', addon)


def browsesingle(type, heading, shares='', mask='', useThumbs=False, treatAsFolder=False, defaultt=None): # pylint: disable=invalid-name,redefined-builtin
def browsesingle(type, heading, shares='', mask='', useThumbs=False, treatAsFolder=False, defaultt=None): # pylint: disable=invalid-name,redefined-builtin,too-many-positional-arguments
"""Show a Kodi browseSingle dialog"""
from xbmcgui import Dialog
if not heading:
Expand Down Expand Up @@ -184,6 +182,7 @@ def get_setting_bool(key, default=None):
try:
return ADDON.getSettingBool(key)
except (AttributeError, TypeError): # On Krypton or older, or when not a boolean
log(3, 'get setting bool')
value = get_setting(key, default)
if value not in ('false', 'true'):
return default
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
"""Implements Unicode Helper functions"""
from __future__ import absolute_import, division, unicode_literals


def to_unicode(text, encoding='utf-8', errors='strict'):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .kodiutils import log


class ZstdDecompressor: # pylint: disable=too-few-public-methods
class ZstdDecompressor: # pylint: disable=too-few-public-methods
"""
zstdandard decompressor class

Expand All @@ -39,7 +39,7 @@ def __init__(self):
self.zstddecomp.argtypes = (c_void_p, c_size_t, c_void_p, c_size_t)
self.iserror = libzstd.ZSTD_isError

def decompress(self, comp_data, comp_size, outsize=8*2**10):
def decompress(self, comp_data, comp_size, outsize=8 * 2 ** 10):
"""main function, decompresses binary string <src>"""
if len(comp_data) != comp_size:
raise IOError("Decompression failed! Length of compressed data doesn't match given size.")
Expand Down Expand Up @@ -168,6 +168,7 @@ class FragmentBlockEntry:
size: int
unused: int # This field has no meaning


class SquashFs:
"""
Main class to handle a squashfs image, find and extract files from it.
Expand Down Expand Up @@ -353,7 +354,7 @@ def _get_dentry(self, name):
header = self._directory_header(data)
data = data[12:]

for _ in range(header.count+1):
for _ in range(header.count + 1):
dentry = self._directory_entry(data)
if dentry.name == bname:
log(0, f"found {bname} in dentry {dentry} after dir header {header}")
Expand Down
Loading