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 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 verify_kodi_defaults(): ''' Make sure we have the kodi default folder in place. ''' node_path = xbmc.translatePath("special://profile/library/video") if not os.path.exists(node_path): try: shutil.copytree( src=xbmc.translatePath("special://xbmc/system/library/video"), dst=xbmc.translatePath("special://profile/library/video")) except Exception as error: LOG.warning(error) xbmcvfs.mkdir(node_path) for index, node in enumerate(['movies', 'tvshows', 'musicvideos']): file = os.path.join(node_path, node, "index.xml") if xbmcvfs.exists(file): xml = etree.parse(file).getroot() xml.set('order', str(17 + index)) tree = etree.ElementTree(xml) tree.write(file) playlist_path = xbmc.translatePath("special://profile/playlists/video") if not xbmcvfs.exists(playlist_path): xbmcvfs.mkdirs(playlist_path)
def get_device(): device = None if xbmc.getCondVisibility('system.platform.windows'): device = 'Windows' if xbmc.getCondVisibility('system.platform.linux') \ and not xbmc.getCondVisibility('system.platform.android'): device = 'Linux' if xbmc.getCondVisibility('system.platform.osx'): device = 'Darwin' if xbmc.getCondVisibility('system.platform.android'): device = 'Android' if xbmcvfs.exists('/proc/device-tree/model'): with closing(xbmcvfs.File('/proc/device-tree/model')) as open_file: if 'Raspberry Pi' in open_file.read(): device = 'Raspberry Pi' if xbmcvfs.exists('/etc/os-release'): with closing(xbmcvfs.File('/etc/os-release')) as open_file: contents = open_file.read() if 'libreelec' in contents: device = 'LibreELEC' if 'osmc' in contents: device = 'OSMC' if device is None: try: device = platform.system() except: # pylint: disable=bare-except try: device = platform.platform(terse=True) except: # pylint: disable=bare-except device = sys.platform return device
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 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 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 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 fileExists(self, dest): if xbmcvfs.exists(dest): if not xbmcgui.Dialog().yesno(ADDON_NAME, LANGUAGE(30004), dest.rsplit('/', 1)[-1], nolabel=LANGUAGE(30005), yeslabel=LANGUAGE(30006)): return True elif CLEAN and xbmcvfs.exists(self.lastPath): self.deleleAPK(self.lastPath) return False
def run(self): while not self.myMonitor.abortRequested(): if self.myMonitor.waitForAbort(2): break elif not M3UXMLTV or self.running: continue lastCheck = float(REAL_SETTINGS.getSetting('Last_Scan') or 0) conditions = [xbmcvfs.exists(M3U_FILE),xbmcvfs.exists(XMLTV_FILE)] if (time.time() > (lastCheck + 3600)) or False in conditions: self.running = True if self.myChannels.buildService(): REAL_SETTINGS.setSetting('Last_Scan',str(time.time())) notificationDialog(LANGUAGE(30007)) self.running = False
def __init__(self, *args, **kwargs): super(xbmcgui.WindowXMLDialog, self).__init__() self.action_exitkeys_id = [10, 13] self.win = xbmcgui.Window(10000) self.build_colors_list() self.result = -1 # check paths if xbmcvfs.exists( SKINCOLORFILE) and not xbmcvfs.exists(SKINCOLORFILES_PATH): xbmcvfs.mkdirs(SKINCOLORFILES_PATH) if not xbmcvfs.exists(COLORFILES_PATH): xbmcvfs.mkdirs(COLORFILES_PATH)
def save_merkliste(merkliste, my_ordner): PLog('save_merkliste:') fname = WATCHFILE if SETTINGS.getSetting( 'pref_merkextern') == 'true': # externe Merkliste gewählt? fname = SETTINGS.getSetting('pref_MerkDest_path') if fname == '' or xbmcvfs.exists(fname) == False: PLog("merkextern: %s, %d" % (fname, xbmcvfs.exists(fname))) msg1 = u"Merkliste nicht gefunden\nBitte Settings überprüfen" return False, err_msg PLog(fname) # Merkliste + Ordnerinfo + Ordner: err_msg = '' # gefüllt von Aufrufer if my_ordner == '' or my_ordner == []: # Fallback Basis-Ordner-Liste my_ordner = ORDNER my_ordner = " ".join(my_ordner) ordner_info = "\n".join(ORDNER_INFO) merkliste = "<merkliste>\n%s</merkliste>\n\n%s\n\n<ordnerliste>%s</ordnerliste>\n" %\ (merkliste, ordner_info, my_ordner) try: if '//' not in fname: err_msg = RSave(fname, merkliste, withcodec=True) # Merkliste speichern if err_msg: ret = False else: ret = True else: PLog("xbmcvfs_fname: " + fname) f = xbmcvfs.File(fname, 'w') if PYTHON2: ret = f.write(merkliste) f.close() else: # Python3: Bytearray buf = bytearray() buf.extend(merkliste.encode()) ret = f.write(buf) f.close() PLog("xbmcvfs_ret: " + str(ret)) if ret: sync_list_intern(src_file=fname, dest_file=WATCHFILE) # Synchronisation return ret, err_msg except Exception as exception: ret = False PLog(str(exception)) err_msg = str(exception) return ret, err_msg
def __init__(self, output_path=None, forced=False): self.working_path = ADDON_PROFILE self.output_path = output_path or xbmc.translatePath( settings.get('output_dir', '').strip() or self.working_path) if not xbmcvfs.exists(self.working_path): xbmcvfs.mkdirs(self.working_path) if not xbmcvfs.exists(self.output_path): xbmcvfs.mkdirs(self.output_path) self.forced = forced self.tmp_file = os.path.join(self.working_path, 'iptv_merge_tmp') self._playlist_epgs = []
def _makedirs(path): if len(path) == 0: return False if(xbmcvfs.exists(path)): return True success = xbmcvfs.mkdir(path) if success == False: if path == os.path.dirname(xbmcvfs.translatePath(path)): return False if FileAccess._makedirs(os.path.dirname(xbmcvfs.translatePath(path))): return xbmcvfs.mkdir(path) return xbmcvfs.exists(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 toggle(self, mode): # create profile file if not xbmcvfs.exists(ADDON_PATH_DATA): xbmcvfs.mkdir(ADDON_PATH_DATA) # try read last active profile f = xbmcvfs.File(os.path.join(ADDON_PATH_DATA, 'profile')) try: profile = f.read() except IOError: profile = '' f.close() if profile: if (len(self.aProfile) == 1) or (profile not in self.aProfile): profile = self.aProfile[0] else: ip = int(self.aProfile.index(profile)) if len(self.aProfile) == ip: try: profile = self.aProfile[0] except IndexError: profile = self.aProfile[0] else: try: profile = self.aProfile[ip + 1] except IndexError: profile = self.aProfile[0] else: profile = self.aProfile[0] self.profile(profile)
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 use_up_next(self): upnext_id = 'service.upnext' s_upnext_enabled = self._get_setting('use_up_next', fresh=True) try: _ = xbmcaddon.Addon(upnext_id) has_upnext = True upnext_disabled = False except RuntimeError: addon_xml = xbmc.translatePath('special://home/addons/%s/addon.xml' % upnext_id) if xbmcvfs.exists(addon_xml): # if addon.xml exists, add-on is disabled has_upnext = True upnext_disabled = True else: has_upnext = False upnext_disabled = False if s_upnext_enabled and has_upnext and upnext_disabled: enable_upnext = xbmcgui.Dialog().yesno(self.addon_name, self.settings.getLocalizedString(30688)) if enable_upnext: upnext_disabled = not self.enable_addon(upnext_id) if (not has_upnext or upnext_disabled) and s_upnext_enabled: self._set_setting('use_up_next', False) return False return s_upnext_enabled and has_upnext and not upnext_disabled
def _mnt_path(cls): ''' Return mount path, usually ~/.kodi/userdata/addon_data/tmp/mnt ''' mnt_path = os.path.join(cls._temp_path(), 'mnt') if not xbmcvfs.exists(mnt_path): xbmcvfs.mkdir(mnt_path) return mnt_path
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 download_external_subs(cls, src, filename): ''' Download external subtitles to temp folder to be able to have proper names to streams. ''' temp = xbmc.translatePath( "special://profile/addon_data/plugin.video.jellyfin/temp/") if not xbmcvfs.exists(temp): xbmcvfs.mkdir(temp) path = os.path.join(temp, filename) try: response = requests.get(src, stream=True, verify=False) response.raise_for_status() except Exception as error: LOG.exception(error) raise else: response.encoding = 'utf-8' with open(path, 'wb') as f: f.write(response.content) del response return path
def get_credentials(): if (3, 0) <= sys.version_info < (3, 6): LOG.error("Python versions 3.0-3.5 are NOT supported.") if not xbmcvfs.exists(ADDON_DATA): xbmcvfs.mkdirs(ADDON_DATA) try: with open(os.path.join(ADDON_DATA, 'data.json'), 'rb') as infile: credentials = json.load(infile) except IOError: 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 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 favourites(param): mode = param[param.find("###MODE###=") + 11:] mode = mode[:mode.find("###")] channelEntry = param[param.find("###USER###="):] user = param[11 + param.find("###USER###="):param.find("###THUMB###")] user = user.encode('utf8') if six.PY2 else user if mode == "ADD": if xbmcvfs.exists(channelFavsFile): with open(channelFavsFile, 'r') as fh: content = fh.read() if content.find(channelEntry) == -1: with open(channelFavsFile, 'a') as fh: fh.write(channelEntry + "\n") else: with open(channelFavsFile, 'a') as fh: fh.write(channelEntry + "\n") fh.close() xbmcgui.Dialog().notification( 'Info:', '{0} {1}!'.format(user, translation(30030)), _icon, 5000, False) elif mode == "REMOVE": refresh = param[param.find("###REFRESH###=") + 14:] refresh = refresh[:refresh.find("###USER###=")] with open(channelFavsFile, 'r') as fh: content = fh.read() # entry = content[content.find(channelEntry):] with open(channelFavsFile, 'w') as fh: fh.write(content.replace(channelEntry + "\n", "")) if refresh == "TRUE": xbmc.executebuiltin("Container.Refresh")
def _temp_path(cls): ''' Return temporary path, usually ~/.kodi/userdata/addon_data/tmp ''' temp_path = os.path.join(ADDON_PROFILE, 'tmp') if not xbmcvfs.exists(temp_path): xbmcvfs.mkdir(temp_path) return temp_path
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 get_device_id(reset=False): ''' Return the device_id if already loaded. It will load from jellyfin_guid file. If it's a fresh setup, it will generate a new GUID to uniquely identify the setup for all users. window prop: jellyfin_deviceId ''' client_id = window('jellyfin_deviceId') if client_id: return client_id directory = xbmc.translatePath( 'special://profile/addon_data/plugin.video.jellyfin/') if not xbmcvfs.exists(directory): xbmcvfs.mkdir(directory) jellyfin_guid = os.path.join(directory, "jellyfin_guid") file_guid = xbmcvfs.File(jellyfin_guid) client_id = file_guid.read() if not client_id or reset: LOG.debug("Generating a new GUID.") client_id = str(create_id()) file_guid = xbmcvfs.File(jellyfin_guid, 'w') file_guid.write(client_id) file_guid.close() LOG.debug("DeviceId loaded: %s", client_id) window('jellyfin_deviceId', value=client_id) return client_id
def _widevine_path(cls): ''' Get full widevine path ''' widevine_path = os.path.join(cls._ia_cdm_path(), config.WIDEVINE_CDM_FILENAME[system_os()]) if xbmcvfs.exists(widevine_path): return widevine_path return False
def build_colors_list(self): ''' build the list of colorswatches we want to display, check if skinner overrides the default provided colorsfile and pick the right colorpalette ''' # prefer skin colors file if xbmcvfs.exists(SKINCOLORFILE): colors_file = SKINCOLORFILE self.colors_path = SKINCOLORFILES_PATH else: colors_file = os.path.join(ADDON_PATH, 'resources', 'colors', 'colors.xml') self.colors_path = COLORFILES_PATH doc = parse(colors_file) palette_listing = doc.documentElement.getElementsByTagName('palette') if palette_listing: # we have multiple palettes specified for item in palette_listing: palette_name = item.attributes['name'].nodeValue self.all_colors[palette_name] = self.get_colors_from_xml(item) self.all_palettes.append(palette_name) else: # we do not have multiple palettes self.all_colors["all"] = self.get_colors_from_xml( doc.documentElement) self.all_palettes.append("all")
def selectPath(self, url, bypass=False): log('selectPath, url = ' + str(url)) newURL = url while not self.myMonitor.abortRequested(): items = list(self.buildItems(url)) if len(items) == 0: break elif len(items) == 2 and not bypass and items[0].getLabel().lower( ) == 'parent directory' and not items[1].getLabel().startswith( '.apk'): select = 1 #If one folder bypass selection. else: select = selectDialog( url.replace(BASE_URL, './').replace('//', '/'), items) if select is None: return #return on cancel. label = items[select].getLabel() newURL = items[select].getPath() preURL = url.rsplit('/', 2)[0] + '/' if newURL.endswith('.apk'): if not xbmcvfs.exists(SETTINGS_LOC): xbmcvfs.mkdir(SETTINGS_LOC) dest = xbmc.translatePath(os.path.join(SETTINGS_LOC, label)) self.setLastPath(url, dest) return self.downloadAPK(newURL, dest) elif label.lower( ) == 'parent directory' and "android" in preURL.lower(): return self.selectPath(preURL, True) elif label.lower( ) == 'parent directory' and "android" not in preURL.lower(): return self.selectPath(self.buildMain(), False) url = newURL + '/'
def download_subs(link, referrer, filename): """ Download selected subs :param link: str - a download link for the subs. :param referrer: str - a referer URL for the episode page (required by addic7ed.com). :param filename: str - the name of the video-file being played. The function must add a single ListItem instance with one property: label - the download location for subs. """ # Re-create a download location in a temporary folder if xbmcvfs.exists(temp_dir): shutil.rmtree(temp_dir) xbmcvfs.mkdirs(temp_dir) # Combine a path where to download the subs subspath = os.path.join(temp_dir, filename[:-3] + 'srt') # Download the subs from addic7ed.com try: parser.download_subs(link, referrer, subspath) except Add7ConnectionError: logger.error('Unable to connect to addic7ed.com') dialog.notification(get_ui_string(32002), get_ui_string(32005), 'error') except DailyLimitError: dialog.notification(get_ui_string(32002), get_ui_string(32003), 'error', 3000) logger.error('Exceeded daily limit for subs downloads.') else: # Create a ListItem for downloaded subs and pass it # to the Kodi subtitles engine to move the downloaded subs file # from the temp folder to the designated # location selected by 'Subtitle storage location' option # in 'Settings > Video > Subtitles' section. # A 2-letter language code will be added to subs filename. list_item = xbmcgui.ListItem(label=subspath) xbmcplugin.addDirectoryItem(handle=handle, url=subspath, listitem=list_item, isFolder=False) dialog.notification(get_ui_string(32000), get_ui_string(32001), icon, 3000, False) logger.notice('Subs downloaded.')
def quickPlayer (self,activity): from . import details #print self.nextUrl Audio = False self.wasFullScreen = True windowed = self.settings.XNEWA_LIVE_SKIN if 'playlist' in activity: import os import re dd = {} xbmc.PlayList(0).clear() for playlist in activity['playlist']: nextUrl = re.sub('[^?&]*client[^&]+&*','',playlist['url'].encode('utf-8')) xbmc.log(nextUrl) url = nextUrl.split('=',1)[1] if url[0:2]=='\\\\': url = 'smb:'+ url.replace('\\','/') if xbmcvfs.exists(url) == False: s = self.base + playlist['url'].replace(' ','+').replace('&f=','&mode=http&f=') xbmc.log(s) xbmc.PlayList(0).add(s) else: xbmc.PlayList(0).add(url) dd['movie'] = False dd['playlist'] = xbmc.PlayList(0) windowed = False elif self.nextUrl.startswith('/live?channel'): try: #v5 if self.settings.XNEWA_INTERFACE == 'XML' or self.settings.XNEWA_INTERFACE == 'Version5': url = self.base + '/services?method=channel.listings.current' + self.xnewa.client + '&channel_id=' + str (activity['channel_id']) xbmc.log(url) dd1 = self.xnewa._progs2array_xml(url) else: url = self.base + '/public/GuideService/Listing' + self.xnewa.jsid + '&channelId=' + str (activity['channel_id']) xbmc.log(url) dd1 = self.xnewa._progs2array_json(url) dd = dd1[0]['progs'][0] dd['program_oid'] = dd['oid'] #dd['season'] = 0 except Exception as err: print(err) dd = {} dd['program_oid'] = 12346 dd['title'] = activity['channel_name'] dd['subtitle'] = str(activity['channel_number']) dd['end'] = '' dd['season'] = 0 dd['desc'] = '' dd['channel_oid'] = activity['channel_id'] channel = {} channel[0] = activity['channel_name'] channel[1] = activity['channel_number'] channel[2] = '0' self.prev_channel = self.channel_number self.channel_number = activity['channel_number'] dd['channel'] = channel dd['bookmarkSecs'] = 0 dd['movie'] = False elif self.nextUrl.startswith('/stream?'): dd = {} dd['title'] = 'title' dd['movie'] = False dd['filename'] = py2_decode(self.nextUrl.split('=',1)[1]).replace('http://plugin','plugin') dd['season'] = 0 if 'duration' in activity: dd['library_duration'] = activity['duration'] else: import re m = re.search('.*_(\d{2})(\d{2})(\d{2})(\d{2})(-\d)\.ts', dd['filename']) if m: start = int(m.group(1)) * 60 + int(m.group(2)) end = int(m.group(3)) * 60 + int(m.group(4)) #print start #print end if start > end: dd['library_duration'] = (start + end - 1440) * 60 else: dd['library_duration'] = (end - start) * 60 dd['filename'] = dd['filename'].replace('127.0.0.1',self.xnewa.ip) #self.getPlaybackPosition(dd['filename']) dd['nextUrl'] = self.nextUrl if 'recording_description' in activity: dd['desc'] = activity['recording_description'] elif 'description' in activity: dd['desc'] = activity['description'] else: dd['desc'] = '' if 'recording_title' in activity: dd['title'] = activity['recording_title'] elif dd['filename'].startswith('http:'): if '.m3u8' not in dd['filename']: Audio = True elif 'title' in activity: dd['title'] = activity['title'] if 'recording_subtitle' in activity: dd['subtitle'] = activity['recording_subtitle'] elif 'subtitle' in activity: dd['subtitle'] = activity['subtitle'] else: dd['subtitle'] = None if 'recording_resume' in activity: dd['bookmarkSecs'] = activity['recording_resume'] dd['resume'] = activity['recording_resume'] else: dd['bookmarkSecs'] = 0 if 'album' in activity: Audio = True if 'recording_id' in activity: dd['recording_oid'] = activity['recording_id'] dd['nextUrl'] = '/live?recording=' + dd['recording_oid'] if self.settings.NextPVR_ICON_DL == 'Yes' and self.xnewa.getShowIcon(dd['title']) is None: self.xnewa.getDetails(self.settings.NextPVR_USER,self.settings.NextPVR_PW,dd['recording_oid'],'R','Yes') else: dd['recording_oid'] = 0 if 'Genres' in activity: dd['genres'] = activity['Genres'] for genre in dd['Genres']: if genre == "Movie" or genre == "Movies" or genre == "Film": dd['movie'] = True break detailDialog = details.DetailDialog("nextpvr_recording_details.xml", WHERE_AM_I,self.settings.XNEWA_SKIN, xnewa=self.xnewa, settings=self.settings, oid=123, epg=True, type="R") xbmc.log(str(windowed)) if self.sdlmode == SDL.disabled: self.setOSDMode(False) windowed = False if isinstance(self.t1, Thread): xbmc.Player().stop() while self.t1.is_alive(): xbmc.sleep(100) self.renderstop = False self.t1 = Thread(target=detailDialog._myPlayer, args=(dd,None,windowed,Audio,False)) self.t1.start() self.state = videoState.started #xbmc.executebuiltin('XBMC.ActivateWindow(25)') #self.player = detailDialog.getPlayer() #self.player.overlay = self #xbmc.executebuiltin('ActivateWindow(visualisation)') #xbmc.executebuiltin('ActivateWindow(musicosd)') return