|
|
@ -53,13 +53,14 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib |
|
|
|
{ |
|
|
|
{ |
|
|
|
try |
|
|
|
try |
|
|
|
{ |
|
|
|
{ |
|
|
|
Either<BaseError, List<TMovie>> entries = await GetMovieLibraryItems(connectionParameters, library); |
|
|
|
Either<BaseError, int> maybeCount = await CountMovieLibraryItems(connectionParameters, library); |
|
|
|
|
|
|
|
foreach (BaseError error in maybeCount.LeftToSeq()) |
|
|
|
foreach (BaseError error in entries.LeftToSeq()) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
return error; |
|
|
|
return error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int count = await maybeCount.RightToSeq().HeadOrNone().IfNoneAsync(1); |
|
|
|
|
|
|
|
|
|
|
|
return await ScanLibrary( |
|
|
|
return await ScanLibrary( |
|
|
|
movieRepository, |
|
|
|
movieRepository, |
|
|
|
connectionParameters, |
|
|
|
connectionParameters, |
|
|
@ -67,7 +68,8 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib |
|
|
|
getLocalPath, |
|
|
|
getLocalPath, |
|
|
|
ffmpegPath, |
|
|
|
ffmpegPath, |
|
|
|
ffprobePath, |
|
|
|
ffprobePath, |
|
|
|
entries.RightToSeq().Flatten().ToList(), |
|
|
|
GetMovieLibraryItems(connectionParameters, library), |
|
|
|
|
|
|
|
count, |
|
|
|
deepScan, |
|
|
|
deepScan, |
|
|
|
cancellationToken); |
|
|
|
cancellationToken); |
|
|
|
} |
|
|
|
} |
|
|
@ -88,21 +90,24 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib |
|
|
|
Func<TMovie, string> getLocalPath, |
|
|
|
Func<TMovie, string> getLocalPath, |
|
|
|
string ffmpegPath, |
|
|
|
string ffmpegPath, |
|
|
|
string ffprobePath, |
|
|
|
string ffprobePath, |
|
|
|
List<TMovie> movieEntries, |
|
|
|
IAsyncEnumerable<TMovie> movieEntries, |
|
|
|
|
|
|
|
int totalMovieCount, |
|
|
|
bool deepScan, |
|
|
|
bool deepScan, |
|
|
|
CancellationToken cancellationToken) |
|
|
|
CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
var incomingItemIds = new List<string>(); |
|
|
|
List<TEtag> existingMovies = await movieRepository.GetExistingMovies(library); |
|
|
|
List<TEtag> existingMovies = await movieRepository.GetExistingMovies(library); |
|
|
|
|
|
|
|
|
|
|
|
var sortedMovies = movieEntries.OrderBy(m => m.MovieMetadata.Head().SortTitle).ToList(); |
|
|
|
await foreach (TMovie incoming in movieEntries.WithCancellation(cancellationToken)) |
|
|
|
foreach (TMovie incoming in sortedMovies) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if (cancellationToken.IsCancellationRequested) |
|
|
|
if (cancellationToken.IsCancellationRequested) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new ScanCanceled(); |
|
|
|
return new ScanCanceled(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
decimal percentCompletion = (decimal)sortedMovies.IndexOf(incoming) / sortedMovies.Count; |
|
|
|
incomingItemIds.Add(MediaServerItemId(incoming)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decimal percentCompletion = Math.Clamp((decimal)incomingItemIds.Count / totalMovieCount, 0, 1); |
|
|
|
await _mediator.Publish(new LibraryScanProgress(library.Id, percentCompletion), cancellationToken); |
|
|
|
await _mediator.Publish(new LibraryScanProgress(library.Id, percentCompletion), cancellationToken); |
|
|
|
|
|
|
|
|
|
|
|
string localPath = getLocalPath(incoming); |
|
|
|
string localPath = getLocalPath(incoming); |
|
|
@ -165,8 +170,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// trash movies that are no longer present on the media server
|
|
|
|
// trash movies that are no longer present on the media server
|
|
|
|
var fileNotFoundItemIds = existingMovies.Map(m => m.MediaServerItemId) |
|
|
|
var fileNotFoundItemIds = existingMovies.Map(m => m.MediaServerItemId).Except(incomingItemIds).ToList(); |
|
|
|
.Except(movieEntries.Map(MediaServerItemId)).ToList(); |
|
|
|
|
|
|
|
List<int> ids = await movieRepository.FlagFileNotFound(library, fileNotFoundItemIds); |
|
|
|
List<int> ids = await movieRepository.FlagFileNotFound(library, fileNotFoundItemIds); |
|
|
|
await _searchIndex.RebuildItems(_searchRepository, ids); |
|
|
|
await _searchIndex.RebuildItems(_searchRepository, ids); |
|
|
|
|
|
|
|
|
|
|
@ -178,7 +182,11 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib |
|
|
|
protected abstract string MediaServerItemId(TMovie movie); |
|
|
|
protected abstract string MediaServerItemId(TMovie movie); |
|
|
|
protected abstract string MediaServerEtag(TMovie movie); |
|
|
|
protected abstract string MediaServerEtag(TMovie movie); |
|
|
|
|
|
|
|
|
|
|
|
protected abstract Task<Either<BaseError, List<TMovie>>> GetMovieLibraryItems( |
|
|
|
protected abstract Task<Either<BaseError, int>> CountMovieLibraryItems( |
|
|
|
|
|
|
|
TConnectionParameters connectionParameters, |
|
|
|
|
|
|
|
TLibrary library); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected abstract IAsyncEnumerable<TMovie> GetMovieLibraryItems( |
|
|
|
TConnectionParameters connectionParameters, |
|
|
|
TConnectionParameters connectionParameters, |
|
|
|
TLibrary library); |
|
|
|
TLibrary library); |
|
|
|
|
|
|
|
|
|
|
|