@ -1,4 +1,5 @@
@@ -1,4 +1,5 @@
using System.IO ;
using System ;
using System.IO ;
using System.Threading ;
using System.Threading.Tasks ;
using ErsatzTV.Core ;
@ -8,14 +9,17 @@ using ErsatzTV.Core.Interfaces.Metadata;
@@ -8,14 +9,17 @@ using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories ;
using LanguageExt ;
using MediatR ;
using Microsoft.Extensions.Logging ;
using Unit = LanguageExt . Unit ;
namespace ErsatzTV.Application.MediaSources.Commands
{
public class ScanLocalMediaSourceHandler : IRequestHandler < ScanLocalMediaSource , Either < BaseError , string > >
public class ScanLocalMediaSourceHandler : IRequestHandler < ForceScanLocalMediaSource , Either < BaseError , string > > ,
IRequestHandler < ScanLocalMediaSourceIfNeeded , Either < BaseError , string > >
{
private readonly IConfigElementRepository _ configElementRepository ;
private readonly IEntityLocker _ entityLocker ;
private readonly ILogger < ScanLocalMediaSourceHandler > _l ogger ;
private readonly IMediaSourceRepository _ mediaSourceRepository ;
private readonly IMovieFolderScanner _ movieFolderScanner ;
private readonly ITelevisionFolderScanner _ televisionFolderScanner ;
@ -25,44 +29,72 @@ namespace ErsatzTV.Application.MediaSources.Commands
@@ -25,44 +29,72 @@ namespace ErsatzTV.Application.MediaSources.Commands
IConfigElementRepository configElementRepository ,
IMovieFolderScanner movieFolderScanner ,
ITelevisionFolderScanner televisionFolderScanner ,
IEntityLocker entityLocker )
IEntityLocker entityLocker ,
ILogger < ScanLocalMediaSourceHandler > logger )
{
_ mediaSourceRepository = mediaSourceRepository ;
_ configElementRepository = configElementRepository ;
_ movieFolderScanner = movieFolderScanner ;
_ televisionFolderScanner = televisionFolderScanner ;
_ entityLocker = entityLocker ;
_l ogger = logger ;
}
public Task < Either < BaseError , string > >
Handle ( ScanLocalMediaSource request , CancellationToken cancellationToken ) = >
public Task < Either < BaseError , string > > Handle (
ForceScanLocalMediaSource request ,
CancellationToken cancellationToken ) = >
Handle ( ( IScanLocalMediaSource ) request , cancellationToken ) ;
public Task < Either < BaseError , string > > Handle (
ScanLocalMediaSourceIfNeeded request ,
CancellationToken cancellationToken ) = >
Handle ( ( IScanLocalMediaSource ) request , cancellationToken ) ;
private Task < Either < BaseError , string > >
Handle ( IScanLocalMediaSource request , CancellationToken cancellationToken ) = >
Validate ( request )
. MapT ( parameters = > PerformScan ( parameters ) . Map ( _ = > parameters . LocalMediaSource . Folder ) )
. Bind ( v = > v . ToEitherAsync ( ) ) ;
private async Task < Unit > PerformScan ( RequestParameters parameters )
{
switch ( parameters . LocalMediaSource . MediaType )
DateTimeOffset lastScan = parameters . LocalMediaSource . LastScan ? ? DateTime . MinValue ;
if ( parameters . ForceScan | | lastScan < DateTimeOffset . Now - TimeSpan . FromHours ( 6 ) )
{
switch ( parameters . LocalMediaSource . MediaType )
{
case MediaType . Movie :
await _ movieFolderScanner . ScanFolder ( parameters . LocalMediaSource , parameters . FFprobePath ) ;
break ;
case MediaType . TvShow :
await _ televisionFolderScanner . ScanFolder ( parameters . LocalMediaSource , parameters . FFprobePath ) ;
break ;
}
parameters . LocalMediaSource . LastScan = DateTimeOffset . Now ;
await _ mediaSourceRepository . Update ( parameters . LocalMediaSource ) ;
}
else
{
case MediaType . Movie :
await _ movieFolderScanner . ScanFolder ( parameters . LocalMediaSource , parameters . FFprobePath ) ;
break ;
case MediaType . TvShow :
await _ televisionFolderScanner . ScanFolder ( parameters . LocalMediaSource , parameters . FFprobePath ) ;
break ;
_l ogger . LogDebug (
"Skipping unforced scan of media source {Folder}" ,
parameters . LocalMediaSource . Folder ) ;
}
_ entityLocker . UnlockMediaSource ( parameters . LocalMediaSource . Id ) ;
return Unit . Default ;
}
private async Task < Validation < BaseError , RequestParameters > > Validate ( ScanLocalMediaSource request ) = >
private async Task < Validation < BaseError , RequestParameters > > Validate ( I ScanLocalMediaSource request ) = >
( await LocalMediaSourceMustExist ( request ) , await ValidateFFprobePath ( ) )
. Apply ( ( localMediaSource , ffprobePath ) = > new RequestParameters ( localMediaSource , ffprobePath ) ) ;
. Apply (
( localMediaSource , ffprobePath ) = > new RequestParameters (
localMediaSource ,
ffprobePath ,
request . ForceScan ) ) ;
private Task < Validation < BaseError , LocalMediaSource > > LocalMediaSourceMustExist (
ScanLocalMediaSource request ) = >
I ScanLocalMediaSource request ) = >
_ mediaSourceRepository . Get ( request . MediaSourceId )
. Map ( maybeMediaSource = > maybeMediaSource . Map ( ms = > ms as LocalMediaSource ) )
. Map ( v = > v . ToValidation < BaseError > ( $"Local media source {request.MediaSourceId} does not exist." ) ) ;
@ -74,6 +106,6 @@ namespace ErsatzTV.Application.MediaSources.Commands
@@ -74,6 +106,6 @@ namespace ErsatzTV.Application.MediaSources.Commands
ffprobePath = >
ffprobePath . ToValidation < BaseError > ( "FFprobe path does not exist on the file system" ) ) ;
private record RequestParameters ( LocalMediaSource LocalMediaSource , string FFprobePath ) ;
private record RequestParameters ( LocalMediaSource LocalMediaSource , string FFprobePath , bool ForceScan ) ;
}
}