def singleNode(self, indexnumber, tagname, mediatype, itemtype): tagname = try_encode(tagname) cleantagname = try_decode(normalize_nodes(tagname)) nodepath = try_decode( xbmc.translatePath("special://profile/library/video/")) nodeXML = "%splex_%s.xml" % (nodepath, cleantagname) path = "library://video/plex_%s.xml" % cleantagname if v.KODIVERSION >= 17: # Krypton windowpath = "ActivateWindow(Videos,%s,return)" % path else: windowpath = "ActivateWindow(Video,%s,return)" % path # Create the video node directory if not exists_dir(nodepath): # We need to copy over the default items copytree( src=try_decode( xbmc.translatePath("special://xbmc/system/library/video")), dst=try_decode( xbmc.translatePath("special://profile/library/video"))) labels = { 'Favorite movies': 30180, 'Favorite tvshows': 30181, 'channels': 30173 } label = lang(labels[tagname]) embynode = "Plex.nodes.%s" % indexnumber window('%s.title' % embynode, value=label) window('%s.path' % embynode, value=windowpath) window('%s.content' % embynode, value=path) window('%s.type' % embynode, value=itemtype) if exists(try_encode(nodeXML)): # Don't recreate xml if already exists return if itemtype == "channels": root = self.commonRoot(order=1, label=label, tagname=tagname, roottype=2) etree.SubElement( root, 'path' ).text = "plugin://plugin.video.plexkodiconnect/?id=0&mode=channels" else: root = self.commonRoot(order=1, label=label, tagname=tagname) etree.SubElement(root, 'order', { 'direction': "ascending" }).text = "sorttitle" etree.SubElement(root, 'content').text = mediatype try: indent(root) except: pass etree.ElementTree(root).write(nodeXML, encoding="UTF-8")
def getVideoFiles(plexId, params): """ GET VIDEO EXTRAS FOR LISTITEM returns the video files for the item as plugin listing, can be used for browsing the actual files or videoextras etc. """ if plexId is None: filename = params.get('filename') if filename is not None: filename = filename[0] import re regex = re.compile(r'''library/metadata/(\d+)''') filename = regex.findall(filename) try: plexId = filename[0] except IndexError: pass if plexId is None: log.info('No Plex ID found, abort getting Extras') return xbmcplugin.endOfDirectory(HANDLE) item = GetPlexMetadata(plexId) try: path = item[0][0][0].attrib['file'] except: log.error('Could not get file path for item %s' % plexId) return xbmcplugin.endOfDirectory(HANDLE) # Assign network protocol if path.startswith('\\\\'): path = path.replace('\\\\', 'smb://') path = path.replace('\\', '/') # Plex returns Windows paths as e.g. 'c:\slfkjelf\slfje\file.mkv' elif '\\' in path: path = path.replace('\\', '\\\\') # Directory only, get rid of filename path = path.replace(basename(path), '') if exists_dir(path): for root, dirs, files in walk(path): for directory in dirs: item_path = try_encode(join(root, directory)) li = ListItem(item_path, path=item_path) xbmcplugin.addDirectoryItem(handle=HANDLE, url=item_path, listitem=li, isFolder=True) for file in files: item_path = try_encode(join(root, file)) li = ListItem(item_path, path=item_path) xbmcplugin.addDirectoryItem(handle=HANDLE, url=file, listitem=li) break else: log.error('Kodi cannot access folder %s' % path) xbmcplugin.endOfDirectory(HANDLE)
def fullTextureCacheSync(self): """ This method will sync all Kodi artwork to textures13.db and cache them locally. This takes diskspace! """ if not dialog('yesno', "Image Texture Cache", lang(39250)): return LOG.info("Doing Image Cache Sync") # ask to rest all existing or not if dialog('yesno', "Image Texture Cache", lang(39251)): LOG.info("Resetting all cache data first") # Remove all existing textures first path = tryDecode(translatePath("special://thumbnails/")) if exists_dir(path): rmtree(path, ignore_errors=True) self.restoreCacheDirectories() # remove all existing data from texture DB connection = kodiSQL('texture') cursor = connection.cursor() query = 'SELECT tbl_name FROM sqlite_master WHERE type=?' cursor.execute(query, ('table', )) rows = cursor.fetchall() for row in rows: tableName = row[0] if tableName != "version": cursor.execute("DELETE FROM %s" % tableName) connection.commit() connection.close() # Cache all entries in video DB connection = kodiSQL('video') cursor = connection.cursor() # dont include actors query = "SELECT url FROM art WHERE media_type != ?" cursor.execute(query, ('actor', )) result = cursor.fetchall() total = len(result) LOG.info("Image cache sync about to process %s video images" % total) connection.close() for url in result: self.cacheTexture(url[0]) # Cache all entries in music DB connection = kodiSQL('music') cursor = connection.cursor() cursor.execute("SELECT url FROM art") result = cursor.fetchall() total = len(result) LOG.info("Image cache sync about to process %s music images" % total) connection.close() for url in result: self.cacheTexture(url[0])
def test(): import utils root = '/home/daniel/work/LbnlIon7350Interface/' paths = [downloads, json_dir, creds, meter_file, log_file] for path in paths: p = path(root) if not utils.exists_dir(p) and not utils.exists_file(p): utils.error('Path does not exist: %s' % (p)) else: print('Path exists: %s' % (p))
def getExtraFanArt(plexid, plexPath): """ Get extrafanart for listitem will be called by skinhelper script to get the extrafanart for tvshows we get the plexid just from the path """ log.debug('Called with plexid: %s, plexPath: %s' % (plexid, plexPath)) if not plexid: if "plugin.video.plexkodiconnect" in plexPath: plexid = plexPath.split("/")[-2] if not plexid: log.error('Could not get a plexid, aborting') return xbmcplugin.endOfDirectory(HANDLE) # We need to store the images locally for this to work # because of the caching system in xbmc fanartDir = try_decode(translatePath( "special://thumbnails/plex/%s/" % plexid)) if not exists_dir(fanartDir): # Download the images to the cache directory makedirs(fanartDir) xml = GetPlexMetadata(plexid) if xml is None: log.error('Could not download metadata for %s' % plexid) return xbmcplugin.endOfDirectory(HANDLE) api = API(xml[0]) backdrops = api.artwork()['Backdrop'] for count, backdrop in enumerate(backdrops): # Same ordering as in artwork fanartFile = try_encode(join(fanartDir, "fanart%.3d.jpg" % count)) li = ListItem("%.3d" % count, path=fanartFile) xbmcplugin.addDirectoryItem( handle=HANDLE, url=fanartFile, listitem=li) copyfile(backdrop, try_decode(fanartFile)) else: log.info("Found cached backdrop.") # Use existing cached images for root, dirs, files in walk(fanartDir): for file in files: fanartFile = try_encode(join(root, file)) li = ListItem(file, path=fanartFile) xbmcplugin.addDirectoryItem(handle=HANDLE, url=fanartFile, listitem=li) xbmcplugin.endOfDirectory(HANDLE)
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False): # Plex: reassign mediatype due to Kodi inner workings # How many items do we get at most? limit = window('fetch_pms_item_number') mediatypes = { 'movie': 'movies', 'show': 'tvshows', 'photo': 'photos', 'homevideo': 'homevideos', 'musicvideos': 'musicvideos' } mediatype = mediatypes[mediatype] if viewtype == "mixed": dirname = "%s-%s" % (viewid, mediatype) else: dirname = viewid # Returns strings path = tryDecode(xbmc.translatePath( "special://profile/library/video/")) nodepath = tryDecode(xbmc.translatePath( "special://profile/library/video/Plex-%s/" % dirname)) if delete: if exists_dir(nodepath): from shutil import rmtree rmtree(nodepath) log.info("Sucessfully removed videonode: %s." % tagname) return # Verify the video directory if not exists_dir(path): copytree( src=tryDecode(xbmc.translatePath( "special://xbmc/system/library/video")), dst=tryDecode(xbmc.translatePath( "special://profile/library/video"))) # Create the node directory if mediatype != "photos": if not exists_dir(nodepath): # folder does not exist yet log.debug('Creating folder %s' % nodepath) makedirs(nodepath) # Create index entry nodeXML = "%sindex.xml" % nodepath # Set windows property path = "library://video/Plex-%s/" % dirname for i in range(1, indexnumber): # Verify to make sure we don't create duplicates if window('Plex.nodes.%s.index' % i) == path: return if mediatype == "photos": path = "plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s&id=%s" % (viewid, viewid) window('Plex.nodes.%s.index' % indexnumber, value=path) # Root if not mediatype == "photos": if viewtype == "mixed": specialtag = "%s-%s" % (tagname, mediatype) root = self.commonRoot(order=0, label=specialtag, tagname=tagname, roottype=0) else: root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0) try: indent(root) except: pass etree.ElementTree(root).write(nodeXML, encoding="UTF-8") nodetypes = { '1': "all", '2': "recent", '3': "recentepisodes", '4': "inprogress", '5': "inprogressepisodes", '6': "unwatched", '7': "nextepisodes", '8': "sets", '9': "genres", '10': "random", '11': "recommended", '12': "ondeck", '13': 'browsefiles' } mediatypes = { # label according to nodetype per mediatype 'movies': { '1': tagname, '2': 30174, # '4': 30177, # '6': 30189, '8': 39501, '9': 135, '10': 30227, '11': 30230, '12': 39500, '13': 39702 }, 'tvshows': { '1': tagname, # '2': 30170, '3': 30174, # '4': 30171, # '5': 30178, # '7': 30179, '9': 135, '10': 30227, # '11': 30230, '12': 39500, '13': 39702 }, 'homevideos': { '1': tagname, '2': 30251, '11': 30253, '13': 39702 }, 'photos': { '1': tagname, '2': 30252, '8': 30255, '11': 30254, '13': 39702 }, 'musicvideos': { '1': tagname, '2': 30256, '4': 30257, '6': 30258, '13': 39702 } } # Key: nodetypes, value: sort order in Kodi sortorder = { '1': '3', # "all", '2': '2', # "recent", '3': '2', # "recentepisodes", # '4': # "inprogress", # '5': # "inprogressepisodes", # '6': # "unwatched", # '7': # "nextepisodes", '8': '7', # "sets", '9': '6', # "genres", '10': '8', # "random", '11': '5', # "recommended", '12': '1', # "ondeck" '13': '9' # browse by folder } nodes = mediatypes[mediatype] for node in nodes: nodetype = nodetypes[node] nodeXML = "%s%s_%s.xml" % (nodepath, viewid, nodetype) # Get label stringid = nodes[node] if node != "1": label = lang(stringid) if not label: label = xbmc.getLocalizedString(stringid) else: label = stringid # Set window properties if (mediatype == "homevideos" or mediatype == "photos") and nodetype == "all": # Custom query path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=browseplex&type=%s" % (viewid, mediatype)) elif (mediatype == "homevideos" or mediatype == "photos"): # Custom query path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=browseplex&type=%s&folderid=%s" % (viewid, mediatype, nodetype)) elif nodetype == "nextepisodes": # Custom query path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=nextup&limit=%s" % (tagname, limit) # elif v.KODIVERSION == 14 and nodetype == "recentepisodes": elif nodetype == "recentepisodes": # Custom query path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=recentepisodes&type=%s&tagname=%s&limit=%s" % (viewid, mediatype, tagname, limit)) elif v.KODIVERSION == 14 and nodetype == "inprogressepisodes": # Custom query path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=%s" % (tagname, limit) elif nodetype == 'ondeck': # PLEX custom query if mediatype == "tvshows": path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=ondeck&type=%s&tagname=%s&limit=%s" % (viewid, mediatype, tagname, limit)) elif mediatype =="movies": # Reset nodetype; we got the label nodetype = 'inprogress' elif nodetype == 'browsefiles': path = 'plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s/folder' % viewid else: path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype) if mediatype == "photos": windowpath = "ActivateWindow(Pictures,%s,return)" % path else: if v.KODIVERSION >= 17: # Krypton windowpath = "ActivateWindow(Videos,%s,return)" % path else: windowpath = "ActivateWindow(Video,%s,return)" % path if nodetype == "all": if viewtype == "mixed": templabel = "%s-%s" % (tagname, mediatype) else: templabel = label embynode = "Plex.nodes.%s" % indexnumber window('%s.title' % embynode, value=templabel) window('%s.path' % embynode, value=windowpath) window('%s.content' % embynode, value=path) window('%s.type' % embynode, value=mediatype) else: embynode = "Plex.nodes.%s.%s" % (indexnumber, nodetype) window('%s.title' % embynode, value=label) window('%s.path' % embynode, value=windowpath) window('%s.content' % embynode, value=path) if mediatype == "photos": # For photos, we do not create a node in videos but we do want the window props # to be created. # To do: add our photos nodes to kodi picture sources somehow continue if exists(tryEncode(nodeXML)): # Don't recreate xml if already exists continue # Create the root if (nodetype in ("nextepisodes", "ondeck", 'recentepisodes', 'browsefiles') or mediatype == "homevideos"): # Folder type with plugin path root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname, roottype=2) etree.SubElement(root, 'path').text = path etree.SubElement(root, 'content').text = "episodes" else: root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname) if nodetype in ('recentepisodes', 'inprogressepisodes'): etree.SubElement(root, 'content').text = "episodes" else: etree.SubElement(root, 'content').text = mediatype # Elements per nodetype if nodetype == "all": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle" elif nodetype == "recent": etree.SubElement(root, 'order', {'direction': "descending"}).text = "dateadded" etree.SubElement(root, 'limit').text = limit if settings('MovieShowWatched') == 'false': rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"}) etree.SubElement(rule, 'value').text = "0" elif nodetype == "inprogress": etree.SubElement(root, 'rule', {'field': "inprogress", 'operator': "true"}) etree.SubElement(root, 'limit').text = limit etree.SubElement( root, 'order', {'direction': 'descending'} ).text = 'lastplayed' elif nodetype == "genres": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle" etree.SubElement(root, 'group').text = "genres" elif nodetype == "unwatched": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle" rule = etree.SubElement(root, "rule", {'field': "playcount", 'operator': "is"}) etree.SubElement(rule, 'value').text = "0" elif nodetype == "sets": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle" etree.SubElement(root, 'group').text = "tags" elif nodetype == "random": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "random" etree.SubElement(root, 'limit').text = limit elif nodetype == "recommended": etree.SubElement(root, 'order', {'direction': "descending"}).text = "rating" etree.SubElement(root, 'limit').text = limit rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"}) etree.SubElement(rule, 'value').text = "0" rule2 = etree.SubElement(root, 'rule', attrib={'field': "rating", 'operator': "greaterthan"}) etree.SubElement(rule2, 'value').text = "7" elif nodetype == "recentepisodes": # Kodi Isengard, Jarvis etree.SubElement(root, 'order', {'direction': "descending"}).text = "dateadded" etree.SubElement(root, 'limit').text = limit rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"}) etree.SubElement(rule, 'value').text = "0" elif nodetype == "inprogressepisodes": # Kodi Isengard, Jarvis etree.SubElement(root, 'limit').text = limit rule = etree.SubElement(root, 'rule', attrib={'field': "inprogress", 'operator':"true"}) try: indent(root) except: pass etree.ElementTree(root).write(nodeXML, encoding="UTF-8")
def main(): # user input if not g_args.type: g_args.type = utils.read_string_input(msg="type", init_value=DEFAULT_TEMPLATE) if not g_args.output: g_args.output = utils.read_path_input(msg="file path") g_args.author = utils.read_string_input(msg="author", init_value=g_args.author) if not g_args.description: g_args.description = utils.read_string_input( msg="description", init_value=HEADER_DESCRIPTION) g_args.description = format_description(g_args.description) if g_args.type != "bash": g_args.copy_utils = utils.confirm("Copy utilities?", "y" if g_args.copy_utils else "n") template_path = utils.join_paths_str(g_args.script_dir, TEMPLATE_OPTIONS[g_args.type]) if utils.exists_dir(g_args.output): print(f"Error: target path is a directory!") sys.exit(0) elif utils.exists_file(g_args.output): if not utils.confirm_delete_file(g_args.output, "n"): utils.exit("Aborted") out_folder = utils.get_file_path(g_args.output) out_file = utils.get_file_name(g_args.output) if not utils.exists_dir(out_folder): utils.make_dir(g_args.output) # copy template utils.copy_to(template_path, g_args.output) print(f"Created file {g_args.output}") if g_args.type == "class": utils.replace_file_text(g_args.output, CLASS_NAME, out_file) if g_args.type != "bash": if g_args.copy_utils: utils_folder = PY_UTILS_DIR out_py_utils_dir = utils.join_paths(out_folder, utils_folder) utils.make_dir(out_py_utils_dir) utils.copy_to(PY_UTILS_FILE, out_py_utils_dir) print(f"Created file {out_py_utils_dir}/{PY_UTILS_FILE}") else: print(""" Important: Please make sure that python utils are available, i.e. inside PYTHONPATH. Clone repository via: git clone https://github.com/amplejoe/py_utils.git """) # header information date = utils.get_date_str() utils.replace_file_text(g_args.output, HEADER_DATE, date) utils.replace_file_text(g_args.output, HEADER_AUTHOR, g_args.author) if g_args.description: utils.replace_file_text(g_args.output, HEADER_DESCRIPTION, g_args.description)