Пример #1
0
        private async Task <Either <BaseError, PlexSeason> > UpdateArtwork(PlexSeason existing, PlexSeason incoming)
        {
            SeasonMetadata existingMetadata = existing.SeasonMetadata.Head();
            SeasonMetadata incomingMetadata = incoming.SeasonMetadata.Head();

            if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
            {
                await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Poster);

                await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated);
            }

            return(existing);
        }
Пример #2
0
    private async Task <Either <BaseError, PlexSeason> > UpdateMetadataAndArtwork(
        PlexSeason existing,
        PlexSeason incoming,
        bool deepScan)
    {
        SeasonMetadata existingMetadata = existing.SeasonMetadata.Head();
        SeasonMetadata incomingMetadata = incoming.SeasonMetadata.Head();

        if (existing.Etag != incoming.Etag || deepScan)
        {
            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);
            }

            await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Poster);

            await _metadataRepository.MarkAsUpdated(existingMetadata, incomingMetadata.DateUpdated);
        }

        return(existing);
    }
Пример #3
0
        private async Task <Either <BaseError, Unit> > ScanEpisodes(
            PlexLibrary plexMediaSourceLibrary,
            PlexSeason season,
            PlexConnection connection,
            PlexServerAuthToken token)
        {
            Either <BaseError, List <PlexEpisode> > entries = await _plexServerApiClient.GetSeasonEpisodes(
                plexMediaSourceLibrary,
                season,
                connection,
                token);

            return(await entries.Match <Task <Either <BaseError, Unit> > >(
                       async episodeEntries =>
            {
                foreach (PlexEpisode incoming in episodeEntries)
                {
                    incoming.SeasonId = season.Id;

                    // TODO: figure out how to rebuild playlists
                    Either <BaseError, PlexEpisode> maybeEpisode = await _televisionRepository
                                                                   .GetOrAddPlexEpisode(plexMediaSourceLibrary, incoming)
                                                                   .BindT(existing => UpdateStatistics(existing, incoming, connection, token))
                                                                   .BindT(existing => UpdateArtwork(existing, incoming));

                    maybeEpisode.IfLeft(
                        error => _logger.LogWarning(
                            "Error processing plex episode at {Key}: {Error}",
                            incoming.Key,
                            error.Value));
                }

                var episodeKeys = episodeEntries.Map(s => s.Key).ToList();
                await _televisionRepository.RemoveMissingPlexEpisodes(season.Key, episodeKeys);

                return Unit.Default;
            },
                       error =>
            {
                _logger.LogWarning(
                    "Error synchronizing plex library {Path}: {Error}",
                    plexMediaSourceLibrary.Name,
                    error.Value);

                return Left <BaseError, Unit>(error).AsTask();
            }));
        }
Пример #4
0
 public async Task <Either <BaseError, List <PlexEpisode> > > GetSeasonEpisodes(
     PlexLibrary library,
     PlexSeason season,
     PlexConnection connection,
     PlexServerAuthToken token)
 {
     try
     {
         IPlexServerApi service = XmlServiceFor(connection.Uri);
         return(await service.GetSeasonChildren(season.Key.Split("/").Reverse().Skip(1).Head(), token.AuthToken)
                .Map(r => r.Metadata.Filter(m => m.Media.Count > 0 && m.Media[0].Part.Count > 0))
                .Map(list => list.Map(metadata => ProjectToEpisode(metadata, library.MediaSourceId)))
                .Map(ProcessMultiEpisodeFiles));
     }
     catch (Exception ex)
     {
         return(BaseError.New(ex.ToString()));
     }
 }
Пример #5
0
 public Task <Either <BaseError, PlexSeason> > GetOrAddPlexSeason(PlexLibrary library, PlexSeason item) =>
 throw new NotSupportedException();
Пример #6
0
 public Task <List <PlexItemEtag> > GetExistingPlexEpisodes(PlexLibrary library, PlexSeason season) =>
 throw new NotSupportedException();
Пример #7
0
 public Task <Unit> SetPlexEtag(PlexSeason season, string etag) => throw new NotSupportedException();
Пример #8
0
        public async Task <Either <BaseError, PlexSeason> > GetOrAddPlexSeason(PlexLibrary library, PlexSeason item)
        {
            await using TvContext dbContext = _dbContextFactory.CreateDbContext();
            Option <PlexSeason> maybeExisting = await dbContext.PlexSeasons
                                                .AsNoTracking()
                                                .Include(i => i.SeasonMetadata)
                                                .ThenInclude(mm => mm.Artwork)
                                                .OrderBy(i => i.Key)
                                                .SingleOrDefaultAsync(i => i.Key == item.Key);

            return(await maybeExisting.Match(
                       plexSeason => Right <BaseError, PlexSeason>(plexSeason).AsTask(),
                       async() => await AddPlexSeason(dbContext, library, item)));
        }
Пример #9
0
    private async Task <Either <BaseError, Unit> > ScanEpisodes(
        PlexLibrary library,
        List <PlexPathReplacement> pathReplacements,
        PlexSeason season,
        PlexConnection connection,
        PlexServerAuthToken token,
        string ffmpegPath,
        string ffprobePath,
        bool deepScan,
        CancellationToken cancellationToken)
    {
        List <PlexItemEtag> existingEpisodes = await _plexTelevisionRepository.GetExistingPlexEpisodes(library, season);

        Either <BaseError, List <PlexEpisode> > entries = await _plexServerApiClient.GetSeasonEpisodes(
            library,
            season,
            connection,
            token);

        foreach (BaseError error in entries.LeftToSeq())
        {
            return(error);
        }

        var episodeEntries = entries.RightToSeq().Flatten().ToList();

        foreach (PlexEpisode incoming in episodeEntries)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(new ScanCanceled());
            }

            if (await ShouldScanItem(library, pathReplacements, existingEpisodes, incoming, deepScan) == false)
            {
                continue;
            }

            incoming.SeasonId = season.Id;

            // TODO: figure out how to rebuild playlists
            Either <BaseError, MediaItemScanResult <PlexEpisode> > maybeEpisode = await _televisionRepository
                                                                                  .GetOrAddPlexEpisode(library, incoming)
                                                                                  .BindT(existing => UpdateMetadata(existing, incoming))
                                                                                  .BindT(
                existing => UpdateStatistics(
                    pathReplacements,
                    existing,
                    incoming,
                    library,
                    connection,
                    token,
                    ffmpegPath,
                    ffprobePath,
                    deepScan))
                                                                                  .BindT(existing => UpdateSubtitles(pathReplacements, existing, incoming))
                                                                                  .BindT(existing => UpdateArtwork(existing, incoming));

            foreach (BaseError error in maybeEpisode.LeftToSeq())
            {
                switch (error)
                {
                case ScanCanceled:
                    return(error);

                default:
                    _logger.LogWarning(
                        "Error processing plex episode at {Key}: {Error}",
                        incoming.Key,
                        error.Value);
                    break;
                }
            }

            foreach (MediaItemScanResult <PlexEpisode> result in maybeEpisode.RightToSeq())
            {
                await _plexTelevisionRepository.SetPlexEtag(result.Item, incoming.Etag);

                string plexPath = incoming.MediaVersions.Head().MediaFiles.Head().Path;

                string localPath = _plexPathReplacementService.GetReplacementPlexPath(
                    pathReplacements,
                    plexPath,
                    false);

                if (_localFileSystem.FileExists(localPath))
                {
                    await _plexTelevisionRepository.FlagNormal(library, result.Item);
                }
                else
                {
                    await _plexTelevisionRepository.FlagUnavailable(library, result.Item);
                }

                if (result.IsAdded)
                {
                    await _searchIndex.AddItems(_searchRepository, new List <MediaItem> {
                        result.Item
                    });
                }
                else
                {
                    await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> {
                        result.Item
                    });
                }
            }
        }

        var        fileNotFoundKeys = existingEpisodes.Map(m => m.Key).Except(episodeEntries.Map(m => m.Key)).ToList();
        List <int> ids = await _plexTelevisionRepository.FlagFileNotFoundEpisodes(library, fileNotFoundKeys);

        await _searchIndex.RebuildItems(_searchRepository, ids);

        _searchIndex.Commit();

        return(Unit.Default);
    }