Exemple #1
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:
        params = {
            'mode': 'play',
            'plex_id': api.plex_id(),
            'plex_type': api.plex_type(),
        }
        url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
    xbmcplugin.addDirectoryItem(handle=HANDLE,
                                url=url,
                                listitem=listitem)
Exemple #2
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
Exemple #3
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.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}')
            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()
Exemple #4
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
                params = {
                    'mode': 'play',
                    'plex_id': api.plex_id(),
                    'plex_type': api.plex_type()
                }
                path = ('plugin://%s/?%s' %
                        (v.ADDON_TYPE[api.plex_type()], urlencode(params)))
                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
Exemple #5
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
Exemple #6
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()