コード例 #1
0
    private async Task <Either <BaseError, MediaItemScanResult <Song> > > UpdateMetadata(
        MediaItemScanResult <Song> result,
        string ffprobePath)
    {
        try
        {
            Song   song = result.Item;
            string path = song.GetHeadVersion().MediaFiles.Head().Path;

            bool shouldUpdate = Optional(song.SongMetadata).Flatten().HeadOrNone().Match(
                m => m.MetadataKind == MetadataKind.Fallback ||
                m.DateUpdated != _localFileSystem.GetLastWriteTime(path),
                true);

            if (shouldUpdate)
            {
                song.SongMetadata ??= new List <SongMetadata>();

                _logger.LogDebug("Refreshing {Attribute} for {Path}", "Metadata", path);
                if (await _localMetadataProvider.RefreshTagMetadata(song, ffprobePath))
                {
                    result.IsUpdated = true;
                }
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #2
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateStatistics(
            MediaItemScanResult <PlexMovie> result,
            PlexMovie incoming,
            PlexConnection connection,
            PlexServerAuthToken token)
        {
            PlexMovie    existing        = result.Item;
            MediaVersion existingVersion = existing.MediaVersions.Head();
            MediaVersion incomingVersion = incoming.MediaVersions.Head();

            if (incomingVersion.DateUpdated > existingVersion.DateUpdated ||
                string.IsNullOrWhiteSpace(existingVersion.SampleAspectRatio))
            {
                Either <BaseError, MediaVersion> maybeStatistics =
                    await _plexServerApiClient.GetStatistics(incoming.Key.Split("/").Last(), connection, token);

                await maybeStatistics.Match(
                    async mediaVersion =>
                {
                    existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio ?? "1:1";
                    existingVersion.VideoScanKind     = mediaVersion.VideoScanKind;
                    existingVersion.DateUpdated       = incomingVersion.DateUpdated;

                    await _metadataRepository.UpdatePlexStatistics(existingVersion);
                },
                    _ => Task.CompletedTask);
            }

            return(result);
        }
コード例 #3
0
 protected override Task <Option <MovieMetadata> > GetFullMetadata(
     EmbyConnectionParameters connectionParameters,
     EmbyLibrary library,
     MediaItemScanResult <EmbyMovie> result,
     EmbyMovie incoming,
     bool deepScan) =>
 Task.FromResult <Option <MovieMetadata> >(None);
コード例 #4
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateMetadata(
        MediaItemScanResult <PlexEpisode> result,
        PlexEpisode incoming)
    {
        PlexEpisode existing = result.Item;

        var toUpdate = existing.EpisodeMetadata
                       .Where(em => incoming.EpisodeMetadata.Any(em2 => em2.EpisodeNumber == em.EpisodeNumber))
                       .ToList();
        var toRemove = existing.EpisodeMetadata.Except(toUpdate).ToList();
        var toAdd    = incoming.EpisodeMetadata
                       .Where(em => existing.EpisodeMetadata.All(em2 => em2.EpisodeNumber != em.EpisodeNumber))
                       .ToList();

        foreach (EpisodeMetadata metadata in toRemove)
        {
            await _televisionRepository.RemoveMetadata(existing, metadata);
        }

        foreach (EpisodeMetadata metadata in toAdd)
        {
            metadata.EpisodeId = existing.Id;
            metadata.Episode   = existing;
            existing.EpisodeMetadata.Add(metadata);

            await _metadataRepository.Add(metadata);
        }

        // TODO: update existing metadata

        return(result);
    }
コード例 #5
0
    protected override async Task <Option <MovieMetadata> > GetFullMetadata(
        PlexConnectionParameters connectionParameters,
        PlexLibrary library,
        MediaItemScanResult <PlexMovie> result,
        PlexMovie incoming,
        bool deepScan)
    {
        if (result.IsAdded || result.Item.Etag != incoming.Etag || deepScan)
        {
            Either <BaseError, MovieMetadata> maybeMetadata = await _plexServerApiClient.GetMovieMetadata(
                library,
                incoming.Key.Split("/").Last(),
                connectionParameters.Connection,
                connectionParameters.Token);

            foreach (BaseError error in maybeMetadata.LeftToSeq())
            {
                _logger.LogWarning("Failed to get movie metadata from Plex: {Error}", error.ToString());
            }

            return(maybeMetadata.ToOption());
        }

        return(None);
    }
コード例 #6
0
    private async Task <Either <BaseError, MediaItemScanResult <OtherVideo> > > UpdateMetadata(
        MediaItemScanResult <OtherVideo> result)
    {
        try
        {
            OtherVideo otherVideo = result.Item;
            if (!Optional(otherVideo.OtherVideoMetadata).Flatten().Any())
            {
                otherVideo.OtherVideoMetadata ??= new List <OtherVideoMetadata>();

                string path = otherVideo.MediaVersions.Head().MediaFiles.Head().Path;
                _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", path);
                if (await _localMetadataProvider.RefreshFallbackMetadata(otherVideo))
                {
                    result.IsUpdated = true;
                }
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #7
0
    private async Task <Either <BaseError, MediaItemScanResult <MusicVideo> > > UpdateSubtitles(
        MediaItemScanResult <MusicVideo> result)
    {
        try
        {
            await _localSubtitlesProvider.UpdateSubtitles(result.Item, None, true);

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #8
0
    private async Task <Either <BaseError, MediaItemScanResult <MusicVideo> > > UpdateMetadata(
        MediaItemScanResult <MusicVideo> result)
    {
        try
        {
            MusicVideo musicVideo = result.Item;

            Option <string> maybeNfoFile = LocateNfoFile(musicVideo);
            if (maybeNfoFile.IsNone)
            {
                if (!Optional(musicVideo.MusicVideoMetadata).Flatten().Any())
                {
                    musicVideo.MusicVideoMetadata ??= new List <MusicVideoMetadata>();

                    string path = musicVideo.MediaVersions.Head().MediaFiles.Head().Path;
                    _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", path);
                    if (await _localMetadataProvider.RefreshFallbackMetadata(musicVideo))
                    {
                        result.IsUpdated = true;
                    }
                }
            }

            foreach (string nfoFile in maybeNfoFile)
            {
                bool shouldUpdate = Optional(musicVideo.MusicVideoMetadata).Flatten().HeadOrNone().Match(
                    m => m.MetadataKind == MetadataKind.Fallback ||
                    m.DateUpdated != _localFileSystem.GetLastWriteTime(nfoFile),
                    true);

                if (shouldUpdate)
                {
                    _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile);
                    if (await _localMetadataProvider.RefreshSidecarMetadata(musicVideo, nfoFile))
                    {
                        result.IsUpdated = true;
                    }
                }
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #9
0
    private async Task <Either <BaseError, MediaItemScanResult <Song> > > UpdateThumbnail(
        MediaItemScanResult <Song> result,
        string ffmpegPath,
        CancellationToken cancellationToken)
    {
        try
        {
            // reload the song from the database at this point
            if (result.IsAdded)
            {
                LibraryPath libraryPath = result.Item.LibraryPath;
                string      path        = result.Item.GetHeadVersion().MediaFiles.Head().Path;
                foreach (MediaItemScanResult <Song> s in (await _songRepository.GetOrAdd(libraryPath, path))
                         .RightToSeq())
                {
                    result.Item = s.Item;
                }
            }

            Song            song           = result.Item;
            Option <string> maybeThumbnail = LocateThumbnail(song);
            if (maybeThumbnail.IsNone)
            {
                await ExtractEmbeddedArtwork(song, ffmpegPath, cancellationToken);
            }


            foreach (string thumbnailFile in maybeThumbnail)
            {
                SongMetadata metadata = song.SongMetadata.Head();
                await RefreshArtwork(
                    thumbnailFile,
                    metadata,
                    ArtworkKind.Thumbnail,
                    ffmpegPath,
                    None,
                    cancellationToken);
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #10
0
    private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateMetadataForShow(
        MediaItemScanResult <Show> result,
        string showFolder)
    {
        try
        {
            Show show = result.Item;

            Option <string> maybeNfo = LocateNfoFileForShow(showFolder);
            if (maybeNfo.IsNone)
            {
                if (!Optional(show.ShowMetadata).Flatten().Any())
                {
                    _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", showFolder);
                    if (await _localMetadataProvider.RefreshFallbackMetadata(show, showFolder))
                    {
                        result.IsUpdated = true;
                    }
                }
            }

            foreach (string nfoFile in maybeNfo)
            {
                bool shouldUpdate = Optional(show.ShowMetadata).Flatten().HeadOrNone().Match(
                    m => m.MetadataKind == MetadataKind.Fallback ||
                    m.DateUpdated != _localFileSystem.GetLastWriteTime(nfoFile),
                    true);

                if (shouldUpdate)
                {
                    _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile);
                    if (await _localMetadataProvider.RefreshSidecarMetadata(show, nfoFile))
                    {
                        result.IsUpdated = true;
                    }
                }
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #11
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateArtwork(
            MediaItemScanResult <PlexShow> result,
            PlexShow incoming)
        {
            PlexShow     existing         = result.Item;
            ShowMetadata existingMetadata = existing.ShowMetadata.Head();
            ShowMetadata incomingMetadata = incoming.ShowMetadata.Head();

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

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

            return(result);
        }
コード例 #12
0
    private async Task <Either <BaseError, MediaItemScanResult <Artist> > > UpdateMetadataForArtist(
        MediaItemScanResult <Artist> result,
        string artistFolder)
    {
        try
        {
            Artist artist = result.Item;
            await LocateNfoFileForArtist(artistFolder).Match(
                async nfoFile =>
            {
                bool shouldUpdate = Optional(artist.ArtistMetadata).Flatten().HeadOrNone().Match(
                    m => m.MetadataKind == MetadataKind.Fallback ||
                    m.DateUpdated != _localFileSystem.GetLastWriteTime(nfoFile),
                    true);

                if (shouldUpdate)
                {
                    _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile);
                    if (await _localMetadataProvider.RefreshSidecarMetadata(artist, nfoFile))
                    {
                        result.IsUpdated = true;
                    }
                }
            },
                async() =>
            {
                if (!Optional(artist.ArtistMetadata).Flatten().Any())
                {
                    _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", artistFolder);
                    if (await _localMetadataProvider.RefreshFallbackMetadata(artist, artistFolder))
                    {
                        result.IsUpdated = true;
                    }
                }
            });

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #13
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateArtwork(
        MediaItemScanResult <PlexEpisode> result,
        PlexEpisode incoming)
    {
        PlexEpisode existing = result.Item;

        foreach (EpisodeMetadata incomingMetadata in incoming.EpisodeMetadata)
        {
            Option <EpisodeMetadata> maybeExistingMetadata = existing.EpisodeMetadata
                                                             .Find(em => em.EpisodeNumber == incomingMetadata.EpisodeNumber);
            if (maybeExistingMetadata.IsSome)
            {
                EpisodeMetadata existingMetadata = maybeExistingMetadata.ValueUnsafe();
                await UpdateArtworkIfNeeded(existingMetadata, incomingMetadata, ArtworkKind.Thumbnail);

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

        return(result);
    }
コード例 #14
0
    private async Task <Either <BaseError, MediaItemScanResult <TMovie> > > UpdateMetadata(
        TConnectionParameters connectionParameters,
        TLibrary library,
        MediaItemScanResult <TMovie> result,
        TMovie incoming,
        bool deepScan)
    {
        foreach (MovieMetadata fullMetadata in await GetFullMetadata(
                     connectionParameters,
                     library,
                     result,
                     incoming,
                     deepScan))
        {
            // TODO: move some of this code into this scanner
            // will have to merge JF, Emby, Plex logic
            return(await UpdateMetadata(result, fullMetadata));
        }

        return(result);
    }
コード例 #15
0
    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);
    }
コード例 #16
0
    private async Task <Either <BaseError, MediaItemScanResult <MusicVideo> > > UpdateThumbnail(
        MediaItemScanResult <MusicVideo> result,
        CancellationToken cancellationToken)
    {
        try
        {
            MusicVideo musicVideo = result.Item;

            Option <string> maybeThumbnail = LocateThumbnail(musicVideo);
            foreach (string thumbnailFile in maybeThumbnail)
            {
                MusicVideoMetadata metadata = musicVideo.MusicVideoMetadata.Head();
                await RefreshArtwork(thumbnailFile, metadata, ArtworkKind.Thumbnail, None, None, cancellationToken);
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #17
0
    private async Task <Either <BaseError, MediaItemScanResult <Movie> > > UpdateArtwork(
        MediaItemScanResult <Movie> result,
        ArtworkKind artworkKind,
        CancellationToken cancellationToken)
    {
        try
        {
            Movie           movie        = result.Item;
            Option <string> maybeArtwork = LocateArtwork(movie, artworkKind);
            foreach (string posterFile in maybeArtwork)
            {
                MovieMetadata metadata = movie.MovieMetadata.Head();
                await RefreshArtwork(posterFile, metadata, artworkKind, None, None, cancellationToken);
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #18
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateSubtitles(
        List <PlexPathReplacement> pathReplacements,
        MediaItemScanResult <PlexEpisode> result,
        PlexEpisode incoming)
    {
        try
        {
            PlexEpisode existing = result.Item;

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

            await _localSubtitlesProvider.UpdateSubtitles(existing, localPath, false);

            return(result);
        }
        catch (Exception ex)
        {
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #19
0
    private async Task <Either <BaseError, MediaItemScanResult <TMovie> > > UpdateSubtitles(
        MediaItemScanResult <TMovie> existing)
    {
        try
        {
            // skip checking subtitles for files that don't exist locally
            if (!_localFileSystem.FileExists(existing.LocalPath))
            {
                return(existing);
            }

            if (await _localSubtitlesProvider.UpdateSubtitles(existing.Item, existing.LocalPath, false))
            {
                return(existing);
            }

            return(BaseError.New("Failed to update local subtitles"));
        }
        catch (Exception ex)
        {
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #20
0
    private async Task <Either <BaseError, MediaItemScanResult <Artist> > > UpdateArtworkForArtist(
        MediaItemScanResult <Artist> result,
        string artistFolder,
        ArtworkKind artworkKind,
        CancellationToken cancellationToken)
    {
        try
        {
            Artist artist = result.Item;
            await LocateArtworkForArtist(artistFolder, artworkKind).IfSomeAsync(
                async artworkFile =>
            {
                ArtistMetadata metadata = artist.ArtistMetadata.Head();
                await RefreshArtwork(artworkFile, metadata, artworkKind, None, None, cancellationToken);
            });

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #21
0
    private async Task <Either <BaseError, MediaItemScanResult <Show> > > UpdateArtworkForShow(
        MediaItemScanResult <Show> result,
        string showFolder,
        ArtworkKind artworkKind,
        CancellationToken cancellationToken)
    {
        try
        {
            Show            show         = result.Item;
            Option <string> maybeArtwork = LocateArtworkForShow(showFolder, artworkKind);
            foreach (string artworkFile in maybeArtwork)
            {
                ShowMetadata metadata = show.ShowMetadata.Head();
                await RefreshArtwork(artworkFile, metadata, artworkKind, None, None, cancellationToken);
            }

            return(result);
        }
        catch (Exception ex)
        {
            _client.Notify(ex);
            return(BaseError.New(ex.ToString()));
        }
    }
コード例 #22
0
 protected override Task <Either <BaseError, MediaItemScanResult <EmbyMovie> > > UpdateMetadata(
     MediaItemScanResult <EmbyMovie> result,
     MovieMetadata fullMetadata) =>
 Task.FromResult <Either <BaseError, MediaItemScanResult <EmbyMovie> > >(result);
コード例 #23
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateMetadata(
            MediaItemScanResult <PlexShow> result,
            PlexShow incoming)
        {
            PlexShow     existing         = result.Item;
            ShowMetadata existingMetadata = existing.ShowMetadata.Head();
            ShowMetadata incomingMetadata = incoming.ShowMetadata.Head();

            // TODO: this probably doesn't work
            // plex doesn't seem to update genres returned by the main library call
            if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
            {
                foreach (Genre genre in existingMetadata.Genres
                         .Filter(g => incomingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Remove(genre);
                    if (await _metadataRepository.RemoveGenre(genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Genre genre in incomingMetadata.Genres
                         .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Add(genre);
                    if (await _televisionRepository.AddGenre(existingMetadata, genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in existingMetadata.Studios
                         .Filter(s => incomingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Remove(studio);
                    if (await _metadataRepository.RemoveStudio(studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in incomingMetadata.Studios
                         .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Add(studio);
                    if (await _televisionRepository.AddStudio(existingMetadata, studio))
                    {
                        result.IsUpdated = true;
                    }
                }

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

            return(result);
        }
コード例 #24
0
    private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateMetadata(
        MediaItemScanResult <PlexShow> result,
        PlexShow incoming,
        PlexLibrary library,
        PlexConnection connection,
        PlexServerAuthToken token,
        bool deepScan)
    {
        PlexShow     existing         = result.Item;
        ShowMetadata existingMetadata = existing.ShowMetadata.Head();

        if (result.IsAdded || existing.Etag != incoming.Etag || deepScan)
        {
            Either <BaseError, ShowMetadata> maybeMetadata =
                await _plexServerApiClient.GetShowMetadata(
                    library,
                    incoming.Key.Replace("/children", string.Empty).Split("/").Last(),
                    connection,
                    token);

            await maybeMetadata.Match(
                async fullMetadata =>
            {
                if (existingMetadata.MetadataKind != MetadataKind.External)
                {
                    existingMetadata.MetadataKind = MetadataKind.External;
                    await _metadataRepository.MarkAsExternal(existingMetadata);
                }

                if (existingMetadata.ContentRating != fullMetadata.ContentRating)
                {
                    existingMetadata.ContentRating = fullMetadata.ContentRating;
                    await _metadataRepository.SetContentRating(existingMetadata, fullMetadata.ContentRating);
                    result.IsUpdated = true;
                }

                foreach (Genre genre in existingMetadata.Genres
                         .Filter(g => fullMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Remove(genre);
                    if (await _metadataRepository.RemoveGenre(genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Genre genre in fullMetadata.Genres
                         .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Add(genre);
                    if (await _televisionRepository.AddGenre(existingMetadata, genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in existingMetadata.Studios
                         .Filter(s => fullMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Remove(studio);
                    if (await _metadataRepository.RemoveStudio(studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in fullMetadata.Studios
                         .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Add(studio);
                    if (await _televisionRepository.AddStudio(existingMetadata, studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Actor actor in existingMetadata.Actors
                         .Filter(
                             a => fullMetadata.Actors.All(
                                 a2 => a2.Name != a.Name || a.Artwork == null && a2.Artwork != null))
                         .ToList())
                {
                    existingMetadata.Actors.Remove(actor);
                    if (await _metadataRepository.RemoveActor(actor))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Actor actor in fullMetadata.Actors
                         .Filter(a => existingMetadata.Actors.All(a2 => a2.Name != a.Name))
                         .ToList())
                {
                    existingMetadata.Actors.Add(actor);
                    if (await _televisionRepository.AddActor(existingMetadata, actor))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (MetadataGuid guid in existingMetadata.Guids
                         .Filter(g => fullMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                         .ToList())
                {
                    existingMetadata.Guids.Remove(guid);
                    if (await _metadataRepository.RemoveGuid(guid))
                    {
                        result.IsUpdated = true;
                    }
                }

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

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

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

                if (result.IsUpdated)
                {
                    await _metadataRepository.MarkAsUpdated(existingMetadata, fullMetadata.DateUpdated);
                }
            },
                _ => Task.CompletedTask);
        }

        return(result);
    }
コード例 #25
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);
    }
コード例 #26
0
 protected abstract Task <Either <BaseError, MediaItemScanResult <TMovie> > > UpdateMetadata(
     MediaItemScanResult <TMovie> result,
     MovieMetadata fullMetadata);
コード例 #27
0
 protected abstract Task <Option <MovieMetadata> > GetFullMetadata(
     TConnectionParameters connectionParameters,
     TLibrary library,
     MediaItemScanResult <TMovie> result,
     TMovie incoming,
     bool deepScan);
コード例 #28
0
        private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateMetadata(
            MediaItemScanResult <PlexMovie> result,
            PlexMovie incoming)
        {
            PlexMovie     existing         = result.Item;
            MovieMetadata existingMetadata = existing.MovieMetadata.Head();
            MovieMetadata incomingMetadata = incoming.MovieMetadata.Head();

            if (incomingMetadata.DateUpdated > existingMetadata.DateUpdated)
            {
                foreach (Genre genre in existingMetadata.Genres
                         .Filter(g => incomingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Remove(genre);
                    if (await _metadataRepository.RemoveGenre(genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Genre genre in incomingMetadata.Genres
                         .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                         .ToList())
                {
                    existingMetadata.Genres.Add(genre);
                    if (await _movieRepository.AddGenre(existingMetadata, genre))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in existingMetadata.Studios
                         .Filter(s => incomingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Remove(studio);
                    if (await _metadataRepository.RemoveStudio(studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                foreach (Studio studio in incomingMetadata.Studios
                         .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                         .ToList())
                {
                    existingMetadata.Studios.Add(studio);
                    if (await _movieRepository.AddStudio(existingMetadata, studio))
                    {
                        result.IsUpdated = true;
                    }
                }

                if (incomingMetadata.SortTitle != existingMetadata.SortTitle)
                {
                    existingMetadata.SortTitle = incomingMetadata.SortTitle;
                    if (await _movieRepository.UpdateSortTitle(existingMetadata))
                    {
                        result.IsUpdated = true;
                    }
                }

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

                // TODO: update other metadata?
            }

            return(result);
        }
コード例 #29
0
    protected override async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > UpdateMetadata(
        MediaItemScanResult <PlexMovie> result,
        MovieMetadata fullMetadata)
    {
        PlexMovie     existing         = result.Item;
        MovieMetadata existingMetadata = existing.MovieMetadata.Head();

        _logger.LogDebug(
            "Refreshing {Attribute} for {Title}",
            "Plex Metadata",
            existingMetadata.Title);

        if (existingMetadata.MetadataKind != MetadataKind.External)
        {
            existingMetadata.MetadataKind = MetadataKind.External;
            await _metadataRepository.MarkAsExternal(existingMetadata);
        }

        if (existingMetadata.ContentRating != fullMetadata.ContentRating)
        {
            existingMetadata.ContentRating = fullMetadata.ContentRating;
            await _metadataRepository.SetContentRating(existingMetadata, fullMetadata.ContentRating);

            result.IsUpdated = true;
        }

        foreach (Genre genre in existingMetadata.Genres
                 .Filter(g => fullMetadata.Genres.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Genres.Remove(genre);
            if (await _metadataRepository.RemoveGenre(genre))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Genre genre in fullMetadata.Genres
                 .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Genres.Add(genre);
            if (await _movieRepository.AddGenre(existingMetadata, genre))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Studio studio in existingMetadata.Studios
                 .Filter(s => fullMetadata.Studios.All(s2 => s2.Name != s.Name))
                 .ToList())
        {
            existingMetadata.Studios.Remove(studio);
            if (await _metadataRepository.RemoveStudio(studio))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Studio studio in fullMetadata.Studios
                 .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name))
                 .ToList())
        {
            existingMetadata.Studios.Add(studio);
            if (await _movieRepository.AddStudio(existingMetadata, studio))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Actor actor in existingMetadata.Actors
                 .Filter(
                     a => fullMetadata.Actors.All(
                         a2 => a2.Name != a.Name || a.Artwork == null && a2.Artwork != null))
                 .ToList())
        {
            existingMetadata.Actors.Remove(actor);
            if (await _metadataRepository.RemoveActor(actor))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Actor actor in fullMetadata.Actors
                 .Filter(a => existingMetadata.Actors.All(a2 => a2.Name != a.Name))
                 .ToList())
        {
            existingMetadata.Actors.Add(actor);
            if (await _movieRepository.AddActor(existingMetadata, actor))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Director director in existingMetadata.Directors
                 .Filter(g => fullMetadata.Directors.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Directors.Remove(director);
            if (await _metadataRepository.RemoveDirector(director))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Director director in fullMetadata.Directors
                 .Filter(g => existingMetadata.Directors.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Directors.Add(director);
            if (await _movieRepository.AddDirector(existingMetadata, director))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Writer writer in existingMetadata.Writers
                 .Filter(g => fullMetadata.Writers.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Writers.Remove(writer);
            if (await _metadataRepository.RemoveWriter(writer))
            {
                result.IsUpdated = true;
            }
        }

        foreach (Writer writer in fullMetadata.Writers
                 .Filter(g => existingMetadata.Writers.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Writers.Add(writer);
            if (await _movieRepository.AddWriter(existingMetadata, writer))
            {
                result.IsUpdated = true;
            }
        }

        foreach (MetadataGuid guid in existingMetadata.Guids
                 .Filter(g => fullMetadata.Guids.All(g2 => g2.Guid != g.Guid))
                 .ToList())
        {
            existingMetadata.Guids.Remove(guid);
            if (await _metadataRepository.RemoveGuid(guid))
            {
                result.IsUpdated = true;
            }
        }

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

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

        foreach (Tag tag in fullMetadata.Tags
                 .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name))
                 .ToList())
        {
            existingMetadata.Tags.Add(tag);
            if (await _movieRepository.AddTag(existingMetadata, tag))
            {
                result.IsUpdated = true;
            }
        }

        if (fullMetadata.SortTitle != existingMetadata.SortTitle)
        {
            existingMetadata.SortTitle = fullMetadata.SortTitle;
            if (await _movieRepository.UpdateSortTitle(existingMetadata))
            {
                result.IsUpdated = true;
            }
        }

        bool poster = await UpdateArtworkIfNeeded(existingMetadata, fullMetadata, ArtworkKind.Poster);

        bool fanArt = await UpdateArtworkIfNeeded(existingMetadata, fullMetadata, ArtworkKind.FanArt);

        if (poster || fanArt)
        {
            result.IsUpdated = true;
        }

        if (result.IsUpdated)
        {
            await _metadataRepository.MarkAsUpdated(existingMetadata, fullMetadata.DateUpdated);
        }

        return(result);
    }