示例#1
0
class KodiMonitor(Monitor):
    def __init__(self, callback):
        self.mgr = callback
        self.doUtils = DownloadUtils().downloadUrl
        self.xbmcplayer = Player()
        self.playqueue = self.mgr.playqueue
        Monitor.__init__(self)
        log.info("Kodi monitor started.")

    def onScanStarted(self, library):
        log.debug("Kodi library scan %s running." % library)
        if library == "video":
            window('plex_kodiScan', value="true")

    def onScanFinished(self, library):
        log.debug("Kodi library scan %s finished." % library)
        if library == "video":
            window('plex_kodiScan', clear=True)

    def onSettingsChanged(self):
        """
        Monitor the PKC settings for changes made by the user
        """
        log.debug('PKC settings change detected')
        changed = False
        # Reset the window variables from the settings variables
        for settings_value, window_value in WINDOW_SETTINGS.iteritems():
            if window(window_value) != settings(settings_value):
                changed = True
                log.debug('PKC window settings changed: %s is now %s' %
                          (settings_value, settings(settings_value)))
                window(window_value, value=settings(settings_value))
                if settings_value == 'fetch_pms_item_number':
                    log.info('Requesting playlist/nodes refresh')
                    plex_command('RUN_LIB_SCAN', 'views')
        # Reset the state variables in state.py
        for settings_value, state_name in STATE_SETTINGS.iteritems():
            new = settings(settings_value)
            if new == 'true':
                new = True
            elif new == 'false':
                new = False
            if getattr(state, state_name) != new:
                changed = True
                log.debug('PKC state settings %s changed from %s to %s' %
                          (settings_value, getattr(state, state_name), new))
                setattr(state, state_name, new)
        # Special cases, overwrite all internal settings
        state.FULL_SYNC_INTERVALL = int(settings('fullSyncInterval')) * 60
        state.BACKGROUNDSYNC_SAFTYMARGIN = int(
            settings('backgroundsync_saftyMargin'))
        state.SYNC_THREAD_NUMBER = int(settings('syncThreadNumber'))
        # Never set through the user
        # state.KODI_PLEX_TIME_OFFSET = float(settings('kodiplextimeoffset'))
        if changed is True:
            # Assume that the user changed the settings so that we can now find
            # the path to all media files
            state.STOP_SYNC = False
            state.PATH_VERIFIED = False

    @CatchExceptions(warnuser=False)
    def onNotification(self, sender, method, data):

        if data:
            data = loads(data, 'utf-8')
            log.debug("Method: %s Data: %s" % (method, data))

        if method == "Player.OnPlay":
            self.PlayBackStart(data)

        elif method == "Player.OnStop":
            # Should refresh our video nodes, e.g. on deck
            # xbmc.executebuiltin('ReloadSkin()')
            pass

        elif method == "VideoLibrary.OnUpdate":
            # Manually marking as watched/unwatched
            playcount = data.get('playcount')
            item = data.get('item')

            try:
                kodiid = item['id']
                item_type = item['type']
            except (KeyError, TypeError):
                log.info("Item is invalid for playstate update.")
            else:
                # Send notification to the server.
                with plexdb.Get_Plex_DB() as plexcur:
                    plex_dbitem = plexcur.getItem_byKodiId(kodiid, item_type)
                try:
                    itemid = plex_dbitem[0]
                except TypeError:
                    log.error("Could not find itemid in plex database for a "
                              "video library update")
                else:
                    # Stop from manually marking as watched unwatched, with
                    # actual playback.
                    if window('plex_skipWatched%s' % itemid) == "true":
                        # property is set in player.py
                        window('plex_skipWatched%s' % itemid, clear=True)
                    else:
                        # notify the server
                        if playcount > 0:
                            scrobble(itemid, 'watched')
                        else:
                            scrobble(itemid, 'unwatched')

        elif method == "VideoLibrary.OnRemove":
            pass

        elif method == "System.OnSleep":
            # Connection is going to sleep
            log.info("Marking the server as offline. SystemOnSleep activated.")
            window('plex_online', value="sleep")

        elif method == "System.OnWake":
            # Allow network to wake up
            sleep(10000)
            window('plex_onWake', value="true")
            window('plex_online', value="false")

        elif method == "GUI.OnScreensaverDeactivated":
            if settings('dbSyncScreensaver') == "true":
                sleep(5000)
                plex_command('RUN_LIB_SCAN', 'full')

        elif method == "System.OnQuit":
            log.info('Kodi OnQuit detected - shutting down')
            state.STOP_PKC = True

    def PlayBackStart(self, data):
        """
        Called whenever a playback is started
        """
        # Get currently playing file - can take a while. Will be utf-8!
        try:
            currentFile = self.xbmcplayer.getPlayingFile()
        except:
            currentFile = None
            count = 0
            while currentFile is None:
                sleep(100)
                try:
                    currentFile = self.xbmcplayer.getPlayingFile()
                except:
                    pass
                if count == 50:
                    log.info("No current File, cancel OnPlayBackStart...")
                    return
                else:
                    count += 1
        # Just to be on the safe side
        currentFile = tryDecode(currentFile)
        log.debug("Currently playing file is: %s" % currentFile)

        # Get the type of media we're playing
        try:
            typus = data['item']['type']
        except (TypeError, KeyError):
            log.info("Item is invalid for PMS playstate update.")
            return
        log.debug("Playing itemtype is (or appears to be): %s" % typus)

        # Try to get a Kodi ID
        # If PKC was used - native paths, not direct paths
        plex_id = window('plex_%s.itemid' % tryEncode(currentFile))
        # Get rid of the '' if the window property was not set
        plex_id = None if not plex_id else plex_id
        kodiid = None
        if plex_id is None:
            log.debug('Did not get Plex id from window properties')
            try:
                kodiid = data['item']['id']
            except (TypeError, KeyError):
                log.debug('Did not get a Kodi id from Kodi, darn')
        # For direct paths, if we're not streaming something
        # When using Widgets, Kodi doesn't tell us shit so we need this hack
        if (kodiid is None and plex_id is None and typus != 'song'
                and not currentFile.startswith('http')):
            (kodiid, typus) = get_kodiid_from_filename(currentFile)
            if kodiid is None:
                return

        if plex_id is None:
            # Get Plex' item id
            with plexdb.Get_Plex_DB() as plexcursor:
                plex_dbitem = plexcursor.getItem_byKodiId(kodiid, typus)
            try:
                plex_id = plex_dbitem[0]
            except TypeError:
                log.info("No Plex id returned for kodiid %s. Aborting playback"
                         " report" % kodiid)
                return
        log.debug("Found Plex id %s for Kodi id %s for type %s" %
                  (plex_id, kodiid, typus))

        # Switch subtitle tracks if applicable
        subtitle = window('plex_%s.subtitle' % tryEncode(currentFile))
        if window(tryEncode('plex_%s.playmethod' % currentFile)) \
                == 'Transcode' and subtitle:
            if window('plex_%s.subtitle' % currentFile) == 'None':
                self.xbmcplayer.showSubtitles(False)
            else:
                self.xbmcplayer.setSubtitleStream(int(subtitle))

        # Set some stuff if Kodi initiated playback
        if ((settings('useDirectPaths') == "1" and not typus == "song")
                or (typus == "song" and settings('enableMusic') == "true")):
            if self.StartDirectPath(plex_id, typus,
                                    tryEncode(currentFile)) is False:
                log.error('Could not initiate monitoring; aborting')
                return

        # Save currentFile for cleanup later and to be able to access refs
        window('plex_lastPlayedFiled', value=currentFile)
        window('plex_currently_playing_itemid', value=plex_id)
        window("plex_%s.itemid" % tryEncode(currentFile), value=plex_id)
        log.info('Finish playback startup')

    def StartDirectPath(self, plex_id, type, currentFile):
        """
        Set some additional stuff if playback was initiated by Kodi, not PKC
        """
        xml = self.doUtils('{server}/library/metadata/%s' % plex_id)
        try:
            xml[0].attrib
        except:
            log.error('Did not receive a valid XML for plex_id %s.' % plex_id)
            return False
        # Setup stuff, because playback was started by Kodi, not PKC
        api = API(xml[0])
        listitem = api.CreateListItemFromPlexItem()
        api.set_playback_win_props(currentFile, listitem)
        if type == "song" and settings('streamMusic') == "true":
            window('plex_%s.playmethod' % currentFile, value="DirectStream")
        else:
            window('plex_%s.playmethod' % currentFile, value="DirectPlay")
        log.debug('Window properties set for direct paths!')
class PlexCompanion(Thread):
    """
    Plex Companion monitoring class. Invoke only once
    """
    def __init__(self):
        LOG.info("----===## Starting PlexCompanion ##===----")
        # Init Plex Companion queue
        # Start GDM for server/client discovery
        self.client = plexgdm.plexgdm()
        self.client.clientDetails()
        LOG.debug("Registration string is:\n%s",
                  self.client.getClientDetails())
        # kodi player instance
        self.player = Player()
        self.httpd = False
        self.subscription_manager = None
        Thread.__init__(self)

    def _process_alexa(self, data):
        xml = PF.GetPlexMetadata(data['key'])
        try:
            xml[0].attrib
        except (AttributeError, IndexError, TypeError):
            LOG.error('Could not download Plex metadata for: %s', data)
            return
        api = API(xml[0])
        if api.plex_type() == v.PLEX_TYPE_ALBUM:
            LOG.debug('Plex music album detected')
            PQ.init_playqueue_from_plex_children(
                api.plex_id(), transient_token=data.get('token'))
        elif data['containerKey'].startswith('/playQueues/'):
            _, container_key, _ = PF.ParseContainerKey(data['containerKey'])
            xml = PF.DownloadChunks('{server}/playQueues/%s?' % container_key)
            if xml is None:
                # "Play error"
                utils.dialog('notification',
                             utils.lang(29999),
                             utils.lang(30128),
                             icon='{error}')
                return
            playqueue = PQ.get_playqueue_from_type(
                v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
            playqueue.clear()
            PL.get_playlist_details_from_xml(playqueue, xml)
            playqueue.plex_transient_token = data.get('token')
            if data.get('offset') != '0':
                offset = float(data['offset']) / 1000.0
            else:
                offset = None
            playback.play_xml(playqueue, xml, offset)
        else:
            state.PLEX_TRANSIENT_TOKEN = data.get('token')
            if data.get('offset') != '0':
                state.RESUMABLE = True
                state.RESUME_PLAYBACK = True
            playback.playback_triage(api.plex_id(),
                                     api.plex_type(),
                                     resolve=False)

    @staticmethod
    def _process_node(data):
        """
        E.g. watch later initiated by Companion. Basically navigating Plex
        """
        state.PLEX_TRANSIENT_TOKEN = data.get('key')
        params = {
            'mode': 'plex_node',
            'key': '{server}%s' % data.get('key'),
            'offset': data.get('offset')
        }
        executebuiltin('RunPlugin(plugin://%s?%s)' %
                       (v.ADDON_ID, urlencode(params)))

    def _process_playlist(self, data):
        # Get the playqueue ID
        _, container_key, query = PF.ParseContainerKey(data['containerKey'])
        try:
            playqueue = PQ.get_playqueue_from_type(
                v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
        except KeyError:
            # E.g. Plex web does not supply the media type
            # Still need to figure out the type (video vs. music vs. pix)
            xml = PF.GetPlexMetadata(data['key'])
            try:
                xml[0].attrib
            except (AttributeError, IndexError, TypeError):
                LOG.error('Could not download Plex metadata')
                return
            api = API(xml[0])
            playqueue = PQ.get_playqueue_from_type(
                v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
        update_playqueue_from_PMS(playqueue,
                                  playqueue_id=container_key,
                                  repeat=query.get('repeat'),
                                  offset=data.get('offset'),
                                  transient_token=data.get('token'))

    def _process_streams(self, data):
        """
        Plex Companion client adjusted audio or subtitle stream
        """
        playqueue = PQ.get_playqueue_from_type(
            v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
        pos = js.get_position(playqueue.playlistid)
        if 'audioStreamID' in data:
            index = playqueue.items[pos].kodi_stream_index(
                data['audioStreamID'], 'audio')
            self.player.setAudioStream(index)
        elif 'subtitleStreamID' in data:
            if data['subtitleStreamID'] == '0':
                self.player.showSubtitles(False)
            else:
                index = playqueue.items[pos].kodi_stream_index(
                    data['subtitleStreamID'], 'subtitle')
                self.player.setSubtitleStream(index)
        else:
            LOG.error('Unknown setStreams command: %s', data)

    def _process_refresh(self, data):
        """
        example data: {'playQueueID': '8475', 'commandID': '11'}
        """
        xml = PL.get_pms_playqueue(data['playQueueID'])
        if xml is None:
            return
        if len(xml) == 0:
            LOG.debug('Empty playqueue received - clearing playqueue')
            plex_type = PL.get_plextype_from_xml(xml)
            if plex_type is None:
                return
            playqueue = PQ.get_playqueue_from_type(
                v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
            playqueue.clear()
            return
        playqueue = PQ.get_playqueue_from_type(
            v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
        update_playqueue_from_PMS(playqueue, data['playQueueID'])

    def _process_tasks(self, task):
        """
        Processes tasks picked up e.g. by Companion listener, e.g.
        {'action': 'playlist',
         'data': {'address': 'xyz.plex.direct',
                  'commandID': '7',
                  'containerKey': '/playQueues/6669?own=1&repeat=0&window=200',
                  'key': '/library/metadata/220493',
                  'machineIdentifier': 'xyz',
                  'offset': '0',
                  'port': '32400',
                  'protocol': 'https',
                  'token': 'transient-cd2527d1-0484-48e0-a5f7-f5caa7d591bd',
                  'type': 'video'}}
        """
        LOG.debug('Processing: %s', task)
        data = task['data']
        if task['action'] == 'alexa':
            with state.LOCK_PLAYQUEUES:
                self._process_alexa(data)
        elif (task['action'] == 'playlist'
              and data.get('address') == 'node.plexapp.com'):
            self._process_node(data)
        elif task['action'] == 'playlist':
            with state.LOCK_PLAYQUEUES:
                self._process_playlist(data)
        elif task['action'] == 'refreshPlayQueue':
            with state.LOCK_PLAYQUEUES:
                self._process_refresh(data)
        elif task['action'] == 'setStreams':
            try:
                self._process_streams(data)
            except KeyError:
                pass

    def run(self):
        """
        Ensure that sockets will be closed no matter what
        """
        try:
            self._run()
        finally:
            try:
                self.httpd.socket.shutdown(SHUT_RDWR)
            except AttributeError:
                pass
            finally:
                try:
                    self.httpd.socket.close()
                except AttributeError:
                    pass
        LOG.info("----===## Plex Companion stopped ##===----")

    def _run(self):
        httpd = self.httpd
        # Cache for quicker while loops
        client = self.client
        stopped = self.stopped
        suspended = self.suspended

        # Start up instances
        request_mgr = httppersist.RequestMgr()
        subscription_manager = subscribers.SubscriptionMgr(
            request_mgr, self.player)
        self.subscription_manager = subscription_manager

        if utils.settings('plexCompanion') == 'true':
            # Start up httpd
            start_count = 0
            while True:
                try:
                    httpd = listener.ThreadedHTTPServer(
                        client, subscription_manager, ('', v.COMPANION_PORT),
                        listener.MyHandler)
                    httpd.timeout = 0.95
                    break
                except:
                    LOG.error("Unable to start PlexCompanion. Traceback:")
                    import traceback
                    LOG.error(traceback.print_exc())
                sleep(3000)
                if start_count == 3:
                    LOG.error("Error: Unable to start web helper.")
                    httpd = False
                    break
                start_count += 1
        else:
            LOG.info('User deactivated Plex Companion')
        client.start_all()
        message_count = 0
        if httpd:
            thread = Thread(target=httpd.handle_request)

        while not stopped():
            # If we are not authorized, sleep
            # Otherwise, we trigger a download which leads to a
            # re-authorizations
            while suspended():
                if stopped():
                    break
                sleep(1000)
            try:
                message_count += 1
                if httpd:
                    if not thread.isAlive():
                        # Use threads cause the method will stall
                        thread = Thread(target=httpd.handle_request)
                        thread.start()

                    if message_count == 3000:
                        message_count = 0
                        if client.check_client_registration():
                            LOG.debug('Client is still registered')
                        else:
                            LOG.debug(
                                'Client is no longer registered. Plex '
                                'Companion still running on port %s',
                                v.COMPANION_PORT)
                            client.register_as_client()
                # Get and set servers
                if message_count % 30 == 0:
                    subscription_manager.serverlist = client.getServerList()
                    subscription_manager.notify()
                    if not httpd:
                        message_count = 0
            except:
                LOG.warn("Error in loop, continuing anyway. Traceback:")
                import traceback
                LOG.warn(traceback.format_exc())
            # See if there's anything we need to process
            try:
                task = state.COMPANION_QUEUE.get(block=False)
            except Empty:
                pass
            else:
                # Got instructions, process them
                self._process_tasks(task)
                state.COMPANION_QUEUE.task_done()
                # Don't sleep
                continue
            sleep(50)
        subscription_manager.signal_stop()
        client.stop_all()
示例#3
0
class KodiMonitor(Monitor):

    def __init__(self, callback):
        self.mgr = callback
        self.doUtils = downloadutils.DownloadUtils().downloadUrl
        self.xbmcplayer = Player()
        self.playqueue = self.mgr.playqueue
        Monitor.__init__(self)
        log.info("Kodi monitor started.")

    def onScanStarted(self, library):
        log.debug("Kodi library scan %s running." % library)
        if library == "video":
            window('plex_kodiScan', value="true")

    def onScanFinished(self, library):
        log.debug("Kodi library scan %s finished." % library)
        if library == "video":
            window('plex_kodiScan', clear=True)

    def onSettingsChanged(self):
        """
        Monitor the PKC settings for changes made by the user
        """
        # settings: window-variable
        items = {
            'logLevel': 'plex_logLevel',
            'enableContext': 'plex_context',
            'plex_restricteduser': '******',
            'dbSyncIndicator': 'dbSyncIndicator',
            'remapSMB': 'remapSMB',
            'replaceSMB': 'replaceSMB',
            'force_transcode_pix': 'plex_force_transcode_pix',
            'fetch_pms_item_number': 'fetch_pms_item_number'
        }
        # Path replacement
        for typus in REMAP_TYPE_FROM_PLEXTYPE.values():
            for arg in ('Org', 'New'):
                key = 'remapSMB%s%s' % (typus, arg)
                items[key] = key
        # Reset the window variables from the settings variables
        for settings_value, window_value in items.iteritems():
            if window(window_value) != settings(settings_value):
                log.debug('PKC settings changed: %s is now %s'
                          % (settings_value, settings(settings_value)))
                window(window_value, value=settings(settings_value))
                if settings_value == 'fetch_pms_item_number':
                    log.info('Requesting playlist/nodes refresh')
                    window('plex_runLibScan', value="views")

    @CatchExceptions(warnuser=False)
    def onNotification(self, sender, method, data):

        if data:
            data = loads(data, 'utf-8')
            log.debug("Method: %s Data: %s" % (method, data))

        if method == "Player.OnPlay":
            self.PlayBackStart(data)

        elif method == "Player.OnStop":
            # Should refresh our video nodes, e.g. on deck
            # xbmc.executebuiltin('ReloadSkin()')
            pass

        elif method == "VideoLibrary.OnUpdate":
            # Manually marking as watched/unwatched
            playcount = data.get('playcount')
            item = data.get('item')
            try:
                kodiid = item['id']
                item_type = item['type']
            except (KeyError, TypeError):
                log.info("Item is invalid for playstate update.")
            else:
                # Send notification to the server.
                with plexdb.Get_Plex_DB() as plexcur:
                    plex_dbitem = plexcur.getItem_byKodiId(kodiid, item_type)
                try:
                    itemid = plex_dbitem[0]
                except TypeError:
                    log.error("Could not find itemid in plex database for a "
                              "video library update")
                else:
                    # Stop from manually marking as watched unwatched, with
                    # actual playback.
                    if window('plex_skipWatched%s' % itemid) == "true":
                        # property is set in player.py
                        window('plex_skipWatched%s' % itemid, clear=True)
                    else:
                        # notify the server
                        if playcount != 0:
                            scrobble(itemid, 'watched')
                        else:
                            scrobble(itemid, 'unwatched')

        elif method == "VideoLibrary.OnRemove":
            pass

        elif method == "System.OnSleep":
            # Connection is going to sleep
            log.info("Marking the server as offline. SystemOnSleep activated.")
            window('plex_online', value="sleep")

        elif method == "System.OnWake":
            # Allow network to wake up
            sleep(10000)
            window('plex_onWake', value="true")
            window('plex_online', value="false")

        elif method == "GUI.OnScreensaverDeactivated":
            if settings('dbSyncScreensaver') == "true":
                sleep(5000)
                window('plex_runLibScan', value="full")

    def PlayBackStart(self, data):
        """
        Called whenever a playback is started
        """
        # Get currently playing file - can take a while. Will be utf-8!
        try:
            currentFile = self.xbmcplayer.getPlayingFile()
        except:
            currentFile = None
            count = 0
            while currentFile is None:
                sleep(100)
                try:
                    currentFile = self.xbmcplayer.getPlayingFile()
                except:
                    pass
                if count == 50:
                    log.info("No current File, cancel OnPlayBackStart...")
                    return
                else:
                    count += 1
        # Just to be on the safe side
        currentFile = tryDecode(currentFile)
        log.debug("Currently playing file is: %s" % currentFile)

        # Get the type of media we're playing
        try:
            typus = data['item']['type']
        except (TypeError, KeyError):
            log.info("Item is invalid for PMS playstate update.")
            return
        log.debug("Playing itemtype is (or appears to be): %s" % typus)

        # Try to get a Kodi ID
        # If PKC was used - native paths, not direct paths
        plex_id = window('plex_%s.itemid' % tryEncode(currentFile))
        # Get rid of the '' if the window property was not set
        plex_id = None if not plex_id else plex_id
        kodiid = None
        if plex_id is None:
            log.debug('Did not get Plex id from window properties')
            try:
                kodiid = data['item']['id']
            except (TypeError, KeyError):
                log.debug('Did not get a Kodi id from Kodi, darn')
        # For direct paths, if we're not streaming something
        # When using Widgets, Kodi doesn't tell us shit so we need this hack
        if (kodiid is None and plex_id is None and typus != 'song'
                and not currentFile.startswith('http')):
            (kodiid, typus) = get_kodiid_from_filename(currentFile)
            if kodiid is None:
                return

        if plex_id is None:
            # Get Plex' item id
            with plexdb.Get_Plex_DB() as plexcursor:
                plex_dbitem = plexcursor.getItem_byKodiId(kodiid, typus)
            try:
                plex_id = plex_dbitem[0]
            except TypeError:
                log.info("No Plex id returned for kodiid %s. Aborting playback"
                         " report" % kodiid)
                return
        log.debug("Found Plex id %s for Kodi id %s for type %s"
                  % (plex_id, kodiid, typus))

        # Switch subtitle tracks if applicable
        subtitle = window('plex_%s.subtitle' % tryEncode(currentFile))
        if window(tryEncode('plex_%s.playmethod' % currentFile)) \
                == 'Transcode' and subtitle:
            if window('plex_%s.subtitle' % currentFile) == 'None':
                self.xbmcplayer.showSubtitles(False)
            else:
                self.xbmcplayer.setSubtitleStream(int(subtitle))

        # Set some stuff if Kodi initiated playback
        if ((settings('useDirectPaths') == "1" and not typus == "song")
                or
                (typus == "song" and settings('enableMusic') == "true")):
            if self.StartDirectPath(plex_id,
                                    typus,
                                    tryEncode(currentFile)) is False:
                log.error('Could not initiate monitoring; aborting')
                return

        # Save currentFile for cleanup later and to be able to access refs
        window('plex_lastPlayedFiled', value=currentFile)
        window('plex_currently_playing_itemid', value=plex_id)
        window("plex_%s.itemid" % tryEncode(currentFile), value=plex_id)
        log.info('Finish playback startup')

    def StartDirectPath(self, plex_id, type, currentFile):
        """
        Set some additional stuff if playback was initiated by Kodi, not PKC
        """
        xml = self.doUtils('{server}/library/metadata/%s' % plex_id)
        try:
            xml[0].attrib
        except:
            log.error('Did not receive a valid XML for plex_id %s.' % plex_id)
            return False
        # Setup stuff, because playback was started by Kodi, not PKC
        api = API(xml[0])
        listitem = api.CreateListItemFromPlexItem()
        api.set_playback_win_props(currentFile, listitem)
        if type == "song" and settings('streamMusic') == "true":
            window('plex_%s.playmethod' % currentFile, value="DirectStream")
        else:
            window('plex_%s.playmethod' % currentFile, value="DirectPlay")
        log.debug('Window properties set for direct paths!')