private async Task <Either <BaseError, Unit> > ScanEpisodes(
        LibraryPath libraryPath,
        string ffmpegPath,
        string ffprobePath,
        Season season,
        string seasonPath,
        CancellationToken cancellationToken)
    {
        var allSeasonFiles = _localFileSystem.ListSubdirectories(seasonPath)
                             .Map(_localFileSystem.ListFiles)
                             .Flatten()
                             .Append(_localFileSystem.ListFiles(seasonPath))
                             .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f)))
                             .Filter(f => !Path.GetFileName(f).StartsWith("._"))
                             .OrderBy(identity)
                             .ToList();

        foreach (string file in allSeasonFiles)
        {
            // TODO: figure out how to rebuild playlists
            Either <BaseError, Episode> maybeEpisode = await _televisionRepository
                                                       .GetOrAddEpisode(season, libraryPath, file)
                                                       .BindT(
                episode => UpdateStatistics(new MediaItemScanResult <Episode>(episode), ffmpegPath, ffprobePath)
                .MapT(_ => episode))
                                                       .BindT(UpdateMetadata)
                                                       .BindT(e => UpdateThumbnail(e, cancellationToken))
                                                       .BindT(UpdateSubtitles)
                                                       .BindT(e => FlagNormal(new MediaItemScanResult <Episode>(e)))
                                                       .MapT(r => r.Item);

            foreach (BaseError error in maybeEpisode.LeftToSeq())
            {
                _logger.LogWarning("Error processing episode at {Path}: {Error}", file, error.Value);
            }

            foreach (Episode episode in maybeEpisode.RightToSeq())
            {
                await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> {
                    episode
                });
            }
        }

        // TODO: remove missing episodes?

        return(Unit.Default);
    }
        private async Task <Unit> ScanEpisodes(
            LibraryPath libraryPath,
            string ffprobePath,
            Season season,
            string seasonPath)
        {
            foreach (string file in _localFileSystem.ListFiles(seasonPath)
                     .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))).OrderBy(identity))
            {
                // TODO: figure out how to rebuild playlists
                Either <BaseError, Episode> maybeEpisode = await _televisionRepository
                                                           .GetOrAddEpisode(season, libraryPath, file)
                                                           .BindT(
                    episode => UpdateStatistics(new MediaItemScanResult <Episode>(episode), ffprobePath)
                    .MapT(_ => episode))
                                                           .BindT(UpdateMetadata)
                                                           .BindT(UpdateThumbnail);

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

            return(Unit.Default);
        }