private async Task <Either <BaseError, MediaItemScanResult <TMovie> > > UpdateStatistics(
        MediaItemScanResult <TMovie> result,
        TMovie incoming,
        string ffmpegPath,
        string ffprobePath)
    {
        TMovie existing = result.Item;

        if (result.IsAdded || MediaServerItemId(existing) != MediaServerItemId(incoming) ||
            existing.MediaVersions.Head().Streams.Count == 0)
        {
            if (_localFileSystem.FileExists(result.LocalPath))
            {
                _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", result.LocalPath);
                Either <BaseError, bool> refreshResult =
                    await _localStatisticsProvider.RefreshStatistics(
                        ffmpegPath,
                        ffprobePath,
                        existing,
                        result.LocalPath);

                foreach (BaseError error in refreshResult.LeftToSeq())
                {
                    _logger.LogWarning(
                        "Unable to refresh {Attribute} for media item {Path}. Error: {Error}",
                        "Statistics",
                        result.LocalPath,
                        error.Value);
                }

                foreach (bool _ in refreshResult.RightToSeq())
                {
                    result.IsUpdated = true;
                }
            }
        }

        return(result);
    }
Пример #2
0
    private async Task <Either <BaseError, Unit> > ProcessEpisodes(
        string showName,
        string seasonName,
        EmbyLibrary library,
        string ffmpegPath,
        string ffprobePath,
        List <EmbyPathReplacement> pathReplacements,
        EmbySeason season,
        List <EmbyItemEtag> existingEpisodes,
        List <EmbyEpisode> episodes,
        CancellationToken cancellationToken)
    {
        foreach (EmbyEpisode incoming in episodes)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(new ScanCanceled());
            }

            EmbyEpisode incomingEpisode  = incoming;
            var         updateStatistics = false;

            Option <EmbyItemEtag> maybeExisting = existingEpisodes.Find(ie => ie.ItemId == incoming.ItemId);
            if (maybeExisting.IsNone)
            {
                try
                {
                    updateStatistics       = true;
                    incoming.LibraryPathId = library.Paths.Head().Id;

                    _logger.LogDebug(
                        "INSERT: Item id is new for show {Show} season {Season} episode {Episode}",
                        showName,
                        seasonName,
                        incoming.EpisodeMetadata.HeadOrNone().Map(em => em.EpisodeNumber));

                    if (await _televisionRepository.AddEpisode(season, incoming))
                    {
                        await _searchIndex.AddItems(_searchRepository, new List <MediaItem> {
                            incoming
                        });
                    }
                }
                catch (Exception ex)
                {
                    updateStatistics = false;
                    _logger.LogError(
                        ex,
                        "Error adding episode {Path}",
                        incoming.MediaVersions.Head().MediaFiles.Head().Path);
                }
            }

            foreach (EmbyItemEtag existing in maybeExisting)
            {
                try
                {
                    if (existing.Etag != incoming.Etag)
                    {
                        _logger.LogDebug(
                            "UPDATE: Etag has changed for show {Show} season {Season} episode {Episode}",
                            showName,
                            seasonName,
                            incoming.EpisodeMetadata.HeadOrNone().Map(em => em.EpisodeNumber));

                        updateStatistics       = true;
                        incoming.SeasonId      = season.Id;
                        incoming.LibraryPathId = library.Paths.Head().Id;

                        Option <EmbyEpisode> maybeUpdated = await _televisionRepository.Update(incoming);

                        foreach (EmbyEpisode updated in maybeUpdated)
                        {
                            await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> {
                                updated
                            });

                            incomingEpisode = updated;
                        }
                    }
                }
                catch (Exception ex)
                {
                    updateStatistics = false;
                    _logger.LogError(
                        ex,
                        "Error updating episode {Path}",
                        incoming.MediaVersions.Head().MediaFiles.Head().Path);
                }
            }

            if (updateStatistics)
            {
                string localPath = _pathReplacementService.GetReplacementEmbyPath(
                    pathReplacements,
                    incoming.MediaVersions.Head().MediaFiles.Head().Path,
                    false);

                _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", localPath);
                Either <BaseError, bool> refreshResult =
                    await _localStatisticsProvider.RefreshStatistics(
                        ffmpegPath,
                        ffprobePath,
                        incomingEpisode,
                        localPath);

                if (refreshResult.Map(t => t).IfLeft(false))
                {
                    refreshResult = await UpdateSubtitles(incomingEpisode, localPath);
                }

                foreach (BaseError error in refreshResult.LeftToSeq())
                {
                    _logger.LogWarning(
                        "Unable to refresh {Attribute} for media item {Path}. Error: {Error}",
                        "Statistics",
                        localPath,
                        error.Value);
                }
            }
        }

        return(Unit.Default);
    }
Пример #3
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateStatistics(
        List <PlexPathReplacement> pathReplacements,
        MediaItemScanResult <PlexEpisode> result,
        PlexEpisode incoming,
        PlexLibrary library,
        PlexConnection connection,
        PlexServerAuthToken token,
        string ffmpegPath,
        string ffprobePath,
        bool deepScan)
    {
        PlexEpisode  existing        = result.Item;
        MediaVersion existingVersion = existing.MediaVersions.Head();
        MediaVersion incomingVersion = incoming.MediaVersions.Head();

        if (result.IsAdded || existing.Etag != incoming.Etag || deepScan || existingVersion.Streams.Count == 0)
        {
            foreach (MediaFile incomingFile in incomingVersion.MediaFiles.HeadOrNone())
            {
                foreach (MediaFile existingFile in existingVersion.MediaFiles.HeadOrNone())
                {
                    if (incomingFile.Path != existingFile.Path)
                    {
                        _logger.LogDebug(
                            "Plex episode has moved from {OldPath} to {NewPath}",
                            existingFile.Path,
                            incomingFile.Path);

                        existingFile.Path = incomingFile.Path;

                        await _televisionRepository.UpdatePath(existingFile.Id, incomingFile.Path);
                    }
                }
            }

            Either <BaseError, bool> refreshResult = true;

            string localPath = _plexPathReplacementService.GetReplacementPlexPath(
                pathReplacements,
                incoming.MediaVersions.Head().MediaFiles.Head().Path,
                false);

            if ((existing.Etag != incoming.Etag || existingVersion.Streams.Count == 0) &&
                _localFileSystem.FileExists(localPath))
            {
                _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", localPath);
                refreshResult = await _localStatisticsProvider.RefreshStatistics(
                    ffmpegPath,
                    ffprobePath,
                    existing,
                    localPath);
            }

            foreach (BaseError error in refreshResult.LeftToSeq())
            {
                _logger.LogWarning(
                    "Unable to refresh {Attribute} for media item {Path}. Error: {Error}",
                    "Statistics",
                    localPath,
                    error.Value);
            }

            foreach (var _ in refreshResult.RightToSeq())
            {
                foreach (MediaItem updated in await _searchRepository.GetItemToIndex(incoming.Id))
                {
                    await _searchIndex.UpdateItems(
                        _searchRepository,
                        new List <MediaItem> {
                        updated
                    });
                }

                Either <BaseError, Tuple <EpisodeMetadata, MediaVersion> > maybeStatistics =
                    await _plexServerApiClient.GetEpisodeMetadataAndStatistics(
                        library,
                        incoming.Key.Split("/").Last(),
                        connection,
                        token);

                foreach (Tuple <EpisodeMetadata, MediaVersion> tuple in maybeStatistics.RightToSeq())
                {
                    (EpisodeMetadata incomingMetadata, MediaVersion mediaVersion) = tuple;

                    Option <EpisodeMetadata> maybeExisting = existing.EpisodeMetadata
                                                             .Find(em => em.EpisodeNumber == incomingMetadata.EpisodeNumber);
                    foreach (EpisodeMetadata existingMetadata in maybeExisting)
                    {
                        foreach (MetadataGuid guid in existingMetadata.Guids
                                 .Filter(g => incomingMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                                 .ToList())
                        {
                            existingMetadata.Guids.Remove(guid);
                            await _metadataRepository.RemoveGuid(guid);
                        }

                        foreach (MetadataGuid guid in incomingMetadata.Guids
                                 .Filter(g => existingMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                                 .ToList())
                        {
                            existingMetadata.Guids.Add(guid);
                            await _metadataRepository.AddGuid(existingMetadata, guid);
                        }

                        foreach (Tag tag in existingMetadata.Tags
                                 .Filter(g => incomingMetadata.Tags.All(g2 => g2.Name != g.Name))
                                 .ToList())
                        {
                            existingMetadata.Tags.Remove(tag);
                            await _metadataRepository.RemoveTag(tag);
                        }

                        foreach (Tag tag in incomingMetadata.Tags
                                 .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name))
                                 .ToList())
                        {
                            existingMetadata.Tags.Add(tag);
                            await _televisionRepository.AddTag(existingMetadata, tag);
                        }
                    }

                    existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio;
                    existingVersion.VideoScanKind     = mediaVersion.VideoScanKind;
                    existingVersion.DateUpdated       = mediaVersion.DateUpdated;

                    await _metadataRepository.UpdatePlexStatistics(existingVersion.Id, mediaVersion);
                }
            }
        }

        return(result);
    }