def get_skin_constants(): '''gets a list of all skin constants as set in the special xml file''' all_constants = {} all_variables = {} addonpath = xbmc.translatePath(os.path.join("special://skin/", 'addon.xml').encode("utf-8")).decode("utf-8") addon = xmltree.parse(addonpath) extensionpoints = addon.findall("extension") for extensionpoint in extensionpoints: if extensionpoint.attrib.get("point") == "xbmc.gui.skin": resolutions = extensionpoint.findall("res") for resolution in resolutions: includes_file = xbmc.translatePath( os.path.join( "special://skin/", try_decode( resolution.attrib.get("folder")), "script-skin_helper_service-includes.xml").encode("utf-8")).decode('utf-8') if xbmcvfs.exists(includes_file): doc = parse(includes_file) listing = doc.documentElement.getElementsByTagName('constant') # constants for item in listing: name = try_decode(item.attributes['name'].nodeValue) value = try_decode(item.firstChild.nodeValue) all_constants[name] = value # variables listing = doc.documentElement.getElementsByTagName('variable') for item in listing: name = try_decode(item.attributes['name'].nodeValue) value_item = item.getElementsByTagName('value')[0] value = try_decode(value_item.firstChild.nodeValue) all_variables[name] = value return all_constants, all_variables
def get_imdb_id(win, metadatautils): '''get imdbnumber for listitem''' content_type = win.getProperty("contenttype") imdb_id = try_decode(xbmc.getInfoLabel("ListItem.IMDBNumber")) if not imdb_id: imdb_id = try_decode( xbmc.getInfoLabel("ListItem.Property(IMDBNumber)")) if imdb_id and not imdb_id.startswith("tt"): imdb_id = "" if not imdb_id: year = try_decode(xbmc.getInfoLabel("ListItem.Year")) title = try_decode( xbmc.getInfoLabel("ListItem.Title")).split(",")[0].split("(")[0] if content_type in ["episodes", "seasons"]: title = try_decode(xbmc.getInfoLabel("ListItem.TvShowTitle")) if title: log_msg( "Animated Art: lookup imdbid by title and year: (%s - %s)" % (title, year), xbmc.LOGINFO) imdb_id = metadatautils.get_omdb_info("", title, year, content_type).get( "imdbnumber", "") if not imdb_id: return title return imdb_id
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 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 kodiid_from_filename(path, kodi_type): """ Returns kodi_id if we have an item in the Kodi video or audio database with said path. Feed with the Kodi itemtype, e.v. 'movie', 'song' Returns None if not possible """ kodi_id = None path = try_decode(path) try: filename = path.rsplit('/', 1)[1] path = path.rsplit('/', 1)[0] + '/' except IndexError: filename = path.rsplit('\\', 1)[1] path = path.rsplit('\\', 1)[0] + '\\' if kodi_type == v.KODI_TYPE_SONG: with GetKodiDB('music') as kodi_db: try: kodi_id, _ = kodi_db.music_id_from_filename(filename, path) except TypeError: log.debug('No Kodi audio db element found for path %s', path) else: with GetKodiDB('video') as kodi_db: try: kodi_id, _ = kodi_db.video_id_from_filename(filename, path) except TypeError: log.debug('No kodi video db element found for path %s', path) return kodi_id
def restore_cache_directories(): LOG.info("Restoring cache directories...") paths = ("", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "Video", "plex") for path in paths: makedirs(try_decode(translatePath("special://thumbnails/%s" % path)))
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 = try_decode(translatePath("special://thumbnails/")) if exists_dir(path): rmtree(path, ignore_errors=True) self.restoreCacheDirectories() # remove all existing data from texture DB connection = kodi_sql('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 = kodi_sql('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 = kodi_sql('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 list_files_in_path(filespath): '''used for easy matching of studio logos''' all_files = {} dirs, files = xbmcvfs.listdir(filespath) if "/" in filespath: sep = "/" else: sep = "\\" for file in files: file = try_decode(file) name = file.split(".png")[0].lower() all_files[name] = filespath + file for directory in dirs: directory = try_decode(directory) files = xbmcvfs.listdir(os.path.join(filespath, directory) + sep)[1] for file in files: file = try_decode(file) name = directory + "/" + file.split(".png")[0].lower() all_files[name] = filespath + directory + sep + file # return the list return all_files
def get_music_artwork(self, artist, album, track, disc, ignore_cache=False, flush_cache=False, manual=False): """ get music metadata by providing artist and/or album/track returns combined result of artist and album metadata """ if artist == track or album == track: track = "" artists = self.get_all_artists(artist, track) album = self.get_clean_title(album) track = self.get_clean_title(track) # retrieve artist and album details artist_details = self.get_artists_metadata(artists, album, track, ignore_cache=ignore_cache, flush_cache=flush_cache, manual=manual) album_artist = artist_details.get("albumartist", artists[0]) if album or track: album_details = self.get_album_metadata(album_artist, album, track, disc, ignore_cache=ignore_cache, flush_cache=flush_cache, manual=manual) else: album_details = {"art": {}} # combine artist details and album details details = extend_dict(album_details, artist_details) # combine artist plot and album plot as extended plot if artist_details.get("plot") and album_details.get("plot"): details["extendedplot"] = "%s -- %s" % try_decode( (album_details["plot"], artist_details["plot"])) else: details["extendedplot"] = details.get("plot", "") # append track title to results if track: details["title"] = track # return the endresult return details
def list_files_in_path(filespath): """used for easy matching of studio logos""" all_files = {} dirs, files = xbmcvfs.listdir(filespath) if "/" in filespath: sep = "/" else: sep = "\\" for file in files: file = try_decode(file) name = file.split(".png")[0].lower() all_files[name] = filespath + file for directory in dirs: directory = try_decode(directory) files = xbmcvfs.listdir(os.path.join(filespath, directory) + sep)[1] for file in files: file = try_decode(file) name = directory + "/" + file.split(".png")[0].lower() all_files[name] = filespath + directory + sep + file # return the list return all_files
def __repr__(self): """ Print the playlist, e.g. to log. Returns utf-8 encoded string """ answ = u'{\'%s\': {\'id\': %s, ' % (self.__class__.__name__, self.id) # For some reason, can't use dir directly for key in self.__dict__: if key in ('id', 'items', 'kodi_pl'): continue if isinstance(getattr(self, key), str): answ += '\'%s\': \'%s\', ' % (key, try_decode(getattr(self, key))) else: # e.g. int answ += '\'%s\': %s, ' % (key, unicode(getattr(self, key))) return try_encode(answ + '\'items\': %s}}') % self.items
def write_skin_constants(self, constants=None, variables=None): """writes the list of all skin constants""" addonpath = xbmc.translatePath( os.path.join("special://skin/", 'addon.xml').encode("utf-8")).decode("utf-8") addon = xmltree.parse(addonpath) extensionpoints = addon.findall("extension") for extensionpoint in extensionpoints: if extensionpoint.attrib.get("point") == "xbmc.gui.skin": resolutions = extensionpoint.findall("res") for resolution in resolutions: includes_file = xbmc.translatePath( os.path.join( "special://skin/", try_decode(resolution.attrib.get("folder")), "script-skin_helper_service-includes.xml").encode( "utf-8")).decode('utf-8') tree = xmltree.ElementTree(xmltree.Element("includes")) root = tree.getroot() if constants: for key, value in constants.iteritems(): if value: child = xmltree.SubElement(root, "constant") child.text = value child.attrib["name"] = key # also write to skin strings xbmc.executebuiltin("Skin.SetString(%s,%s)" % (key.encode("utf-8"), value.encode("utf-8"))) if variables: for key, value in variables.iteritems(): if value: child = xmltree.SubElement(root, "variable") child.attrib["name"] = key child2 = xmltree.SubElement(child, "value") child2.text = value self.indent_xml(tree.getroot()) xmlstring = xmltree.tostring(tree.getroot(), encoding="utf-8") fileobj = xbmcvfs.File(includes_file, 'w') fileobj.write(xmlstring) fileobj.close() xbmc.executebuiltin("ReloadSkin()")
def reload_pkc(): """ Will reload state.py entirely and then initiate some values from the Kodi settings file """ LOG.info('Start (re-)loading PKC settings') # Reset state.py reload(state) # Reset window props for prop in WINDOW_PROPERTIES: window(prop, clear=True) # Clear video nodes properties VideoNodes().clearProperties() # Initializing state.VERIFY_SSL_CERT = settings('sslverify') == 'true' state.SSL_CERT_PATH = settings('sslcert') \ if settings('sslcert') != 'None' else None state.FULL_SYNC_INTERVALL = int(settings('fullSyncInterval')) * 60 state.SYNC_THREAD_NUMBER = int(settings('syncThreadNumber')) state.SYNC_DIALOG = settings('dbSyncIndicator') == 'true' state.ENABLE_MUSIC = settings('enableMusic') == 'true' state.BACKGROUND_SYNC = settings('enableBackgroundSync') == 'true' state.BACKGROUNDSYNC_SAFTYMARGIN = int( settings('backgroundsync_saftyMargin')) state.REPLACE_SMB_PATH = settings('replaceSMB') == 'true' state.REMAP_PATH = settings('remapSMB') == 'true' state.KODI_PLEX_TIME_OFFSET = float(settings('kodiplextimeoffset')) state.FETCH_PMS_ITEM_NUMBER = settings('fetch_pms_item_number') # Init some Queues() state.COMMAND_PIPELINE_QUEUE = Queue() state.COMPANION_QUEUE = Queue(maxsize=100) state.WEBSOCKET_QUEUE = Queue() set_replace_paths() set_webserver() # To detect Kodi profile switches window('plex_kodiProfile', value=try_decode(translatePath("special://profile"))) getDeviceId() # Initialize the PKC playqueues PQ.init_playqueues() LOG.info('Done (re-)loading PKC settings')
def __repr__(self): """ Print the playlist item, e.g. to log. Returns utf-8 encoded string """ answ = (u'{\'%s\': {\'id\': \'%s\', \'plex_id\': \'%s\', ' % (self.__class__.__name__, self.id, self.plex_id)) for key in self.__dict__: if key in ('id', 'plex_id', 'xml'): continue if isinstance(getattr(self, key), str): answ += '\'%s\': \'%s\', ' % (key, try_decode(getattr(self, key))) else: # e.g. int answ += '\'%s\': %s, ' % (key, unicode(getattr(self, key))) if self.xml is None: answ += '\'xml\': None}}' else: answ += '\'xml\': \'%s\'}}' % self.xml.tag return try_encode(answ)
def deleteCachedArtwork(self, url): # Only necessary to remove and apply a new backdrop or poster connection = kodi_sql('texture') cursor = connection.cursor() try: cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url, )) cachedurl = cursor.fetchone()[0] except TypeError: LOG.info("Could not find cached url.") else: # Delete thumbnail as well as the entry path = translatePath("special://thumbnails/%s" % cachedurl) LOG.debug("Deleting cached thumbnail: %s" % path) if exists(path): rmtree(try_decode(path), ignore_errors=True) cursor.execute("DELETE FROM texture WHERE url = ?", (url, )) connection.commit() finally: connection.close()
def write_skin_constants(self, constants=None, variables=None): """writes the list of all skin constants""" addonpath = xbmc.translatePath(os.path.join("special://skin/", "addon.xml").encode("utf-8")).decode("utf-8") addon = xmltree.parse(addonpath) extensionpoints = addon.findall("extension") for extensionpoint in extensionpoints: if extensionpoint.attrib.get("point") == "xbmc.gui.skin": resolutions = extensionpoint.findall("res") for resolution in resolutions: includes_file = xbmc.translatePath( os.path.join( "special://skin/", try_decode(resolution.attrib.get("folder")), "script-skin_helper_service-includes.xml", ).encode("utf-8") ).decode("utf-8") tree = xmltree.ElementTree(xmltree.Element("includes")) root = tree.getroot() if constants: for key, value in constants.iteritems(): if value: child = xmltree.SubElement(root, "constant") child.text = value child.attrib["name"] = key # also write to skin strings xbmc.executebuiltin( "Skin.SetString(%s,%s)" % (key.encode("utf-8"), value.encode("utf-8")) ) if variables: for key, value in variables.iteritems(): if value: child = xmltree.SubElement(root, "variable") child.attrib["name"] = key child2 = xmltree.SubElement(child, "value") child2.text = value self.indent_xml(tree.getroot()) xmlstring = xmltree.tostring(tree.getroot(), encoding="utf-8") fileobj = xbmcvfs.File(includes_file, "w") fileobj.write(xmlstring) fileobj.close() xbmc.executebuiltin("ReloadSkin()")
def delete_cached_artwork(url): """ Deleted the cached artwork with path url (if it exists) """ connection = kodi_sql('texture') cursor = connection.cursor() try: cursor.execute("SELECT cachedurl FROM texture WHERE url=? LIMIT 1", (url,)) cachedurl = cursor.fetchone()[0] except TypeError: # Could not find cached url pass else: # Delete thumbnail as well as the entry path = translatePath("special://thumbnails/%s" % cachedurl) LOG.debug("Deleting cached thumbnail: %s", path) if exists(path): rmtree(try_decode(path), ignore_errors=True) cursor.execute("DELETE FROM texture WHERE url = ?", (url,)) connection.commit() finally: connection.close()
script.skin.helper.service Contextmenu for Pvr art ''' import os, sys import xbmc import xbmcgui from metadatautils import MetadataUtils from utils import try_decode # pylint: disable-msg=invalid-constant-name # Kodi contextmenu item to configure pvr artwork if __name__ == '__main__': ##### PVR Artwork ######## win = xbmcgui.Window(10000) win.setProperty("SkinHelper.Artwork.ManualLookup", "busy") xbmc.executebuiltin("ActivateWindow(busydialog)") title = try_decode(xbmc.getInfoLabel("ListItem.Title")) if not title: title = try_decode(xbmc.getInfoLabel("ListItem.Label")) channel = try_decode(xbmc.getInfoLabel("ListItem.ChannelName")) genre = try_decode(xbmc.getInfoLabel("ListItem.Genre")) metadatautils = MetadataUtils() metadatautils.pvr_artwork_options(title, channel, genre) xbmc.executebuiltin("Dialog.Close(busydialog)") win.clearProperty("SkinHelper.Artwork.ManualLookup") metadatautils.close() del win
def _plex_gdm(): """ PlexGDM - looks for PMS in the local LAN and returns a list of the PMS found """ # Import here because we might not need to do gdm because we already # connected to a PMS successfully in the past import struct import socket # setup socket for discovery -> multicast message gdm = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) gdm.settimeout(2.0) # Set the time-to-live for messages to 2 for local network ttl = struct.pack('b', 2) gdm.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) return_data = [] try: # Send data to the multicast group gdm.sendto(PLEX_GDM_MSG, (PLEX_GDM_IP, PLEX_GDM_PORT)) # Look for responses from all recipients while True: try: data, server = gdm.recvfrom(1024) return_data.append({'from': server, 'data': data}) except socket.timeout: break except Exception as e: # Probably error: (101, 'Network is unreachable') LOG.error(e) import traceback LOG.error("Traceback:\n%s", traceback.format_exc()) finally: gdm.close() LOG.debug('Plex GDM returned the data: %s', return_data) pms_list = [] for response in return_data: # Check if we had a positive HTTP response if '200 OK' not in response['data']: continue pms = { 'ip': response['from'][0], 'scheme': None, 'local': True, # Since we found it using GDM 'product': None, 'baseURL': None, 'name': None, 'version': None, 'token': None, 'ownername': None, 'device': None, 'platform': None, 'owned': None, 'relay': None, 'presence': True, # Since we're talking to the PMS 'httpsRequired': None, } for line in response['data'].split('\n'): if 'Content-Type:' in line: pms['product'] = try_decode(line.split(':')[1].strip()) elif 'Host:' in line: pms['baseURL'] = line.split(':')[1].strip() elif 'Name:' in line: pms['name'] = try_decode(line.split(':')[1].strip()) elif 'Port:' in line: pms['port'] = line.split(':')[1].strip() elif 'Resource-Identifier:' in line: pms['machineIdentifier'] = line.split(':')[1].strip() elif 'Version:' in line: pms['version'] = line.split(':')[1].strip() pms_list.append(pms) return pms_list
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 = state.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 = try_decode( xbmc.translatePath("special://profile/library/video/")) nodepath = try_decode( 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=try_decode( xbmc.translatePath("special://xbmc/system/library/video")), dst=try_decode( 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(try_encode(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")
import os, sys import xbmc import xbmcgui from metadatautils import MetadataUtils from utils import try_decode import time # pylint: disable-msg=invalid-constant-name # Kodi contextmenu item to configure music artwork if __name__ == '__main__': win = xbmcgui.Window(10000) metadatautils = MetadataUtils() win.setProperty("SkinHelper.Artwork.ManualLookup", "busy") track = try_decode(xbmc.getInfoLabel("ListItem.Title")) album = try_decode(xbmc.getInfoLabel("ListItem.Album")) artist = try_decode(xbmc.getInfoLabel("ListItem.Artist")) disc = try_decode(xbmc.getInfoLabel("ListItem.DiscNumber")) metadatautils.music_artwork_options(artist, album, track, disc) metadatautils.close() # refresh music widgets timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime()) win.setProperty("widgetreload-music", timestr) win.setProperty("widgetreloadmusic", timestr) win.setProperty("widgetreload-albums", timestr) win.setProperty("widgetreload-songs", timestr) win.clearProperty("SkinHelper.Artwork.ManualLookup") del win del metadatautils