private async Task <Unit> PerformScan(RequestParameters parameters)
        {
            (LocalLibrary localLibrary, string ffprobePath, bool forceScan) = parameters;

            var lastScan = new DateTimeOffset(localLibrary.LastScan ?? DateTime.MinValue, TimeSpan.Zero);

            if (forceScan || lastScan < DateTimeOffset.Now - TimeSpan.FromHours(6))
            {
                foreach (LibraryPath libraryPath in localLibrary.Paths)
                {
                    switch (localLibrary.MediaKind)
                    {
                    case LibraryMediaKind.Movies:
                        await _movieFolderScanner.ScanFolder(libraryPath, ffprobePath);

                        break;

                    case LibraryMediaKind.Shows:
                        await _televisionFolderScanner.ScanFolder(libraryPath, ffprobePath);

                        break;
                    }
                }

                localLibrary.LastScan = DateTime.UtcNow;
                await _libraryRepository.UpdateLastScan(localLibrary);
            }
            else
            {
                _logger.LogDebug(
                    "Skipping unforced scan of library {Name}",
                    localLibrary.Name);
            }

            _entityLocker.UnlockLibrary(localLibrary.Id);
            return(Unit.Default);
        }
    private async Task <Unit> PerformScan(RequestParameters parameters, CancellationToken cancellationToken)
    {
        (LocalLibrary localLibrary, string ffprobePath, string ffmpegPath, bool forceScan,
         int libraryRefreshInterval) = parameters;

        try
        {
            var sw = new Stopwatch();
            sw.Start();

            var scanned = false;

            for (var i = 0; i < localLibrary.Paths.Count; i++)
            {
                LibraryPath libraryPath = localLibrary.Paths[i];

                decimal progressMin = (decimal)i / localLibrary.Paths.Count;
                decimal progressMax = (decimal)(i + 1) / localLibrary.Paths.Count;

                var            lastScan = new DateTimeOffset(libraryPath.LastScan ?? SystemTime.MinValueUtc, TimeSpan.Zero);
                DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
                if (forceScan || nextScan < DateTimeOffset.Now)
                {
                    scanned = true;

                    Either <BaseError, Unit> result = localLibrary.MediaKind switch
                    {
                        LibraryMediaKind.Movies =>
                        await _movieFolderScanner.ScanFolder(
                            libraryPath,
                            ffmpegPath,
                            ffprobePath,
                            progressMin,
                            progressMax,
                            cancellationToken),
                        LibraryMediaKind.Shows =>
                        await _televisionFolderScanner.ScanFolder(
                            libraryPath,
                            ffmpegPath,
                            ffprobePath,
                            progressMin,
                            progressMax,
                            cancellationToken),
                        LibraryMediaKind.MusicVideos =>
                        await _musicVideoFolderScanner.ScanFolder(
                            libraryPath,
                            ffmpegPath,
                            ffprobePath,
                            progressMin,
                            progressMax,
                            cancellationToken),
                        LibraryMediaKind.OtherVideos =>
                        await _otherVideoFolderScanner.ScanFolder(
                            libraryPath,
                            ffmpegPath,
                            ffprobePath,
                            progressMin,
                            progressMax,
                            cancellationToken),
                        LibraryMediaKind.Songs =>
                        await _songFolderScanner.ScanFolder(
                            libraryPath,
                            ffprobePath,
                            ffmpegPath,
                            progressMin,
                            progressMax,
                            cancellationToken),
                        _ => Unit.Default
                    };

                    if (result.IsRight)
                    {
                        libraryPath.LastScan = DateTime.UtcNow;
                        await _libraryRepository.UpdateLastScan(libraryPath);
                    }
                }

                await _mediator.Publish(new LibraryScanProgress(libraryPath.LibraryId, progressMax), cancellationToken);
            }

            sw.Stop();

            if (scanned)
            {
                _logger.LogDebug(
                    "Scan of library {Name} completed in {Duration}",
                    localLibrary.Name,
                    TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds));
            }
            else
            {
                _logger.LogDebug(
                    "Skipping unforced scan of local media library {Name}",
                    localLibrary.Name);
            }

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

            return(Unit.Default);
        }
        finally
        {
            _entityLocker.UnlockLibrary(localLibrary.Id);
        }
    }