Beispiel #1
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)
 def triage(self, item):
     _, params = item.split('?', 1)
     params = dict(parse_qsl(params))
     mode = params.get('mode')
     log.debug('Received mode: %s, params: %s' % (mode, params))
     try:
         if mode == 'play':
             result = self.process_play(params.get('id'),
                                        params.get('dbid'))
         elif mode == 'companion':
             result = self.process_companion()
         elif mode == 'plex_node':
             result = self.process_plex_node(
                 params.get('key'),
                 params.get('view_offset'),
                 directplay=True if params.get('play_directly') else False,
                 node=False if params.get('node') == 'false' else True)
     except:
         log.error('Error encountered for mode %s, params %s'
                   % (mode, params))
         import traceback
         log.error(traceback.format_exc())
         # Let default.py know!
         pickle_me(None)
     else:
         pickle_me(result)
Beispiel #3
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.setPartNumber(item.part)
        api.CreateListItemFromPlexItem(listitem)
        playutils = PlayUtils(api, item)
        playurl = playutils.getPlayUrl()
    else:
        playurl = item.file
    listitem.setPath(tryEncode(playurl))
    if item.playmethod in ('DirectStream', 'DirectPlay'):
        listitem.setSubtitles(api.externalSubs())
    else:
        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
    state.RESUMABLE = False
    result.listitem = listitem
    pickle_me(result)
    LOG.info('Done concluding playback')
Beispiel #4
0
def _ensure_resolve():
    """
    Will check whether RESOLVE=True and if so, fail Kodi playback startup
    with the path 'PKC_Dummy_Path_Which_Fails' using setResolvedUrl (and some
    pickling)

    This way we're making sure that other Python instances (calling default.py)
    will be destroyed.
    """
    if RESOLVE is True:
        state.PKC_CAUSED_STOP = True
        result = Playback_Successful()
        result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
        pickle_me(result)
 def triage(self, item):
     _, params = item.split('?', 1)
     params = dict(parse_qsl(params))
     mode = params.get('mode')
     LOG.debug('Received mode: %s, params: %s', mode, params)
     if mode == 'play':
         playback.playback_triage(plex_id=params.get('plex_id'),
                                  plex_type=params.get('plex_type'),
                                  path=params.get('path'))
     elif mode == 'plex_node':
         playback.process_indirect(params['key'], params['offset'])
     elif mode == 'context_menu':
         ContextMenu()
         result = Playback_Successful()
         # Let default.py know!
         pickle_me(result)
Beispiel #6
0
def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
    """
    Hit this function for addon path playback, Plex trailers, etc.
    Will setup playback first, then on second call complete playback.

    Will set Playback_Successful() with potentially a PKC_ListItem() attached
    (to be consumed by setResolvedURL in default.py)

    If trailers or additional (movie-)parts are added, default.py is released
    and a completely new player instance is called with a new playlist. This
    circumvents most issues with Kodi & playqueues

    Set resolve to False if you do not want setResolvedUrl to be called on
    the first pass - e.g. if you're calling this function from the original
    service.py Python instance
    """
    LOG.info('playback_triage called with plex_id %s, plex_type %s, path %s',
             plex_id, plex_type, path)
    if not state.AUTHENTICATED:
        LOG.error('Not yet authenticated for PMS, abort starting playback')
        if resolve is True:
            # Release default.py
            pickle_me(Playback_Successful())
        # "Unauthorized for PMS"
        dialog('notification', lang(29999), lang(30017))
        return
    playqueue = PQ.get_playqueue_from_type(
        v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
    pos = js.get_position(playqueue.playlistid)
    # Can return -1 (as in "no playlist")
    pos = pos if pos != -1 else 0
    LOG.debug('playQueue position: %s for %s', pos, playqueue)
    # Have we already initiated playback?
    try:
        playqueue.items[pos]
    except IndexError:
        # Release our default.py before starting our own Kodi player instance
        if resolve is True:
            state.PKC_CAUSED_STOP = True
            result = Playback_Successful()
            result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
            pickle_me(result)
        playback_init(plex_id, plex_type, playqueue)
    else:
        # kick off playback on second pass
        conclude_playback(playqueue, pos)
Beispiel #7
0
 def triage(self, item):
     mode, params = item.split('?', 1)
     params = dict(parse_qsl(params))
     log.debug('Received mode: %s, params: %s' % (mode, params))
     try:
         if mode == 'play':
             result = self.process_play(params.get('id'),
                                        params.get('dbid'))
         elif mode == 'companion':
             result = self.process_companion()
     except:
         log.error('Error encountered for mode %s, params %s'
                   % (mode, params))
         import traceback
         log.error(traceback.format_exc())
         # Let default.py know!
         pickle_me(None)
     else:
         pickle_me(result)
Beispiel #8
0
def _ensure_resolve(abort=False):
    """
    Will check whether RESOLVE=True and if so, fail Kodi playback startup
    with the path 'PKC_Dummy_Path_Which_Fails' using setResolvedUrl (and some
    pickling)

    This way we're making sure that other Python instances (calling default.py)
    will be destroyed.
    """
    if RESOLVE:
        LOG.debug('Passing dummy path to Kodi')
        if not state.CONTEXT_MENU_PLAY:
            # Because playback won't start with context menu play
            state.PKC_CAUSED_STOP = True
        result = Playback_Successful()
        result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
        pickle_me(result)
    if abort:
        # Reset some playback variables
        state.CONTEXT_MENU_PLAY = False
        state.FORCE_TRANSCODE = False
        state.RESUME_PLAYBACK = False
Beispiel #9
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()