def _is_kodi_supported_version(cls): if utils.get_kodi_major_version() < 18: utils.dialog( 'Kodi 18+ Required', 'The minimum version of Kodi required for DASH/DRM ' 'protected content is v18. Please upgrade in order to ' 'use this feature.') return False return True
def _get_ia_direct(self, update=False, drm=True): """Get IA direct Download inputstream.adaptive zip file from remote repository and save in Kodi's 'home' folder, unzip to addons folder. """ utils.dialog( 'No longer supported', 'This feature is no longer supported. Please upgrade ' 'your Kodi installation to a newer v18 build, or for ' 'Linux installations you should be able to obtain ' 'from your package manager eg. ' '"sudo apt update && sudo apt install kodi-inputstream' '-adaptive"')
def _install_addon(self): try: # see if there's an installed repo that has it xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', True) addon = self._get_addon() utils.log('inputstream.adaptive installed from repo') return addon except RuntimeError: utils.dialog( 'inputstream.adaptive not installed', 'inputstream.adaptive not installed. This ' 'addon now comes supplied with newer builds ' 'of Kodi 18 for Windows/Mac/LibreELEC/OSMC, ' 'and can be installed from most Linux package ' 'managers eg. "sudo apt install kodi-' 'inputstream-adaptive"')
def _progress_download(self, url, download_path, display_filename=None): """Progress download Download file in Kodi with progress bar """ utils.log('Downloading {0}'.format(url)) try: res = requests.get(url, stream=True, verify=False) res.raise_for_status() except requests.exceptions.HTTPError: utils.dialog('Download failed', 'HTTP ' + str(res.status_code) + ' error') return False except Exception as exc: utils.dialog('Download failed', 'Exception was: {0}'.format(exc)) return False total_length = float(res.headers.get('content-length')) dp = xbmcgui.DialogProgress() if not display_filename: display_filename = download_path.split()[-1] dp.create("Downloading {0}".format(display_filename), "Downloading File", url) with open(download_path, 'wb') as f: chunk_size = 1024 downloaded = 0 for chunk in res.iter_content(chunk_size=chunk_size): f.write(chunk) downloaded += len(chunk) percent = int(downloaded * 100 / total_length) if dp.iscanceled(): dp.close() res.close() dp.update(percent) utils.log('Download {0} bytes complete, saved in {1}'.format( int(total_length), download_path)) dp.close() return True
def _get_wvcdm(self): """Get the Widevine CDM library Win/Mac: download Chrome extension blob ~2MB and extract widevinecdm.dll Linux: download Chrome package ~50MB and extract libwidevinecdm.so Linux arm: download widevine package ~2MB from 3rd party host """ addon = self.get_addon() if not addon: utils.dialog('inputstream.adaptive not found' 'inputstream.adaptive add-on must be installed ' 'before installing widevide_cdm module') return if self._is_android(): utils.dialog('Not available', 'This module cannot be updated on Android') return cdm_paths = self._get_wvcdm_paths(addon) cdm_path = self._get_wvcdm_path(addon, cdm_paths) plat = self._get_platform() current_cdm_ver = self._get_wvcdm_current_ver() url = config.WIDEVINE_CDM_URL[plat].format(current_cdm_ver) filename = url.split('/')[-1] wv_cdm_fn = self._get_wvcdm_filename() if not os.path.isdir(cdm_path): utils.log('Creating directory: {0}'.format(cdm_path)) os.makedirs(cdm_path) cdm_fn = os.path.join(cdm_path, wv_cdm_fn) if os.path.isfile(cdm_fn): utils.log('Removing existing widevine_cdm: {0}'.format(cdm_fn)) os.remove(cdm_fn) home_folder = self._get_home_folder() download_path = os.path.join(home_folder, filename) if not self._progress_download(url, download_path, wv_cdm_fn): return dp = xbmcgui.DialogProgress() dp.create('Extracting {0}'.format(wv_cdm_fn), 'Extracting {0} from {1}'.format(wv_cdm_fn, filename)) dp.update(0) if self._is_windows(): self._unzip_windows_cdm(download_path, cdm_path) else: self._execute_cdm_command(plat, filename, cdm_path, home_folder) dp.close() # TODO(andy): Test it was actually successful. Can be cancelled utils.dialog( 'Success', '{0} successfully installed at {1}'.format( wv_cdm_fn, os.path.join(cdm_path, wv_cdm_fn))) return True
def check_inputstream(self, drm=True): """Check InputStream Adaptive is installed and ready Main function call to check all components required are available for DRM playback before setting the resolved URL in Kodi. drm -- set to false if you just want to check for inputstream.adaptive and not widevine components eg. HLS playback """ # DRM not supported if drm and not self._is_wv_drm_supported(): # TODO(andy): Store something in settings to prevent this message # appearing more than once? utils.dialog( 'Platform not supported', '{0} not supported for DRM playback. ' 'For more information, see our DRM FAQ at {1}' ''.format(self.get_platform_name(), config.DRM_INFO)) return False # Kodi version too old if drm and utils.get_kodi_major_version() < 18: utils.dialog( 'Kodi version not supported for DRM', 'This version of Kodi is not currently supported for viewing ' 'DRM encrypted content. Please upgrade to Kodi v18.') return False addon = self.get_addon() if not addon: utils.dialog( 'Missing inputstream.adaptive add-on', 'inputstream.adaptive VideoPlayer InputStream add-on not ' 'found or not enabled. This add-on is required to view DRM ' 'protected content.') return False utils.log('Found inputstream.adaptive version is {0}'.format( addon.getAddonInfo('version'))) # widevine built into android - not supported on 17 atm though if self._is_android(): utils.log('Running on Android') return True # checking for installation of inputstream.adaptive (eg HLS playback) if not drm: utils.log('DRM checking not requested') return True # only 32bit userspace supported for linux aarch64 no 64bit wvcdm if self._get_platform() == ('Linux', 'aarch64'): if self._get_kodi_arch() == '64bit': utils.dialog( '64 bit build for aarch64 not supported', 'A build of your OS that supports 32 bit userspace ' 'binaries is required for DRM playback. We recommend ' 'CoreELEC to support this.') cdm_fn = self._get_wvcdm_filename() cdm_paths = self._get_wvcdm_paths(addon) if not any(os.path.isfile(os.path.join(p, cdm_fn)) for p in cdm_paths): if utils.dialog_yn( 'Missing Widevine module', '{0} not found in any expected location.'.format(cdm_fn), 'Do you want to attempt downloading the missing ' 'Widevine CDM module to your system for DRM support?'): self._get_wvcdm() else: # TODO(andy): Ask to never attempt again return False return True