def ffmpeg_location(): ffmpeg_src = xbmc.translatePath(plugin.get_setting('ffmpeg', str)) if xbmc.getCondVisibility('system.platform.android'): ffmpeg_dst = '/data/data/%s/ffmpeg' % android_get_current_appid() if (plugin.get_setting('ffmpeg', str) != plugin.get_setting( 'ffmpeg.last', str)) or (not xbmcvfs.exists(ffmpeg_dst) and ffmpeg_src != ffmpeg_dst): xbmcvfs.copy(ffmpeg_src, ffmpeg_dst) plugin.set_setting('ffmpeg.last', plugin.get_setting('ffmpeg', str)) ffmpeg = ffmpeg_dst else: ffmpeg = ffmpeg_src if ffmpeg: try: st = os.stat(ffmpeg) if not (st.st_mode & stat.S_IXUSR): try: os.chmod(ffmpeg, st.st_mode | stat.S_IXUSR) except: pass except: pass if xbmcvfs.exists(ffmpeg): return ffmpeg else: xbmcgui.Dialog().notification("IPTV Archive Downloader", addon.getLocalizedString(30056))
def create_color_swatch_image(self, colorstring): '''helper method to generate a colorized image using PIL''' color_image_file = None if colorstring: paths = [] paths.append(u"%s%s.png" % (COLORFILES_PATH, colorstring)) if xbmcvfs.exists(SKINCOLORFILE): paths.append(u"%s%s.png" % (SKINCOLORFILES_PATH, colorstring)) for color_image_file in paths: if not xbmcvfs.exists(color_image_file): if SUPPORTS_PIL: # create image with PIL try: colorstring = colorstring.strip() if colorstring[0] == '#': colorstring = colorstring[1:] a, r, g, b = colorstring[:2], colorstring[ 2:4], colorstring[4:6], colorstring[6:] a, r, g, b = [int(n, 16) for n in (a, r, g, b)] color = (r, g, b, a) img = Image.new("RGBA", (16, 16), color) img.save(color_image_file) del img except Exception as exc: log_exception(__name__, exc) else: # create image with online service if no pil support xbmcvfs.copy( "https://dummyimage.com/16/%s/%s.png" % (colorstring[2:], colorstring[2:]), color_image_file) log_msg( "Local PIL module not available, generating color swatch image with online service", xbmc.LOGWARNING) return color_image_file
def copy_file(path, dest): ''' Copy specific file. ''' if path.endswith('.pyo'): return xbmcvfs.copy(path, dest) LOG.debug("copy: %s to %s", path, dest)
def _process_source(self, source, method_name, file_path): remove_file(file_path) path = source.path.strip() source_type = source.source_type archive_type = source.archive_type if source_type == Source.TYPE_ADDON: addon_id = path addon, data = merge_info(addon_id, self.integrations, merging=True) if method_name not in data: raise Error('{} could not be found for {}'.format( method_name, addon_id)) template_tags = { '$ID': addon_id, '$FILE': file_path, '$IP': xbmc.getIPAddress(), } path = data[method_name] for tag in template_tags: path = path.replace(tag, template_tags[tag]) path = path.strip() if path.lower().startswith('plugin'): self._call_addon_method(path) return if path.lower().startswith('http'): source_type = Source.TYPE_URL else: source_type = Source.TYPE_FILE archive_extensions = { '.gz': Source.ARCHIVE_GZIP, '.xz': Source.ARCHIVE_XZ, } name, ext = os.path.splitext(path.lower()) archive_type = archive_extensions.get(ext, Source.ARCHIVE_NONE) if source_type == Source.TYPE_URL and path.lower().startswith('http'): log.debug('Downloading: {} > {}'.format(path, file_path)) Session().chunked_dl(path, file_path) elif not xbmcvfs.exists(path): raise Error(_(_.LOCAL_PATH_MISSING, path=path)) else: log.debug('Copying local file: {} > {}'.format(path, file_path)) xbmcvfs.copy(path, file_path) if archive_type == Source.ARCHIVE_GZIP: gzip_extract(file_path) elif archive_type == Source.ARCHIVE_XZ: xz_extract(file_path)
def verify_kodi_defaults(): ''' Make sure we have the kodi default folder in place. ''' source_base_path = xbmc.translatePath("special://xbmc/system/library/video") dest_base_path = xbmc.translatePath("special://profile/library/video") # Make sure the files exist in the local profile. # TODO: Investigate why this is needed. # I would think Kodi pulls data from the default profile # if we don't do this. for source_path, dirs, files in os.walk(source_base_path): relative_path = os.path.relpath(source_path, source_base_path) dest_path = os.path.join(dest_base_path, relative_path) if not os.path.exists(dest_path): os.mkdir(os.path.normpath(dest_path)) for file_name in files: dest_file = os.path.join(dest_path, file_name) copy = False if not os.path.exists(dest_file): copy = True elif os.path.splitext(file_name)[1].lower() == '.xml': try: etree.parse(dest_file) except etree.ParseError: LOG.warning("Unable to parse `{}`, recovering from default.".format(dest_file)) copy = True if copy: source_file = os.path.join(source_path, file_name) LOG.debug("Copying `{}` -> `{}`".format(source_file, dest_file)) xbmcvfs.copy(source_file, dest_file) # This code seems to enforce a fixed ordering. # Is it really desirable to force this on users? # The default (system wide) order is [10, 20, 30] in Kodi 19. for index, node in enumerate(['movies', 'tvshows', 'musicvideos']): file_name = os.path.join(dest_base_path, node, "index.xml") if xbmcvfs.exists(file_name): try: tree = etree.parse(file_name) except etree.ParseError: LOG.error("Unable to parse `{}`".format(file_name)) LOG.exception("We ensured the file was OK above, something is wrong!") tree.getroot().set('order', str(17 + index)) tree.write(file_name) playlist_path = xbmc.translatePath("special://profile/playlists/video") if not xbmcvfs.exists(playlist_path): xbmcvfs.mkdirs(playlist_path)
def safe_copy(src, dst, del_src=False): src = xbmc.translatePath(src) dst = xbmc.translatePath(dst) if not xbmcvfs.exists(src) or same_file(src, dst): return if xbmcvfs.exists(dst): xbmcvfs.delete(dst) log.debug('Copying: {} > {}'.format(src, dst)) xbmcvfs.copy(src, dst) if del_src: xbmcvfs.delete(src)
def copy_directory_contents_xbmcvfs(directory_from, directory_to): overall_success = True files_out = list() dirs_in_dir, files_in_dir = xbmcvfs.listdir( os.path.join(directory_from, '')) for ff in files_in_dir: if not xbmcvfs.copy( os.path.join(directory_from, ff), os.path.join( directory_to, ff)): #If move does not work, then copy overall_success = False else: xbmc.log( msg= 'Retro BIOS Tool: The file was copied from: %(file_from)s, to: %(file_to)s' % { 'file_from': os.path.join(directory_from, ff), 'file_to': os.path.join(directory_to, ff) }, level=xbmc.LOGDEBUG) files_out.append(os.path.join(directory_to, ff)) for dd in dirs_in_dir: if xbmcvfs.exists(os.path.join(directory_to, dd, '')) or xbmcvfs.mkdir( os.path.join(directory_to, dd)): files_out2, success = copy_directory_contents_xbmcvfs( os.path.join(directory_from, dd), os.path.join(directory_to, dd)) files_out = files_out + files_out2 else: overall_success = False return files_out, overall_success
def sync_list_intern(src_file, dest_file): PLog('sync_list_intern:') # 1. Vorprüfung: Setting Sync / externe Merkliste if SETTINGS.getSetting('pref_merksync') == 'false' or SETTINGS.getSetting( 'pref_merkextern') == 'false': PLog("Sync_OFF") return # 2. Vorprüfung: externe Merkliste ist gleichzeitig interne Merkliste? if src_file == WATCHFILE: PLog("Sync_Block_WATCHFILE") return f = xbmcvfs.File(src_file) s1 = f.size() f.close() ret1 = False ret2 = False if s1 > 100: # Mindestbreite bis dirID=, Eintrag immer > 100 Zeichen ret1 = xbmcvfs.delete(dest_file) PLog('xbmcvfs.delete: ' + str(ret1)) ret2 = xbmcvfs.copy(src_file, dest_file) PLog('xbmcvfs.copy: ' + str(ret2)) f = xbmcvfs.File(dest_file) s2 = f.size() f.close() # Größenvergleich PLog("s1: %d, s2: %d" % (s1, s2)) if ret1 and ret2 and s2 == s1: # ohne Rückgabe PLog("Sync_OK") else: PLog("Sync_Error, s1: %d" % s1) return
def sync_list_intern(src_file, dest_file): PLog('sync_list_intern:') # Vorprüfung Setting Sync / externe Merkliste if SETTINGS.getSetting('pref_merksync') == 'false' or SETTINGS.getSetting( 'pref_merkextern') == 'false': PLog("Sync_OFF") return f = xbmcvfs.File(src_file) s1 = f.size() f.close() if s1 > 100: # Mindestbreite bis dirID=, Eintrag immer größer ret1 = xbmcvfs.delete(dest_file) PLog('xbmcvfs.delete: ' + str(ret1)) ret2 = xbmcvfs.copy(src_file, dest_file) PLog('xbmcvfs.copy: ' + str(ret2)) f = xbmcvfs.File(dest_file) s2 = f.size() f.close() # Größenvergleich PLog("s1: %d, s2: %d" % (s1, s2)) if ret1 and ret2 and s2 == s1: # ohne Rückgabe PLog("Sync_OK") else: PLog("Sync_Error") return
def get_fanart(item_id, path, server_id=None): ''' Get extra fanart for listitems. This is called by skinhelper. Images are stored locally, due to the Kodi caching system. ''' if not item_id and 'plugin.video.jellyfin' in path: item_id = path.split('/')[-2] if not item_id: return LOG.info("[ extra fanart ] %s", item_id) objects = Objects() list_li = [] directory = xbmc.translatePath("special://thumbnails/jellyfin/%s/" % item_id) server = TheVoid('GetServerAddress', {'ServerId': server_id}).get() if not xbmcvfs.exists(directory): xbmcvfs.mkdirs(directory) item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get() obj = objects.map(item, 'Artwork') backdrops = api.API(item, server).get_all_artwork(obj) tags = obj['BackdropTags'] for index, backdrop in enumerate(backdrops): tag = tags[index] fanart = os.path.join(directory, "fanart%s.jpg" % tag) li = xbmcgui.ListItem(tag, path=fanart) xbmcvfs.copy(backdrop, fanart) list_li.append((fanart, li, False)) else: LOG.debug("cached backdrop found") dirs, files = xbmcvfs.listdir(directory) for file in files: fanart = os.path.join(directory, file) li = xbmcgui.ListItem(file, path=fanart) list_li.append((fanart, li, False)) xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li)) xbmcplugin.endOfDirectory(int(sys.argv[1]))
def backup(): ''' Jellyfin backup. ''' from helper.utils import delete_folder, copytree path = settings('backupPath') folder_name = "Kodi%s.%s" % (xbmc.getInfoLabel('System.BuildVersion')[:2], xbmc.getInfoLabel('System.Date(dd-mm-yy)')) folder_name = dialog("input", heading=translate(33089), defaultt=folder_name) if not folder_name: return backup = os.path.join(path, folder_name) if xbmcvfs.exists(backup + '/'): if not dialog("yesno", heading="{jellyfin}", line1=translate(33090)): return backup() delete_folder(backup) addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin") destination_data = os.path.join(backup, "addon_data", "plugin.video.jellyfin") destination_databases = os.path.join(backup, "Database") if not xbmcvfs.mkdirs(path) or not xbmcvfs.mkdirs(destination_databases): LOG.info("Unable to create all directories") dialog("notification", heading="{jellyfin}", icon="{jellyfin}", message=translate(33165), sound=False) return copytree(addon_data, destination_data) databases = Objects().objects db = xbmc.translatePath(databases['jellyfin']) xbmcvfs.copy(db, os.path.join(destination_databases, db.rsplit('\\', 1)[1])) LOG.info("copied jellyfin.db") db = xbmc.translatePath(databases['video']) filename = db.rsplit('\\', 1)[1] xbmcvfs.copy(db, os.path.join(destination_databases, filename)) LOG.info("copied %s", filename) if settings('enableMusic.bool'): db = xbmc.translatePath(databases['music']) filename = db.rsplit('\\', 1)[1] xbmcvfs.copy(db, os.path.join(destination_databases, filename)) LOG.info("copied %s", filename) LOG.info("backup completed") dialog("ok", heading="{jellyfin}", line1="%s %s" % (translate(33091), backup))
def safe_copy(src, dst, del_src=False): src = xbmc.translatePath(src) dst = xbmc.translatePath(dst) if not xbmcvfs.exists(src) or same_file(src, dst): return if xbmcvfs.exists(dst): if xbmcvfs.delete(dst): log.debug('Deleted: {}'.format(dst)) else: log.debug('Failed to delete: {}'.format(dst)) if xbmcvfs.copy(src, dst): log.debug('Copied: {} > {}'.format(src, dst)) else: log.debug('Failed to copy: {} > {}'.format(src, dst)) if del_src: xbmcvfs.delete(src)
def rbt_main(): # WIN = xbmcgui.Window(10000) # WIN.clearProperty('rbt.script_started') # if not WIN.getProperty('rbt.script_started'): xbmc.log(msg='Retro BIOS Tool: Tool Started', level=xbmc.LOGINFO) # WIN.setProperty('rbt.script_started','True') addon_name = 'plugin.program.retrobiostool' addon_handle = xbmcaddon.Addon(id='%(addon_name)s' % {'addon_name': addon_name}) bios_folder = addon_handle.getSetting(id='rbt_folder') if addon_handle.getSetting(id='rbt_generate_report') == 'true': generate_report = True else: generate_report = False addon_timeout = 5 bios_keyword = [ 'firmware%(number)s_path' % { 'number': x } for x in range(0, 21) ] libretro_git = r'https://raw.githubusercontent.com/libretro/libretro-super/master/dist/info/xxx_core_xxx.info' #These games are already known to not require any system/bios files, so skip them to make the tool faster ignore_these_addons = [ 'game.libretro', 'game.libretro.2048', 'game.libretro.2048_libretro_buildbot', 'game.libretro.81', 'game.libretro.81_libretro_buildbot', 'game.libretro.beetle-bsnes', 'game.libretro.beetle-bsnes_libretro_buildbot', 'game.libretro.beetle-bsnes_cplusplus98', 'game.libretro.beetle-bsnes_cplusplus98_libretro_buildbot', 'game.libretro.beetle-ngp', 'game.libretro.beetle-ngp_libretro_buildbot', 'game.libretro.beetle-vb', 'game.libretro.beetle-vb_libretro_buildbot', 'game.libretro.beetle-wswan', 'game.libretro.beetle-wswan_libretro_buildbot', 'game.libretro.bnes', 'game.libretro.bnes_libretro_buildbot', 'game.libretro.cannonball', 'game.libretro.cannonball_libretro_buildbot', 'game.libretro.cap32', 'game.libretro.cap32_libretro_buildbot', 'game.libretro.chailove', 'game.libretro.chailove_libretro_buildbot', 'game.libretro.craft', 'game.libretro.craft_libretro_buildbot', 'game.libretro.crocods', 'game.libretro.crocods_libretro_buildbot', 'game.libretro.daphne', 'game.libretro.daphne_libretro_buildbot', 'game.libretro.dinothawr', 'game.libretro.dinothawr_libretro_buildbot', 'game.libretro.dosbox', 'game.libretro.dosbox_libretro_buildbot', 'game.libretro.dosbox_svn', 'game.libretro.dosbox_svn_libretro_buildbot', 'game.libretro.easyrpg', 'game.libretro.easyrpg_libretro_buildbot', 'game.libretro.emux_nes', 'game.libretro.emux_nes_libretro_buildbot', 'game.libretro.fbalpha', 'game.libretro.fbalpha2012', 'game.libretro.fbalpha2012_libretro_buildbot', 'game.libretro.fbalpha2012_cps1', 'game.libretro.fbalpha2012_cps1_libretro_buildbot', 'game.libretro.fbalpha2012_cps2', 'game.libretro.fbalpha2012_cps2_libretro_buildbot', 'game.libretro.fbalpha2012_neogeo', 'game.libretro.fbalpha2012_neogeo_libretro_buildbot', 'game.libretro.fbalpha_libretro_buildbot', 'game.libretro.fuse', 'game.libretro.fuse_libretro_buildbot', 'game.libretro.gearboy', 'game.libretro.gearboy_libretro_buildbot', 'game.libretro.gearsystem', 'game.libretro.gearsystem_libretro_buildbot', 'game.libretro.gme', 'game.libretro.gme_libretro_buildbot', 'game.libretro.gw', 'game.libretro.gw_libretro_buildbot', 'game.libretro.lutro', 'game.libretro.lutro_libretro_buildbot', 'game.libretro.mednafen_ngp', 'game.libretro.mednafen_ngp_libretro_buildbot', 'game.libretro.mednafen_snes', 'game.libretro.mednafen_snes_libretro_buildbot', 'game.libretro.mednafen_vb', 'game.libretro.mednafen_vb_libretro_buildbot', 'game.libretro.mednafen_wswan', 'game.libretro.mednafen_wswan_libretro_buildbot', 'game.libretro.meteor', 'game.libretro.meteor_libretro_buildbot', 'game.libretro.mrboom', 'game.libretro.mrboom_libretro_buildbot', 'game.libretro.nekop2', 'game.libretro.nekop2_libretro_buildbot', 'game.libretro.nx', 'game.libretro.nx_libretro_buildbot', 'game.libretro.nxengine', 'game.libretro.nxengine_libretro_buildbot', 'game.libretro.openlara', 'game.libretro.openlara_libretro_buildbot', 'game.libretro.pocketcdg', 'game.libretro.pocketcdg_libretro_buildbot', 'game.libretro.prboom', 'game.libretro.prboom_libretro_buildbot', 'game.libretro.quicknes', 'game.libretro.quicknes_libretro_buildbot', 'game.libretro.reminiscence', 'game.libretro.reminiscence_libretro_buildbot', 'game.libretro.scummvm', 'game.libretro.scummvm_libretro_buildbot', 'game.libretro.snes9x2002', 'game.libretro.snes9x2002_libretro_buildbot', 'game.libretro.snes9x2005', 'game.libretro.snes9x2005_libretro_buildbot', 'game.libretro.snes9x2005_plus', 'game.libretro.snes9x2005_plus_libretro_buildbot', 'game.libretro.snes9x2010', 'game.libretro.snes9x2010_libretro_buildbot', 'game.libretro.stella', 'game.libretro.stella2014', 'game.libretro.stella2014_libretro_buildbot', 'game.libretro.stella_libretro_buildbot', 'game.libretro.tgbdual', 'game.libretro.tgbdual_libretro_buildbot', 'game.libretro.theodore', 'game.libretro.theodore_libretro_buildbot', 'game.libretro.thepowdertoy', 'game.libretro.thepowdertoy_libretro_buildbot', 'game.libretro.tyrquake', 'game.libretro.tyrquake_libretro_buildbot', 'game.libretro.vecx', 'game.libretro.vecx_libretro_buildbot', 'game.libretro.vice_x128', 'game.libretro.vice_x128_libretro_buildbot', 'game.libretro.vice_x64', 'game.libretro.vice_x64_libretro_buildbot', 'game.libretro.vice_x64sc', 'game.libretro.vice_x64sc_libretro_buildbot', 'game.libretro.vice_xplus4', 'game.libretro.vice_xplus4_libretro_buildbot', 'game.libretro.vice_xvic', 'game.libretro.vice_xvic_libretro_buildbot', 'game.libretro.virtualjaguar', 'game.libretro.virtualjaguar_libretro_buildbot', 'game.libretro.xrick', 'game.libretro.xrick_libretro_buildbot' ] #Rename the following addons to match libretro naming retroplayer_to_libretro_map = { 'bsnes-mercury-accuracy': 'bsnes_mercury_accuracy', 'bsnes-mercury-balanced': 'bsnes_mercury_balanced', 'bsnes-mercury-performance': 'bsnes_mercury_performance', 'genplus': 'genesis_plus_gx', 'beetle-gba': 'mednafen_gba', 'beetle-lynx': 'mednafen_lynx', 'beetle-ngp': 'mednafen_ngp', 'beetle-pce-fast': 'mednafen_pce_fast', 'beetle-pcfx': 'mednafen_pcfx', 'beetle-psx': 'mednafen_psx', 'beetle-saturn': 'mednafen_saturn', 'beetle-bsnes': 'mednafen_snes', 'beetle-supergrafx': 'mednafen_supergrafx', 'beetle-vb': 'mednafen_vb', 'beetle-wswan': 'mednafen_wswan', 'pcsx-rearmed': 'pcsx_rearmed', 'uae': 'puae', 'vba-next': 'vba_next', 'vice': 'vice_x64' } #These special cases have folders listed in their info files rather than all the individual files, need to copy the entire folder special_folder_cases_map = { 'game.libretro.bluemsx': ['Databases', 'Machines'], 'game.libretro.bluemsx_libretro_buildbot': ['Databases', 'Machines'], 'game.libretro.reicast': ['dc'], 'game.libretro.dolphin_libretro_buildbot': ['dolphin-emu'], 'game.libretro.dolphin': ['dolphin-emu'], 'game.libretro.mame': ['mame'], 'game.libretro.mame_libretro_buildbot': ['mame'], 'game.libretro.mame2000': ['mame2000'], 'game.libretro.mame2000_libretro_buildbot': ['mame2000'], 'game.libretro.mame2003': ['mame2003'], 'game.libretro.mame2003_libretro_buildbot': ['mame2003'], 'game.libretro.mame2003_plus': ['mame2003-plus'], 'game.libretro.mame2003_plus_libretro_buildbot': ['mame2003-plus'], 'game.libretro.mame2010': ['mame2010'], 'game.libretro.mame2010_libretro_buildbot': ['mame2010'], 'game.libretro.mame2014': ['mame2014'], 'game.libretro.mame2014_libretro_buildbot': ['mame2014'], 'game.libretro.mame2015': ['mame2015'], 'game.libretro.mame2015_libretro_buildbot': ['mame2015'], 'game.libretro.mess2015': ['mess2015'], 'game.libretro.mess2015_libretro_buildbot': ['mess2015'], 'game.libretro.ppsspp': ['PPSSPP'], 'game.libretro.ppsspp_libretro_buildbot': ['PPSSPP'], 'game.libretro.puae': ['uae_data'], 'game.libretro.puae_libretro_buildbot': ['uae_data'], 'game.libretro.ume2014': ['ume2014'], 'game.libretro.ume2014_libretro_buildbot': ['ume2014'], } #Initialize report dict report_data = dict() report_data['addon_id'] = list() report_data['firmware_listed'] = list() report_data['firmware_files'] = list() report_data['firmware_found'] = list() report_data['info_file'] = list() if bios_folder is None or len(bios_folder) < 1: current_dialog = xbmcgui.Dialog() ret = current_dialog.ok( 'Retro BIOS Tool', 'The tool did not run.[CR]Enter a BIOS file location in settings first!' ) else: try: addons_available = xbmc.executeJSONRPC( '{ "jsonrpc": "2.0", "method": "Addons.GetAddons","params":{"type":"kodi.gameclient", "enabled": true}, "id": "1"}' ) addon_ids = [ x.get('addonid') for x in json.loads(addons_available).get( 'result').get('addons') if x.get('type') == 'kodi.gameclient' and x.get('addonid') not in ignore_these_addons ] xbmc.log( msg= 'Retro BIOS Tool: The following addons will be checked %(current_aids)s' % {'current_aids': ', '.join(addon_ids)}, level=xbmc.LOGDEBUG) except: addon_ids = None if addon_ids is not None: total_files_copied = 0 dp = xbmcgui.DialogProgress() dp.create('Retro BIOS Tools', 'Checking for BIOS Files') dp.update(0) s = requests.Session() for iiaid, aid in enumerate(addon_ids): dp.update(int(100 * (iiaid + 1) / len(addon_ids))) xbmc.log( msg='Retro BIOS Tool: Checking addon %(current_aid)s' % {'current_aid': aid}, level=xbmc.LOGINFO) report_data['addon_id'].append(aid) report_data['firmware_listed'].append(False) report_data['firmware_files'].append(None) report_data['firmware_found'].append(None) report_data['info_file'].append('') if dp.iscanceled(): run_was_cancelled = True dp.close() raise if aid.replace('game.libretro.', '').replace( '_libretro_buildbot', '') in retroplayer_to_libretro_map.keys(): current_git_url = libretro_git.replace( 'xxx_core_xxx', retroplayer_to_libretro_map[aid.replace( 'game.libretro.', '').replace( '_libretro_buildbot', '')] + '_libretro') else: current_git_url = libretro_git.replace( 'xxx_core_xxx', aid.replace('game.libretro.', '').replace( '_libretro_buildbot', '') + '_libretro') xbmc.log( msg= 'Retro BIOS Tool: Checking libretro for core info at %(current_git_url)s' % {'current_git_url': current_git_url}, level=xbmc.LOGDEBUG) try: r = s.get(current_git_url, verify=False, stream=True, timeout=addon_timeout) except Exception as current_exc: xbmc.log( msg= 'Retro BIOS Tool: Error getting libretro for core info at %(current_exc)s' % {'current_exc': current_exc}, level=xbmc.LOGDEBUG) current_info = r.text if len(current_info) > 0: report_data['info_file'][-1] = current_info current_bios_files = list() for bk in bios_keyword: current_check = re.findall( r'%(current_bk)s\s+=\s+\"(.*?)\"' % {'current_bk': bk}, current_info) if current_check is not None and len(current_check) > 0: current_bios_files.append(current_check[0].strip()) if len(current_bios_files) > 0: report_data['firmware_listed'][-1] = True if type(current_bios_files) is list: report_data['firmware_files'][-1] = current_bios_files report_data['firmware_found'][-1] = [ False for x in current_bios_files ] else: report_data['firmware_files'][-1] = [ current_bios_files ] report_data['firmware_found'][-1] = [False] xbmc.log( msg= 'Retro BIOS Tool: Looking for the following bios files %(current_files)s' % {'current_files': ', '.join(current_bios_files)}, level=xbmc.LOGDEBUG) current_addon = xbmcaddon.Addon(id='%(addon_name)s' % {'addon_name': aid}) current_addon_data_folder = py2_decode( xbmc.translatePath( current_addon.getAddonInfo('profile'))) current_addon_resources_folder = os.path.join( current_addon_data_folder, 'resources') current_addon_systems_folder = os.path.join( current_addon_resources_folder, 'system') for cbf in current_bios_files: current_bios_fullpath = os.path.join( bios_folder, *os.path.split(cbf)) if xbmcvfs.exists(current_bios_fullpath): xbmc.log( msg= 'Retro BIOS Tool: Found file %(current_cbf)s' % {'current_cbf': cbf}, level=xbmc.LOGDEBUG) if not xbmcvfs.exists( os.path.join(current_addon_data_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_data_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join(current_addon_data_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join( current_addon_resources_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_resources_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join( current_addon_resources_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data resources folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join(current_addon_systems_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_systems_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join( current_addon_systems_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data resources/system folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join(current_addon_systems_folder, cbf)): if xbmcvfs.copy( os.path.join(bios_folder, cbf), os.path.join( current_addon_systems_folder, cbf) ): #Copy the file to the correct system folder xbmc.log( msg= 'Retro BIOS Tool: Copying file %(current_cbf)s to %(current_folder)s' % { 'current_cbf': os.path.join(bios_folder, cbf), 'current_folder': os.path.join( current_addon_systems_folder, cbf) }, level=xbmc.LOGINFO) total_files_copied = total_files_copied + 1 report_data['firmware_found'][-1][ report_data['firmware_files'] [-1].index(cbf)] = True else: xbmc.log( msg= 'Retro BIOS Tool: Error copying file %(current_cbf)s to %(current_folder)s' % { 'current_cbf': os.path.join(bios_folder, cbf), 'current_folder': os.path.join( current_addon_systems_folder, cbf) }, level=xbmc.LOGERROR) else: xbmc.log( msg= 'Retro BIOS Tool: BIOS file %(current_cbf)s already present in %(current_folder)s' % { 'current_cbf': cbf, 'current_folder': os.path.join( current_addon_systems_folder, cbf) }, level=xbmc.LOGDEBUG) report_data['firmware_found'][-1][report_data[ 'firmware_files'][-1].index(cbf)] = True else: if xbmcvfs.exists( os.path.join(current_addon_systems_folder, cbf)): report_data['firmware_found'][-1][report_data[ 'firmware_files'][-1].index(cbf)] = True else: report_data['firmware_found'][-1][report_data[ 'firmware_files'][-1].index(cbf)] = False xbmc.log( msg= 'Retro BIOS Tool: Unable to find the file in your BIOS folder %(current_cbf)s ' % { 'current_cbf': os.path.join( bios_folder, cbf) }, level=xbmc.LOGERROR) else: xbmc.log( msg= 'Retro BIOS Tool: No bios files found for %(current_aid)s' % {'current_aid': aid}, level=xbmc.LOGDEBUG) report_data['firmware_listed'][-1] = False #Check folder specific cases if aid in special_folder_cases_map.keys(): current_addon = xbmcaddon.Addon(id='%(addon_name)s' % {'addon_name': aid}) current_addon_data_folder = py2_decode( xbmc.translatePath( current_addon.getAddonInfo('profile'))) current_addon_resources_folder = os.path.join( current_addon_data_folder, 'resources') current_addon_systems_folder = os.path.join( current_addon_resources_folder, 'system') current_bios_folder_fullpaths = [ os.path.join(bios_folder, x) for x in special_folder_cases_map[aid] ] current_ind_folders = [ x for x in special_folder_cases_map[aid] ] for cbfi, current_bios_folder_fullpath in enumerate( current_bios_folder_fullpaths): report_data['firmware_listed'][-1] = True report_data['firmware_files'][-1] = [ ', '.join([ x + ' (Folder)' for x in special_folder_cases_map[aid] ]) ] report_data['firmware_found'][-1] = [False] xbmc.log( msg= 'Retro BIOS Tool: Looking for the following bios folder %(current_folder)s' % {'current_folder': current_ind_folders[cbfi]}, level=xbmc.LOGDEBUG) if xbmcvfs.exists( os.path.join(current_bios_folder_fullpath, '')): if not xbmcvfs.exists( os.path.join(current_addon_data_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_data_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join(current_addon_data_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join( current_addon_resources_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_resources_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join( current_addon_resources_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data resources folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join(current_addon_systems_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: The folder %(current_folder)s does not yet exist, so it will be created' % { 'current_folder': current_addon_systems_folder }, level=xbmc.LOGDEBUG) if not xbmcvfs.mkdir( os.path.join( current_addon_systems_folder, '')): xbmc.log( msg= 'Retro BIOS Tool: Unable to create addon_data resources/system folder', level=xbmc.LOGERROR) if not xbmcvfs.exists( os.path.join(current_addon_systems_folder, current_ind_folders[cbfi], '')): copied_folder_files, folder_copy_success = copy_directory_contents_xbmcvfs( current_bios_folder_fullpath, os.path.join(current_addon_systems_folder, current_ind_folders[cbfi])) if folder_copy_success: xbmc.log( msg= 'Retro BIOS Tool: Successfully copied the BIOS folder %(current_folder)s ' % { 'current_folder': os.path.join( bios_folder, current_ind_folders[cbfi]) }, level=xbmc.LOGDEBUG) report_data['firmware_found'][-1] = [True] total_files_copied = total_files_copied + 1 else: xbmc.log( msg= 'Retro BIOS Tool: The BIOS folder %(current_folder)s was found but could not be copied' % { 'current_folder': os.path.join( bios_folder, current_ind_folders[cbfi]) }, level=xbmc.LOGERROR) report_data['firmware_found'][-1] = [False] else: xbmc.log( msg= 'Retro BIOS Tool: The BIOS folder %(current_folder)s is already present' % { 'current_folder': os.path.join( current_addon_systems_folder, current_ind_folders[cbfi]) }, level=xbmc.LOGDEBUG) report_data['firmware_found'][-1] = [True] else: if xbmcvfs.exists( os.path.join(current_addon_systems_folder, current_ind_folders[cbfi], '')): report_data['firmware_found'][-1] = [True] xbmc.log( msg= 'Retro BIOS Tool: The BIOS folder is already present in your addon folder %(current_folder)s ' % { 'current_folder': os.path.join( current_addon_systems_folder, current_ind_folders[cbfi]) }, level=xbmc.LOGDEBUG) else: report_data['firmware_found'][-1] = [False] xbmc.log( msg= 'Retro BIOS Tool: Unable to find the folder in your BIOS folder %(current_folder)s ' % { 'current_folder': os.path.join( current_addon_systems_folder, current_ind_folders[cbfi]) }, level=xbmc.LOGDEBUG) dp.close() current_dialog = xbmcgui.Dialog() if total_files_copied > 0: ok_ret = current_dialog.ok( 'Completed', 'Tool copied %(total_files_copied)s total files.' % {'total_files_copied': total_files_copied}) else: ok_ret = current_dialog.ok( 'Completed', 'Tool did not copy any files' % {'total_files_copied': total_files_copied}) if generate_report: xbmc.log(msg='Retro BIOS Tool: Report Generated', level=xbmc.LOGDEBUG) xbmcplugin.addDirectoryItem( plugin_handle.handle, '', xbmcgui.ListItem( 'Retro BIOS Tool Report ([COLOR green]green=present[/COLOR], [COLOR red]red=missing[/COLOR]): ', offscreen=True)) for iiaid, aid in enumerate(report_data['addon_id']): report_item = 'Addon: %(current_addon_id)s, BIOS Listed: %(current_firmware_listed)s, ' % { 'current_addon_id': aid, 'current_firmware_listed': report_data['firmware_listed'][iiaid] } if report_data['firmware_listed'][iiaid]: report_subitem = 'Files: ' for icff, cff in enumerate( report_data['firmware_files'][iiaid]): if report_data['firmware_found'][iiaid][icff]: report_subitem = report_subitem + '[COLOR green]%(current_ff)s[/COLOR], ' % { 'current_ff': cff } else: report_subitem = report_subitem + '[COLOR red]%(current_ff)s[/COLOR], ' % { 'current_ff': cff } report_item = report_item + report_subitem if report_item.endswith(', '): report_item = report_item[:-2] li = xbmcgui.ListItem(report_item, offscreen=True) li.setInfo('video', { 'plot': report_subitem + '[CR]' + report_data['info_file'][iiaid] }) if xbmcvfs.exists( xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'icon.png'))): li.setArt({ 'icon': xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'icon.png')) }) elif xbmcvfs.exists( xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'resources', 'icon.png'))): li.setArt({ 'icon': xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'resources', 'icon.png')) }) elif xbmcvfs.exists( xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'icon.jpg'))): li.setArt({ 'icon': xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'icon.jpg')) }) elif xbmcvfs.exists( xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'resources', 'icon.jpg'))): li.setArt({ 'icon': xbmc.translatePath( os.path.join('special://home', 'addons', str(aid), 'resources', 'icon.jpg')) }) else: xbmc.log( msg='Retro BIOS Tool: No icon found for %(current_aid)s' % {'current_aid': aid}, level=xbmc.LOGDEBUG) xbmcplugin.addDirectoryItem(plugin_handle.handle, '', li) xbmcplugin.endOfDirectory(plugin_handle.handle) else: xbmc.log(msg='Retro BIOS Tool: Report Skipped', level=xbmc.LOGDEBUG) # WIN.clearProperty('rbt.script_started') xbmc.log(msg='Retro BIOS Tool: Tool completed', level=xbmc.LOGINFO)
def extract(self, current_archive_file=None, current_directory_out=None, files_to_extract=None, extract_all=True): files_out = list() overall_success = True if current_archive_file is None: current_archive_file = self.archive_file if current_directory_out is None: current_directory_out = self.directory_out if files_to_extract is None: if not extract_all and (self.files_to_extract is None or len(self.files_to_extract) == 0): xbmc.log( msg= 'archive_tool error: extract_all set to False and no files were identified for extraction', level=xbmc.LOGERROR) overall_success = False return files_out, overall_success else: files_to_extract = self.files_to_extract else: if type(files_to_extract) is list and len(files_to_extract) > 0: extract_all = False #Override default extract_all if files_to_extract is populated if current_archive_file is not None: if current_directory_out is None: #Default to the same directory as the current_archive_file directory_to = os.path.join( os.path.split(xbmc.translatePath(current_archive_file))[0], '') else: directory_to = os.path.join( xbmc.translatePath(current_directory_out), '') if 'archive://' in current_archive_file or 'rar://' in current_archive_file: archive_path = current_archive_file else: if self.use_vfs_rar: archive_path = 'rar://%(archive_file)s' % { 'archive_file': url_quote(xbmc.translatePath(current_archive_file)) } else: archive_path = 'archive://%(archive_file)s' % { 'archive_file': url_quote(xbmc.translatePath(current_archive_file)) } dirs_in_archive, files_in_archive = xbmcvfs.listdir(archive_path) for ff in files_in_archive: file_from = os.path.join(archive_path, ff).replace( '\\', '/' ) #Windows unexpectedly requires a forward slash in the path if extract_all or file_from in files_to_extract: success = xbmcvfs.copy( file_from, os.path.join( xbmc.translatePath(directory_to), ff)) #Extract the file to the correct directory if not success: xbmc.log( msg= 'archive_tool error: Error extracting file %(ff)s from archive %(archive_file)s' % { 'ff': ff, 'archive_file': current_archive_file }, level=xbmc.LOGERROR) overall_success = False else: xbmc.log( msg= 'archive_tool: Extracted file %(ff)s from archive %(archive_file)s' % { 'ff': ff, 'archive_file': current_archive_file }, level=xbmc.LOGDEBUG) files_out.append( os.path.join(xbmc.translatePath(directory_to), ff) ) #Append the file to the list of extracted files else: xbmc.log( msg= 'archive_tool: The file %(ff)s from archive %(archive_file)s was not listed for extraction, so it will be skipped' % { 'ff': file_from, 'archive_file': current_archive_file }, level=xbmc.LOGDEBUG) for dd in dirs_in_archive: if xbmcvfs.mkdir( os.path.join(xbmc.translatePath(directory_to), dd) ): #Make the archive directory in the directory_to xbmc.log( msg= 'archive_tool: Created folder %(dd)s for archive %(archive_file)s' % { 'dd': os.path.join(xbmc.translatePath(directory_to), dd, ''), 'archive_file': current_archive_file }, level=xbmc.LOGDEBUG) files_out2, success2 = self.extract( current_archive_file=os.path.join( archive_path, dd, '').replace('\\', '/'), current_directory_out=os.path.join(directory_to, dd)) if success2: files_out = files_out + files_out2 #Append the files in the subdir to the list of extracted files else: xbmc.log( msg= 'archive_tool error: Error extracting files from the subdirectory %(dd)s in the archive %(archive_file)s' % { 'dd': dd, 'archive_file': current_archive_file }, level=xbmc.LOGERROR) overall_success = False else: overall_success = False xbmc.log( msg= 'archive_tool error: Unable to create the archive subdirectory %(dir_from)s in the archive %(archive_file)s' % { 'dir_from': os.path.join(xbmc.translatePath(directory_to), dd), 'archive_file': current_archive_file }, level=xbmc.LOGERROR) else: xbmc.log( msg= 'archive_tool error: The current archive file is not valid', level=xbmc.LOGERROR) overall_success = False return files_out, overall_success
def unzip_file(path, dest): ''' Unzip specific file. Path should start with zip:// ''' xbmcvfs.copy(path, dest) LOG.debug("unzip: %s to %s", path, dest)
def xmltv(): load_groups = plugin.get_storage('load_groups') load_channels = {} dialog = xbmcgui.DialogProgressBG() dialog.create("IPTV Recorder", get_string("Loading data...")) profilePath = xbmc.translatePath(plugin.addon.getAddonInfo('profile')) xbmcvfs.mkdirs(profilePath) shifts = {} streams_to_insert = [] for x in ["1", "2"]: dialog.update(0, message=get_string("Finding streams")) mode = plugin.get_setting('external.m3u.' + x, str) if mode == "0": if x == "1": try: m3uPathType = xbmcaddon.Addon('pvr.iptvsimple').getSetting( 'm3uPathType') if m3uPathType == "0": path = xbmcaddon.Addon('pvr.iptvsimple').getSetting( 'm3uPath') else: path = xbmcaddon.Addon('pvr.iptvsimple').getSetting( 'm3uUrl') except: path = "" else: path = "" elif mode == "1": if x == "1": try: m3uPathType = xbmcaddon.Addon( 'pvr.iptvarchive').getSetting('m3uPathType') if m3uPathType == "0": path = xbmcaddon.Addon('pvr.iptvarchive').getSetting( 'm3uPath') else: path = xbmcaddon.Addon('pvr.iptvarchive').getSetting( 'm3uUrl') except: path = "" else: path = "" elif mode == "2": path = plugin.get_setting('external.m3u.file.' + x, str) else: path = plugin.get_setting('external.m3u.url.' + x, str) if path: m3uFile = 'special://profile/addon_data/plugin.video.iptv.archive.downloader/channels' + x + '.m3u' xbmcvfs.copy(path, m3uFile) f = open(xbmc.translatePath(m3uFile), 'rb') data = f.read() data = data.decode('utf8') settings_shift = float( plugin.get_setting('external.m3u.shift.' + x, str)) global_shift = settings_shift header = re.search('#EXTM3U(.*)', data) if header: tvg_shift = re.search('tvg-shift="(.*?)"', header.group(1)) if tvg_shift: tvg_shift = tvg_shift.group(1) if tvg_shift: global_shift = float(tvg_shift) + settings_shift channels = re.findall( '#EXTINF:(.*?)(?:\r\n|\r|\n)(.*?)(?:\r\n|\r|\n|$)', data, flags=(re.I | re.DOTALL)) total = len(channels) i = 0 for channel in channels: name = None if ',' in re.sub('tvg-[a-z]+"[^"]*"', '', channel[0], flags=re.I): name = channel[0].rsplit(',', 1)[-1].strip() name = name.replace('+', '') name = name.replace(':', '') name = name.replace('#', '') #name = name.encode("utf8") tvg_name = re.search('tvg-name="(.*?)"', channel[0], flags=re.I) if tvg_name: tvg_name = tvg_name.group(1) or None #else: #tvg_name = name tvg_id = re.search('tvg-id="(.*?)"', channel[0], flags=re.I) if tvg_id: tvg_id = tvg_id.group(1) or None tvg_logo = re.search('tvg-logo="(.*?)"', channel[0], flags=re.I) if tvg_logo: tvg_logo = tvg_logo.group(1) or None shifts[tvg_id] = global_shift tvg_shift = re.search('tvg-shift="(.*?)"', channel[0], flags=re.I) if tvg_shift: tvg_shift = tvg_shift.group(1) if tvg_shift and tvg_id: shifts[tvg_id] = float(tvg_shift) + settings_shift url = channel[1] search = plugin.get_setting('m3u.regex.search', str) replace = plugin.get_setting('m3u.regex.replace', str) if search: url = re.sub(search, replace, url) groups = re.search('group-title="(.*?)"', channel[0], flags=re.I) if groups: groups = groups.group(1) or None streams_to_insert.append( (name, tvg_name, tvg_id, tvg_logo, groups, url.strip(), i)) i += 1 percent = 0 + int(100.0 * i / total) dialog.update(percent, message=get_string("Finding streams")) ''' missing_streams = conn.execute('SELECT name, tvg_name FROM streams WHERE tvg_id IS null OR tvg_id IS ""').fetchall() sql_channels = conn.execute('SELECT id, name FROM channels').fetchall() lower_channels = {x[1].lower():x[0] for x in sql_channels} for name, tvg_name in missing_streams: if tvg_name: tvg_id = None _tvg_name = tvg_name.replace("_"," ").lower() if _tvg_name in lower_channels: tvg_id = lower_channels[_tvg_name] conn.execute("UPDATE streams SET tvg_id=? WHERE tvg_name=?", (tvg_id, tvg_name)) elif name.lower() in lower_channels: tvg_id = lower_channels[name.lower()] conn.execute("UPDATE streams SET tvg_id=? WHERE name=?", (tvg_id, name)) ''' for _, _, tvg_id, _, groups, _, _ in streams_to_insert: if groups in load_groups: load_channels[tvg_id] = "" dialog.update(0, message=get_string("Creating database")) databasePath = os.path.join(profilePath, 'xmltv.db') conn = sqlite3.connect(databasePath, detect_types=sqlite3.PARSE_DECLTYPES) conn.execute('PRAGMA foreign_keys = ON') conn.row_factory = sqlite3.Row conn.execute('DROP TABLE IF EXISTS streams') conn.execute( 'CREATE TABLE IF NOT EXISTS streams(uid INTEGER PRIMARY KEY ASC, name TEXT, tvg_name TEXT, tvg_id TEXT, tvg_logo TEXT, groups TEXT, url TEXT, tv_number INTEGER)' ) dialog.update(0, message=get_string("Updating database")) conn.executemany( "INSERT OR IGNORE INTO streams(name, tvg_name, tvg_id, tvg_logo, groups, url, tv_number) VALUES (?, ?, ?, ?, ?, ?, ?)", streams_to_insert) conn.commit() conn.close() dialog.update(100, message=get_string("Finished loading data")) time.sleep(1) dialog.close() return
def copy(orgfilename, newfilename): log('FileAccess: copying ' + orgfilename + ' to ' + newfilename) dir, file = os.path.split(newfilename) if not FileAccess.exists(dir): FileAccess.makedirs(dir) return xbmcvfs.copy(orgfilename, newfilename)