예제 #1
0
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")
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
    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()
예제 #5
0
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)
예제 #6
0
    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
            )