def grab_tv_guide(menu_id, menu): xmltv_url = get_xmltv_url(menu_id) Script.log('xmltv url of {}: {}'.format(menu_id, xmltv_url)) xmltv_fn = os.path.basename(urlparse(xmltv_url).path) Script.log('xmltv filename of {}: {}'.format(menu_id, xmltv_fn)) xmltv_fp = os.path.join(Script.get_info('profile'), xmltv_fn) # Remove old xmltv files of this country dirs, files = xbmcvfs.listdir(Script.get_info('profile')) for fn in files: if xmltv_infos[menu_id]['keyword'] in fn and fn != xmltv_fn: Script.log('Remove old xmltv file: {}'.format(fn)) xbmcvfs.delete(os.path.join(Script.get_info('profile'), fn)) # Check if we need to download a fresh xmltv file if not xbmcvfs.exists(xmltv_fp): Script.log("xmltv file of {} for today does not exist, let's download it".format(menu_id)) r = urlquick.get(xmltv_url) with open(xmltv_fp, 'wb') as f: f.write(r.content) # Grab programmes in xmltv file programmes = read_current_programmes(xmltv_fp) # Use the channel as key tv_guide = {} for programme in programmes: programme = programme_post_treatment(programme) tv_guide[programme['channel']] = programme return tv_guide
def migrate_from_pickled_fav(): """ This function moves existing pickled favourites in the new json file used for the favourites. The new format (json) appeared in 0.2.17~beta04 All user with version >= 0.2.17 will use favourites in the JSON format Maybe we can remove the migration check on version 0.2.20? """ # Move all pickled existing favs in json file fav_pickle_fp = os.path.join(Script.get_info('profile'), "favourites.pickle") if xbmcvfs.exists(fav_pickle_fp): Script.log('Start favourites migration from pickle file to json file') new_fav_dict = {} with storage.PersistentDict("favourites.pickle") as db: new_fav_dict = dict(db) # Fix old fav for item_hash, item_dict in new_fav_dict.items(): if 'params' in item_dict and isinstance(item_dict['params'], listing.Params): new_fav_dict[item_hash]['params'] = dict(new_fav_dict[item_hash]['params']) try: del new_fav_dict[item_hash]['params']['item_dict']['params'] except Exception: pass if 'properties' in item_dict: if isinstance(item_dict['properties'], listing.Property): new_fav_dict[item_hash]['properties'] = dict(new_fav_dict[item_hash]['properties']) fav_json_fp = os.path.join(Script.get_info('profile'), "favourites.json") with open(fav_json_fp, 'w') as f: json.dump(new_fav_dict, f, indent=4) xbmcvfs.delete(fav_pickle_fp)
def reset_artwork(): ''' Remove all existing texture. ''' thumbnails = xbmc.translatePath('special://thumbnails/') if xbmcvfs.exists(thumbnails): dirs, ignore = xbmcvfs.listdir(thumbnails) for directory in dirs: ignore, thumbs = xbmcvfs.listdir( os.path.join(thumbnails, directory)) for thumb in thumbs: LOG.debug("DELETE thumbnail %s", thumb) xbmcvfs.delete(os.path.join(thumbnails, directory, thumb)) with Database('texture') as texdb: texdb.cursor.execute( "SELECT tbl_name FROM sqlite_master WHERE type='table'") for table in texdb.cursor.fetchall(): name = table[0] if name != 'version': texdb.cursor.execute("DELETE FROM " + name) LOG.info("[ reset artwork ]")
def get_fav_dict_from_json(): """Get favourites dict from favourites.json Returns: dict: Favourites dict """ def get_fresh_dict(): return { 'items': {}, 'format_version': FAV_FORMAT_VERSION } if not xbmcvfs.exists(FAV_JSON_FP): return get_fresh_dict() try: with open(FAV_JSON_FP) as f: fav_dict = json.load(f) current_fav_format = fav_dict.get('format_version', 0) if current_fav_format < FAV_FORMAT_VERSION: fav_dict = migrate_fav_format(current_fav_format, fav_dict) return fav_dict except Exception: Script.log('Failed to load favourites json data') xbmcvfs.delete(FAV_JSON_FP) return get_fresh_dict()
def _get_database(self): '''get reference to our sqllite _database - performs basic integrity check''' addon = xbmcaddon.Addon(ADDON_ID) dbpath = addon.getAddonInfo('profile') dbfile = xbmc.translatePath("%s/simplecache.db" % dbpath) if not xbmcvfs.exists(dbpath): xbmcvfs.mkdirs(dbpath) del addon try: connection = sqlite3.connect(dbfile, timeout=30, isolation_level=None) connection.execute('SELECT * FROM simplecache LIMIT 1') return connection except Exception as error: # our _database is corrupt or doesn't exist yet, we simply try to recreate it if xbmcvfs.exists(dbfile): xbmcvfs.delete(dbfile) try: connection = sqlite3.connect(dbfile, timeout=30, isolation_level=None) connection.execute("""CREATE TABLE IF NOT EXISTS simplecache( id TEXT UNIQUE, expires INTEGER, data TEXT, checksum INTEGER)""" ) return connection except Exception as error: self._log_msg( "Exception while initializing _database: %s" % str(error), xbmc.LOGWARNING) self.close() return None
def download_xmltv_file(country_id, day_delta=0): """Try to download XMLTV file of country_id for today + day_delta. Args: country_id (str) day_delta (int): 0: Today, 1: Tomorrow,... Returns: str: xmltv filepath. """ # Retrieve URL xmltv_url = get_xmltv_url(country_id, day_delta=day_delta) Script.log('xmltv url of {} country with day_delta {}: {}'.format( country_id, day_delta, xmltv_url)) # Compute dst filepath xmltv_fn = os.path.basename(urlparse(xmltv_url).path) Script.log('xmltv filename: {}'.format(xmltv_fn)) xmltv_fp = os.path.join(Script.get_info('profile'), xmltv_fn) # Remove old xmltv files of this country dirs, files = xbmcvfs.listdir(Script.get_info('profile')) today = datetime.date.today() for fn in files: if xmltv_infos[country_id]['keyword'] not in fn: continue try: file_date_s = fn.split( xmltv_infos[country_id]['keyword'])[1].split('.xml')[0] file_date = datetime_strptime(file_date_s, '%Y%m%d').date() if file_date < today: Script.log('Remove old xmltv file: {}'.format(fn)) xbmcvfs.delete(os.path.join(Script.get_info('profile'), fn)) except Exception: pass # Check if we need to download a fresh xmltv file need_to_downlod_xmltv_file = False if not xbmcvfs.exists(xmltv_fp): Script.log( "xmltv file of {} for today does not exist, let's download it". format(country_id)) need_to_downlod_xmltv_file = True else: # Check if we have the last version of the file current_file_md5 = compute_md5(xmltv_fp) remote_file_md5 = get_remote_xmltv_md5(country_id, day_delta=day_delta) print(current_file_md5) print(remote_file_md5) if current_file_md5 != remote_file_md5: Script.log( "A new version of xmltv file of {} for today exists, let's download it" .format(country_id)) need_to_downlod_xmltv_file = True if need_to_downlod_xmltv_file: r = urlquick.get(xmltv_url, max_age=-1) with open(xmltv_fp, 'wb') as f: f.write(r.content) return xmltv_fp
def delete_favourites(plugin): """ Callback function of 'Delete favourites' setting button """ Script.log('Delete favourites db') xbmcvfs.delete( os.path.join(Script.get_info('profile'), 'favourites.pickle')) Script.notify(Script.localize(30374), '')
def remLoginData(info=True): xbmcvfs.delete(CookieFile) writeConfig('accounts', '') writeConfig('login_name', '') writeConfig('login_pass', '') if info: var.addon.setSetting('login_acc', '') writeConfig('accounts.lst', '') Dialog.notification(pluginname, getString(30211), xbmcgui.NOTIFICATION_INFO)
def remove_widevine(self): """Removes Widevine CDM""" widevinecdm = self._widevine_path() if widevinecdm and xbmcvfs.exists(widevinecdm): log('Remove Widevine CDM at {path}', path=widevinecdm) xbmcvfs.delete(widevinecdm) xbmcgui.Dialog().notification(localize(30037), localize(30052)) # Success! Widevine successfully removed. return True xbmcgui.Dialog().notification(localize(30004), localize(30053)) # Error. Widevine CDM not found. return False
def delete_recursive(path, dirs): ''' Delete files and dirs recursively. ''' for directory in dirs: dirs2, files = xbmcvfs.listdir(os.path.join(path, directory)) for file in files: xbmcvfs.delete(os.path.join(path, directory, file)) delete_recursive(os.path.join(path, directory), dirs2) xbmcvfs.rmdir(os.path.join(path, directory))
def nuke(): if not (xbmcgui.Dialog().yesno("IPTV Archive Downloader", addon.getLocalizedString(30057))): return xbmcvfs.delete( xbmc.translatePath('%sxmltv.db' % plugin.addon.getAddonInfo('profile'))) time.sleep(5) full_service()
def nuke(): if not (xbmcgui.Dialog().yesno( "IPTV Archive Downloader", get_string("Delete Everything and Start Again?"))): return xbmcvfs.delete( xbmc.translatePath('%sxmltv.db' % plugin.addon.getAddonInfo('profile'))) time.sleep(5) full_service()
def clear_cache(plugin): # Callback function of clear cache setting button # Clear urlquick cache urlquick.cache_cleanup(-1) Script.notify(plugin.localize(30371), '') # Remove all tv guides dirs, files = xbmcvfs.listdir(Script.get_info('profile')) for fn in files: if '.xml' in fn and fn != 'settings.xml': Script.log('Remove xmltv file: {}'.format(fn)) xbmcvfs.delete(os.path.join(Script.get_info('profile'), fn))
def writeConfig(cfile, value=''): cfgfile = os.path.join(configpath, cfile) cfglockfile = os.path.join(configpath, cfile + '.lock') if not xbmcvfs.exists(configpath): xbmcvfs.mkdirs(configpath) while True: if not xbmcvfs.exists(cfglockfile): l = xbmcvfs.File(cfglockfile, 'w') l.write(str(time.time())) l.close() if value == '': xbmcvfs.delete(cfgfile) else: f = xbmcvfs.File(cfgfile, 'w') f.write(value.__str__()) f.close() xbmcvfs.delete(cfglockfile) xbmcvfs.delete(cfglockfile) return True else: l = xbmcvfs.File(cfglockfile) modified = l.read() modified = float(modified) if modified else 0 l.close() if time.time() - modified > 0.1: xbmcvfs.delete(cfglockfile)
def ask_to_share_log(): """ Ask the if he wants to share his log directly by mail with a QR code or by sharing the pastebin URL by mail, on github or forum """ r = xbmcgui.Dialog().yesno(Script.localize(LABELS['Information']), Script.localize(30860)) if not r: return if not xbmcvfs.exists(PROFILE): xbmcvfs.mkdirs(PROFILE) succes, data = read_log(LOGFILE) print_error = False error_message = "" if succes: content = clean_log(data) succes, data = post_log(content) if succes: imagefile = os.path.join(xbmc.translatePath(PROFILE), '%s.png' % str(data.split('/')[-1])) message = Script.localize(30861) message = message.replace("URL_TO_REPLACE", data) mail_url = 'mailto:[email protected]?subject=Kodi%20log&body=' + data qrIMG = pyqrcode.create(mail_url) qrIMG.png(imagefile, scale=10) qr = QRCode("script-loguploader-main.xml", CWD, "default", image=imagefile, text=message) qr.doModal() del qr xbmcvfs.delete(imagefile) else: print_error = True error_message = data else: print_error = True error_message = data if print_error: xbmcgui.Dialog().ok(Script.localize(LABELS['Information']), Script.localize(30862) + ': ' + error_message) return
def delete_folder(path): ''' Delete objects from kodi cache ''' LOG.debug("--[ delete folder ]") dirs, files = xbmcvfs.listdir(path) delete_recursive(path, dirs) for file in files: xbmcvfs.delete(os.path.join(path, file)) xbmcvfs.delete(path) LOG.info("DELETE %s", 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 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_fav_dict_from_json(): """Get favourites dict from favourites.json Returns: dict: Favourites dict """ if not xbmcvfs.exists(FAV_JSON_FP): return {} try: with open(FAV_JSON_FP) as f: return json.load(f) except Exception: Script.log('Failed to load favourites json data') xbmcvfs.delete(FAV_JSON_FP) return {}
def deleteLast(self, lastPath): log('deleteLast') #some file systems don't release the file lock instantly. for count in range(3): if self.myMonitor.waitForAbort(1): return try: if xbmcvfs.delete(lastPath): return except: pass
def delete_cache(self, url): ''' Delete cached artwork. ''' from database import Database with Database('texture') as texturedb: try: texturedb.cursor.execute(QUTEX.get_cache, (url,)) cached = texturedb.cursor.fetchone()[0] except TypeError: LOG.debug("Could not find cached url: %s", url) else: thumbnails = xbmc.translatePath("special://thumbnails/%s" % cached) xbmcvfs.delete(thumbnails) texturedb.cursor.execute(QUTEX.delete_cache, (url,)) LOG.info("DELETE cached %s", cached)
def downloadVideo(title, vid): global downloadDir if not downloadDir: xbmcgui.Dialog().notification('Download:', translation(30110), _icon, 5000, False) return url, hstr = getStreamUrl(vid).split('|') if six.PY2: vidfile = xbmc.makeLegalFilename( (downloadDir + title.decode('utf-8') + '.mp4').encode('utf-8')) else: vidfile = xbmcvfs.makeLegalFilename(downloadDir + title + '.mp4') if not xbmcvfs.exists(vidfile): tmp_file = tempfile.mktemp(dir=downloadDir, suffix='.mp4') if six.PY2: tmp_file = xbmc.makeLegalFilename(tmp_file) else: tmp_file = xbmcvfs.makeLegalFilename(tmp_file) pDialog.create('Dailymotion', '{0}[CR]{1}'.format(translation(30044), title)) dfile = requests.get(url, headers=dict(urllib_parse.parse_qsl(hstr)), stream=True) totalsize = float(dfile.headers['content-length']) handle = open(tmp_file, "wb") chunks = 0 for chunk in dfile.iter_content(chunk_size=2097152): if chunk: # filter out keep-alive new chunks handle.write(chunk) chunks += 1 percent = int(float(chunks * 209715200) / totalsize) pDialog.update(percent) if pDialog.iscanceled(): handle.close() xbmcvfs.delete(tmp_file) break handle.close() try: xbmcvfs.rename(tmp_file, vidfile) return vidfile except: return tmp_file else: xbmcgui.Dialog().notification('Download:', translation(30109), _icon, 5000, False)
def deleteFile(self, file): log("deleteFile") for i in range(3): try: if xbmcvfs.delete(file): return True except: pass if self.myMonitor.waitForAbort(1): break if xbmcvfs.exists(file): return False return True
def grab_tv_guide(menu_id): try: xmltv_url = get_xmltv_url(menu_id) Script.log('xmltv url of {}: {}'.format(menu_id, xmltv_url)) xmltv_fn = os.path.basename(urlparse(xmltv_url).path) Script.log('xmltv filename of {}: {}'.format(menu_id, xmltv_fn)) xmltv_fp = os.path.join(Script.get_info('profile'), xmltv_fn) # Remove old xmltv files of this country dirs, files = xbmcvfs.listdir(Script.get_info('profile')) for fn in files: if xmltv_infos[menu_id]['keyword'] in fn and fn != xmltv_fn: Script.log('Remove old xmltv file: {}'.format(fn)) xbmcvfs.delete(os.path.join(Script.get_info('profile'), fn)) # Check if we need to download a fresh xmltv file if not xbmcvfs.exists(xmltv_fp): Script.log( "xmltv file of {} for today does not exist, let's download it". format(menu_id)) r = urlquick.get(xmltv_url) with open(xmltv_fp, 'wb') as f: f.write(r.content) # Grab programmes in xmltv file programmes = read_current_programmes(xmltv_fp) # Use the channel as key tv_guide = {} for programme in programmes: programme = programme_post_treatment(programme) tv_guide[programme['channel']] = programme return tv_guide except Exception as e: Script.notify(Script.localize(LABELS['TV guide']), Script.localize( LABELS['An error occurred while getting TV guide']), display_time=7000) Script.log('xmltv module failed with error: {}'.format( e, lvl=Script.ERROR)) return {}
def get_credentials(): path = xbmc.translatePath( "special://profile/addon_data/plugin.video.jellyfin/") if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) try: with open(os.path.join(path, 'data.json'), 'rb') as infile: credentials = json.load(infile, encoding='utf8') except Exception: try: with open(os.path.join(path, 'data.txt'), 'rb') as infile: credentials = json.load(infile, encoding='utf-8') save_credentials(credentials) xbmcvfs.delete(os.path.join(path, 'data.txt')) except Exception: credentials = {} credentials['Servers'] = credentials.get('Servers', []) # Migration for #145 # TODO: CLEANUP for 1.0.0 release for server in credentials['Servers']: # Functionality removed in #60 if 'RemoteAddress' in server: del server['RemoteAddress'] if 'ManualAddress' in server: server['address'] = server['ManualAddress'] del server['ManualAddress'] # If manual is present, local should always be here, but better to be safe if 'LocalAddress' in server: del server['LocalAddress'] elif 'LocalAddress' in server: server['address'] = server['LocalAddress'] del server['LocalAddress'] if 'LastConnectionMode' in server: del server['LastConnectionMode'] return credentials
def deleleAPK(self, path): count = 0 #some file systems don't release the file lock instantly. while not self.myMonitor.abortRequested() and count < 3: count += 1 if self.myMonitor.waitForAbort(1): return try: if xbmcvfs.delete(path): return except: pass
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 writeConfig(cfile, value): cfgfile = OSPJoin(writeConfig.configPath, cfile) cfglockfile = OSPJoin(writeConfig.configPath, cfile + '.lock') if not xbmcvfs.exists(writeConfig.configPath): xbmcvfs.mkdirs(writeConfig.configPath) while True: if not xbmcvfs.exists(cfglockfile): l = xbmcvfs.File(cfglockfile, 'w') l.write(str(time.time())) l.close() if value == '': xbmcvfs.delete(cfgfile) else: f = xbmcvfs.File(cfgfile, 'w') f.write(value.__str__()) f.close() xbmcvfs.delete(cfglockfile) return True else: try: l = xbmcvfs.File(cfglockfile) modified = float(l.read()) l.close() if time.time() - modified > 0.1: xbmcvfs.delete(cfglockfile) except: pass
def reset(): ''' Reset both the jellyfin database and the kodi database. ''' from views import Views views = Views() if not dialog("yesno", heading="{jellyfin}", line1=translate(33074)): return window('jellyfin_should_stop.bool', True) count = 10 while window('jellyfin_sync.bool'): LOG.info("Sync is running...") count -= 1 if not count: dialog("ok", heading="{jellyfin}", line1=translate(33085)) return if xbmc.Monitor().waitForAbort(1): return reset_kodi() reset_jellyfin() views.delete_playlists() views.delete_nodes() if dialog("yesno", heading="{jellyfin}", line1=translate(33086)): reset_artwork() addon_data = xbmc.translatePath( "special://profile/addon_data/plugin.video.jellyfin/") if dialog("yesno", heading="{jellyfin}", line1=translate(33087)): xbmcvfs.delete(os.path.join(addon_data, "settings.xml")) xbmcvfs.delete(os.path.join(addon_data, "data.json")) LOG.info("[ reset settings ]") if xbmcvfs.exists(os.path.join(addon_data, "sync.json")): xbmcvfs.delete(os.path.join(addon_data, "sync.json")) settings('enableMusic.bool', False) settings('MinimumSetup', "") settings('MusicRescan.bool', False) settings('SyncInstallRunDone.bool', False) dialog("ok", heading="{jellyfin}", line1=translate(33088)) xbmc.executebuiltin('RestartApp')