def get_library_subfolders(folder_name): """Returns all the subfolders contained in a folder of library path""" section_path = common.join_folders_paths(get_library_path(), folder_name) return [ common.join_folders_paths(section_path, G.py2_decode(folder)) for folder in common.list_dir(section_path)[0] ]
def get_library_subfolders(folder_name, custom_lib_path=None): """Returns all the subfolders contained in a folder of library path""" section_path = common.join_folders_paths( custom_lib_path or get_library_path(), folder_name) return [ common.join_folders_paths(section_path, folder) for folder in common.list_dir(section_path)[0] ]
def export_item(self, job_data, library_home): """Create strm file for an item and add it to the library""" # Paths must be legal to ensure NFS compatibility destination_folder = common.join_folders_paths(library_home, job_data['root_folder_name'], job_data['folder_name']) common.create_folder(destination_folder) if job_data['create_strm_file']: strm_file_path = common.join_folders_paths(destination_folder, job_data['filename'] + '.strm') insert_videoid_to_db(job_data['videoid'], strm_file_path, job_data['nfo_data'] is not None) common.write_strm_file(job_data['videoid'], strm_file_path) if job_data['create_nfo_file']: nfo_file_path = common.join_folders_paths(destination_folder, job_data['filename'] + '.nfo') common.write_nfo_file(job_data['nfo_data'], nfo_file_path) common.debug('Exported {}: {}', job_data['videoid'], job_data['title'])
def remove_item(self, job_data, library_home=None): # pylint: disable=unused-argument """Remove an item from the Kodi library, delete it from disk, remove add-on database references""" videoid = job_data['videoid'] LOG.debug('Removing {} ({}) from add-on library', videoid, job_data['title']) try: # Remove the STRM file exported exported_file_path = G.py2_decode( xbmc.translatePath(job_data['file_path'])) common.delete_file_safe(exported_file_path) parent_folder = G.py2_decode( xbmc.translatePath(os.path.dirname(exported_file_path))) # Remove the NFO file of the related STRM file nfo_file = os.path.splitext(exported_file_path)[0] + '.nfo' common.delete_file_safe(nfo_file) dirs, files = common.list_dir(parent_folder) # Remove the tvshow NFO file (only when it is the last file in the folder) tvshow_nfo_file = common.join_folders_paths( parent_folder, 'tvshow.nfo') # (users have the option of removing even single seasons) if xbmcvfs.exists(tvshow_nfo_file) and not dirs and len( files) == 1: xbmcvfs.delete(tvshow_nfo_file) # Delete parent folder xbmcvfs.rmdir(parent_folder) # Delete parent folder when empty if not dirs and not files: xbmcvfs.rmdir(parent_folder) # Remove videoid records from add-on database remove_videoid_from_db(videoid) except ItemNotFound: LOG.warn( 'The videoid {} not exists in the add-on library database', videoid) except Exception as exc: # pylint: disable=broad-except import traceback LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) ui.show_addon_error_info(exc)
def clear_library(self, show_prg_dialog=True): """ Delete all exported items to the library :param show_prg_dialog: if True, will be show a progress dialog window """ LOG.info('Start deleting exported library items') # This will clear all the add-on library data, to prevents possible inconsistencies when for some reason # such as improper use of the add-on, unexpected error or other has broken the library database data or files with ui.ProgressDialog(show_prg_dialog, common.get_local_string(30245), max_value=3) as progress_dlg: progress_dlg.perform_step() progress_dlg.set_wait_message() G.SHARED_DB.purge_library() for folder_name in [FOLDER_NAME_MOVIES, FOLDER_NAME_SHOWS]: progress_dlg.perform_step() progress_dlg.set_wait_message() section_root_dir = common.join_folders_paths(get_library_path(), folder_name) common.delete_folder_contents(section_root_dir, delete_subfolders=True) # Clean the Kodi library database common.clean_library(show_prg_dialog)
def import_videoid_from_existing_strm(self, folder_path, folder_name): """ Get a VideoId from an existing STRM file that was exported """ for filename in common.list_dir(folder_path)[1]: filename = G.py2_decode(filename) if not filename.endswith('.strm'): continue file_path = common.join_folders_paths(folder_path, filename) # Only get a VideoId from the first file in each folder. # For tv shows all episodes will result in the same VideoId, the movies only contain one file. file_content = common.load_file(file_path) if not file_content: common.warn('Import error: folder "{}" skipped, STRM file empty or corrupted', folder_name) return None if 'action=play_video' in file_content: common.debug('Trying to import (v0.13.x): {}', file_path) return self._import_videoid_old(file_content, folder_name) common.debug('Trying to import: {}', file_path) return self._import_videoid(file_content, folder_name)
def _get_cdm_file_path(): if common.get_system_platform() == 'linux': lib_filename = 'libwidevinecdm.so' elif common.get_system_platform() in ['windows', 'uwp']: lib_filename = 'widevinecdm.dll' elif common.get_system_platform() == 'osx': lib_filename = 'libwidevinecdm.dylib' # import ctypes.util # lib_filename = util.find_library('libwidevinecdm.dylib') else: lib_filename = None if not lib_filename: raise Exception( 'Widevine library filename not mapped for this operative system') # Get the CDM path from inputstream.adaptive (such as: ../.kodi/cdm) from xbmcaddon import Addon addon = Addon('inputstream.adaptive') cdm_path = xbmcvfs.translatePath(addon.getSetting('DECRYPTERPATH')) if not common.folder_exists(cdm_path): raise Exception(f'The CDM path {cdm_path} not exists') return common.join_folders_paths(cdm_path, lib_filename)
def _save_system_info(): # Ask to save to a file filename = 'NFSystemInfo.txt' path = ui.show_browse_dialog( f'{common.get_local_string(30603)} - {filename}') if not path: return # This collect the main data to allow verification checks for problems data = f'Netflix add-on version: {G.VERSION}' data += f'\nDebug enabled: {LOG.is_enabled}' data += f'\nSystem platform: {common.get_system_platform()}' data += f'\nMachine architecture: {common.get_machine()}' data += f'\nUser agent string: {common.get_user_agent()}' data += '\n\n#### Widevine info ####\n' if common.get_system_platform() == 'android': data += f'\nSystem ID: {G.LOCAL_DB.get_value("drm_system_id", "--not obtained--", TABLE_SESSION)}' data += f'\nSecurity level: {G.LOCAL_DB.get_value("drm_security_level", "--not obtained--", TABLE_SESSION)}' data += f'\nHDCP level: {G.LOCAL_DB.get_value("drm_hdcp_level", "--not obtained--", TABLE_SESSION)}' wv_force_sec_lev = G.LOCAL_DB.get_value('widevine_force_seclev', WidevineForceSecLev.DISABLED, TABLE_SESSION) data += f'\nForced security level setting is: {wv_force_sec_lev}' else: try: from ctypes import (CDLL, c_char_p) cdm_lib_file_path = _get_cdm_file_path() try: lib = CDLL(cdm_lib_file_path) data += '\nLibrary status: Correctly loaded' try: lib.GetCdmVersion.restype = c_char_p data += f'\nVersion: {lib.GetCdmVersion().decode("utf-8")}' except Exception: # pylint: disable=broad-except # This can happen if the endpoint 'GetCdmVersion' is changed data += '\nVersion: Reading error' except Exception as exc: # pylint: disable=broad-except # This should not happen but currently InputStream Helper does not perform any verification checks on # downloaded and installed files, so if due to an problem it installs a CDM for a different architecture # or the files are corrupted, the user can no longer play videos and does not know what to do data += '\nLibrary status: Error loading failed' data += '\n>>> It is possible that is installed a CDM of a wrong architecture or is corrupted' data += '\n>>> Suggested solutions:' data += '\n>>> - Restore a previous version of Widevine library from InputStream Helper add-on settings' data += '\n>>> - Report the problem to the GitHub of InputStream Helper add-on' data += f'\n>>> Error details: {exc}' except Exception as exc: # pylint: disable=broad-except data += f'\nThe data could not be obtained. Error details: {exc}' data += '\n\n#### ESN ####\n' esn = get_esn() or '--not obtained--' data += f'\nUsed ESN: {common.censure(esn) if len(esn) > 50 else esn}' data += f'\nWebsite ESN: {get_website_esn() or "--not obtained--"}' data += f'\nAndroid generated ESN: {(generate_android_esn() or "--not obtained--")}' if common.get_system_platform() == 'android': data += '\n\n#### Device system info ####\n' try: import subprocess info = subprocess.check_output(['/system/bin/getprop' ]).decode('utf-8') data += f'\n{info}' except Exception as exc: # pylint: disable=broad-except data += f'\nThe data could not be obtained. Error: {exc}' data += '\n' try: common.save_file(common.join_folders_paths(path, filename), data.encode('utf-8')) ui.show_notification( f'{xbmc.getLocalizedString(35259)}: {filename}') # 35259=Saved except Exception as exc: # pylint: disable=broad-except LOG.error('save_file error: {}', exc) ui.show_notification('Error! Try another path')