示例#1
0
 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
示例#2
0
 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
示例#4
0
    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")
示例#5
0
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
示例#7
0
 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)))
示例#8
0
    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])
示例#9
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
示例#10
0
    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
示例#11
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
示例#12
0
 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()")
示例#14
0
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')
示例#15
0
 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)
示例#16
0
 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()")
示例#18
0
 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
示例#20
0
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
示例#21
0
    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")
示例#22
0
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