Exemplo n.º 1
0
def __build_item(xml_element):
    api = API(xml_element)
    listitem = api.CreateListItemFromPlexItem()
    resume = api.getResume()
    if resume:
        listitem.setProperty('resumetime', str(resume))
    if (api.getKey().startswith('/system/services') or
            api.getKey().startswith('http')):
        params = {
            'mode': 'plex_node',
            'key': xml_element.attrib.get('key'),
            'offset': xml_element.attrib.get('viewOffset', '0'),
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    elif api.getType() == v.PLEX_TYPE_PHOTO:
        url = api.get_picture_path()
    else:
        params = {
            'mode': 'play',
            'plex_id': api.getRatingKey(),
            'plex_type': api.getType(),
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    xbmcplugin.addDirectoryItem(handle=HANDLE,
                                url=url,
                                listitem=listitem)
 def play_all(self):
     """
     Play all items contained in the xml passed in. Called by Plex Companion
     """
     log.info("Playbackutils play_all called")
     window('plex_playbackProps', value="true")
     self.currentPosition = 0
     for item in self.xml:
         api = API(item)
         if api.getType() == v.PLEX_TYPE_CLIP:
             self.add_trailer(item)
         else:
             with Get_Plex_DB() as plex_db:
                 db_item = plex_db.getItem_byId(api.getRatingKey())
             if db_item is not None:
                 if add_item_to_kodi_playlist(self.playqueue,
                                              self.currentPosition,
                                              kodi_id=db_item[0],
                                              kodi_type=db_item[4]) is True:
                     self.currentPosition += 1
                     if len(item[0]) > 1:
                         self.add_part(item, api, db_item[0], db_item[4])
             else:
                 # Item not in Kodi DB
                 self.add_trailer(item)
         self.playqueue.items[self.currentPosition - 1].ID = item.get(
             '%sItemID' % self.playqueue.kind)
Exemplo n.º 3
0
def playlist_item_from_xml(playlist, xml_video_element, kodi_id=None,
                           kodi_type=None):
    """
    Returns a playlist element for the playqueue using the Plex xml

    xml_video_element: etree xml piece 1 level underneath <MediaContainer>
    """
    item = Playlist_Item()
    api = API(xml_video_element)
    item.plex_id = api.getRatingKey()
    item.plex_type = api.getType()
    try:
        item.id = xml_video_element.attrib['%sItemID' % playlist.kind]
    except KeyError:
        pass
    item.guid = xml_video_element.attrib.get('guid')
    if item.guid is not None:
        item.guid = escape_html(item.guid)
    if kodi_id is not None:
        item.kodi_id = kodi_id
        item.kodi_type = kodi_type
    elif item.plex_id is not None:
        with plexdb.Get_Plex_DB() as plex_db:
            db_element = plex_db.getItem_byId(item.plex_id)
        try:
            item.kodi_id, item.kodi_type = int(db_element[0]), db_element[4]
        except TypeError:
            pass
    item.xml = xml_video_element
    LOG.debug('Created new playlist item from xml: %s', item)
    return item
Exemplo n.º 4
0
 def play_all(self):
     """
     Play all items contained in the xml passed in. Called by Plex Companion
     """
     log.info("Playbackutils play_all called")
     window('plex_playbackProps', value="true")
     self.currentPosition = 0
     for item in self.xml:
         api = API(item)
         successful = True
         if api.getType() == v.PLEX_TYPE_CLIP:
             self.add_trailer(item)
         else:
             with Get_Plex_DB() as plex_db:
                 db_item = plex_db.getItem_byId(api.getRatingKey())
             if db_item is not None:
                 successful = add_item_to_kodi_playlist(
                     self.playqueue,
                     self.currentPosition,
                     kodi_id=db_item[0],
                     kodi_type=db_item[4])
                 if successful is True:
                     self.currentPosition += 1
                     if len(item[0]) > 1:
                         self.add_part(item,
                                       api,
                                       db_item[0],
                                       db_item[4])
             else:
                 # Item not in Kodi DB
                 self.add_trailer(item)
         if successful is True:
             self.playqueue.items[self.currentPosition - 1].ID = item.get(
                 '%sItemID' % self.playqueue.kind)
Exemplo n.º 5
0
 def process_play(self, plex_id, kodi_id=None):
     """
     Processes Kodi playback init for ONE item
     """
     log.info("Process_play called with plex_id %s, kodi_id %s"
              % (plex_id, kodi_id))
     if window('plex_authenticated') != "true":
         log.error('Not yet authenticated for PMS, abort starting playback')
         # Todo: Warn user with dialog
         return
     xml = GetPlexMetadata(plex_id)
     try:
         xml[0].attrib
     except (IndexError, TypeError, AttributeError):
         log.error('Could not get a PMS xml for plex id %s' % plex_id)
         return
     api = API(xml[0])
     if api.getType() == v.PLEX_TYPE_PHOTO:
         # Photo
         result = Playback_Successful()
         listitem = PKC_ListItem()
         listitem = api.CreateListItemFromPlexItem(listitem)
         result.listitem = listitem
     else:
         # Video and Music
         playqueue = self.playqueue.get_playqueue_from_type(
             v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
         with lock:
             result = PlaybackUtils(xml, playqueue).play(
                 plex_id,
                 kodi_id,
                 xml.attrib.get('librarySectionUUID'))
     log.info('Done process_play, playqueues: %s'
              % self.playqueue.playqueues)
     return result
Exemplo n.º 6
0
def playback_init(plex_id, plex_type, playqueue):
    """
    Playback setup if Kodi starts playing an item for the first time.
    """
    LOG.info('Initializing PKC playback')
    xml = GetPlexMetadata(plex_id)
    try:
        xml[0].attrib
    except (IndexError, TypeError, AttributeError):
        LOG.error('Could not get a PMS xml for plex id %s', plex_id)
        # "Play error"
        dialog('notification', lang(29999), lang(30128), icon='{error}')
        return
    trailers = False
    api = API(xml[0])
    if (plex_type == v.PLEX_TYPE_MOVIE and not api.getResume()
            and settings('enableCinema') == "true"):
        if settings('askCinema') == "true":
            # "Play trailers?"
            trailers = dialog('yesno', lang(29999), lang(33016))
            trailers = True if trailers else False
        else:
            trailers = True
    LOG.debug('Playing trailers: %s', trailers)
    playqueue.clear()
    if plex_type != v.PLEX_TYPE_CLIP:
        # Post to the PMS to create a playqueue - in any case due to Companion
        xml = init_plex_playqueue(plex_id,
                                  xml.attrib.get('librarySectionUUID'),
                                  mediatype=plex_type,
                                  trailers=trailers)
        if xml is None:
            LOG.error('Could not get a playqueue xml for plex id %s, UUID %s',
                      plex_id, xml.attrib.get('librarySectionUUID'))
            # "Play error"
            dialog('notification', lang(29999), lang(30128), icon='{error}')
            return
        # Should already be empty, but just in case
        PL.get_playlist_details_from_xml(playqueue, xml)
    stack = _prep_playlist_stack(xml)
    # Sleep a bit to let setResolvedUrl do its thing - bit ugly
    sleep(200)
    _process_stack(playqueue, stack)
    # Reset some playback variables
    state.CONTEXT_MENU_PLAY = False
    state.FORCE_TRANSCODE = False
    # New thread to release this one sooner (e.g. harddisk spinning up)
    thread = Thread(target=Player().play, args=(playqueue.kodi_pl, ))
    thread.setDaemon(True)
    LOG.info('Done initializing PKC playback, starting Kodi player')
    # By design, PKC will start Kodi playback using Player().play(). Kodi
    # caches paths like our plugin://pkc. If we use Player().play() between
    # 2 consecutive startups of exactly the same Kodi library item, Kodi's
    # cache will have been flushed for some reason. Hence the 2nd call for
    # plugin://pkc will be lost; Kodi will try to startup playback for an empty
    # path: log entry is "CGUIWindowVideoBase::OnPlayMedia <missing path>"
    thread.start()
Exemplo n.º 7
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
    """
    import xbmcvfs
    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 = tryDecode(translatePath(
        "special://thumbnails/plex/%s/" % plexid))
    if not xbmcvfs.exists(fanartDir):
        # Download the images to the cache directory
        xbmcvfs.mkdirs(tryEncode(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.getAllArtwork()['Backdrop']
        for count, backdrop in enumerate(backdrops):
            # Same ordering as in artwork
            if os_path.supports_unicode_filenames:
                fanartFile = os_path.join(fanartDir,
                                          "fanart%.3d.jpg" % count)
            else:
                fanartFile = os_path.join(
                    tryEncode(fanartDir),
                    tryEncode("fanart%.3d.jpg" % count))
            li = ListItem("%.3d" % count, path=fanartFile)
            xbmcplugin.addDirectoryItem(
                handle=HANDLE,
                url=fanartFile,
                listitem=li)
            xbmcvfs.copy(backdrop, fanartFile)
    else:
        log.info("Found cached backdrop.")
        # Use existing cached images
        dirs, files = xbmcvfs.listdir(fanartDir)
        for file in files:
            fanartFile = os_path.join(fanartDir, tryDecode(file))
            li = ListItem(file, path=fanartFile)
            xbmcplugin.addDirectoryItem(handle=HANDLE,
                                        url=fanartFile,
                                        listitem=li)
    xbmcplugin.endOfDirectory(HANDLE)
Exemplo n.º 8
0
 def process_plex_node(self, url, viewOffset, directplay=False,
                       node=True):
     """
     Called for Plex directories or redirect for playback (e.g. trailers,
     clips, watchlater)
     """
     log.info('process_plex_node called with url: %s, viewOffset: %s'
              % (url, viewOffset))
     # Plex redirect, e.g. watch later. Need to get actual URLs
     if url.startswith('http') or url.startswith('{server}'):
         xml = DownloadUtils().downloadUrl(url)
     else:
         xml = DownloadUtils().downloadUrl('{server}%s' % url)
     try:
         xml[0].attrib
     except:
         log.error('Could not download PMS metadata')
         return
     if viewOffset != '0':
         try:
             viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(viewOffset))
         except:
             pass
         else:
             window('plex_customplaylist.seektime', value=str(viewOffset))
             log.info('Set resume point to %s' % str(viewOffset))
     api = API(xml[0])
     typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()]
     if node is True:
         plex_id = None
         kodi_id = 'plexnode'
     else:
         plex_id = api.getRatingKey()
         kodi_id = None
         with plexdb.Get_Plex_DB() as plex_db:
             plexdb_item = plex_db.getItem_byId(plex_id)
             try:
                 kodi_id = plexdb_item[0]
             except TypeError:
                 log.info('Couldnt find item %s in Kodi db'
                          % api.getRatingKey())
     playqueue = self.playqueue.get_playqueue_from_type(typus)
     with lock:
         result = PlaybackUtils(xml, playqueue).play(
             plex_id,
             kodi_id=kodi_id,
             plex_lib_UUID=xml.attrib.get('librarySectionUUID'))
     if directplay:
         if result.listitem:
             listitem = convert_PKC_to_listitem(result.listitem)
             Player().play(listitem.getfilename(), listitem)
         return Playback_Successful()
     else:
         return result
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
    """
    import xbmcvfs
    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 = tryDecode(
        translatePath("special://thumbnails/plex/%s/" % plexid))
    if not xbmcvfs.exists(fanartDir):
        # Download the images to the cache directory
        xbmcvfs.mkdirs(tryEncode(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.getAllArtwork()['Backdrop']
        for count, backdrop in enumerate(backdrops):
            # Same ordering as in artwork
            if os_path.supports_unicode_filenames:
                fanartFile = os_path.join(fanartDir, "fanart%.3d.jpg" % count)
            else:
                fanartFile = os_path.join(tryEncode(fanartDir),
                                          tryEncode("fanart%.3d.jpg" % count))
            li = ListItem("%.3d" % count, path=fanartFile)
            xbmcplugin.addDirectoryItem(handle=HANDLE,
                                        url=fanartFile,
                                        listitem=li)
            xbmcvfs.copy(backdrop, fanartFile)
    else:
        log.info("Found cached backdrop.")
        # Use existing cached images
        dirs, files = xbmcvfs.listdir(fanartDir)
        for file in files:
            fanartFile = os_path.join(fanartDir, tryDecode(file))
            li = ListItem(file, path=fanartFile)
            xbmcplugin.addDirectoryItem(handle=HANDLE,
                                        url=fanartFile,
                                        listitem=li)
    xbmcplugin.endOfDirectory(HANDLE)
Exemplo n.º 10
0
def playlist_item_from_xml(xml_video_element, kodi_id=None, kodi_type=None):
    """
    Returns a playlist element for the playqueue using the Plex xml

    xml_video_element: etree xml piece 1 level underneath <MediaContainer>
    """
    item = Playlist_Item()
    api = API(xml_video_element)
    item.plex_id = api.plex_id()
    item.plex_type = api.plex_type()
    # item.id will only be set if you passed in an xml_video_element from e.g.
    # a playQueue
    item.id = api.item_id()
    if kodi_id is not None:
        item.kodi_id = kodi_id
        item.kodi_type = kodi_type
    elif item.plex_id is not None:
        with plexdb.Get_Plex_DB() as plex_db:
            db_element = plex_db.getItem_byId(item.plex_id)
        try:
            item.kodi_id, item.kodi_type = db_element[0], db_element[4]
        except TypeError:
            pass
    item.guid = api.guid_html_escaped()
    item.playcount = api.viewcount()
    item.offset = api.resume_point()
    item.xml = xml_video_element
    LOG.debug('Created new playlist item from xml: %s', item)
    return item
Exemplo n.º 11
0
def playlist_item_from_xml(playlist, xml_video_element):
    """
    Returns a playlist element for the playqueue using the Plex xml
    """
    item = Playlist_Item()
    api = API(xml_video_element)
    item.plex_id = api.getRatingKey()
    item.ID = xml_video_element.attrib['%sItemID' % playlist.kind]
    item.guid = xml_video_element.attrib.get('guid')
    if item.plex_id:
        with plexdb.Get_Plex_DB() as plex_db:
            db_element = plex_db.getItem_byId(item.plex_id)
        try:
            item.kodi_id, item.kodi_type = int(db_element[0]), db_element[4]
        except TypeError:
            pass
    log.debug('Created new playlist item from xml: %s' % item)
    return item
Exemplo n.º 12
0
 def init_playqueue_from_plex_children(self, plex_id):
     """
     Init a new playqueue e.g. from an album. Alexa does this
     """
     xml = GetAllPlexChildren(plex_id)
     try:
         xml[0].attrib
     except (TypeError, IndexError, AttributeError):
         log.error('Could not download the PMS xml for %s' % plex_id)
         return
     playqueue = self.get_playqueue_from_type(
         v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
     playqueue.clear()
     for i, child in enumerate(xml):
         api = API(child)
         PL.add_item_to_playlist(playqueue, i, plex_id=api.getRatingKey())
     log.debug('Firing up Kodi player')
     Player().play(playqueue.kodi_pl, None, False, 0)
Exemplo n.º 13
0
 def init_playqueue_from_plex_children(self, plex_id):
     """
     Init a new playqueue e.g. from an album. Alexa does this
     """
     xml = GetAllPlexChildren(plex_id)
     try:
         xml[0].attrib
     except (TypeError, IndexError, AttributeError):
         log.error('Could not download the PMS xml for %s' % plex_id)
         return
     playqueue = self.get_playqueue_from_type(
         v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
     playqueue.clear()
     for i, child in enumerate(xml):
         api = API(child)
         PL.add_item_to_playlist(playqueue, i, plex_id=api.getRatingKey())
     log.debug('Firing up Kodi player')
     Player().play(playqueue.kodi_pl, None, False, 0)
Exemplo n.º 14
0
def playlist_item_from_xml(playlist, xml_video_element):
    """
    Returns a playlist element for the playqueue using the Plex xml
    """
    item = Playlist_Item()
    api = API(xml_video_element)
    item.plex_id = api.getRatingKey()
    item.ID = xml_video_element.attrib['%sItemID' % playlist.kind]
    item.guid = xml_video_element.attrib.get('guid')
    if item.plex_id:
        with plexdb.Get_Plex_DB() as plex_db:
            db_element = plex_db.getItem_byId(item.plex_id)
        try:
            item.kodi_id, item.kodi_type = int(db_element[0]), db_element[4]
        except TypeError:
            pass
    log.debug('Created new playlist item from xml: %s' % item)
    return item
Exemplo n.º 15
0
 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!')
Exemplo n.º 16
0
 def StartDirectPath(self, plexid, type, currentFile):
     """
     Set some additional stuff if playback was initiated by Kodi, not PKC
     """
     xml = self.doUtils('{server}/library/metadata/%s' % plexid)
     try:
         xml[0].attrib
     except:
         log.error('Did not receive a valid XML for plexid %s.' % plexid)
         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!')
Exemplo n.º 17
0
def play_resume(playqueue, xml, stack):
    """
    If there exists a resume point, Kodi will ask the user whether to continue
    playback. We thus need to use setResolvedUrl "correctly". Mind that there
    might be several parts!
    """
    result = Playback_Successful()
    listitem = PKC_ListItem()
    # Only get the very first item of our playqueue (i.e. the very first part)
    stack_item = stack.pop(0)
    api = API(xml[0])
    item = PL.playlist_item_from_xml(playqueue,
                                     xml[0],
                                     kodi_id=stack_item['kodi_id'],
                                     kodi_type=stack_item['kodi_type'])
    api.setPartNumber(item.part)
    item.playcount = stack_item['playcount']
    item.offset = stack_item['offset']
    item.part = stack_item['part']
    api.CreateListItemFromPlexItem(listitem)
    playutils = PlayUtils(api, item)
    playurl = playutils.getPlayUrl()
    listitem.setPath(tryEncode(playurl))
    if item.playmethod in ('DirectStream', 'DirectPlay'):
        listitem.setSubtitles(api.externalSubs())
    else:
        playutils.audio_subtitle_prefs(listitem)
    result.listitem = listitem
    # Add to our playlist
    playqueue.items.append(item)
    # This will release default.py with setResolvedUrl
    pickle_me(result)
    # Add remaining parts to the playlist, if any
    if stack:
        _process_stack(playqueue, stack)
Exemplo n.º 18
0
def init_playqueue_from_plex_children(plex_id, transient_token=None):
    """
    Init a new playqueue e.g. from an album. Alexa does this

    Returns the Playlist_Object
    """
    xml = GetAllPlexChildren(plex_id)
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not download the PMS xml for %s', plex_id)
        return
    playqueue = get_playqueue_from_type(
        v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
    playqueue.clear()
    for i, child in enumerate(xml):
        api = API(child)
        PL.add_item_to_playlist(playqueue, i, plex_id=api.plex_id())
    playqueue.plex_transient_token = transient_token
    LOG.debug('Firing up Kodi player')
    Player().play(playqueue.kodi_pl, None, False, 0)
    return playqueue
Exemplo n.º 19
0
 def _process_playlist(self, data):
     # Get the playqueue ID
     _, container_key, query = 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 = 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()])
     PQ.update_playqueue_from_PMS(playqueue,
                                  playqueue_id=container_key,
                                  repeat=query.get('repeat'),
                                  offset=data.get('offset'),
                                  transient_token=data.get('token'))
Exemplo n.º 20
0
 def add_trailer(self, item):
     # Playurl needs to point back so we can get metadata!
     path = "plugin://plugin.video.plexkodiconnect/movies/"
     params = {
         'mode': "play",
         'dbid': 'plextrailer'
     }
     introAPI = API(item)
     listitem = introAPI.CreateListItemFromPlexItem()
     params['id'] = introAPI.getRatingKey()
     params['filename'] = introAPI.getKey()
     introPlayurl = path + '?' + urlencode(params)
     introAPI.set_listitem_artwork(listitem)
     # Overwrite the Plex url
     listitem.setPath(introPlayurl)
     log.info("Adding Plex trailer: %s" % introPlayurl)
     add_listitem_to_Kodi_playlist(
         self.playqueue,
         self.currentPosition,
         listitem,
         introPlayurl,
         xml_video_element=item)
     self.currentPosition += 1
Exemplo n.º 21
0
 def _process_alexa(self, data):
     xml = 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.getType() == v.PLEX_TYPE_ALBUM:
         LOG.debug('Plex music album detected')
         PQ.init_playqueue_from_plex_children(
             api.getRatingKey(),
             transient_token=data.get('token'))
     else:
         state.PLEX_TRANSIENT_TOKEN = data.get('token')
         params = {
             'mode': 'plex_node',
             'key': '{server}%s' % data.get('key'),
             'view_offset': data.get('offset'),
             'play_directly': 'true',
             'node': 'false'
         }
         executebuiltin('RunPlugin(plugin://%s?%s)'
                        % (v.ADDON_ID, urlencode(params)))
Exemplo n.º 22
0
def _conclude_playback(playqueue, pos):
    """
    ONLY if actually being played (e.g. at 5th position of a playqueue).

        Decide on direct play, direct stream, transcoding
        path to
            direct paths: file itself
            PMS URL
            Web URL
        audiostream (e.g. let user choose)
        subtitle stream (e.g. let user choose)
        Init Kodi Playback (depending on situation):
            start playback
            return PKC listitem attached to result
    """
    LOG.info('Concluding playback for playqueue position %s', pos)
    result = Playback_Successful()
    listitem = PKC_ListItem()
    item = playqueue.items[pos]
    if item.xml is not None:
        # Got a Plex element
        api = API(item.xml)
        api.set_part_number(item.part)
        api.create_listitem(listitem)
        playutils = PlayUtils(api, item)
        playurl = playutils.getPlayUrl()
    else:
        playurl = item.file
    listitem.setPath(try_encode(playurl))
    if item.playmethod == 'DirectStream':
        listitem.setSubtitles(api.cache_external_subs())
    elif item.playmethod == 'Transcode':
        playutils.audio_subtitle_prefs(listitem)

    if state.RESUME_PLAYBACK is True:
        state.RESUME_PLAYBACK = False
        if (item.offset is None and item.plex_type
                not in (v.PLEX_TYPE_SONG, v.PLEX_TYPE_CLIP)):
            with plexdb.Get_Plex_DB() as plex_db:
                plex_dbitem = plex_db.getItem_byId(item.plex_id)
                file_id = plex_dbitem[1] if plex_dbitem else None
            with kodidb.GetKodiDB('video') as kodi_db:
                item.offset = kodi_db.get_resume(file_id)
        LOG.info('Resuming playback at %s', item.offset)
        listitem.setProperty('StartOffset', str(item.offset))
        listitem.setProperty('resumetime', str(item.offset))
    # Reset the resumable flag
    result.listitem = listitem
    pickle_me(result)
    LOG.info('Done concluding playback')
Exemplo n.º 23
0
 def add_trailer(self, item):
     # Playurl needs to point back so we can get metadata!
     path = "plugin://plugin.video.plexkodiconnect/movies/"
     params = {'mode': "play", 'dbid': 'plextrailer'}
     introAPI = API(item)
     listitem = introAPI.CreateListItemFromPlexItem()
     params['id'] = introAPI.getRatingKey()
     params['filename'] = introAPI.getKey()
     introPlayurl = path + '?' + urlencode(params)
     introAPI.set_listitem_artwork(listitem)
     # Overwrite the Plex url
     listitem.setPath(introPlayurl)
     log.info("Adding Plex trailer: %s" % introPlayurl)
     add_listitem_to_Kodi_playlist(self.playqueue,
                                   self.currentPosition,
                                   listitem,
                                   introPlayurl,
                                   xml_video_element=item)
     self.currentPosition += 1
Exemplo n.º 24
0
 def _process_alexa(self, data):
     xml = 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, _ = ParseContainerKey(data['containerKey'])
         xml = DownloadChunks('{server}/playQueues/%s?' % container_key)
         if xml is None:
             # "Play error"
             dialog('notification',
                    lang(29999),
                    lang(30128),
                    icon='{error}')
             return
         playqueue = PQ.get_playqueue_from_type(
             v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
         playqueue.clear()
         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
         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_triage(api.plex_id(), api.plex_type(), resolve=False)
Exemplo n.º 25
0
def __build_item(xml_element):
    api = API(xml_element)
    listitem = api.CreateListItemFromPlexItem()
    if (api.getKey().startswith('/system/services') or
            api.getKey().startswith('http')):
        params = {
            'mode': 'plex_node',
            'key': xml_element.attrib.get('key'),
            'view_offset': xml_element.attrib.get('viewOffset', '0'),
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    elif api.getType() == v.PLEX_TYPE_PHOTO:
        url = api.get_picture_path()
    else:
        params = {
            'mode': 'play',
            'filename': api.getKey(),
            'id': api.getRatingKey(),
            'dbid': listitem.getProperty('dbid')
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    xbmcplugin.addDirectoryItem(handle=HANDLE,
                                url=url,
                                listitem=listitem)
Exemplo n.º 26
0
def watchlater():
    """
    Listing for plex.tv Watch Later section (if signed in to plex.tv)
    """
    if window('plex_token') == '':
        log.error('No watch later - not signed in to plex.tv')
        return xbmcplugin.endOfDirectory(HANDLE, False)
    if window('plex_restricteduser') == 'true':
        log.error('No watch later - restricted user')
        return xbmcplugin.endOfDirectory(HANDLE, False)

    xml = downloadutils.DownloadUtils().downloadUrl(
        'https://plex.tv/pms/playlists/queue/all',
        authenticate=False,
        headerOptions={'X-Plex-Token': window('plex_token')})
    if xml in (None, 401):
        log.error('Could not download watch later list from plex.tv')
        return xbmcplugin.endOfDirectory(HANDLE, False)

    log.info('Displaying watch later plex.tv items')
    xbmcplugin.setContent(HANDLE, 'movies')
    url = "plugin://plugin.video.plexkodiconnect/"
    params = {
        'mode': "Plex_Node",
    }
    for item in xml:
        api = API(item)
        listitem = api.CreateListItemFromPlexItem()
        api.AddStreamInfo(listitem)
        api.set_listitem_artwork(listitem)
        params['id'] = item.attrib.get('key')
        params['viewOffset'] = item.attrib.get('viewOffset', '0')
        params['plex_type'] = item.attrib.get('type')
        xbmcplugin.addDirectoryItem(handle=HANDLE,
                                    url="%s?%s" % (url, urlencode(params)),
                                    listitem=listitem)

    xbmcplugin.endOfDirectory(
        handle=HANDLE, cacheToDisc=settings('enableTextureCache') == 'true')
Exemplo n.º 27
0
def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None):
    """
    Adds a new item to the playlist at position pos [int] only on the Plex
    side of things (e.g. because the user changed the Kodi side)
    WILL ALSO UPDATE OUR PLAYLISTS

    Returns the PKC PlayList item or raises PlaylistError
    """
    verify_kodi_item(plex_id, kodi_item)
    if plex_id:
        item = playlist_item_from_plex(plex_id)
    else:
        item = playlist_item_from_kodi(kodi_item)
    url = "{server}/%ss/%s?uri=%s" % (playlist.kind, playlist.id, item.uri)
    # Will always put the new item at the end of the Plex playlist
    xml = DU().downloadUrl(url, action_type="PUT")
    try:
        xml[-1].attrib
    except (TypeError, AttributeError, KeyError, IndexError):
        raise PlaylistError('Could not add item %s to playlist %s' %
                            (kodi_item, playlist))
    api = API(xml[-1])
    item.xml = xml[-1]
    item.id = api.item_id()
    item.guid = api.guid_html_escaped()
    item.offset = api.resume_point()
    item.playcount = api.viewcount()
    playlist.items.append(item)
    if pos == len(playlist.items) - 1:
        # Item was added at the end
        _get_playListVersion_from_xml(playlist, xml)
    else:
        # Move the new item to the correct position
        move_playlist_item(playlist, len(playlist.items) - 1, pos)
    LOG.debug('Successfully added item on the Plex side: %s', playlist)
    return item
Exemplo n.º 28
0
def getOnDeck(viewid, mediatype, tagname, limit):
    """
    Retrieves Plex On Deck items, currently only for TV shows

    Input:
        viewid:             Plex id of the library section, e.g. '1'
        mediatype:          Kodi mediatype, e.g. 'tvshows', 'movies',
                            'homevideos', 'photos'
        tagname:            Name of the Plex library, e.g. "My Movies"
        limit:              Max. number of items to retrieve, e.g. 50
    """
    xbmcplugin.setContent(HANDLE, 'episodes')
    append_show_title = settings('OnDeckTvAppendShow') == 'true'
    append_sxxexx = settings('OnDeckTvAppendSeason') == 'true'
    directpaths = settings('useDirectPaths') == 'true'
    if settings('OnDeckTVextended') == 'false':
        # Chances are that this view is used on Kodi startup
        # Wait till we've connected to a PMS. At most 30s
        counter = 0
        while window('plex_authenticated') != 'true':
            counter += 1
            if counter >= 300:
                log.error('Aborting On Deck view, we were not authenticated '
                          'for the PMS')
                return xbmcplugin.endOfDirectory(HANDLE, False)
            sleep(100)
        xml = downloadutils.DownloadUtils().downloadUrl(
            '{server}/library/sections/%s/onDeck' % viewid)
        if xml in (None, 401):
            log.error('Could not download PMS xml for view %s' % viewid)
            return xbmcplugin.endOfDirectory(HANDLE)
        limitcounter = 0
        for item in xml:
            api = API(item)
            listitem = api.create_listitem(
                append_show_title=append_show_title,
                append_sxxexx=append_sxxexx)
            if directpaths:
                url = api.file_path()
            else:
                params = {
                    'mode': "play",
                    'plex_id': api.plex_id(),
                    'plex_type': api.plex_type()
                }
                url = "plugin://plugin.video.plexkodiconnect/tvshows/?%s" \
                      % urlencode(params)
            xbmcplugin.addDirectoryItem(
                handle=HANDLE,
                url=url,
                listitem=listitem)
            limitcounter += 1
            if limitcounter == limit:
                break
        return xbmcplugin.endOfDirectory(
            handle=HANDLE,
            cacheToDisc=settings('enableTextureCache') == 'true')

    # if the addon is called with nextup parameter,
    # we return the nextepisodes list of the given tagname
    # First we get a list of all the TV shows - filtered by tag
    params = {
        'sort': {'order': "descending", 'method': "lastplayed"},
        'filter': {
            'and': [
                {'operator': "true", 'field': "inprogress", 'value': ""},
                {'operator': "is", 'field': "tag", 'value': "%s" % tagname}
            ]}
    }
    items = js.get_tv_shows(params)
    if not items:
        # Now items retrieved - empty directory
        xbmcplugin.endOfDirectory(handle=HANDLE)
        return

    params = {
        'sort': {'method': "episode"},
        'limits': {"end": 1},
        'properties': [
            "title", "playcount", "season", "episode", "showtitle",
            "plot", "file", "rating", "resume", "tvshowid", "art",
            "streamdetails", "firstaired", "runtime", "cast", "writer",
            "dateadded", "lastplayed"
        ],
    }
    if settings('ignoreSpecialsNextEpisodes') == "true":
        params['filter'] = {
            'and': [
                {'operator': "lessthan", 'field': "playcount", 'value': "1"},
                {'operator': "greaterthan", 'field': "season", 'value': "0"}
            ]
        }
    else:
        params['filter'] = {
            'or': [
                {'operator': "lessthan", 'field': "playcount", 'value': "1"},
                {'operator': "true", 'field': "inprogress", 'value': ""}
            ]
        }

    # Are there any episodes still in progress/not yet finished watching?!?
    # Then we should show this episode, NOT the "next up"
    inprog_params = {
        'sort': {'method': "episode"},
        'filter': {'operator': "true", 'field': "inprogress", 'value': ""},
        'properties': params['properties']
    }

    count = 0
    for item in items:
        inprog_params['tvshowid'] = item['tvshowid']
        episodes = js.get_episodes(inprog_params)
        if not episodes:
            # No, there are no episodes not yet finished. Get "next up"
            params['tvshowid'] = item['tvshowid']
            episodes = js.get_episodes(params)
            if not episodes:
                # Also no episodes currently coming up
                continue
        for episode in episodes:
            # There will always be only 1 episode ('limit=1')
            listitem = createListItem(episode,
                                      append_show_title=append_show_title,
                                      append_sxxexx=append_sxxexx)
            xbmcplugin.addDirectoryItem(handle=HANDLE,
                                        url=episode['file'],
                                        listitem=listitem,
                                        isFolder=False)
        count += 1
        if count >= limit:
            break
    xbmcplugin.endOfDirectory(handle=HANDLE)
Exemplo n.º 29
0
    def play(self, plex_id, kodi_id=None, plex_lib_UUID=None):
        """
        plex_lib_UUID: xml attribute 'librarySectionUUID', needed for posting
        to the PMS
        """
        log.info("Playbackutils called")
        item = self.xml[0]
        api = API(item)
        playqueue = self.playqueue
        xml = None
        result = Playback_Successful()
        listitem = ListItem()
        playutils = putils.PlayUtils(item)
        playurl = playutils.getPlayUrl()
        if not playurl:
            log.error('No playurl found, aborting')
            return

        if kodi_id in (None, 'plextrailer', 'plexnode'):
            # Item is not in Kodi database, is a trailer/clip or plex redirect
            # e.g. plex.tv watch later
            api.CreateListItemFromPlexItem(listitem)
            api.set_listitem_artwork(listitem)
            if kodi_id == 'plexnode':
                # Need to get yet another xml to get final url
                window('plex_%s.playmethod' % playurl, clear=True)
                xml = downloadutils.DownloadUtils().downloadUrl(
                    '{server}%s' % item[0][0].attrib.get('key'))
                try:
                    xml[0].attrib
                except (TypeError, AttributeError):
                    log.error('Could not download %s' %
                              item[0][0].attrib.get('key'))
                    return
                playurl = tryEncode(xml[0].attrib.get('key'))
                window('plex_%s.playmethod' % playurl, value='DirectStream')

            playmethod = window('plex_%s.playmethod' % playurl)
            if playmethod == "Transcode":
                playutils.audioSubsPref(listitem, tryDecode(playurl))
            listitem.setPath(playurl)
            api.set_playback_win_props(playurl, listitem)
            result.listitem = listitem
            return result

        kodi_type = v.KODITYPE_FROM_PLEXTYPE[api.getType()]
        kodi_id = int(kodi_id)

        # ORGANIZE CURRENT PLAYLIST ################
        contextmenu_play = window('plex_contextplay') == 'true'
        window('plex_contextplay', clear=True)
        homeScreen = getCondVisibility('Window.IsActive(home)')
        sizePlaylist = len(playqueue.items)
        if contextmenu_play:
            # Need to start with the items we're inserting here
            startPos = sizePlaylist
        else:
            # Can return -1
            startPos = max(playqueue.kodi_pl.getposition(), 0)
        self.currentPosition = startPos

        propertiesPlayback = window('plex_playbackProps') == "true"
        introsPlaylist = False
        dummyPlaylist = False

        log.info("Playing from contextmenu: %s" % contextmenu_play)
        log.info("Playlist start position: %s" % startPos)
        log.info("Playlist plugin position: %s" % self.currentPosition)
        log.info("Playlist size: %s" % sizePlaylist)

        # RESUME POINT ################
        seektime, runtime = api.getRuntime()
        if window('plex_customplaylist.seektime'):
            # Already got seektime, e.g. from playqueue & Plex companion
            seektime = int(window('plex_customplaylist.seektime'))

        # We need to ensure we add the intro and additional parts only once.
        # Otherwise we get a loop.
        if not propertiesPlayback:
            window('plex_playbackProps', value="true")
            log.info("Setting up properties in playlist.")
            # Where will the player need to start?
            # Do we need to get trailers?
            trailers = False
            if (api.getType() == v.PLEX_TYPE_MOVIE and not seektime
                    and sizePlaylist < 2
                    and settings('enableCinema') == "true"):
                if settings('askCinema') == "true":
                    trailers = xbmcgui.Dialog().yesno(lang(29999),
                                                      "Play trailers?")
                else:
                    trailers = True
            # Post to the PMS. REUSE THE PLAYQUEUE!
            xml = init_plex_playqueue(plex_id,
                                      plex_lib_UUID,
                                      mediatype=api.getType(),
                                      trailers=trailers)
            try:
                get_playlist_details_from_xml(playqueue, xml=xml)
            except KeyError:
                return

            if (not homeScreen and not seektime and sizePlaylist < 2
                    and window('plex_customplaylist') != "true"
                    and not contextmenu_play):
                # Need to add a dummy file because the first item will fail
                log.debug("Adding dummy file to playlist.")
                dummyPlaylist = True
                add_listitem_to_Kodi_playlist(playqueue, startPos,
                                              xbmcgui.ListItem(), playurl,
                                              xml[0])
                # Remove the original item from playlist
                remove_from_Kodi_playlist(playqueue, startPos + 1)
                # Readd the original item to playlist - via jsonrpc so we have
                # full metadata
                add_item_to_kodi_playlist(playqueue,
                                          self.currentPosition + 1,
                                          kodi_id=kodi_id,
                                          kodi_type=kodi_type,
                                          file=playurl)
                self.currentPosition += 1

            # -- ADD TRAILERS ################
            if trailers:
                for i, item in enumerate(xml):
                    if i == len(xml) - 1:
                        # Don't add the main movie itself
                        break
                    self.add_trailer(item)
                    introsPlaylist = True

            # -- ADD MAIN ITEM ONLY FOR HOMESCREEN ##############
            if homeScreen and not seektime and not sizePlaylist:
                # Extend our current playlist with the actual item to play
                # only if there's no playlist first
                log.info("Adding main item to playlist.")
                add_item_to_kodi_playlist(playqueue, self.currentPosition,
                                          kodi_id, kodi_type)

            elif contextmenu_play:
                if state.DIRECT_PATHS:
                    # Cannot add via JSON with full metadata because then we
                    # Would be using the direct path
                    log.debug("Adding contextmenu item for direct paths")
                    if window('plex_%s.playmethod' % playurl) == "Transcode":
                        playutils.audioSubsPref(listitem, tryDecode(playurl))
                    api.CreateListItemFromPlexItem(listitem)
                    api.set_playback_win_props(playurl, listitem)
                    api.set_listitem_artwork(listitem)
                    add_listitem_to_Kodi_playlist(
                        playqueue,
                        self.currentPosition + 1,
                        convert_PKC_to_listitem(listitem),
                        file=playurl,
                        kodi_item={
                            'id': kodi_id,
                            'type': kodi_type
                        })
                else:
                    # Full metadata$
                    add_item_to_kodi_playlist(playqueue,
                                              self.currentPosition + 1,
                                              kodi_id, kodi_type)
                self.currentPosition += 1
                if seektime:
                    window('plex_customplaylist.seektime', value=str(seektime))

            # Ensure that additional parts are played after the main item
            self.currentPosition += 1

            # -- CHECK FOR ADDITIONAL PARTS ################
            if len(item[0]) > 1:
                self.add_part(item, api, kodi_id, kodi_type)

            if dummyPlaylist:
                # Added a dummy file to the playlist,
                # because the first item is going to fail automatically.
                log.info("Processed as a playlist. First item is skipped.")
                # Delete the item that's gonna fail!
                del playqueue.items[startPos]
                # Don't attach listitem
                return result

        # We just skipped adding properties. Reset flag for next time.
        elif propertiesPlayback:
            log.debug("Resetting properties playback flag.")
            window('plex_playbackProps', clear=True)

        # SETUP MAIN ITEM ##########
        # For transcoding only, ask for audio/subs pref
        if (window('plex_%s.playmethod' % playurl) == "Transcode"
                and not contextmenu_play):
            playutils.audioSubsPref(listitem, tryDecode(playurl))

        listitem.setPath(playurl)
        api.set_playback_win_props(playurl, listitem)
        api.set_listitem_artwork(listitem)

        # PLAYBACK ################
        if (homeScreen and seektime and window('plex_customplaylist') != "true"
                and not contextmenu_play):
            log.info("Play as a widget item")
            api.CreateListItemFromPlexItem(listitem)
            result.listitem = listitem
            return result

        elif ((introsPlaylist and window('plex_customplaylist') == "true")
              or (homeScreen and not sizePlaylist) or contextmenu_play):
            # Playlist was created just now, play it.
            # Contextmenu plays always need this
            log.info("Play playlist from starting position %s" % startPos)
            # Need a separate thread because Player won't return in time
            thread = Thread(target=Player().play,
                            args=(playqueue.kodi_pl, None, False, startPos))
            thread.setDaemon(True)
            thread.start()
            # Don't attach listitem
            return result
        else:
            log.info("Play as a regular item")
            result.listitem = listitem
            return result
Exemplo n.º 30
0
def _playback_init(plex_id, plex_type, playqueue, pos):
    """
    Playback setup if Kodi starts playing an item for the first time.
    """
    LOG.info('Initializing PKC playback')
    xml = GetPlexMetadata(plex_id)
    try:
        xml[0].attrib
    except (IndexError, TypeError, AttributeError):
        LOG.error('Could not get a PMS xml for plex id %s', plex_id)
        # "Play error"
        dialog('notification', lang(29999), lang(30128), icon='{error}')
        _ensure_resolve(abort=True)
        return
    if playqueue.kodi_pl.size() > 1:
        # Special case - we already got a filled Kodi playqueue
        try:
            _init_existing_kodi_playlist(playqueue)
        except PL.PlaylistError:
            LOG.error('Aborting playback_init for longer Kodi playlist')
            _ensure_resolve(abort=True)
            return
        # Now we need to use setResolvedUrl for the item at position pos
        _conclude_playback(playqueue, pos)
        return
    # "Usual" case - consider trailers and parts and build both Kodi and Plex
    # playqueues
    # Fail the item we're trying to play now so we can restart the player
    _ensure_resolve()
    api = API(xml[0])
    trailers = False
    if (plex_type == v.PLEX_TYPE_MOVIE and not api.resume_point()
            and settings('enableCinema') == "true"):
        if settings('askCinema') == "true":
            # "Play trailers?"
            trailers = dialog('yesno', lang(29999), lang(33016))
            trailers = True if trailers else False
        else:
            trailers = True
    LOG.debug('Playing trailers: %s', trailers)
    playqueue.clear()
    if plex_type != v.PLEX_TYPE_CLIP:
        # Post to the PMS to create a playqueue - in any case due to Companion
        xml = init_plex_playqueue(plex_id,
                                  xml.attrib.get('librarySectionUUID'),
                                  mediatype=plex_type,
                                  trailers=trailers)
        if xml is None:
            LOG.error('Could not get a playqueue xml for plex id %s, UUID %s',
                      plex_id, xml.attrib.get('librarySectionUUID'))
            # "Play error"
            dialog('notification', lang(29999), lang(30128), icon='{error}')
            _ensure_resolve(abort=True)
            return
        # Should already be empty, but just in case
        PL.get_playlist_details_from_xml(playqueue, xml)
    stack = _prep_playlist_stack(xml)
    # Sleep a bit to let setResolvedUrl do its thing - bit ugly
    sleep(200)
    _process_stack(playqueue, stack)
    # Always resume if playback initiated via PMS and there IS a resume
    # point
    offset = api.resume_point() * 1000 if state.CONTEXT_MENU_PLAY else None
    # Reset some playback variables
    state.CONTEXT_MENU_PLAY = False
    state.FORCE_TRANSCODE = False
    # Do NOT set offset, because Kodi player will return here to resolveURL
    # New thread to release this one sooner (e.g. harddisk spinning up)
    thread = Thread(target=threaded_playback,
                    args=(playqueue.kodi_pl, pos, offset))
    thread.setDaemon(True)
    LOG.info(
        'Done initializing playback, starting Kodi player at pos %s and '
        'resume point %s', pos, offset)
    # By design, PKC will start Kodi playback using Player().play(). Kodi
    # caches paths like our plugin://pkc. If we use Player().play() between
    # 2 consecutive startups of exactly the same Kodi library item, Kodi's
    # cache will have been flushed for some reason. Hence the 2nd call for
    # plugin://pkc will be lost; Kodi will try to startup playback for an empty
    # path: log entry is "CGUIWindowVideoBase::OnPlayMedia <missing path>"
    thread.start()
    def processTasks(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']

        # Get the token of the user flinging media (might be different one)
        token = data.get('token')
        if task['action'] == 'alexa':
            # e.g. Alexa
            xml = GetPlexMetadata(data['key'])
            try:
                xml[0].attrib
            except (AttributeError, IndexError, TypeError):
                log.error('Could not download Plex metadata')
                return
            api = API(xml[0])
            if api.getType() == v.PLEX_TYPE_ALBUM:
                log.debug('Plex music album detected')
                queue = self.mgr.playqueue.init_playqueue_from_plex_children(
                    api.getRatingKey())
                queue.plex_transient_token = token
            else:
                state.PLEX_TRANSIENT_TOKEN = token
                params = {
                    'mode': 'plex_node',
                    'key': '{server}%s' % data.get('key'),
                    'view_offset': data.get('offset'),
                    'play_directly': 'true',
                    'node': 'false'
                }
                executebuiltin('RunPlugin(plugin://%s?%s)' %
                               (v.ADDON_ID, urlencode(params)))

        elif (task['action'] == 'playlist'
              and data.get('address') == 'node.plexapp.com'):
            # E.g. watch later initiated by Companion
            state.PLEX_TRANSIENT_TOKEN = token
            params = {
                'mode': 'plex_node',
                'key': '{server}%s' % data.get('key'),
                'view_offset': data.get('offset'),
                'play_directly': 'true'
            }
            executebuiltin('RunPlugin(plugin://%s?%s)' %
                           (v.ADDON_ID, urlencode(params)))

        elif task['action'] == 'playlist':
            # Get the playqueue ID
            try:
                typus, ID, query = ParseContainerKey(data['containerKey'])
            except Exception as e:
                log.error('Exception while processing: %s' % e)
                import traceback
                log.error("Traceback:\n%s" % traceback.format_exc())
                return
            try:
                playqueue = self.mgr.playqueue.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 = GetPlexMetadata(data['key'])
                try:
                    xml[0].attrib
                except (AttributeError, IndexError, TypeError):
                    log.error('Could not download Plex metadata')
                    return
                api = API(xml[0])
                playqueue = self.mgr.playqueue.get_playqueue_from_type(
                    v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
            self.mgr.playqueue.update_playqueue_from_PMS(
                playqueue,
                ID,
                repeat=query.get('repeat'),
                offset=data.get('offset'))
            playqueue.plex_transient_token = token

        elif task['action'] == 'refreshPlayQueue':
            # example data: {'playQueueID': '8475', 'commandID': '11'}
            xml = get_pms_playqueue(data['playQueueID'])
            if xml is None:
                return
            if len(xml) == 0:
                log.debug('Empty playqueue received - clearing playqueue')
                plex_type = get_plextype_from_xml(xml)
                if plex_type is None:
                    return
                playqueue = self.mgr.playqueue.get_playqueue_from_type(
                    v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
                playqueue.clear()
                return
            playqueue = self.mgr.playqueue.get_playqueue_from_type(
                v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
            self.mgr.playqueue.update_playqueue_from_PMS(
                playqueue, data['playQueueID'])
Exemplo n.º 32
0
def _prep_playlist_stack(xml):
    stack = []
    for item in xml:
        api = API(item)
        if (state.CONTEXT_MENU_PLAY is False
                and api.getType() != v.PLEX_TYPE_CLIP):
            # If user chose to play via PMS or force transcode, do not
            # use the item path stored in the Kodi DB
            with plexdb.Get_Plex_DB() as plex_db:
                plex_dbitem = plex_db.getItem_byId(api.getRatingKey())
            kodi_id = plex_dbitem[0] if plex_dbitem else None
            kodi_type = plex_dbitem[4] if plex_dbitem else None
        else:
            # We will never store clips (trailers) in the Kodi DB
            kodi_id = None
            kodi_type = None
        for part, _ in enumerate(item[0]):
            api.setPartNumber(part)
            if kodi_id is None:
                # Need to redirect again to PKC to conclude playback
                params = {
                    'mode': 'play',
                    'plex_id': api.getRatingKey(),
                    'plex_type': api.getType()
                }
                path = ('plugin://plugin.video.plexkodiconnect?%s' %
                        urlencode(params))
                listitem = api.CreateListItemFromPlexItem()
                listitem.setPath(tryEncode(path))
            else:
                # Will add directly via the Kodi DB
                path = None
                listitem = None
            stack.append({
                'kodi_id': kodi_id,
                'kodi_type': kodi_type,
                'file': path,
                'xml_video_element': item,
                'listitem': listitem,
                'part': part,
                'playcount': api.getViewCount(),
                'offset': api.getResume(),
                'id': api.getItemId()
            })
    return stack
Exemplo n.º 33
0
def process_indirect(key, offset, resolve=True):
    """
    Called e.g. for Plex "Play later" - Plex items where we need to fetch an
    additional xml for the actual playurl. In the PMS metadata, indirect="1" is
    set.

    Will release default.py with setResolvedUrl

    Set resolve to False if playback should be kicked off directly, not via
    setResolvedUrl
    """
    LOG.info('process_indirect called with key: %s, offset: %s', key, offset)
    result = Playback_Successful()
    if key.startswith('http') or key.startswith('{server}'):
        xml = DU().downloadUrl(key)
    elif key.startswith('/system/services'):
        xml = DU().downloadUrl('http://node.plexapp.com:32400%s' % key)
    else:
        xml = DU().downloadUrl('{server}%s' % key)
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not download PMS metadata')
        if resolve is True:
            # Release default.py
            pickle_me(result)
        return
    if offset != '0':
        offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
        # Todo: implement offset
    api = API(xml[0])
    listitem = PKC_ListItem()
    api.CreateListItemFromPlexItem(listitem)
    playqueue = PQ.get_playqueue_from_type(
        v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
    playqueue.clear()
    item = PL.Playlist_Item()
    item.xml = xml[0]
    item.offset = int(offset)
    item.plex_type = v.PLEX_TYPE_CLIP
    item.playmethod = 'DirectStream'
    # Need to get yet another xml to get the final playback url
    xml = DU().downloadUrl('http://node.plexapp.com:32400%s' %
                           xml[0][0][0].attrib['key'])
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not download last xml for playurl')
        if resolve is True:
            # Release default.py
            pickle_me(result)
        return
    playurl = xml[0].attrib['key']
    item.file = playurl
    listitem.setPath(tryEncode(playurl))
    playqueue.items.append(item)
    if resolve is True:
        result.listitem = listitem
        pickle_me(result)
    else:
        thread = Thread(target=Player().play,
                        args={
                            'item': tryEncode(playurl),
                            'listitem': listitem
                        })
        thread.setDaemon(True)
        LOG.info('Done initializing PKC playback, starting Kodi player')
        thread.start()
Exemplo n.º 34
0
    def play(self, plex_id, kodi_id=None, plex_lib_UUID=None):
        """
        plex_lib_UUID: xml attribute 'librarySectionUUID', needed for posting
        to the PMS
        """
        log.info("Playbackutils called")
        item = self.xml[0]
        api = API(item)
        playqueue = self.playqueue
        xml = None
        result = Playback_Successful()
        listitem = ListItem()
        playutils = putils.PlayUtils(item)
        playurl = playutils.getPlayUrl()
        if not playurl:
            log.error('No playurl found, aborting')
            return

        if kodi_id in (None, 'plextrailer', 'plexnode'):
            # Item is not in Kodi database, is a trailer/clip or plex redirect
            # e.g. plex.tv watch later
            api.CreateListItemFromPlexItem(listitem)
            api.set_listitem_artwork(listitem)
            if kodi_id == 'plexnode':
                # Need to get yet another xml to get final url
                window('plex_%s.playmethod' % playurl, clear=True)
                xml = downloadutils.DownloadUtils().downloadUrl(
                    '{server}%s' % item[0][0].attrib.get('key'))
                try:
                    xml[0].attrib
                except (TypeError, AttributeError):
                    log.error('Could not download %s'
                              % item[0][0].attrib.get('key'))
                    return
                playurl = tryEncode(xml[0].attrib.get('key'))
                window('plex_%s.playmethod' % playurl, value='DirectStream')

            playmethod = window('plex_%s.playmethod' % playurl)
            if playmethod == "Transcode":
                window('plex_%s.playmethod' % playurl, clear=True)
                playurl = tryEncode(playutils.audioSubsPref(
                    listitem, tryDecode(playurl)))
                window('plex_%s.playmethod' % playurl, "Transcode")
            listitem.setPath(playurl)
            api.set_playback_win_props(playurl, listitem)
            result.listitem = listitem
            return result

        kodi_type = v.KODITYPE_FROM_PLEXTYPE[api.getType()]
        kodi_id = int(kodi_id)

        # ORGANIZE CURRENT PLAYLIST ################
        contextmenu_play = window('plex_contextplay') == 'true'
        window('plex_contextplay', clear=True)
        homeScreen = getCondVisibility('Window.IsActive(home)')
        sizePlaylist = len(playqueue.items)
        if contextmenu_play:
            # Need to start with the items we're inserting here
            startPos = sizePlaylist
        else:
            # Can return -1
            startPos = max(playqueue.kodi_pl.getposition(), 0)
        self.currentPosition = startPos

        propertiesPlayback = window('plex_playbackProps') == "true"
        introsPlaylist = False
        dummyPlaylist = False

        log.info("Playing from contextmenu: %s" % contextmenu_play)
        log.info("Playlist start position: %s" % startPos)
        log.info("Playlist plugin position: %s" % self.currentPosition)
        log.info("Playlist size: %s" % sizePlaylist)

        # RESUME POINT ################
        seektime, runtime = api.getRuntime()
        if window('plex_customplaylist.seektime'):
            # Already got seektime, e.g. from playqueue & Plex companion
            seektime = int(window('plex_customplaylist.seektime'))

        # We need to ensure we add the intro and additional parts only once.
        # Otherwise we get a loop.
        if not propertiesPlayback:
            window('plex_playbackProps', value="true")
            log.info("Setting up properties in playlist.")
            # Where will the player need to start?
            # Do we need to get trailers?
            trailers = False
            if (api.getType() == v.PLEX_TYPE_MOVIE and
                    not seektime and
                    sizePlaylist < 2 and
                    settings('enableCinema') == "true"):
                if settings('askCinema') == "true":
                    trailers = xbmcgui.Dialog().yesno(
                        lang(29999),
                        "Play trailers?")
                else:
                    trailers = True
            # Post to the PMS. REUSE THE PLAYQUEUE!
            xml = init_plex_playqueue(plex_id,
                                      plex_lib_UUID,
                                      mediatype=api.getType(),
                                      trailers=trailers)
            try:
                get_playlist_details_from_xml(playqueue, xml=xml)
            except KeyError:
                return

            if (not homeScreen and not seektime and sizePlaylist < 2 and
                    window('plex_customplaylist') != "true" and
                    not contextmenu_play):
                # Need to add a dummy file because the first item will fail
                log.debug("Adding dummy file to playlist.")
                dummyPlaylist = True
                add_listitem_to_Kodi_playlist(
                    playqueue,
                    startPos,
                    xbmcgui.ListItem(),
                    playurl,
                    xml[0])
                # Remove the original item from playlist
                remove_from_Kodi_playlist(
                    playqueue,
                    startPos+1)
                # Readd the original item to playlist - via jsonrpc so we have
                # full metadata
                add_item_to_kodi_playlist(
                    playqueue,
                    self.currentPosition+1,
                    kodi_id=kodi_id,
                    kodi_type=kodi_type,
                    file=playurl)
                self.currentPosition += 1

            # -- ADD TRAILERS ################
            if trailers:
                for i, item in enumerate(xml):
                    if i == len(xml) - 1:
                        # Don't add the main movie itself
                        break
                    self.add_trailer(item)
                    introsPlaylist = True

            # -- ADD MAIN ITEM ONLY FOR HOMESCREEN ##############
            if homeScreen and not seektime and not sizePlaylist:
                # Extend our current playlist with the actual item to play
                # only if there's no playlist first
                log.info("Adding main item to playlist.")
                add_item_to_kodi_playlist(
                    playqueue,
                    self.currentPosition,
                    kodi_id,
                    kodi_type)

            elif contextmenu_play:
                if window('useDirectPaths') == 'true':
                    # Cannot add via JSON with full metadata because then we
                    # Would be using the direct path
                    log.debug("Adding contextmenu item for direct paths")
                    if window('plex_%s.playmethod' % playurl) == "Transcode":
                        window('plex_%s.playmethod' % playurl,
                               clear=True)
                        playurl = tryEncode(playutils.audioSubsPref(
                            listitem, tryDecode(playurl)))
                        window('plex_%s.playmethod' % playurl,
                               value="Transcode")
                    api.CreateListItemFromPlexItem(listitem)
                    api.set_playback_win_props(playurl, listitem)
                    api.set_listitem_artwork(listitem)
                    add_listitem_to_Kodi_playlist(
                        playqueue,
                        self.currentPosition+1,
                        convert_PKC_to_listitem(listitem),
                        playurl,
                        kodi_item={'id': kodi_id, 'type': kodi_type})
                else:
                    # Full metadata$
                    add_item_to_kodi_playlist(
                        playqueue,
                        self.currentPosition+1,
                        kodi_id,
                        kodi_type)
                self.currentPosition += 1
                if seektime:
                    window('plex_customplaylist.seektime', value=str(seektime))

            # Ensure that additional parts are played after the main item
            self.currentPosition += 1

            # -- CHECK FOR ADDITIONAL PARTS ################
            if len(item[0]) > 1:
                self.add_part(item, api, kodi_id, kodi_type)

            if dummyPlaylist:
                # Added a dummy file to the playlist,
                # because the first item is going to fail automatically.
                log.info("Processed as a playlist. First item is skipped.")
                # Delete the item that's gonna fail!
                del playqueue.items[startPos]
                # Don't attach listitem
                return result

        # We just skipped adding properties. Reset flag for next time.
        elif propertiesPlayback:
            log.debug("Resetting properties playback flag.")
            window('plex_playbackProps', clear=True)

        # SETUP MAIN ITEM ##########
        # For transcoding only, ask for audio/subs pref
        if (window('plex_%s.playmethod' % playurl) == "Transcode" and
                not contextmenu_play):
            window('plex_%s.playmethod' % playurl, clear=True)
            playurl = tryEncode(playutils.audioSubsPref(
                listitem, tryDecode(playurl)))
            window('plex_%s.playmethod' % playurl, value="Transcode")

        listitem.setPath(playurl)
        api.set_playback_win_props(playurl, listitem)
        api.set_listitem_artwork(listitem)

        # PLAYBACK ################
        if (homeScreen and seektime and window('plex_customplaylist') != "true"
                and not contextmenu_play):
            log.info("Play as a widget item")
            api.CreateListItemFromPlexItem(listitem)
            result.listitem = listitem
            return result

        elif ((introsPlaylist and window('plex_customplaylist') == "true") or
                (homeScreen and not sizePlaylist) or
                contextmenu_play):
            # Playlist was created just now, play it.
            # Contextmenu plays always need this
            log.info("Play playlist from starting position %s" % startPos)
            # Need a separate thread because Player won't return in time
            thread = Thread(target=Player().play,
                            args=(playqueue.kodi_pl, None, False, startPos))
            thread.setDaemon(True)
            thread.start()
            # Don't attach listitem
            return result
        else:
            log.info("Play as a regular item")
            result.listitem = listitem
            return result
Exemplo n.º 35
0
def set_excludefromscan_music_folders():
    """
    Gets a complete list of paths for music libraries from the PMS. Sets them
    to be excluded in the advancedsettings.xml from being scanned by Kodi.
    Existing keys will be replaced

    Returns False if no new Plex libraries needed to be exluded, True otherwise
    """
    changed = False
    write_xml = False
    xml = get_plex_sections()
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        log.error('Could not get Plex sections')
        return
    # Build paths
    paths = []
    api = API(item=None)
    for library in xml:
        if library.attrib['type'] != v.PLEX_TYPE_ARTIST:
            # Only look at music libraries
            continue
        for location in library:
            if location.tag == 'Location':
                path = api.validatePlayurl(location.attrib['path'],
                                           typus=v.PLEX_TYPE_ARTIST,
                                           omitCheck=True)
                paths.append(__turn_to_regex(path))
    # Get existing advancedsettings
    root, tree = advancedsettings_xml(['audio', 'excludefromscan'],
                                      force_create=True)

    for path in paths:
        for element in root:
            if element.text == path:
                # Path already excluded
                break
        else:
            changed = True
            write_xml = True
            log.info('New Plex music library detected: %s' % path)
            element = etree.Element(tag='regexp')
            element.text = path
            root.append(element)

    # Delete obsolete entries (unlike above, we don't change 'changed' to not
    # enforce a restart)
    for element in root:
        for path in paths:
            if element.text == path:
                break
        else:
            log.info('Deleting Plex music library from advancedsettings: %s'
                     % element.text)
            root.remove(element)
            write_xml = True

    if write_xml is True:
        indent(tree.getroot())
        tree.write('%sadvancedsettings.xml' % v.KODI_PROFILE, encoding="UTF-8")
    return changed
Exemplo n.º 36
0
def getOnDeck(viewid, mediatype, tagname, limit):
    """
    Retrieves Plex On Deck items, currently only for TV shows

    Input:
        viewid:             Plex id of the library section, e.g. '1'
        mediatype:          Kodi mediatype, e.g. 'tvshows', 'movies',
                            'homevideos', 'photos'
        tagname:            Name of the Plex library, e.g. "My Movies"
        limit:              Max. number of items to retrieve, e.g. 50
    """
    xbmcplugin.setContent(HANDLE, 'episodes')
    appendShowTitle = settings('OnDeckTvAppendShow') == 'true'
    appendSxxExx = settings('OnDeckTvAppendSeason') == 'true'
    directpaths = settings('useDirectPaths') == 'true'
    if settings('OnDeckTVextended') == 'false':
        # Chances are that this view is used on Kodi startup
        # Wait till we've connected to a PMS. At most 30s
        counter = 0
        while window('plex_authenticated') != 'true':
            counter += 1
            if counter >= 300:
                log.error('Aborting On Deck view, we were not authenticated '
                          'for the PMS')
                return xbmcplugin.endOfDirectory(HANDLE, False)
            sleep(100)
        xml = downloadutils.DownloadUtils().downloadUrl(
            '{server}/library/sections/%s/onDeck' % viewid)
        if xml in (None, 401):
            log.error('Could not download PMS xml for view %s' % viewid)
            return xbmcplugin.endOfDirectory(HANDLE)
        limitcounter = 0
        for item in xml:
            api = API(item)
            listitem = api.CreateListItemFromPlexItem(
                appendShowTitle=appendShowTitle,
                appendSxxExx=appendSxxExx)
            if directpaths:
                url = api.getFilePath()
            else:
                params = {
                    'mode': "play",
                    'id': api.getRatingKey(),
                    'dbid': listitem.getProperty('dbid')
                }
                url = "plugin://plugin.video.plexkodiconnect/tvshows/?%s" \
                      % urlencode(params)
            xbmcplugin.addDirectoryItem(
                handle=HANDLE,
                url=url,
                listitem=listitem)
            limitcounter += 1
            if limitcounter == limit:
                break
        return xbmcplugin.endOfDirectory(
            handle=HANDLE,
            cacheToDisc=settings('enableTextureCache') == 'true')

    # if the addon is called with nextup parameter,
    # we return the nextepisodes list of the given tagname
    # First we get a list of all the TV shows - filtered by tag
    params = {
        'sort': {'order': "descending", 'method': "lastplayed"},
        'filter': {
            'and': [
                {'operator': "true", 'field': "inprogress", 'value': ""},
                {'operator': "is", 'field': "tag", 'value': "%s" % tagname}
            ]}
    }
    result = JSONRPC('VideoLibrary.GetTVShows').execute(params)
    # If we found any, find the oldest unwatched show for each one.
    try:
        items = result['result'][mediatype]
    except (KeyError, TypeError):
        # Now items retrieved - empty directory
        xbmcplugin.endOfDirectory(handle=HANDLE)
        return

    params = {
        'sort': {'method': "episode"},
        'limits': {"end": 1},
        'properties': [
            "title", "playcount", "season", "episode", "showtitle",
            "plot", "file", "rating", "resume", "tvshowid", "art",
            "streamdetails", "firstaired", "runtime", "cast", "writer",
            "dateadded", "lastplayed"
        ],
    }
    if settings('ignoreSpecialsNextEpisodes') == "true":
        params['filter'] = {
            'and': [
                {'operator': "lessthan", 'field': "playcount", 'value': "1"},
                {'operator': "greaterthan", 'field': "season", 'value': "0"}
            ]
        }
    else:
        params['filter'] = {
            'or': [
                {'operator': "lessthan", 'field': "playcount", 'value': "1"},
                {'operator': "true", 'field': "inprogress", 'value': ""}
            ]
        }

    # Are there any episodes still in progress/not yet finished watching?!?
    # Then we should show this episode, NOT the "next up"
    inprog_params = {
        'sort': {'method': "episode"},
        'filter': {'operator': "true", 'field': "inprogress", 'value': ""},
        'properties': params['properties']
    }

    count = 0
    for item in items:
        inprog_params['tvshowid'] = item['tvshowid']
        result = JSONRPC('VideoLibrary.GetEpisodes').execute(inprog_params)
        try:
            episodes = result['result']['episodes']
        except (KeyError, TypeError):
            # No, there are no episodes not yet finished. Get "next up"
            params['tvshowid'] = item['tvshowid']
            result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
            try:
                episodes = result['result']['episodes']
            except (KeyError, TypeError):
                # Also no episodes currently coming up
                continue
        for episode in episodes:
            # There will always be only 1 episode ('limit=1')
            li = createListItem(episode,
                                appendShowTitle=appendShowTitle,
                                appendSxxExx=appendSxxExx)
            xbmcplugin.addDirectoryItem(
                handle=HANDLE,
                url=episode['file'],
                listitem=li,
                isFolder=False)

        count += 1
        if count >= limit:
            break

    xbmcplugin.endOfDirectory(handle=HANDLE)
Exemplo n.º 37
0
def excludefromscan_music_folders():
    """
    Gets a complete list of paths for music libraries from the PMS. Sets them
    to be excluded in the advancedsettings.xml from being scanned by Kodi.
    Existing keys will be replaced

    Reboots Kodi if new library detected
    """
    xml = get_plex_sections()
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not get Plex sections')
        return
    # Build paths
    paths = []
    api = API(item=None)
    for library in xml:
        if library.attrib['type'] != v.PLEX_TYPE_ARTIST:
            # Only look at music libraries
            continue
        for location in library:
            if location.tag == 'Location':
                path = api.validate_playurl(location.attrib['path'],
                                            typus=v.PLEX_TYPE_ARTIST,
                                            omit_check=True)
                paths.append(__turn_to_regex(path))
    try:
        with XmlKodiSetting('advancedsettings.xml',
                            force_create=True,
                            top_element='advancedsettings') as xml:
            parent = xml.set_setting(['audio', 'excludefromscan'])
            for path in paths:
                for element in parent:
                    if element.text == path:
                        # Path already excluded
                        break
                else:
                    LOG.info('New Plex music library detected: %s', path)
                    xml.set_setting(['audio', 'excludefromscan', 'regexp'],
                                    value=path,
                                    append=True)
            # We only need to reboot if we ADD new paths!
            reboot = xml.write_xml
            # Delete obsolete entries
            for element in parent:
                for path in paths:
                    if element.text == path:
                        break
                else:
                    LOG.info(
                        'Deleting music library from advancedsettings: %s',
                        element.text)
                    parent.remove(element)
    except (ParseError, IOError):
        LOG.error('Could not adjust advancedsettings.xml')
        reboot = False
    if reboot is True:
        #  'New Plex music library detected. Sorry, but we need to
        #  restart Kodi now due to the changes made.'
        reboot_kodi(lang(39711))
Exemplo n.º 38
0
def _prep_playlist_stack(xml):
    stack = []
    for item in xml:
        api = API(item)
        if (state.CONTEXT_MENU_PLAY is False
                and api.plex_type() != v.PLEX_TYPE_CLIP):
            # If user chose to play via PMS or force transcode, do not
            # use the item path stored in the Kodi DB
            with plexdb.Get_Plex_DB() as plex_db:
                plex_dbitem = plex_db.getItem_byId(api.plex_id())
            kodi_id = plex_dbitem[0] if plex_dbitem else None
            kodi_type = plex_dbitem[4] if plex_dbitem else None
        else:
            # We will never store clips (trailers) in the Kodi DB.
            # Also set kodi_id to None for playback via PMS, so that we're
            # using add-on paths.
            kodi_id = None
            kodi_type = None
        for part, _ in enumerate(item[0]):
            api.set_part_number(part)
            if kodi_id is None:
                # Need to redirect again to PKC to conclude playback
                path = ('plugin://%s/?plex_id=%s&plex_type=%s&mode=play' %
                        (v.ADDON_TYPE[api.plex_type()], api.plex_id(),
                         api.plex_type()))
                listitem = api.create_listitem()
                listitem.setPath(try_encode(path))
            else:
                # Will add directly via the Kodi DB
                path = None
                listitem = None
            stack.append({
                'kodi_id': kodi_id,
                'kodi_type': kodi_type,
                'file': path,
                'xml_video_element': item,
                'listitem': listitem,
                'part': part,
                'playcount': api.viewcount(),
                'offset': api.resume_point(),
                'id': api.item_id()
            })
    return stack
Exemplo n.º 39
0
def __build_item(xml_element):
    api = API(xml_element)
    listitem = api.create_listitem()
    resume = api.resume_point()
    if resume:
        listitem.setProperty('resumetime', str(resume))
    if (api.path_and_plex_id().startswith('/system/services')
            or api.path_and_plex_id().startswith('http')):
        params = {
            'mode': 'plex_node',
            'key': xml_element.attrib.get('key'),
            'offset': xml_element.attrib.get('viewOffset', '0'),
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    elif api.plex_type() == v.PLEX_TYPE_PHOTO:
        url = api.get_picture_path()
    else:
        url = 'plugin://%s/?plex_id=%s&plex_type=%s&mode=play' \
              % (v.ADDON_TYPE[api.plex_type()], api.plex_id(), api.plex_type())
    xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=listitem)