private async Task <Either <BaseError, Unit> > ScanLibrary( PlexConnection connection, PlexServerAuthToken token, PlexLibrary library, string ffmpegPath, string ffprobePath, bool deepScan, List <PlexShow> showEntries, CancellationToken cancellationToken) { List <PlexItemEtag> existingShows = await _plexTelevisionRepository.GetExistingPlexShows(library); List <PlexPathReplacement> pathReplacements = await _mediaSourceRepository .GetPlexPathReplacements(library.MediaSourceId); foreach (PlexShow incoming in showEntries) { if (cancellationToken.IsCancellationRequested) { return(new ScanCanceled()); } decimal percentCompletion = (decimal)showEntries.IndexOf(incoming) / showEntries.Count; await _mediator.Publish(new LibraryScanProgress(library.Id, percentCompletion), cancellationToken); // TODO: figure out how to rebuild playlists Either <BaseError, MediaItemScanResult <PlexShow> > maybeShow = await _televisionRepository .GetOrAddPlexShow(library, incoming) .BindT(existing => UpdateMetadata(existing, incoming, library, connection, token, deepScan)) .BindT(existing => UpdateArtwork(existing, incoming)); if (maybeShow.IsLeft) { foreach (BaseError error in maybeShow.LeftToSeq()) { _logger.LogWarning( "Error processing plex show at {Key}: {Error}", incoming.Key, error.Value); } continue; } foreach (MediaItemScanResult <PlexShow> result in maybeShow.RightToSeq()) { Either <BaseError, Unit> scanResult = await ScanSeasons( library, pathReplacements, result.Item, connection, token, ffmpegPath, ffprobePath, deepScan, cancellationToken); foreach (ScanCanceled error in scanResult.LeftToSeq().OfType <ScanCanceled>()) { return(error); } await _plexTelevisionRepository.SetPlexEtag(result.Item, incoming.Etag); // TODO: if any seasons are unavailable or not found, flag show as unavailable/not found 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 fileNotFoundKeys = existingShows.Map(m => m.Key).Except(showEntries.Map(m => m.Key)).ToList(); List <int> ids = await _plexTelevisionRepository.FlagFileNotFoundShows(library, fileNotFoundKeys); await _searchIndex.RebuildItems(_searchRepository, ids); await _mediator.Publish(new LibraryScanProgress(library.Id, 0), cancellationToken); return(Unit.Default); }
public async Task <Either <BaseError, Unit> > ScanLibrary( PlexConnection connection, PlexServerAuthToken token, PlexLibrary plexMediaSourceLibrary) { Either <BaseError, List <PlexShow> > entries = await _plexServerApiClient.GetShowLibraryContents( plexMediaSourceLibrary, connection, token); return(await entries.Match <Task <Either <BaseError, Unit> > >( async showEntries => { foreach (PlexShow incoming in showEntries) { // TODO: figure out how to rebuild playlists Either <BaseError, MediaItemScanResult <PlexShow> > maybeShow = await _televisionRepository .GetOrAddPlexShow(plexMediaSourceLibrary, incoming) .BindT(existing => UpdateMetadata(existing, incoming)) .BindT(existing => UpdateArtwork(existing, incoming)); await maybeShow.Match( async result => { if (result.IsAdded) { await _searchIndex.AddItems(new List <MediaItem> { result.Item }); } else if (result.IsUpdated) { await _searchIndex.UpdateItems(new List <MediaItem> { result.Item }); } await ScanSeasons(plexMediaSourceLibrary, result.Item, connection, token); }, error => { _logger.LogWarning( "Error processing plex show at {Key}: {Error}", incoming.Key, error.Value); return Task.CompletedTask; }); } var showKeys = showEntries.Map(s => s.Key).ToList(); List <int> ids = await _televisionRepository.RemoveMissingPlexShows(plexMediaSourceLibrary, showKeys); await _searchIndex.RemoveItems(ids); return Unit.Default; }, error => { _logger.LogWarning( "Error synchronizing plex library {Path}: {Error}", plexMediaSourceLibrary.Name, error.Value); return Left <BaseError, Unit>(error).AsTask(); })); }