コード例 #1
0
    private async Task <bool> ShouldScanItem(
        IMediaServerMovieRepository <TLibrary, TMovie, TEtag> movieRepository,
        TLibrary library,
        List <TEtag> existingMovies,
        TMovie incoming,
        string localPath,
        bool deepScan)
    {
        // deep scan will always pull every movie
        if (deepScan)
        {
            return(true);
        }

        Option <TEtag> maybeExisting =
            existingMovies.Find(m => m.MediaServerItemId == MediaServerItemId(incoming));
        string existingItemId = await maybeExisting.Map(e => e.MediaServerItemId).IfNoneAsync(string.Empty);

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

        if (existingState == MediaItemState.Unavailable)
        {
            // skip scanning unavailable items that still don't exist locally
            if (!_localFileSystem.FileExists(localPath))
            {
                return(false);
            }
        }
        else if (existingItemId == MediaServerItemId(incoming))
        {
            // item is unchanged, but file does not exist
            // don't scan, but mark as unavailable
            if (!_localFileSystem.FileExists(localPath))
            {
                foreach (int id in await movieRepository.FlagUnavailable(library, incoming))
                {
                    await _searchIndex.RebuildItems(_searchRepository, new List <int> {
                        id
                    });
                }
            }

            return(false);
        }

        if (maybeExisting.IsNone)
        {
            _logger.LogDebug("INSERT: new movie {Movie}", incoming.MovieMetadata.Head().Title);
        }
        else
        {
            _logger.LogDebug("UPDATE: Etag has changed for movie {Movie}", incoming.MovieMetadata.Head().Title);
        }

        return(true);
    }
コード例 #2
0
    protected async Task <Either <BaseError, Unit> > ScanLibrary(
        IMediaServerMovieRepository <TLibrary, TMovie, TEtag> movieRepository,
        TConnectionParameters connectionParameters,
        TLibrary library,
        Func <TMovie, string> getLocalPath,
        string ffmpegPath,
        string ffprobePath,
        bool deepScan,
        CancellationToken cancellationToken)
    {
        try
        {
            Either <BaseError, List <TMovie> > entries = await GetMovieLibraryItems(connectionParameters, library);

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

            return(await ScanLibrary(
                       movieRepository,
                       connectionParameters,
                       library,
                       getLocalPath,
                       ffmpegPath,
                       ffprobePath,
                       entries.RightToSeq().Flatten().ToList(),
                       deepScan,
                       cancellationToken));
        }
        catch (Exception ex) when(ex is TaskCanceledException or OperationCanceledException)
        {
            return(new ScanCanceled());
        }
        finally
        {
            _searchIndex.Commit();
        }
    }
コード例 #3
0
    private async Task <Either <BaseError, Unit> > ScanLibrary(
        IMediaServerMovieRepository <TLibrary, TMovie, TEtag> movieRepository,
        TConnectionParameters connectionParameters,
        TLibrary library,
        Func <TMovie, string> getLocalPath,
        string ffmpegPath,
        string ffprobePath,
        List <TMovie> movieEntries,
        bool deepScan,
        CancellationToken cancellationToken)
    {
        List <TEtag> existingMovies = await movieRepository.GetExistingMovies(library);

        foreach (TMovie incoming in movieEntries)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(new ScanCanceled());
            }

            decimal percentCompletion = (decimal)movieEntries.IndexOf(incoming) / movieEntries.Count;
            await _mediator.Publish(new LibraryScanProgress(library.Id, percentCompletion), cancellationToken);

            string localPath = getLocalPath(incoming);

            if (await ShouldScanItem(movieRepository, library, existingMovies, incoming, localPath, deepScan) == false)
            {
                continue;
            }

            Either <BaseError, MediaItemScanResult <TMovie> > maybeMovie = await movieRepository
                                                                           .GetOrAdd(library, incoming)
                                                                           .MapT(
                result =>
            {
                result.LocalPath = localPath;
                return(result);
            })
                                                                           .BindT(existing => UpdateMetadata(connectionParameters, library, existing, incoming, deepScan))
                                                                           .BindT(existing => UpdateStatistics(existing, incoming, ffmpegPath, ffprobePath))
                                                                           .BindT(UpdateSubtitles);

            if (maybeMovie.IsLeft)
            {
                foreach (BaseError error in maybeMovie.LeftToSeq())
                {
                    _logger.LogWarning(
                        "Error processing movie {Title}: {Error}",
                        incoming.MovieMetadata.Head().Title,
                        error.Value);
                }

                continue;
            }

            foreach (MediaItemScanResult <TMovie> result in maybeMovie.RightToSeq())
            {
                await movieRepository.SetEtag(result.Item, MediaServerEtag(incoming));

                if (_localFileSystem.FileExists(result.LocalPath))
                {
                    if (await movieRepository.FlagNormal(library, result.Item))
                    {
                        result.IsUpdated = true;
                    }
                }
                else
                {
                    Option <int> flagResult = await movieRepository.FlagUnavailable(library, result.Item);

                    if (flagResult.IsSome)
                    {
                        result.IsUpdated = true;
                    }
                }

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

        // trash items that are no longer present on the media server
        var fileNotFoundItemIds = existingMovies.Map(m => m.MediaServerItemId)
                                  .Except(movieEntries.Map(MediaServerItemId)).ToList();
        List <int> ids = await movieRepository.FlagFileNotFound(library, fileNotFoundItemIds);

        await _searchIndex.RebuildItems(_searchRepository, ids);

        await _mediator.Publish(new LibraryScanProgress(library.Id, 0), cancellationToken);

        return(Unit.Default);
    }