コード例 #1
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);
    }
    private async Task <string> GetPlayoutItemPath(PlayoutItem playoutItem)
    {
        MediaVersion version = playoutItem.MediaItem.GetHeadVersion();

        MediaFile file = version.MediaFiles.Head();
        string    path = file.Path;

        return(playoutItem.MediaItem switch
        {
            PlexMovie plexMovie => await _plexPathReplacementService.GetReplacementPlexPath(
                plexMovie.LibraryPathId,
                path),
            PlexEpisode plexEpisode => await _plexPathReplacementService.GetReplacementPlexPath(
                plexEpisode.LibraryPathId,
                path),
            JellyfinMovie jellyfinMovie => await _jellyfinPathReplacementService.GetReplacementJellyfinPath(
                jellyfinMovie.LibraryPathId,
                path),
            JellyfinEpisode jellyfinEpisode => await _jellyfinPathReplacementService.GetReplacementJellyfinPath(
                jellyfinEpisode.LibraryPathId,
                path),
            EmbyMovie embyMovie => await _embyPathReplacementService.GetReplacementEmbyPath(
                embyMovie.LibraryPathId,
                path),
            EmbyEpisode embyEpisode => await _embyPathReplacementService.GetReplacementEmbyPath(
                embyEpisode.LibraryPathId,
                path),
            _ => path
        });
コード例 #3
0
        private async Task <Either <BaseError, PlexEpisode> > UpdateStatistics(
            PlexEpisode existing,
            PlexEpisode incoming,
            PlexConnection connection,
            PlexServerAuthToken token)
        {
            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(Right <BaseError, PlexEpisode>(existing));
        }
コード例 #4
0
        public static async Task SingleEpisodeCheck(bool useImdb, IQueryable <PlexEpisode> allEpisodes, EpisodeRequests episode,
                                                    SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb)
        {
            PlexEpisode epExists = null;

            if (useImdb)
            {
                epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                 x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                 x.Series.ImdbId == item.ImdbId.ToString());
            }

            if (useTheMovieDb)
            {
                epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                 x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                 x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
            }

            if (useTvDb)
            {
                epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                 x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                 x.Series.TvDbId == item.TvDbId.ToString());
            }

            if (epExists != null)
            {
                episode.Available = true;
            }
        }
コード例 #5
0
ファイル: PlexContentRepository.cs プロジェクト: anojht/Ombi
        public async Task <PlexEpisode> Add(PlexEpisode content)
        {
            await Db.PlexEpisode.AddAsync(content);

            await InternalSaveChanges();

            return(content);
        }
コード例 #6
0
    private async Task <bool> ShouldScanItem(
        PlexLibrary library,
        List <PlexPathReplacement> pathReplacements,
        List <PlexItemEtag> existingEpisodes,
        PlexEpisode incoming,
        bool deepScan)
    {
        // deep scan will pull every episode individually from the plex api
        if (!deepScan)
        {
            Option <PlexItemEtag> maybeExisting = existingEpisodes.Find(ie => ie.Key == incoming.Key);
            string existingTag = await maybeExisting
                                 .Map(e => e.Etag ?? string.Empty)
                                 .IfNoneAsync(string.Empty);

            MediaItemState existingState = await maybeExisting
                                           .Map(e => e.State)
                                           .IfNoneAsync(MediaItemState.Normal);

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

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

            // if media is unavailable, only scan if file now exists
            if (existingState == MediaItemState.Unavailable)
            {
                if (!_localFileSystem.FileExists(localPath))
                {
                    return(false);
                }
            }
            else if (existingTag == incoming.Etag)
            {
                if (!_localFileSystem.FileExists(localPath))
                {
                    foreach (int id in await _plexTelevisionRepository.FlagUnavailable(library, incoming))
                    {
                        await _searchIndex.RebuildItems(_searchRepository, new List <int> {
                            id
                        });
                    }
                }

                // _logger.LogDebug("NOOP: etag has not changed for plex episode with key {Key}", incoming.Key);
                return(false);
            }

            // _logger.LogDebug(
            //     "UPDATE: Etag has changed for episode {Episode}",
            //     $"s{season.SeasonNumber}e{incoming.EpisodeMetadata.Head().EpisodeNumber}");
        }

        return(true);
    }
コード例 #7
0
        private async Task <Either <BaseError, PlexEpisode> > UpdateArtwork(PlexEpisode existing, PlexEpisode incoming)
        {
            EpisodeMetadata existingMetadata = existing.EpisodeMetadata.Head();
            EpisodeMetadata incomingMetadata = incoming.EpisodeMetadata.Head();

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

            return(existing);
        }
コード例 #8
0
        private async Task <string> GetPlayoutItemPath(PlayoutItem playoutItem)
        {
            MediaVersion version = playoutItem.MediaItem switch
            {
                Movie m => m.MediaVersions.Head(),
                Episode e => e.MediaVersions.Head(),
                         _ => throw new ArgumentOutOfRangeException(nameof(playoutItem))
            };

            MediaFile file = version.MediaFiles.Head();
            string    path = file.Path;

            return(playoutItem.MediaItem switch
            {
                PlexMovie plexMovie => await GetReplacementPlexPath(plexMovie.LibraryPathId, path),
                PlexEpisode plexEpisode => await GetReplacementPlexPath(plexEpisode.LibraryPathId, path),
                _ => path
            });
コード例 #9
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);
    }
コード例 #10
0
        public static async Task SingleEpisodeCheck(bool useImdb, IQueryable <PlexEpisode> allEpisodes, EpisodeRequests episode,
                                                    SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log)
        {
            PlexEpisode epExists = null;

            try
            {
                if (useImdb)
                {
                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                     x.Series.ImdbId == item.ImdbId);
                }

                if (useTheMovieDb)
                {
                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                     x.Series.TheMovieDbId == item.TheMovieDbId);
                }

                if (useTvDb)
                {
                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                     x.Series.TvDbId == item.TvDbId);
                }
            }
            catch (Exception e)
            {
                log.LogError(e, "Exception thrown when attempting to check if something is available");
            }

            if (epExists != null)
            {
                episode.Available = true;
            }
        }
コード例 #11
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()));
        }
    }
コード例 #12
0
ファイル: PlexContentRepository.cs プロジェクト: anojht/Ombi
 public async Task DeleteEpisode(PlexEpisode content)
 {
     Db.PlexEpisode.Remove(content);
     await InternalSaveChanges();
 }
コード例 #13
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);
    }
コード例 #14
0
ファイル: PlexContentRepository.cs プロジェクト: anojht/Ombi
 public void DeleteWithoutSave(PlexEpisode content)
 {
     Db.PlexEpisode.Remove(content);
 }
コード例 #15
0
 public Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > GetOrAddPlexEpisode(
     PlexLibrary library,
     PlexEpisode item) =>
 throw new NotSupportedException();
コード例 #16
0
 public Task <Unit> SetPlexEtag(PlexEpisode episode, string etag) => throw new NotSupportedException();
コード例 #17
0
        public async Task <RuleResult> Execute(SearchViewModel obj)
        {
            PlexServerContent item = null;
            var useImdb            = false;
            var useTheMovieDb      = false;
            var useTvDb            = false;

            if (obj.ImdbId.HasValue())
            {
                item = await PlexContentRepository.Get(obj.ImdbId);

                if (item != null)
                {
                    useImdb = true;
                }
            }
            if (item == null)
            {
                if (obj.TheMovieDbId.HasValue())
                {
                    item = await PlexContentRepository.Get(obj.TheMovieDbId);

                    if (item != null)
                    {
                        useTheMovieDb = true;
                    }
                }

                if (item == null)
                {
                    if (obj.TheTvDbId.HasValue())
                    {
                        item = await PlexContentRepository.Get(obj.TheTvDbId);

                        if (item != null)
                        {
                            useTvDb = true;
                        }
                    }
                }
            }

            if (item != null)
            {
                obj.Available = true;
                obj.PlexUrl   = item.Url;
                obj.Quality   = item.Quality;

                if (obj.Type == RequestType.TvShow)
                {
                    var search = (SearchTvShowViewModel)obj;
                    // Let's go through the episodes now
                    if (search.SeasonRequests.Any())
                    {
                        var allEpisodes = PlexContentRepository.GetAllEpisodes();
                        foreach (var season in search.SeasonRequests)
                        {
                            foreach (var episode in season.Episodes)
                            {
                                PlexEpisode epExists = null;
                                if (useImdb)
                                {
                                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                                     x.Series.ImdbId == item.ImdbId.ToString());
                                }
                                if (useTheMovieDb)
                                {
                                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                                     x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
                                }
                                if (useTvDb)
                                {
                                    epExists = await allEpisodes.FirstOrDefaultAsync(x =>
                                                                                     x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
                                                                                     x.Series.TvDbId == item.TvDbId.ToString());
                                }

                                if (epExists != null)
                                {
                                    episode.Available = true;
                                }
                            }
                        }

                        if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
                        {
                            search.FullyAvailable = true;
                        }
                    }
                }
            }
            return(Success());
        }
コード例 #18
0
        public async Task <Either <BaseError, PlexEpisode> > GetOrAddPlexEpisode(PlexLibrary library, PlexEpisode item)
        {
            await using TvContext dbContext = _dbContextFactory.CreateDbContext();
            Option <PlexEpisode> maybeExisting = await dbContext.PlexEpisodes
                                                 .AsNoTracking()
                                                 .Include(i => i.EpisodeMetadata)
                                                 .ThenInclude(mm => mm.Artwork)
                                                 .Include(i => i.MediaVersions)
                                                 .ThenInclude(mv => mv.MediaFiles)
                                                 .OrderBy(i => i.Key)
                                                 .SingleOrDefaultAsync(i => i.Key == item.Key);

            return(await maybeExisting.Match(
                       plexEpisode => Right <BaseError, PlexEpisode>(plexEpisode).AsTask(),
                       async() => await AddPlexEpisode(dbContext, library, item)));
        }
コード例 #19
0
 public async Task DeleteEpisode(PlexEpisode content)
 {
     Db.PlexEpisode.Remove(content);
     await Db.SaveChangesAsync();
 }