def _process_refresh(self, data): """ 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 = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type]) playqueue.clear() return playqueue = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']]) PQ.update_playqueue_from_PMS(playqueue, data['playQueueID'])
def _PMS_play(self): """ For using direct paths: Initiates playback using the PMS """ playqueue = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_KODI_TYPE[self.kodi_type]) playqueue.clear() state.CONTEXT_MENU_PLAY = True handle = ('plugin://%s/?plex_id=%s&plex_type=%s&mode=play' % (v.ADDON_TYPE[self.plex_type], self.plex_id, self.plex_type)) executebuiltin('RunPlugin(%s)' % handle)
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'))
def _PMS_play(self): """ For using direct paths: Initiates playback using the PMS """ playqueue = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_KODI_TYPE[self.kodi_type]) playqueue.clear() state.CONTEXT_MENU_PLAY = True params = { 'mode': 'play', 'plex_id': self.plex_id, 'plex_type': self.plex_type } from urllib import urlencode handle = ("plugin://plugin.video.plexkodiconnect/movies?%s" % urlencode(params)) executebuiltin('RunPlugin(%s)' % handle)
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)
def _process_streams(self, data): """ Plex Companion client adjusted audio or subtitle stream """ playqueue = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']]) pos = js.get_position(playqueue.playlistid) if 'audioStreamID' in data: index = playqueue.items[pos].kodi_stream_index( data['audioStreamID'], 'audio') self.player.setAudioStream(index) elif 'subtitleStreamID' in data: if data['subtitleStreamID'] == '0': self.player.showSubtitles(False) else: index = playqueue.items[pos].kodi_stream_index( data['subtitleStreamID'], 'subtitle') self.player.setSubtitleStream(index) else: LOG.error('Unknown setStreams command: %s', data)
def _process_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)
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()