def refreshMetadata(item: ListItem, itemId: int, mediaProvider: xbmcmediaimport.MediaProvider): # create a Plex server instance server = Server(mediaProvider) if not server.Authenticate(): contextLog( f"failed to connect to Plex Media Server for {mediaProvider2str(mediaProvider)}", xbmc.LOGWARNING, entry='refresh') return plexItemClass = Api.getPlexMediaClassFromListItem(item) # get the Plex item with all its details plexItem = Api.getPlexItemDetails(server.PlexServer(), itemId, plexItemClass=plexItemClass) if not plexItem: contextLog( f"failed to determine Plex item for {listItem2str(item, itemId)} from {mediaProvider2str(mediaProvider)}", xbmc.LOGWARNING, entry='refresh') return # trigger a metadata refresh on the Plex server plexItem.refresh() contextLog( f"triggered metadata refresh for {listItem2str(item, itemId)} on {mediaProvider2str(mediaProvider)}", entry="refresh")
def play(item, itemId, mediaProvider): if item.isFolder(): contextLog(f"cannot play folder item {listItem2str(item, itemId)}", xbmc.LOGERROR, entry='play') return # create a Plex server instance server = Server(mediaProvider) if not server.Authenticate(): contextLog( f"failed to connect to Plex Media Server for {mediaProvider2str(mediaProvider)}", xbmc.LOGWARNING, entry='sync') return plexItemClass = Api.getPlexMediaClassFromListItem(item) # cannot play folders if plexItemClass in (collection.Collection, video.Show, video.Season): contextLog(f"cannot play folder item {listItem2str(item, itemId)}", xbmc.LOGERROR, entry='play') return # get the Plex item with all its details plexItem = Api.getPlexItemDetails(server.PlexServer(), itemId, plexItemClass=plexItemClass) if not plexItem: contextLog( f"failed to determine Plex item for {listItem2str(item, itemId)} from {mediaProvider2str(mediaProvider)}", xbmc.LOGWARNING, entry='refresh') return # cannot play folders if not Api.canPlay(plexItem): contextLog(f"cannot play item {listItem2str(item, itemId)}", xbmc.LOGERROR, entry='play') return playChoices = [] playChoicesUrl = [] # determine whether Direct Play is allowed mediaProviderSettings = mediaProvider.getSettings() allowDirectPlay = mediaProviderSettings.getBool(SETTINGS_PROVIDER_PLAYBACK_ALLOW_DIRECT_PLAY) # check if the item supports Direct Play if allowDirectPlay: directPlayUrl = Api.getDirectPlayUrlFromPlexItem(plexItem) if directPlayUrl: playChoices.append(localize(32103)) playChoicesUrl.append(directPlayUrl) # check if the item supports streaming directStreamUrl = Api.getStreamUrlFromPlexItem(plexItem, server.PlexServer()) if directStreamUrl: playChoices.append(localize(32104)) playChoicesUrl.append(directStreamUrl) # check if the item has multiple versions multipleVersions = [] if len(plexItem.media) > 1: for mediaStream in plexItem.media: url = None if allowDirectPlay: directPlayUrl = Api.getDirectPlayUrlFromMedia(mediaStream) if directPlayUrl: url = directPlayUrl if not url: url = Api.getStreamUrlFromMedia(mediaStream, server.PlexServer()) # get the display title of the first videostream for mediaPart in mediaStream.parts: # get all video streams videoStreams = (stream for stream in mediaPart.streams if isinstance(stream, media.VideoStream)) # extract the first non-empty display resolution displayResolution = next( ( stream.displayTitle or stream.extendedDisplayTitle for stream in videoStreams if stream.displayTitle or stream.extendedDisplayTitle ), None) if displayResolution: break # fall back to the basic video resolution of the stream if not displayResolution: displayResolution = mediaStream.videoResolution multipleVersions.append((url, mediaStream.bitrate, displayResolution)) if len(multipleVersions) > 1: playChoices.append(localize(32105)) playChoicesUrl.append(PLAY_MULTIPLE_VERSIONS_KEY) # if there are no options something went wrong if not playChoices: contextLog( f"cannot play {listItem2str(item, itemId)} from {mediaProvider2str(mediaProvider)}", xbmc.LOGERROR, entry='play') return # ask the user how to play playChoice = Dialog().contextmenu(playChoices) if playChoice < 0 or playChoice >= len(playChoices): return playUrl = playChoicesUrl[playChoice] # check if the user chose to choose which version to play if playUrl == PLAY_MULTIPLE_VERSIONS_KEY: playChoices.clear() playChoicesUrl.clear() # sort the available versions by bitrate (second field) multipleVersions.sort(key=lambda version: version[1], reverse=True) for version in multipleVersions: playChoices.append( localize(32106, bitrate=bitrate2str(version[1]), resolution=version[2])) playChoicesUrl.append(version[0]) # ask the user which version to play playChoice = Dialog().contextmenu(playChoices) if playChoice < 0 or playChoice >= len(playChoices): return playUrl = playChoicesUrl[playChoice] # play the item contextLog( ( f'playing {listItem2str(item, itemId)} using "{playChoices[playChoice]}" ({playUrl}) ' f'from {mediaProvider2str(mediaProvider)}' ), entry='play') # overwrite the dynamic path of the ListItem item.setDynamicPath(playUrl) xbmc.Player().play(playUrl, item)
def updateOnProvider(handle, options): # retrieve the media import mediaImport = xbmcmediaimport.getImport(handle) if not mediaImport: log('cannot retrieve media import', xbmc.LOGERROR) return # retrieve the media provider mediaProvider = mediaImport.getProvider() if not mediaProvider: log('cannot retrieve media provider', xbmc.LOGERROR) return # prepare the media provider settings if not mediaProvider.prepareSettings(): log('cannot prepare media provider settings', xbmc.LOGERROR) return # prepare and get the media import settings importSettings = mediaImport.prepareSettings() if not importSettings: log('cannot prepare media import settings', xbmc.LOGERROR) return item = xbmcmediaimport.getUpdatedItem(handle) if not item: log('cannot retrieve updated item', xbmc.LOGERROR) return itemVideoInfoTag = item.getVideoInfoTag() if not itemVideoInfoTag: log('updated item is not a video item', xbmc.LOGERROR) return # determine the item's identifier / ratingKey itemId = Api.getItemIdFromListItem(item) if not itemId: log('cannot determine the identifier of the updated item: {}'.format(itemVideoInfoTag.getPath()), xbmc.LOGERROR) return # create a Plex server instance server = Server(mediaProvider) if not server.Authenticate(): log('failed to connect to Plex Media Server for {}'.format(mediaProvider2str(mediaProvider)), xbmc.LOGWARNING) return plexItem = Api.getPlexItemDetails(server.PlexServer(), itemId, Api.getPlexMediaClassFromMediaType(itemVideoInfoTag.getMediaType())) if not plexItem: log('cannot retrieve details of updated item {} with id {}'.format(itemVideoInfoTag.getPath(), itemId), xbmc.LOGERROR) return # check / update watched state playcount = itemVideoInfoTag.getPlayCount() watched = playcount > 0 if watched != plexItem.isWatched: if watched: plexItem.markWatched() else: plexItem.markUnwatched() # TODO(Montellese): check / update last played # TODO(Montellese): check / update resume point xbmcmediaimport.finishUpdateOnProvider(handle)
def _startPlayback(self): '''Identifies the item (if from Plex) and initializes the player state''' if not self._file: return if not self.isPlayingVideo(): return playingItem = self.getPlayingItem() if not playingItem: return # check if the item has been imported from a media provider mediaProviderId = playingItem.getMediaProviderId() if not mediaProviderId: return if not mediaProviderId in self._providers: log('currently playing item {} ({}) has been imported from an unknown media provider {}' \ .format(playingItem.getLabel(), self._file, mediaProviderId), xbmc.LOGWARNING) return self._mediaProvider = self._providers[mediaProviderId] videoInfoTag = self.getVideoInfoTag() if not videoInfoTag: return itemId = videoInfoTag.getUniqueID(PLEX_PROTOCOL) if not itemId: return if not itemId.isdigit(): log('invalid item id plex://{} (non digit). Kodi will not report playback state to Plex Media Server' \ .format(itemId), xbmc.LOGERROR) return self._itemId = int(itemId) if self._mediaProvider: # save item plexServer = Server(self._mediaProvider) self._item = Api.getPlexItemDetails( plexServer.PlexServer(), self._itemId, Api.getPlexMediaClassFromMediaType( videoInfoTag.getMediaType())) self._duration = toMilliseconds(self.getTotalTime()) # register settings settings = self._mediaProvider.prepareSettings() if not settings: log('failed to load settings for {} ({}) playing from {}' \ .format(self._item.title, self._file, mediaProvider2str(self._mediaProvider)), xbmc.LOGWARNING) self._reset() return # load external subtitles if settings.getBool( SETTINGS_PROVIDER_PLAYBACK_ENABLE_EXTERNAL_SUBTITLES): self._addExternalSubtitles(plexServer.PlexServer()) else: self._reset()
def updateOnProvider(handle: int, _options: dict): """Perform update/export of library items from Kodi into conifigured PMS (watch status, resume points, etc.) :param handle: Handle id from input :type handle: int :param _options: Options/parameters passed in with the call, Unused :type _options: dict """ # retrieve the media import mediaImport = xbmcmediaimport.getImport(handle) if not mediaImport: log("cannot retrieve media import", xbmc.LOGERROR) return # retrieve the media provider mediaProvider = mediaImport.getProvider() if not mediaProvider: log("cannot retrieve media provider", xbmc.LOGERROR) return # prepare the media provider settings if not mediaProvider.prepareSettings(): log("cannot prepare media provider settings", xbmc.LOGERROR) return # prepare and get the media import settings importSettings = mediaImport.prepareSettings() if not importSettings: log("cannot prepare media import settings", xbmc.LOGERROR) return item = xbmcmediaimport.getUpdatedItem(handle) if not item: log("cannot retrieve updated item", xbmc.LOGERROR) return itemVideoInfoTag = item.getVideoInfoTag() if not itemVideoInfoTag: log("updated item is not a video item", xbmc.LOGERROR) return # determine the item's identifier / ratingKey itemId = Api.getItemIdFromListItem(item) if not itemId: log( f"cannot determine the identifier of the updated item: {itemVideoInfoTag.getPath()}", xbmc.LOGERROR) return # create a Plex server instance server = Server(mediaProvider) if not server.Authenticate(): log( f"failed to connect to Plex Media Server for {mediaProvider2str(mediaProvider)}", xbmc.LOGWARNING) return plexItem = Api.getPlexItemDetails( server.PlexServer(), itemId, Api.getPlexMediaClassFromMediaType(itemVideoInfoTag.getMediaType())) if not plexItem: log( f"cannot retrieve details of updated item {itemVideoInfoTag.getPath()} with id {itemId}", xbmc.LOGERROR) return # check / update watched state playcount = itemVideoInfoTag.getPlayCount() watched = playcount > 0 if watched != plexItem.isWatched: if watched: plexItem.markWatched() else: plexItem.markUnwatched() # TODO(Montellese): check / update last played # TODO(Montellese): check / update resume point xbmcmediaimport.finishUpdateOnProvider(handle)
def _startPlayback(self): """Identifies the item (if from Plex) and initializes the player state""" if not self._file: return if not self.isPlayingVideo(): return playingItem = self.getPlayingItem() if not playingItem: return # check if the item has been imported from a media provider mediaProviderId = playingItem.getMediaProviderId() if not mediaProviderId: return if mediaProviderId not in self._providers: log( ( f"currently playing item {playingItem.getLabel()} ({self._file}) " f"has been imported from an unknown media provider {mediaProviderId}" ), xbmc.LOGWARNING ) return self._mediaProvider = self._providers[mediaProviderId] if not self._mediaProvider: return videoInfoTag = self.getVideoInfoTag() if not videoInfoTag: return itemId = videoInfoTag.getUniqueID(PLEX_PROTOCOL) if not itemId: return if not itemId.isdigit(): log( f"Item id is not a digit: plex://{itemId}. Kodi will not report playback state to Plex Media Server", xbmc.LOGERROR ) return self._itemId = int(itemId) # save item plexServer = Server(self._mediaProvider) self._item = Api.getPlexItemDetails( plexServer.PlexServer(), self._itemId, Api.getPlexMediaClassFromMediaType(videoInfoTag.getMediaType()) ) if not self._item: log( ( f"failed to retrieve details for item {self._itemId} ({self._file}) " f"playing from {mediaProvider2str(self._mediaProvider)}" ), xbmc.LOGWARNING ) self._reset() return self._duration = toMilliseconds(self.getTotalTime()) # handle any provider specific settings self._handleProviderSettings(plexServer.PlexServer()) # get the matching media import self._mediaImport = self._mediaProvider.getImportByMediaType(videoInfoTag.getMediaType()) if self._mediaImport: # handle any import specific settings self._handleImportSettings() else: log( ( f"failed to determine import for {self._item.title} ({self._file}) " f"playing from {mediaProvider2str(self._mediaProvider)}" ), xbmc.LOGWARNING )