Browse Source

remove fileexists

pull/2655/head
Jason Dove 8 months ago
parent
commit
1a1d02a609
No known key found for this signature in database
  1. 10
      ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs
  2. 16
      ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs
  3. 8
      ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs
  4. 6
      ErsatzTV.Application/Channels/Queries/GetChannelGuideHandler.cs
  5. 6
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs
  6. 4
      ErsatzTV.Application/Graphics/Commands/RefreshGraphicsElementsHandler.cs
  7. 10
      ErsatzTV.Application/Playouts/Commands/CreateExternalJsonPlayoutHandler.cs
  8. 30
      ErsatzTV.Application/Playouts/Commands/CreateScriptedPlayoutHandler.cs
  9. 31
      ErsatzTV.Application/Playouts/Commands/CreateSequentialPlayoutHandler.cs
  10. 36
      ErsatzTV.Application/Playouts/Commands/DeletePlayoutHandler.cs
  11. 6
      ErsatzTV.Application/Playouts/Commands/UpdateScriptedPlayoutHandler.cs
  12. 7
      ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs
  13. 6
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  14. 8
      ErsatzTV.Application/Streaming/Queries/GetLastPtsTimeHandler.cs
  15. 8
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  16. 6
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedShowSubtitlesHandler.cs
  17. 8
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs
  18. 12
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandlerBase.cs
  19. 4
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs
  20. 7
      ErsatzTV.Core.Tests/FFmpeg/FFmpegStreamSelectorTests.cs
  21. 3
      ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs
  22. 11
      ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/ContinuePlayoutTests.cs
  23. 35
      ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/NewPlayoutTests.cs
  24. 8
      ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/PlayoutBuilderTestBase.cs
  25. 5
      ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/RefreshPlayoutTests.cs
  26. 6
      ErsatzTV.Core.Tests/Scheduling/ScheduleIntegrationTests.cs
  27. 11
      ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs
  28. 1
      ErsatzTV.Core/Interfaces/Metadata/ILocalFileSystem.cs
  29. 10
      ErsatzTV.Core/Metadata/LocalFileSystem.cs
  30. 12
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  31. 6
      ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs
  32. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/SequentialPlayoutBuilder.cs
  33. 1
      ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
  34. 2
      ErsatzTV.Infrastructure.Tests/Metadata/LocalStatisticsProviderTests.cs
  35. 8
      ErsatzTV.Infrastructure/Data/Repositories/TemplateDataRepository.cs
  36. 2
      ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs
  37. 30
      ErsatzTV.Infrastructure/Images/ImageCache.cs
  38. 6
      ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs
  39. 13
      ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs
  40. 18
      ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
  41. 1
      ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs
  42. 34
      ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs
  43. 1
      ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
  44. 8
      ErsatzTV.Scanner/Core/Emby/EmbyMovieLibraryScanner.cs
  45. 8
      ErsatzTV.Scanner/Core/Emby/EmbyTelevisionLibraryScanner.cs
  46. 8
      ErsatzTV.Scanner/Core/Jellyfin/JellyfinMovieLibraryScanner.cs
  47. 8
      ErsatzTV.Scanner/Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs
  48. 8
      ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs
  49. 13
      ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs
  50. 10
      ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs
  51. 14
      ErsatzTV.Scanner/Core/Metadata/MediaServerMovieLibraryScanner.cs
  52. 14
      ErsatzTV.Scanner/Core/Metadata/MediaServerOtherVideoLibraryScanner.cs
  53. 18
      ErsatzTV.Scanner/Core/Metadata/MediaServerTelevisionLibraryScanner.cs
  54. 14
      ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs
  55. 16
      ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs
  56. 12
      ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs
  57. 8
      ErsatzTV.Scanner/Core/Metadata/RemoteStreamFolderScanner.cs
  58. 10
      ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs
  59. 18
      ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs
  60. 8
      ErsatzTV.Scanner/Core/Plex/PlexMovieLibraryScanner.cs
  61. 6
      ErsatzTV.Scanner/Core/Plex/PlexOtherVideoLibraryScanner.cs
  62. 8
      ErsatzTV.Scanner/Core/Plex/PlexTelevisionLibraryScanner.cs
  63. 6
      ErsatzTV/Controllers/Api/TroubleshootController.cs
  64. 6
      ErsatzTV/Pages/Troubleshooting/PlaybackTroubleshooting.razor
  65. 40
      ErsatzTV/Services/RunOnce/CacheCleanerService.cs

10
ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -12,19 +12,19 @@ namespace ErsatzTV.Application.Channels; @@ -12,19 +12,19 @@ namespace ErsatzTV.Application.Channels;
public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ISearchTargets _searchTargets;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public DeleteChannelHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ISearchTargets searchTargets)
{
_workerChannel = workerChannel;
_dbContextFactory = dbContextFactory;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_searchTargets = searchTargets;
}
@ -44,7 +44,7 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr @@ -44,7 +44,7 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr
// delete channel data from channel guide cache
string cacheFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, $"{channel.Number}.xml");
if (_localFileSystem.FileExists(cacheFile))
if (_fileSystem.File.Exists(cacheFile))
{
File.Delete(cacheFile);
}

16
ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Globalization;
using System.IO.Abstractions;
using System.Xml;
using ErsatzTV.Application.Configuration;
using ErsatzTV.Core;
@ -26,6 +27,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -26,6 +27,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RefreshChannelDataHandler> _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
@ -33,12 +35,14 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -33,12 +35,14 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
public RefreshChannelDataHandler(
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IConfigElementRepository configElementRepository,
ILogger<RefreshChannelDataHandler> logger)
{
_recyclableMemoryStreamManager = recyclableMemoryStreamManager;
_dbContextFactory = dbContextFactory;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_configElementRepository = configElementRepository;
_logger = logger;
@ -886,7 +890,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -886,7 +890,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
"movie.sbntxt");
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate movie XMLTV fragment without template file {File}; please restart ErsatzTV",
@ -905,7 +909,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -905,7 +909,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
"episode.sbntxt");
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate episode XMLTV fragment without template file {File}; please restart ErsatzTV",
@ -924,7 +928,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -924,7 +928,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
"musicVideo.sbntxt");
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate music video XMLTV fragment without template file {File}; please restart ErsatzTV",
@ -943,7 +947,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -943,7 +947,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
"song.sbntxt");
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate song XMLTV fragment without template file {File}; please restart ErsatzTV",
@ -962,7 +966,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -962,7 +966,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
"otherVideo.sbntxt");
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate other video XMLTV fragment without template file {File}; please restart ErsatzTV",
@ -1077,7 +1081,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -1077,7 +1081,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
var result = new List<PlayoutItem>();
if (_localFileSystem.FileExists(path))
if (_fileSystem.File.Exists(path))
{
Option<ExternalJsonChannel> maybeChannel = JsonConvert.DeserializeObject<ExternalJsonChannel>(
await File.ReadAllTextAsync(path));

8
ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Data.Common;
using System.IO.Abstractions;
using System.Net;
using System.Xml;
using Dapper;
@ -19,6 +20,7 @@ namespace ErsatzTV.Application.Channels; @@ -19,6 +20,7 @@ namespace ErsatzTV.Application.Channels;
public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RefreshChannelListHandler> _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
@ -26,11 +28,13 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList> @@ -26,11 +28,13 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
public RefreshChannelListHandler(
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILogger<RefreshChannelListHandler> logger)
{
_recyclableMemoryStreamManager = recyclableMemoryStreamManager;
_dbContextFactory = dbContextFactory;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_logger = logger;
}
@ -44,13 +48,13 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList> @@ -44,13 +48,13 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "channel.sbntxt");
// fall back to default template
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_channel.sbntxt");
}
// fail if file doesn't exist
if (!_localFileSystem.FileExists(templateFileName))
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate channel list without template file {File}; please restart ErsatzTV",

6
ErsatzTV.Application/Channels/Queries/GetChannelGuideHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using System.Text;
using System.Text.RegularExpressions;
using ErsatzTV.Core;
@ -15,14 +16,17 @@ public partial class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, E @@ -15,14 +16,17 @@ public partial class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, E
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
private readonly IFileSystem _fileSystem;
public GetChannelGuideHandler(
IDbContextFactory<TvContext> dbContextFactory,
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem)
{
_dbContextFactory = dbContextFactory;
_recyclableMemoryStreamManager = recyclableMemoryStreamManager;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
}
@ -39,7 +43,7 @@ public partial class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, E @@ -39,7 +43,7 @@ public partial class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, E
.ToImmutableHashSet();
string channelsFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, "channels.xml");
if (!_localFileSystem.FileExists(channelsFile))
if (!_fileSystem.File.Exists(channelsFile))
{
return BaseError.New($"Required file {channelsFile} is missing");
}

6
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs

@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
using System.Diagnostics;
using System.Globalization;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.FFmpeg;
using ErsatzTV.Application.Subtitles;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.FFmpegProfiles;
public class UpdateFFmpegSettingsHandler(
IConfigElementRepository configElementRepository,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ChannelWriter<IBackgroundServiceRequest> workerChannel)
: IRequestHandler<UpdateFFmpegSettings, Either<BaseError, Unit>>
{
@ -35,7 +35,7 @@ public class UpdateFFmpegSettingsHandler( @@ -35,7 +35,7 @@ public class UpdateFFmpegSettingsHandler(
private async Task<Validation<BaseError, Unit>> ValidateToolPath(string path, string name)
{
if (!localFileSystem.FileExists(path))
if (!fileSystem.File.Exists(path))
{
return BaseError.New($"{name} path does not exist");
}

4
ErsatzTV.Application/Graphics/Commands/RefreshGraphicsElementsHandler.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
@ -10,6 +11,7 @@ namespace ErsatzTV.Application.Graphics; @@ -10,6 +11,7 @@ namespace ErsatzTV.Application.Graphics;
public class RefreshGraphicsElementsHandler(
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IGraphicsElementLoader graphicsElementLoader,
ILogger<RefreshGraphicsElementsHandler> logger)
@ -24,7 +26,7 @@ public class RefreshGraphicsElementsHandler( @@ -24,7 +26,7 @@ public class RefreshGraphicsElementsHandler(
.ToListAsync(cancellationToken);
var missing = allExisting
.Where(e => !localFileSystem.FileExists(e.Path) || (Path.GetExtension(e.Path) != ".yml" && Path.GetExtension(e.Path) != ".yaml"))
.Where(e => !fileSystem.File.Exists(e.Path) || (Path.GetExtension(e.Path) != ".yml" && Path.GetExtension(e.Path) != ".yaml"))
.ToList();
foreach (GraphicsElement existing in missing)

10
ErsatzTV.Application/Playouts/Commands/CreateExternalJsonPlayoutHandler.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Scheduling;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -14,16 +14,16 @@ namespace ErsatzTV.Application.Playouts; @@ -14,16 +14,16 @@ namespace ErsatzTV.Application.Playouts;
public class CreateExternalJsonPlayoutHandler
: IRequestHandler<CreateExternalJsonPlayout, Either<BaseError, CreatePlayoutResponse>>
{
private readonly IFileSystem _fileSystem;
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
public CreateExternalJsonPlayoutHandler(
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory)
{
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_channel = channel;
_dbContextFactory = dbContextFactory;
}
@ -76,7 +76,7 @@ public class CreateExternalJsonPlayoutHandler @@ -76,7 +76,7 @@ public class CreateExternalJsonPlayoutHandler
private Validation<BaseError, string> ValidateExternalJsonFile(CreateExternalJsonPlayout request)
{
if (!_localFileSystem.FileExists(request.ScheduleFile))
if (!_fileSystem.File.Exists(request.ScheduleFile))
{
return BaseError.New("External Json File does not exist!");
}

30
ErsatzTV.Application/Playouts/Commands/CreateScriptedPlayoutHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.CommandLine.Parsing;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
@ -12,28 +13,17 @@ using Channel = ErsatzTV.Core.Domain.Channel; @@ -12,28 +13,17 @@ using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Playouts;
public class CreateScriptedPlayoutHandler
public class CreateScriptedPlayoutHandler(
IFileSystem fileSystem,
ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<CreateScriptedPlayout, Either<BaseError, CreatePlayoutResponse>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
public CreateScriptedPlayoutHandler(
ILocalFileSystem localFileSystem,
ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory)
{
_localFileSystem = localFileSystem;
_channel = channel;
_dbContextFactory = dbContextFactory;
}
public async Task<Either<BaseError, CreatePlayoutResponse>> Handle(
CreateScriptedPlayout request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Playout> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(playout => PersistPlayout(dbContext, playout, cancellationToken));
}
@ -45,15 +35,15 @@ public class CreateScriptedPlayoutHandler @@ -45,15 +35,15 @@ public class CreateScriptedPlayoutHandler
{
await dbContext.Playouts.AddAsync(playout, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await _channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Reset), cancellationToken);
await channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Reset), cancellationToken);
if (playout.Channel.PlayoutMode is ChannelPlayoutMode.OnDemand)
{
await _channel.WriteAsync(
await channel.WriteAsync(
new TimeShiftOnDemandPlayout(playout.Id, DateTimeOffset.Now, false),
cancellationToken);
}
await _channel.WriteAsync(new RefreshChannelList(), cancellationToken);
await channel.WriteAsync(new RefreshChannelList(), cancellationToken);
return new CreatePlayoutResponse(playout.Id);
}
@ -91,7 +81,7 @@ public class CreateScriptedPlayoutHandler @@ -91,7 +81,7 @@ public class CreateScriptedPlayoutHandler
{
var args = CommandLineParser.SplitCommandLine(request.ScheduleFile).ToList();
string scriptFile = args[0];
if (!_localFileSystem.FileExists(scriptFile))
if (!fileSystem.File.Exists(scriptFile))
{
return BaseError.New("Scripted schedule does not exist!");
}

31
ErsatzTV.Application/Playouts/Commands/CreateSequentialPlayoutHandler.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Scheduling;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -11,28 +11,17 @@ using Channel = ErsatzTV.Core.Domain.Channel; @@ -11,28 +11,17 @@ using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Playouts;
public class CreateSequentialPlayoutHandler
public class CreateSequentialPlayoutHandler(
IFileSystem fileSystem,
ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<CreateSequentialPlayout, Either<BaseError, CreatePlayoutResponse>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
public CreateSequentialPlayoutHandler(
ILocalFileSystem localFileSystem,
ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory)
{
_localFileSystem = localFileSystem;
_channel = channel;
_dbContextFactory = dbContextFactory;
}
public async Task<Either<BaseError, CreatePlayoutResponse>> Handle(
CreateSequentialPlayout request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Playout> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(playout => PersistPlayout(dbContext, playout, cancellationToken));
}
@ -44,15 +33,15 @@ public class CreateSequentialPlayoutHandler @@ -44,15 +33,15 @@ public class CreateSequentialPlayoutHandler
{
await dbContext.Playouts.AddAsync(playout, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await _channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Reset), cancellationToken);
await channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Reset), cancellationToken);
if (playout.Channel.PlayoutMode is ChannelPlayoutMode.OnDemand)
{
await _channel.WriteAsync(
await channel.WriteAsync(
new TimeShiftOnDemandPlayout(playout.Id, DateTimeOffset.Now, false),
cancellationToken);
}
await _channel.WriteAsync(new RefreshChannelList(), cancellationToken);
await channel.WriteAsync(new RefreshChannelList(), cancellationToken);
return new CreatePlayoutResponse(playout.Id);
}
@ -87,7 +76,7 @@ public class CreateSequentialPlayoutHandler @@ -87,7 +76,7 @@ public class CreateSequentialPlayoutHandler
private Validation<BaseError, string> ValidateYamlFile(CreateSequentialPlayout request)
{
if (!_localFileSystem.FileExists(request.ScheduleFile))
if (!fileSystem.File.Exists(request.ScheduleFile))
{
return BaseError.New("Sequential schedule does not exist!");
}

36
ErsatzTV.Application/Playouts/Commands/DeletePlayoutHandler.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.Threading.Channels;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Notifications;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -10,28 +10,16 @@ using Microsoft.EntityFrameworkCore; @@ -10,28 +10,16 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Playouts;
public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseError, Unit>>
public class DeletePlayoutHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
IMediator mediator)
: IRequestHandler<DeletePlayout, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly IMediator _mediator;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public DeletePlayoutHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
ILocalFileSystem localFileSystem,
IMediator mediator)
{
_workerChannel = workerChannel;
_dbContextFactory = dbContextFactory;
_localFileSystem = localFileSystem;
_mediator = mediator;
}
public async Task<Either<BaseError, Unit>> Handle(DeletePlayout request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<Playout> maybePlayout = await dbContext.Playouts
.Include(p => p.Channel)
@ -44,15 +32,15 @@ public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseEr @@ -44,15 +32,15 @@ public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseEr
// delete channel data from channel guide cache
string cacheFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, $"{playout.Channel.Number}.xml");
if (_localFileSystem.FileExists(cacheFile))
if (fileSystem.File.Exists(cacheFile))
{
File.Delete(cacheFile);
}
// refresh channel list to remove channel that has no playout
await _workerChannel.WriteAsync(new RefreshChannelList(), cancellationToken);
await workerChannel.WriteAsync(new RefreshChannelList(), cancellationToken);
await _mediator.Publish(new PlayoutUpdatedNotification(playout.Id, false), cancellationToken);
await mediator.Publish(new PlayoutUpdatedNotification(playout.Id, false), cancellationToken);
}
return maybePlayout

6
ErsatzTV.Application/Playouts/Commands/UpdateScriptedPlayoutHandler.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using System.CommandLine.Parsing;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
@ -14,7 +14,7 @@ public class @@ -14,7 +14,7 @@ public class
UpdateScriptedPlayoutHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel,
ILocalFileSystem localFileSystem)
IFileSystem fileSystem)
: IRequestHandler<UpdateScriptedPlayout,
Either<BaseError, PlayoutNameViewModel>>
{
@ -63,7 +63,7 @@ public class @@ -63,7 +63,7 @@ public class
{
var args = CommandLineParser.SplitCommandLine(request.ScheduleFile).ToList();
string scriptFile = args[0];
if (!localFileSystem.FileExists(scriptFile))
if (!fileSystem.File.Exists(scriptFile))
{
return BaseError.New("Scripted schedule does not exist!");
}

7
ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Threading.Channels;
using System.IO.Abstractions;
using System.Threading.Channels;
using Bugsnag;
using ErsatzTV.Application.Channels;
using ErsatzTV.Application.Graphics;
@ -21,6 +22,7 @@ namespace ErsatzTV.Application.Streaming; @@ -21,6 +22,7 @@ namespace ErsatzTV.Application.Streaming;
public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Either<BaseError, Unit>>
{
private readonly IClient _client;
private readonly IFileSystem _fileSystem;
private readonly IConfigElementRepository _configElementRepository;
private readonly IFFmpegSegmenterService _ffmpegSegmenterService;
private readonly IGraphicsEngine _graphicsEngine;
@ -40,6 +42,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit @@ -40,6 +42,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit
IServiceScopeFactory serviceScopeFactory,
IMediator mediator,
IClient client,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILogger<StartFFmpegSessionHandler> logger,
ILogger<HlsSessionWorker> sessionWorkerLogger,
@ -54,6 +57,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit @@ -54,6 +57,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit
_serviceScopeFactory = serviceScopeFactory;
_mediator = mediator;
_client = client;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_logger = logger;
_sessionWorkerLogger = sessionWorkerLogger;
@ -129,6 +133,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit @@ -129,6 +133,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit
_hlsPlaylistFilter,
_hlsInitSegmentCache,
_configElementRepository,
_fileSystem,
_localFileSystem,
_sessionWorkerLogger,
targetFramerate)

6
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO.Abstractions;
using System.IO.Pipelines;
using System.Text;
using System.Timers;
@ -30,6 +31,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -30,6 +31,7 @@ public class HlsSessionWorker : IHlsSessionWorker
private readonly IHlsInitSegmentCache _hlsInitSegmentCache;
private readonly Dictionary<long, int> _discontinuityMap = [];
private readonly IConfigElementRepository _configElementRepository;
private readonly IFileSystem _fileSystem;
private readonly IGraphicsEngine _graphicsEngine;
private readonly IHlsPlaylistFilter _hlsPlaylistFilter;
private readonly ILocalFileSystem _localFileSystem;
@ -60,6 +62,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -60,6 +62,7 @@ public class HlsSessionWorker : IHlsSessionWorker
IHlsPlaylistFilter hlsPlaylistFilter,
IHlsInitSegmentCache hlsInitSegmentCache,
IConfigElementRepository configElementRepository,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILogger<HlsSessionWorker> logger,
Option<int> targetFramerate)
@ -72,6 +75,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -72,6 +75,7 @@ public class HlsSessionWorker : IHlsSessionWorker
_hlsInitSegmentCache = hlsInitSegmentCache;
_hlsPlaylistFilter = hlsPlaylistFilter;
_configElementRepository = configElementRepository;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_logger = logger;
_targetFramerate = targetFramerate;
@ -308,7 +312,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -308,7 +312,7 @@ public class HlsSessionWorker : IHlsSessionWorker
string playlistFileName = Path.Combine(_workingDirectory, "live.m3u8");
_logger.LogDebug("Waiting for playlist to exist");
while (!_localFileSystem.FileExists(playlistFileName))
while (!_fileSystem.File.Exists(playlistFileName))
{
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
}

8
ErsatzTV.Application/Streaming/Queries/GetLastPtsTimeHandler.cs

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
using System.Text;
using System.IO.Abstractions;
using System.Text;
using Bugsnag;
using CliWrap;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
@ -14,7 +14,7 @@ namespace ErsatzTV.Application.Streaming; @@ -14,7 +14,7 @@ namespace ErsatzTV.Application.Streaming;
public class GetLastPtsTimeHandler(
IClient client,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ITempFilePool tempFilePool,
IConfigElementRepository configElementRepository,
ILogger<GetLastPtsTimeHandler> logger)
@ -168,7 +168,7 @@ public class GetLastPtsTimeHandler( @@ -168,7 +168,7 @@ public class GetLastPtsTimeHandler(
string playlistFileName = Path.Combine(FileSystemLayout.TranscodeFolder, channelNumber, "live.m3u8");
string playlistContents = string.Empty;
if (localFileSystem.FileExists(playlistFileName))
if (fileSystem.File.Exists(playlistFileName))
{
playlistContents = await File.ReadAllTextAsync(playlistFileName);
}

8
ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using CliWrap;
using System.IO.Abstractions;
using CliWrap;
using Dapper;
using ErsatzTV.Application.Playouts;
using ErsatzTV.Core;
@ -31,6 +32,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -31,6 +32,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
private readonly IEmbyPathReplacementService _embyPathReplacementService;
private readonly IExternalJsonPlayoutItemProvider _externalJsonPlayoutItemProvider;
private readonly IFFmpegProcessService _ffmpegProcessService;
private readonly IFileSystem _fileSystem;
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<GetPlayoutItemProcessByChannelNumberHandler> _logger;
@ -47,6 +49,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -47,6 +49,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
public GetPlayoutItemProcessByChannelNumberHandler(
IDbContextFactory<TvContext> dbContextFactory,
IFFmpegProcessService ffmpegProcessService,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IExternalJsonPlayoutItemProvider externalJsonPlayoutItemProvider,
IPlexPathReplacementService plexPathReplacementService,
@ -64,6 +67,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -64,6 +67,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
: base(dbContextFactory)
{
_ffmpegProcessService = ffmpegProcessService;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_externalJsonPlayoutItemProvider = externalJsonPlayoutItemProvider;
_plexPathReplacementService = plexPathReplacementService;
@ -775,7 +779,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -775,7 +779,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
}
// check filesystem first
if (_localFileSystem.FileExists(path))
if (_fileSystem.File.Exists(path))
{
if (playoutItem.MediaItem is RemoteStream remoteStream)
{

6
ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedShowSubtitlesHandler.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
@ -7,7 +8,6 @@ using Microsoft.Extensions.Logging; @@ -7,7 +8,6 @@ using Microsoft.Extensions.Logging;
using Dapper;
using ErsatzTV.Application.Maintenance;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.Subtitles;
@ -16,9 +16,9 @@ public class ExtractEmbeddedShowSubtitlesHandler( @@ -16,9 +16,9 @@ public class ExtractEmbeddedShowSubtitlesHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IConfigElementRepository configElementRepository,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILogger<ExtractEmbeddedSubtitlesHandler> logger)
: ExtractEmbeddedSubtitlesHandlerBase(localFileSystem, logger),
: ExtractEmbeddedSubtitlesHandlerBase(fileSystem, logger),
IRequestHandler<ExtractEmbeddedShowSubtitles, Option<BaseError>>
{
public async Task<Option<BaseError>> Handle(

8
ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using System.Threading.Channels;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application.Maintenance;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -23,12 +23,12 @@ public class ExtractEmbeddedSubtitlesHandler : ExtractEmbeddedSubtitlesHandlerBa @@ -23,12 +23,12 @@ public class ExtractEmbeddedSubtitlesHandler : ExtractEmbeddedSubtitlesHandlerBa
public ExtractEmbeddedSubtitlesHandler(
IDbContextFactory<TvContext> dbContextFactory,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
IEntityLocker entityLocker,
IConfigElementRepository configElementRepository,
ChannelWriter<IBackgroundServiceRequest> workerChannel,
ILogger<ExtractEmbeddedSubtitlesHandler> logger)
: base(localFileSystem, logger)
: base(fileSystem, logger)
{
_dbContextFactory = dbContextFactory;
_entityLocker = entityLocker;

12
ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandlerBase.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using System.Security.Cryptography;
using System.Text;
using CliWrap;
@ -8,7 +9,6 @@ using Dapper; @@ -8,7 +9,6 @@ using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
@ -17,7 +17,7 @@ using Microsoft.Extensions.Logging; @@ -17,7 +17,7 @@ using Microsoft.Extensions.Logging;
namespace ErsatzTV.Application.Subtitles;
[SuppressMessage("Security", "CA5351:Do Not Use Broken Cryptographic Algorithms")]
public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem localFileSystem, ILogger logger)
public abstract class ExtractEmbeddedSubtitlesHandlerBase(IFileSystem fileSystem, ILogger logger)
{
protected static Task<Validation<BaseError, string>> FFmpegPathMustExist(
TvContext dbContext,
@ -133,7 +133,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local @@ -133,7 +133,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local
{
string fullOutputPath = Path.Combine(FileSystemLayout.SubtitleCacheFolder, subtitle.OutputPath);
Directory.CreateDirectory(Path.GetDirectoryName(fullOutputPath));
if (localFileSystem.FileExists(fullOutputPath))
if (fileSystem.File.Exists(fullOutputPath))
{
File.Delete(fullOutputPath);
}
@ -193,7 +193,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local @@ -193,7 +193,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local
}
string fullOutputPath = Path.Combine(FileSystemLayout.FontsCacheFolder, fontStream.FileName);
if (localFileSystem.FileExists(fullOutputPath))
if (fileSystem.File.Exists(fullOutputPath))
{
// already extracted
continue;
@ -212,7 +212,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local @@ -212,7 +212,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local
// ffmpeg seems to return exit code 1 in all cases when dumping an attachment
// so ignore it and check success a different way
if (localFileSystem.FileExists(fullOutputPath))
if (fileSystem.File.Exists(fullOutputPath))
{
logger.LogDebug("Successfully extracted font {Font}", fontStream.FileName);
}
@ -300,7 +300,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local @@ -300,7 +300,7 @@ public abstract class ExtractEmbeddedSubtitlesHandlerBase(ILocalFileSystem local
{
foreach (string path in GetRelativeOutputPath(mediaItemId, subtitle))
{
return !localFileSystem.FileExists(path);
return !fileSystem.File.Exists(path);
}
return false;

4
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.IO.Abstractions;
using Dapper;
using ErsatzTV.Application.Streaming;
using ErsatzTV.Core;
@ -30,6 +31,7 @@ public class PrepareTroubleshootingPlaybackHandler( @@ -30,6 +31,7 @@ public class PrepareTroubleshootingPlaybackHandler(
IJellyfinPathReplacementService jellyfinPathReplacementService,
IEmbyPathReplacementService embyPathReplacementService,
IFFmpegProcessService ffmpegProcessService,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ISongVideoGenerator songVideoGenerator,
IWatermarkSelector watermarkSelector,
@ -471,7 +473,7 @@ public class PrepareTroubleshootingPlaybackHandler( @@ -471,7 +473,7 @@ public class PrepareTroubleshootingPlaybackHandler(
string path = await GetLocalPath(mediaItem, cancellationToken);
// check filesystem first
if (localFileSystem.FileExists(path))
if (fileSystem.File.Exists(path))
{
if (mediaItem is RemoteStream remoteStream)
{

7
ErsatzTV.Core.Tests/FFmpeg/FFmpegStreamSelectorTests.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Core.Tests.FFmpeg;
@ -61,7 +62,7 @@ public class FFmpegStreamSelectorTests @@ -61,7 +62,7 @@ public class FFmpegStreamSelectorTests
new ScriptEngine(Substitute.For<ILogger<ScriptEngine>>()),
Substitute.For<IStreamSelectorRepository>(),
Substitute.For<IConfigElementRepository>(),
Substitute.For<ILocalFileSystem>(),
new MockFileSystem(),
languageCodeService,
Substitute.For<ILogger<FFmpegStreamSelector>>());
@ -123,7 +124,7 @@ public class FFmpegStreamSelectorTests @@ -123,7 +124,7 @@ public class FFmpegStreamSelectorTests
new ScriptEngine(Substitute.For<ILogger<ScriptEngine>>()),
Substitute.For<IStreamSelectorRepository>(),
Substitute.For<IConfigElementRepository>(),
Substitute.For<ILocalFileSystem>(),
new MockFileSystem(),
languageCodeService,
Substitute.For<ILogger<FFmpegStreamSelector>>());
@ -173,7 +174,7 @@ public class FFmpegStreamSelectorTests @@ -173,7 +174,7 @@ public class FFmpegStreamSelectorTests
new ScriptEngine(Substitute.For<ILogger<ScriptEngine>>()),
Substitute.For<IStreamSelectorRepository>(),
Substitute.For<IConfigElementRepository>(),
Substitute.For<ILocalFileSystem>(),
new MockFileSystem(),
languageCodeService,
Substitute.For<ILogger<FFmpegStreamSelector>>());

3
ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Metadata;
namespace ErsatzTV.Core.Tests.Fakes;

11
ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/ContinuePlayoutTests.cs

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling;
@ -8,6 +7,7 @@ using ErsatzTV.Core.Tests.Fakes; @@ -8,6 +7,7 @@ using ErsatzTV.Core.Tests.Fakes;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Core.Tests.Scheduling.ClassicScheduling;
@ -588,7 +588,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -588,7 +588,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -596,7 +595,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -596,7 +595,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -714,7 +713,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -714,7 +713,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -722,7 +720,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -722,7 +720,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -842,7 +840,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -842,7 +840,6 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -850,7 +847,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase @@ -850,7 +847,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);

35
ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/NewPlayoutTests.cs

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling;
@ -9,6 +8,7 @@ using ErsatzTV.Core.Tests.Fakes; @@ -9,6 +8,7 @@ using ErsatzTV.Core.Tests.Fakes;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Core.Tests.Scheduling.ClassicScheduling;
@ -597,7 +597,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -597,7 +597,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -605,7 +604,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -605,7 +604,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -717,7 +716,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -717,7 +716,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -725,7 +723,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -725,7 +723,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -888,7 +886,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -888,7 +886,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -896,7 +893,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -896,7 +893,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1018,7 +1015,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1018,7 +1015,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1026,7 +1022,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1026,7 +1022,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1147,7 +1143,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1147,7 +1143,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1155,7 +1150,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1155,7 +1150,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1277,7 +1272,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1277,7 +1272,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1285,7 +1279,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1285,7 +1279,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1412,7 +1406,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1412,7 +1406,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1420,7 +1413,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1420,7 +1413,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1547,7 +1540,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1547,7 +1540,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1555,7 +1547,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1555,7 +1547,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1691,7 +1683,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1691,7 +1683,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1699,7 +1690,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1699,7 +1690,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1828,7 +1819,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1828,7 +1819,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1836,7 +1826,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1836,7 +1826,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -1931,7 +1921,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1931,7 +1921,6 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -1939,7 +1928,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase @@ -1939,7 +1928,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);

8
ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/PlayoutBuilderTestBase.cs

@ -2,7 +2,6 @@ using Destructurama; @@ -2,7 +2,6 @@ using Destructurama;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling;
@ -11,6 +10,7 @@ using Microsoft.Extensions.Logging; @@ -11,6 +10,7 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using NUnit.Framework;
using Serilog;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Core.Tests.Scheduling.ClassicScheduling;
@ -66,7 +66,6 @@ public abstract class PlayoutBuilderTestBase @@ -66,7 +66,6 @@ public abstract class PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -74,7 +73,7 @@ public abstract class PlayoutBuilderTestBase @@ -74,7 +73,7 @@ public abstract class PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);
@ -182,7 +181,6 @@ public abstract class PlayoutBuilderTestBase @@ -182,7 +181,6 @@ public abstract class PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -190,7 +188,7 @@ public abstract class PlayoutBuilderTestBase @@ -190,7 +188,7 @@ public abstract class PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);

5
ErsatzTV.Core.Tests/Scheduling/ClassicScheduling/RefreshPlayoutTests.cs

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling;
@ -8,6 +7,7 @@ using ErsatzTV.Core.Tests.Fakes; @@ -8,6 +7,7 @@ using ErsatzTV.Core.Tests.Fakes;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Core.Tests.Scheduling.ClassicScheduling;
@ -101,7 +101,6 @@ public class RefreshPlayoutTests : PlayoutBuilderTestBase @@ -101,7 +101,6 @@ public class RefreshPlayoutTests : PlayoutBuilderTestBase
IArtistRepository artistRepo = Substitute.For<IArtistRepository>();
IMultiEpisodeShuffleCollectionEnumeratorFactory factory =
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>();
ILocalFileSystem localFileSystem = Substitute.For<ILocalFileSystem>();
IRerunHelper rerunHelper = Substitute.For<IRerunHelper>();
var builder = new PlayoutBuilder(
configRepo,
@ -109,7 +108,7 @@ public class RefreshPlayoutTests : PlayoutBuilderTestBase @@ -109,7 +108,7 @@ public class RefreshPlayoutTests : PlayoutBuilderTestBase
televisionRepo,
artistRepo,
factory,
localFileSystem,
new MockFileSystem(),
rerunHelper,
Logger);

6
ErsatzTV.Core.Tests/Scheduling/ScheduleIntegrationTests.cs

@ -24,6 +24,7 @@ using NUnit.Framework; @@ -24,6 +24,7 @@ using NUnit.Framework;
using Serilog;
using Serilog.Events;
using Serilog.Extensions.Logging;
using MockFileSystem = Testably.Abstractions.Testing.MockFileSystem;
namespace ErsatzTV.Core.Tests.Scheduling;
@ -108,6 +109,7 @@ public class ScheduleIntegrationTests @@ -108,6 +109,7 @@ public class ScheduleIntegrationTests
ISearchIndex searchIndex = provider.GetRequiredService<ISearchIndex>();
await searchIndex.Initialize(
new LocalFileSystem(
new MockFileSystem(),
provider.GetRequiredService<IClient>(),
provider.GetRequiredService<ILogger<LocalFileSystem>>()),
provider.GetRequiredService<IConfigElementRepository>(),
@ -125,7 +127,7 @@ public class ScheduleIntegrationTests @@ -125,7 +127,7 @@ public class ScheduleIntegrationTests
new TelevisionRepository(factory, provider.GetRequiredService<ILogger<TelevisionRepository>>()),
new ArtistRepository(factory),
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>(),
Substitute.For<ILocalFileSystem>(),
new MockFileSystem(),
Substitute.For<IRerunHelper>(),
provider.GetRequiredService<ILogger<PlayoutBuilder>>());
@ -321,7 +323,7 @@ public class ScheduleIntegrationTests @@ -321,7 +323,7 @@ public class ScheduleIntegrationTests
new TelevisionRepository(factory, provider.GetRequiredService<ILogger<TelevisionRepository>>()),
new ArtistRepository(factory),
Substitute.For<IMultiEpisodeShuffleCollectionEnumeratorFactory>(),
Substitute.For<ILocalFileSystem>(),
new MockFileSystem(),
Substitute.For<IRerunHelper>(),
provider.GetRequiredService<ILogger<PlayoutBuilder>>());

11
ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO.Abstractions;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Metadata;
@ -15,7 +16,7 @@ namespace ErsatzTV.Core.FFmpeg; @@ -15,7 +16,7 @@ namespace ErsatzTV.Core.FFmpeg;
public class FFmpegStreamSelector : IFFmpegStreamSelector
{
private readonly IConfigElementRepository _configElementRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILanguageCodeService _languageCodeService;
private readonly ILogger<FFmpegStreamSelector> _logger;
private readonly IScriptEngine _scriptEngine;
@ -25,14 +26,14 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -25,14 +26,14 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
IScriptEngine scriptEngine,
IStreamSelectorRepository streamSelectorRepository,
IConfigElementRepository configElementRepository,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILanguageCodeService languageCodeService,
ILogger<FFmpegStreamSelector> logger)
{
_scriptEngine = scriptEngine;
_streamSelectorRepository = streamSelectorRepository;
_configElementRepository = configElementRepository;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_languageCodeService = languageCodeService;
_logger = logger;
}
@ -318,7 +319,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -318,7 +319,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
"js");
_logger.LogDebug("Checking for JS Script at {Path}", jsScriptPath);
if (!_localFileSystem.FileExists(jsScriptPath))
if (!_fileSystem.File.Exists(jsScriptPath))
{
_logger.LogDebug("Unable to locate episode audio stream selector script; falling back to built-in logic");
return Option<MediaStream>.None;
@ -358,7 +359,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -358,7 +359,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
"js");
_logger.LogDebug("Checking for JS Script at {Path}", jsScriptPath);
if (!_localFileSystem.FileExists(jsScriptPath))
if (!_fileSystem.File.Exists(jsScriptPath))
{
_logger.LogDebug(
"Unable to locate movie audio stream selector script; falling back to built-in logic");

1
ErsatzTV.Core/Interfaces/Metadata/ILocalFileSystem.cs

@ -8,7 +8,6 @@ public interface ILocalFileSystem @@ -8,7 +8,6 @@ public interface ILocalFileSystem
IEnumerable<string> ListFiles(string folder);
IEnumerable<string> ListFiles(string folder, string searchPattern);
IEnumerable<string> ListFiles(string folder, params string[] searchPatterns);
bool FileExists(string path);
bool FolderExists(string folder);
Task<Either<BaseError, Unit>> CopyFile(string source, string destination);
Unit EmptyFolder(string folder);

10
ErsatzTV.Core/Metadata/LocalFileSystem.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using System.Security.Cryptography;
using Bugsnag;
using ErsatzTV.Core.Interfaces.Metadata;
@ -6,7 +7,7 @@ using Microsoft.Extensions.Logging; @@ -6,7 +7,7 @@ using Microsoft.Extensions.Logging;
namespace ErsatzTV.Core.Metadata;
public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) : ILocalFileSystem
public class LocalFileSystem(IFileSystem fileSystem, IClient client, ILogger<LocalFileSystem> logger) : ILocalFileSystem
{
public Unit EnsureFolderExists(string folder)
{
@ -114,7 +115,8 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) : @@ -114,7 +115,8 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) :
return searchPatterns
.SelectMany(searchPattern =>
Directory.EnumerateFiles(folder, searchPattern, SearchOption.TopDirectoryOnly)
.Where(path => !Path.GetFileName(path).StartsWith("._", StringComparison.OrdinalIgnoreCase)))
.Where(path =>
!Path.GetFileName(path).StartsWith("._", StringComparison.OrdinalIgnoreCase)))
.Distinct();
}
catch (UnauthorizedAccessException)
@ -131,8 +133,6 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) : @@ -131,8 +133,6 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) :
return new List<string>();
}
public bool FileExists(string path) => File.Exists(path);
public bool FolderExists(string folder) => Directory.Exists(folder);
public async Task<Either<BaseError, Unit>> CopyFile(string source, string destination)
@ -193,6 +193,6 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) : @@ -193,6 +193,6 @@ public class LocalFileSystem(IClient client, ILogger<LocalFileSystem> logger) :
public string GetCustomOrDefaultFile(string folder, string file)
{
string path = Path.Combine(folder, file);
return FileExists(path) ? path : Path.Combine(folder, $"_{file}");
return fileSystem.File.Exists(path) ? path : Path.Combine(folder, $"_{file}");
}
}

12
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using System.Reflection;
using System.IO.Abstractions;
using System.Reflection;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling.Engine;
@ -20,10 +20,10 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -20,10 +20,10 @@ public class PlayoutBuilder : IPlayoutBuilder
{
private readonly IArtistRepository _artistRepository;
private readonly IConfigElementRepository _configElementRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly IRerunHelper _rerunHelper;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly IMultiEpisodeShuffleCollectionEnumeratorFactory _multiEpisodeFactory;
private readonly IFileSystem _fileSystem;
private readonly ITelevisionRepository _televisionRepository;
private Playlist _debugPlaylist;
private ILogger<PlayoutBuilder> _logger;
@ -34,7 +34,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -34,7 +34,7 @@ public class PlayoutBuilder : IPlayoutBuilder
ITelevisionRepository televisionRepository,
IArtistRepository artistRepository,
IMultiEpisodeShuffleCollectionEnumeratorFactory multiEpisodeFactory,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
IRerunHelper rerunHelper,
ILogger<PlayoutBuilder> logger)
{
@ -43,7 +43,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -43,7 +43,7 @@ public class PlayoutBuilder : IPlayoutBuilder
_televisionRepository = televisionRepository;
_artistRepository = artistRepository;
_multiEpisodeFactory = multiEpisodeFactory;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_rerunHelper = rerunHelper;
_logger = logger;
}
@ -1403,7 +1403,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -1403,7 +1403,7 @@ public class PlayoutBuilder : IPlayoutBuilder
guid.Guid.Replace("://", "_")),
"js");
_logger.LogDebug("Checking for JS Script at {Path}", jsScriptPath);
if (_localFileSystem.FileExists(jsScriptPath))
if (_fileSystem.File.Exists(jsScriptPath))
{
_logger.LogDebug("Found JS Script at {Path}", jsScriptPath);
try

6
ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.CommandLine.Parsing;
using System.IO.Abstractions;
using CliWrap;
using CliWrap.Buffered;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling.Engine;
@ -14,7 +14,7 @@ public class ScriptedPlayoutBuilder( @@ -14,7 +14,7 @@ public class ScriptedPlayoutBuilder(
IConfigElementRepository configElementRepository,
IScriptedPlayoutBuilderService scriptedPlayoutBuilderService,
ISchedulingEngine schedulingEngine,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILogger<ScriptedPlayoutBuilder> logger)
: IScriptedPlayoutBuilder
{
@ -38,7 +38,7 @@ public class ScriptedPlayoutBuilder( @@ -38,7 +38,7 @@ public class ScriptedPlayoutBuilder(
string scriptFile = args[0];
string[] scriptArgs = args.Skip(1).ToArray();
if (!localFileSystem.FileExists(scriptFile))
if (!fileSystem.File.Exists(scriptFile))
{
logger.LogError(
"Cannot build scripted playout; schedule file {File} does not exist",

6
ErsatzTV.Core/Scheduling/YamlScheduling/SequentialPlayoutBuilder.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
//using ErsatzTV.Core.Scheduling.Engine;
@ -17,7 +17,7 @@ namespace ErsatzTV.Core.Scheduling.YamlScheduling; @@ -17,7 +17,7 @@ namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class SequentialPlayoutBuilder(
//ISchedulingEngine schedulingEngine,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
IConfigElementRepository configElementRepository,
IMediaCollectionRepository mediaCollectionRepository,
IChannelRepository channelRepository,
@ -38,7 +38,7 @@ public class SequentialPlayoutBuilder( @@ -38,7 +38,7 @@ public class SequentialPlayoutBuilder(
PlayoutBuildResult result = PlayoutBuildResult.Empty;
if (!localFileSystem.FileExists(playout.ScheduleFile))
if (!fileSystem.File.Exists(playout.ScheduleFile))
{
logger.LogWarning("Sequential schedule file {File} does not exist; aborting.", playout.ScheduleFile);
return BaseError.New($"Sequential schedule file {playout.ScheduleFile} does not exist");

1
ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj

@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Shouldly" Version="4.3.0" />
<PackageReference Include="Testably.Abstractions.Testing" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

2
ErsatzTV.Infrastructure.Tests/Metadata/LocalStatisticsProviderTests.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
namespace ErsatzTV.Infrastructure.Tests.Metadata;
@ -21,6 +22,7 @@ public class LocalStatisticsProviderTests @@ -21,6 +22,7 @@ public class LocalStatisticsProviderTests
{
var provider = new LocalStatisticsProvider(
Substitute.For<IMetadataRepository>(),
new MockFileSystem(),
Substitute.For<ILocalFileSystem>(),
Substitute.For<IClient>(),
Substitute.For<IHardwareCapabilitiesFactory>(),

8
ErsatzTV.Infrastructure/Data/Repositories/TemplateDataRepository.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.Globalization;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Infrastructure.Epg;
@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore; @@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Data.Repositories;
public class TemplateDataRepository(ILocalFileSystem localFileSystem, IDbContextFactory<TvContext> dbContextFactory)
public class TemplateDataRepository(IFileSystem fileSystem, IDbContextFactory<TvContext> dbContextFactory)
: ITemplateDataRepository
{
public async Task<Option<Dictionary<string, object>>> GetMediaItemTemplateData(
@ -65,9 +65,9 @@ public class TemplateDataRepository(ILocalFileSystem localFileSystem, IDbContext @@ -65,9 +65,9 @@ public class TemplateDataRepository(ILocalFileSystem localFileSystem, IDbContext
}
string targetFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, $"{channelNumber}.xml");
if (localFileSystem.FileExists(targetFile))
if (fileSystem.File.Exists(targetFile))
{
await using FileStream stream = File.OpenRead(targetFile);
await using FileSystemStream stream = fileSystem.File.OpenRead(targetFile);
List<EpgProgramme> xmlProgrammes = EpgReader.FindProgrammesAt(stream, time, count);
var result = new List<Dictionary<string, object>>();

2
ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs

@ -28,7 +28,7 @@ public class MpegTsScriptService( @@ -28,7 +28,7 @@ public class MpegTsScriptService(
foreach (string folder in localFileSystem.ListSubdirectories(FileSystemLayout.MpegTsScriptsFolder))
{
string definition = Path.Combine(folder, "mpegts.yml");
if (!Scripts.ContainsKey(folder) && localFileSystem.FileExists(definition))
if (!Scripts.ContainsKey(folder) && fileSystem.File.Exists(definition))
{
Option<MpegTsScript> maybeScript = FromYaml(await fileSystem.File.ReadAllTextAsync(definition));
foreach (var script in maybeScript)

30
ErsatzTV.Infrastructure/Images/ImageCache.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO.Abstractions;
using System.Security.Cryptography;
using System.Text;
using Blurhash.SkiaSharp;
@ -14,27 +15,18 @@ using SkiaSharp; @@ -14,27 +15,18 @@ using SkiaSharp;
namespace ErsatzTV.Infrastructure.Images;
[SuppressMessage("Security", "CA5350:Do Not Use Weak Cryptographic Algorithms")]
public class ImageCache : IImageCache
public class ImageCache(IFileSystem fileSystem, ILocalFileSystem localFileSystem, ITempFilePool tempFilePool)
: IImageCache
{
private static readonly SHA1 Crypto;
private readonly ILocalFileSystem _localFileSystem;
private readonly ITempFilePool _tempFilePool;
static ImageCache() => Crypto = SHA1.Create();
public ImageCache(
ILocalFileSystem localFileSystem,
ITempFilePool tempFilePool)
{
_localFileSystem = localFileSystem;
_tempFilePool = tempFilePool;
}
public async Task<Either<BaseError, string>> SaveArtworkToCache(Stream stream, ArtworkKind artworkKind)
{
try
{
string tempFileName = _tempFilePool.GetNextTempFile(TempFileCategory.CachedArtwork);
string tempFileName = tempFilePool.GetNextTempFile(TempFileCategory.CachedArtwork);
// ReSharper disable once UseAwaitUsing
using (var fs = new FileStream(tempFileName, FileMode.OpenOrCreate, FileAccess.Write))
{
@ -63,7 +55,7 @@ public class ImageCache : IImageCache @@ -63,7 +55,7 @@ public class ImageCache : IImageCache
Directory.CreateDirectory(baseFolder);
}
await _localFileSystem.CopyFile(tempFileName, target);
await localFileSystem.CopyFile(tempFileName, target);
return hex;
}
@ -77,7 +69,7 @@ public class ImageCache : IImageCache @@ -77,7 +69,7 @@ public class ImageCache : IImageCache
{
try
{
var filenameKey = $"{path}:{_localFileSystem.GetLastWriteTime(path).ToFileTimeUtc()}";
var filenameKey = $"{path}:{localFileSystem.GetLastWriteTime(path).ToFileTimeUtc()}";
byte[] hash = Crypto.ComputeHash(Encoding.UTF8.GetBytes(filenameKey));
string hex = Convert.ToHexString(hash);
string subfolder = hex[..2];
@ -90,7 +82,7 @@ public class ImageCache : IImageCache @@ -90,7 +82,7 @@ public class ImageCache : IImageCache
_ => FileSystemLayout.LegacyImageCacheFolder
};
string target = Path.Combine(baseFolder, hex);
Either<BaseError, Unit> maybeResult = await _localFileSystem.CopyFile(path, target);
Either<BaseError, Unit> maybeResult = await localFileSystem.CopyFile(path, target);
return maybeResult.Match<Either<BaseError, string>>(
_ => hex,
error => error);
@ -159,14 +151,14 @@ public class ImageCache : IImageCache @@ -159,14 +151,14 @@ public class ImageCache : IImageCache
{
byte[] bytes = Encoding.UTF8.GetBytes(blurHash);
string base64 = Convert.ToBase64String(bytes).Replace("+", "_").Replace("/", "-").Replace("=", "");
string targetFile = GetPathForImage(base64, ArtworkKind.Poster, targetSize.Height);
if (!_localFileSystem.FileExists(targetFile))
string targetFile = GetPathForImage(base64, ArtworkKind.Poster, targetSize.Height) ?? string.Empty;
if (!fileSystem.File.Exists(targetFile))
{
string folder = Path.GetDirectoryName(targetFile);
_localFileSystem.EnsureFolderExists(folder);
localFileSystem.EnsureFolderExists(folder);
// ReSharper disable once ConvertToUsingDeclaration
using (FileStream fs = File.OpenWrite(targetFile))
using (FileSystemStream fs = fileSystem.File.OpenWrite(targetFile))
{
using (SKBitmap image = Blurhasher.Decode(blurHash, targetSize.Width, targetSize.Height))
{

6
ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO.Abstractions;
using System.Text;
using System.Text.RegularExpressions;
using Bugsnag;
@ -25,15 +26,18 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider @@ -25,15 +26,18 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<LocalStatisticsProvider> _logger;
private readonly IMetadataRepository _metadataRepository;
private readonly IFileSystem _fileSystem;
public LocalStatisticsProvider(
IMetadataRepository metadataRepository,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IClient client,
IHardwareCapabilitiesFactory hardwareCapabilitiesFactory,
ILogger<LocalStatisticsProvider> logger)
{
_metadataRepository = metadataRepository;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_client = client;
_hardwareCapabilitiesFactory = hardwareCapabilitiesFactory;
@ -146,7 +150,7 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider @@ -146,7 +150,7 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider
}
if (filePath.StartsWith("http", StringComparison.OrdinalIgnoreCase) ||
!_localFileSystem.FileExists(filePath))
!_fileSystem.File.Exists(filePath))
{
_logger.LogDebug("Skipping interlaced ratio check for remote content");
return Option<double>.None;

13
ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Globalization;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
@ -19,7 +20,7 @@ namespace ErsatzTV.Infrastructure.Streaming; @@ -19,7 +20,7 @@ namespace ErsatzTV.Infrastructure.Streaming;
public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILogger<ExternalJsonPlayoutItemProvider> _logger;
private readonly IPlexPathReplacementService _plexPathReplacementService;
@ -28,7 +29,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider @@ -28,7 +29,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
public ExternalJsonPlayoutItemProvider(
IDbContextFactory<TvContext> dbContextFactory,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
IPlexPathReplacementService plexPathReplacementService,
IPlexServerApiClient plexServerApiClient,
IPlexSecretStore plexSecretStore,
@ -36,7 +37,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider @@ -36,7 +37,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
ILogger<ExternalJsonPlayoutItemProvider> logger)
{
_dbContextFactory = dbContextFactory;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_plexPathReplacementService = plexPathReplacementService;
_plexServerApiClient = plexServerApiClient;
_plexSecretStore = plexSecretStore;
@ -62,7 +63,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider @@ -62,7 +63,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
if (playout.ScheduleKind == PlayoutScheduleKind.ExternalJson)
{
// json file must exist
if (_localFileSystem.FileExists(playout.ScheduleFile))
if (_fileSystem.File.Exists(playout.ScheduleFile))
{
return await GetExternalJsonPlayoutItem(dbContext, playout, now, ffprobePath, cancellationToken);
}
@ -86,7 +87,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider @@ -86,7 +87,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
CancellationToken cancellationToken)
{
Option<ExternalJsonChannel> maybeChannel = JsonConvert.DeserializeObject<ExternalJsonChannel>(
await File.ReadAllTextAsync(playout.ScheduleFile, cancellationToken));
await _fileSystem.File.ReadAllTextAsync(playout.ScheduleFile, cancellationToken));
// must deserialize channel from json
foreach (ExternalJsonChannel channel in maybeChannel)
@ -139,7 +140,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider @@ -139,7 +140,7 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider
program.File,
cancellationToken);
if (_localFileSystem.FileExists(localPath))
if (_fileSystem.File.Exists(localPath))
{
return await StreamLocally(startTime, program, ffprobePath, localPath);
}

18
ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs

@ -34,6 +34,7 @@ using NSubstitute; @@ -34,6 +34,7 @@ using NSubstitute;
using NUnit.Framework;
using Serilog;
using Shouldly;
using Testably.Abstractions.Testing;
using MediaStream = ErsatzTV.Core.Domain.MediaStream;
namespace ErsatzTV.Scanner.Tests.Core.FFmpeg;
@ -235,8 +236,10 @@ public class TranscodingTests @@ -235,8 +236,10 @@ public class TranscodingTests
StreamingMode streamingMode)
{
var localFileSystem = new LocalFileSystem(
new MockFileSystem(),
Substitute.For<IClient>(),
LoggerFactory.CreateLogger<LocalFileSystem>());
var fileSystem = new MockFileSystem();
var tempFilePool = new TempFilePool();
ImageCache mockImageCache = Substitute.For<ImageCache>(localFileSystem, tempFilePool);
@ -353,7 +356,8 @@ public class TranscodingTests @@ -353,7 +356,8 @@ public class TranscodingTests
var localStatisticsProvider = new LocalStatisticsProvider(
metadataRepository,
new LocalFileSystem(Substitute.For<IClient>(), LoggerFactory.CreateLogger<LocalFileSystem>()),
fileSystem,
localFileSystem,
Substitute.For<IClient>(),
Substitute.For<IHardwareCapabilitiesFactory>(),
LoggerFactory.CreateLogger<LocalStatisticsProvider>());
@ -460,6 +464,12 @@ public class TranscodingTests @@ -460,6 +464,12 @@ public class TranscodingTests
// do nothing
}
var localFileSystem = new LocalFileSystem(
new MockFileSystem(),
Substitute.For<IClient>(),
LoggerFactory.CreateLogger<LocalFileSystem>());
var fileSystem = new MockFileSystem();
string file = fileToTest;
if (string.IsNullOrWhiteSpace(file))
{
@ -503,7 +513,8 @@ public class TranscodingTests @@ -503,7 +513,8 @@ public class TranscodingTests
var localStatisticsProvider = new LocalStatisticsProvider(
metadataRepository,
new LocalFileSystem(Substitute.For<IClient>(), LoggerFactory.CreateLogger<LocalFileSystem>()),
fileSystem,
localFileSystem,
Substitute.For<IClient>(),
Substitute.For<IHardwareCapabilitiesFactory>(),
LoggerFactory.CreateLogger<LocalStatisticsProvider>());
@ -669,9 +680,6 @@ public class TranscodingTests @@ -669,9 +680,6 @@ public class TranscodingTests
SubtitleMode = subtitleMode
};
var localFileSystem = new LocalFileSystem(
Substitute.For<IClient>(),
LoggerFactory.CreateLogger<LocalFileSystem>());
var tempFilePool = new TempFilePool();
ImageCache mockImageCache = Substitute.For<ImageCache>(localFileSystem, tempFilePool);

1
ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
namespace ErsatzTV.Scanner.Tests.Core.Fakes;

34
ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs

@ -17,16 +17,14 @@ using NSubstitute; @@ -17,16 +17,14 @@ using NSubstitute;
using NUnit.Framework;
using Serilog;
using Shouldly;
using Testably.Abstractions.Testing;
using Testably.Abstractions.Testing.Initializer;
namespace ErsatzTV.Scanner.Tests.Core.Metadata;
[TestFixture]
public class MovieFolderScannerTests
{
private static readonly string BadFakeRoot = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? @"C:\Movies-That-Dont-Exist"
: @"/movies-that-dont-exist";
private static readonly string FakeRoot = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? @"C:\Movies"
: "/movies";
@ -718,9 +716,18 @@ public class MovieFolderScannerTests @@ -718,9 +716,18 @@ public class MovieFolderScannerTests
await _mediaItemRepository.Received(1).FlagFileNotFound(libraryPath, oldMoviePath);
}
private MovieFolderScanner GetService(params FakeFileEntry[] files) =>
new(
private MovieFolderScanner GetService(params FakeFileEntry[] files)
{
var fileSystem = new MockFileSystem();
IFileSystemInitializer<MockFileSystem> init = fileSystem.Initialize();
foreach (var file in files)
{
init.WithFile(file.Path).Which(f => f.File.LastWriteTime = file.LastWriteTime);
}
return new MovieFolderScanner(
_scannerProxy,
fileSystem,
new FakeLocalFileSystem([..files]),
_movieRepository,
_localStatisticsProvider,
@ -735,10 +742,20 @@ public class MovieFolderScannerTests @@ -735,10 +742,20 @@ public class MovieFolderScannerTests
Substitute.For<ITempFilePool>(),
Substitute.For<IClient>(),
Logger);
}
private MovieFolderScanner GetService(params FakeFolderEntry[] folders) =>
new(
private MovieFolderScanner GetService(params FakeFolderEntry[] folders)
{
var fileSystem = new MockFileSystem();
IFileSystemInitializer<MockFileSystem> init = fileSystem.Initialize();
foreach (var folder in folders)
{
init.WithSubdirectory(folder.Path);
}
return new MovieFolderScanner(
_scannerProxy,
fileSystem,
new FakeLocalFileSystem([], [..folders]),
_movieRepository,
_localStatisticsProvider,
@ -753,5 +770,6 @@ public class MovieFolderScannerTests @@ -753,5 +770,6 @@ public class MovieFolderScannerTests
Substitute.For<ITempFilePool>(),
Substitute.For<IClient>(),
Logger);
}
}
}

1
ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj

@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Shouldly" Version="4.3.0" />
<PackageReference Include="Testably.Abstractions.Testing" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

8
ErsatzTV.Scanner/Core/Emby/EmbyMovieLibraryScanner.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Scanner.Core.Interfaces;
@ -29,13 +29,13 @@ public class EmbyMovieLibraryScanner : @@ -29,13 +29,13 @@ public class EmbyMovieLibraryScanner :
IMediaSourceRepository mediaSourceRepository,
IEmbyMovieRepository embyMovieRepository,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger<EmbyMovieLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

8
ErsatzTV.Scanner/Core/Emby/EmbyTelevisionLibraryScanner.cs

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Scanner.Core.Interfaces;
@ -30,13 +30,13 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner< @@ -30,13 +30,13 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner<
IMediaSourceRepository mediaSourceRepository,
IEmbyTelevisionRepository televisionRepository,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger<EmbyTelevisionLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

8
ErsatzTV.Scanner/Core/Jellyfin/JellyfinMovieLibraryScanner.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin;
using ErsatzTV.Core.Metadata;
@ -29,13 +29,13 @@ public class JellyfinMovieLibraryScanner : @@ -29,13 +29,13 @@ public class JellyfinMovieLibraryScanner :
IJellyfinMovieRepository jellyfinMovieRepository,
IJellyfinPathReplacementService pathReplacementService,
IMediaSourceRepository mediaSourceRepository,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger<JellyfinMovieLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

8
ErsatzTV.Scanner/Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin;
using ErsatzTV.Core.Metadata;
@ -31,13 +31,13 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan @@ -31,13 +31,13 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan
IMediaSourceRepository mediaSourceRepository,
IJellyfinTelevisionRepository televisionRepository,
IJellyfinPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger<JellyfinTelevisionLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

8
ErsatzTV.Scanner/Core/Metadata/ImageFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -22,6 +23,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner @@ -22,6 +23,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner
private readonly IImageRepository _imageRepository;
private readonly ILibraryRepository _libraryRepository;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILogger<ImageFolderScanner> _logger;
@ -29,6 +31,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner @@ -29,6 +31,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner
public ImageFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
@ -41,7 +44,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner @@ -41,7 +44,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner
ITempFilePool tempFilePool,
IClient client,
ILogger<ImageFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -52,6 +55,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner @@ -52,6 +55,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_localMetadataProvider = localMetadataProvider;
_imageRepository = imageRepository;
@ -226,7 +230,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner @@ -226,7 +230,7 @@ public class ImageFolderScanner : LocalFolderScanner, IImageFolderScanner
foreach (string path in await _imageRepository.FindImagePaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing image at {Path}", path);
List<int> imageIds = await FlagFileNotFound(libraryPath, path);

13
ErsatzTV.Scanner/Core/Metadata/LocalFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using CliWrap;
using ErsatzTV.Core;
@ -59,7 +60,7 @@ public abstract class LocalFolderScanner @@ -59,7 +60,7 @@ public abstract class LocalFolderScanner
private readonly IImageCache _imageCache;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILogger _logger;
private readonly IMediaItemRepository _mediaItemRepository;
@ -67,7 +68,7 @@ public abstract class LocalFolderScanner @@ -67,7 +68,7 @@ public abstract class LocalFolderScanner
private readonly ITempFilePool _tempFilePool;
protected LocalFolderScanner(
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalStatisticsProvider localStatisticsProvider,
IMetadataRepository metadataRepository,
IMediaItemRepository mediaItemRepository,
@ -77,7 +78,7 @@ public abstract class LocalFolderScanner @@ -77,7 +78,7 @@ public abstract class LocalFolderScanner
IClient client,
ILogger logger)
{
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_localStatisticsProvider = localStatisticsProvider;
_metadataRepository = metadataRepository;
_mediaItemRepository = mediaItemRepository;
@ -100,7 +101,7 @@ public abstract class LocalFolderScanner @@ -100,7 +101,7 @@ public abstract class LocalFolderScanner
string path = version.MediaFiles.Head().Path;
if (version.DateUpdated != _localFileSystem.GetLastWriteTime(path) || version.Streams.Count == 0)
if (version.DateUpdated != _fileSystem.File.GetLastWriteTime(path) || version.Streams.Count == 0)
{
_logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", path);
Either<BaseError, bool> refreshResult =
@ -141,7 +142,7 @@ public abstract class LocalFolderScanner @@ -141,7 +142,7 @@ public abstract class LocalFolderScanner
Option<int> attachedPicIndex,
CancellationToken cancellationToken)
{
DateTime lastWriteTime = _localFileSystem.GetLastWriteTime(artworkFile);
DateTime lastWriteTime = _fileSystem.File.GetLastWriteTime(artworkFile);
metadata.Artwork ??= new List<Artwork>();
@ -311,5 +312,5 @@ public abstract class LocalFolderScanner @@ -311,5 +312,5 @@ public abstract class LocalFolderScanner
protected bool ShouldIncludeFolder(string folder) =>
!string.IsNullOrWhiteSpace(folder) &&
!Path.GetFileName(folder).StartsWith('.') &&
!_localFileSystem.FileExists(Path.Combine(folder, ".etvignore"));
!_fileSystem.File.Exists(Path.Combine(folder, ".etvignore"));
}

10
ErsatzTV.Scanner/Core/Metadata/LocalMetadataProvider.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using Bugsnag;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
@ -22,6 +23,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -22,6 +23,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
private readonly IClient _client;
private readonly IEpisodeNfoReader _episodeNfoReader;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly IFileSystem _fileSystem;
private readonly IImageRepository _imageRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalStatisticsProvider _localStatisticsProvider;
@ -49,6 +51,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -49,6 +51,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
IImageRepository imageRepository,
IRemoteStreamRepository remoteStreamRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IMovieNfoReader movieNfoReader,
IEpisodeNfoReader episodeNfoReader,
@ -70,6 +73,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -70,6 +73,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
_imageRepository = imageRepository;
_remoteStreamRepository = remoteStreamRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_movieNfoReader = movieNfoReader;
_episodeNfoReader = episodeNfoReader;
@ -86,7 +90,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -86,7 +90,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
{
string nfoFileName = Path.Combine(showFolder, "tvshow.nfo");
Option<ShowMetadata> maybeMetadata = None;
if (_localFileSystem.FileExists(nfoFileName))
if (_fileSystem.File.Exists(nfoFileName))
{
maybeMetadata = await LoadTelevisionShowMetadata(nfoFileName);
}
@ -106,7 +110,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -106,7 +110,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
{
string nfoFileName = Path.Combine(artistFolder, "artist.nfo");
Option<ArtistMetadata> maybeMetadata = None;
if (_localFileSystem.FileExists(nfoFileName))
if (_fileSystem.File.Exists(nfoFileName))
{
maybeMetadata = await LoadArtistMetadata(nfoFileName);
}

14
ErsatzTV.Scanner/Core/Metadata/MediaServerMovieLibraryScanner.cs

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.MediaServer;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Scanner.Core.Interfaces;
@ -21,19 +21,19 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -21,19 +21,19 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
{
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
private readonly IMetadataRepository _metadataRepository;
protected MediaServerMovieLibraryScanner(
IScannerProxy scannerProxy,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger logger)
{
_scannerProxy = scannerProxy;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_localChaptersProvider = localChaptersProvider;
_metadataRepository = metadataRepository;
_logger = logger;
@ -167,7 +167,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -167,7 +167,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
{
await movieRepository.SetEtag(result.Item, MediaServerEtag(incoming));
if (_localFileSystem.FileExists(result.LocalPath))
if (_fileSystem.File.Exists(result.LocalPath))
{
Option<int> flagResult = await movieRepository.FlagNormal(library, result.Item);
if (flagResult.IsSome)
@ -270,7 +270,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -270,7 +270,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
existingEtag == MediaServerEtag(incoming))
{
// skip scanning unavailable/file not found items that are unchanged and still don't exist locally
if (!_localFileSystem.FileExists(localPath) && !ServerSupportsRemoteStreaming)
if (!_fileSystem.File.Exists(localPath) && !ServerSupportsRemoteStreaming)
{
return false;
}
@ -279,7 +279,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -279,7 +279,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
{
// item is unchanged, but file does not exist
// don't scan, but mark as unavailable
if (!_localFileSystem.FileExists(localPath))
if (!_fileSystem.File.Exists(localPath))
{
if (ServerSupportsRemoteStreaming)
{

14
ErsatzTV.Scanner/Core/Metadata/MediaServerOtherVideoLibraryScanner.cs

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.MediaServer;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Scanner.Core.Interfaces;
@ -21,19 +21,19 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters, @@ -21,19 +21,19 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters,
{
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
private readonly IMetadataRepository _metadataRepository;
protected MediaServerOtherVideoLibraryScanner(
IScannerProxy scannerProxy,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger logger)
{
_scannerProxy = scannerProxy;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_localChaptersProvider = localChaptersProvider;
_metadataRepository = metadataRepository;
_logger = logger;
@ -174,7 +174,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters, @@ -174,7 +174,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters,
{
await otherVideoRepository.SetEtag(result.Item, MediaServerEtag(incoming));
if (_localFileSystem.FileExists(result.LocalPath))
if (_fileSystem.File.Exists(result.LocalPath))
{
Option<int> flagResult = await otherVideoRepository.FlagNormal(library, result.Item);
if (flagResult.IsSome)
@ -277,7 +277,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters, @@ -277,7 +277,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters,
existingEtag == MediaServerEtag(incoming))
{
// skip scanning unavailable/file not found items that are unchanged and still don't exist locally
if (!_localFileSystem.FileExists(localPath) && !ServerSupportsRemoteStreaming)
if (!_fileSystem.File.Exists(localPath) && !ServerSupportsRemoteStreaming)
{
return false;
}
@ -286,7 +286,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters, @@ -286,7 +286,7 @@ public abstract class MediaServerOtherVideoLibraryScanner<TConnectionParameters,
{
// item is unchanged, but file does not exist
// don't scan, but mark as unavailable
if (!_localFileSystem.FileExists(localPath))
if (!_fileSystem.File.Exists(localPath))
{
if (ServerSupportsRemoteStreaming)
{

18
ErsatzTV.Scanner/Core/Metadata/MediaServerTelevisionLibraryScanner.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.MediaServer;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Scanner.Core.Interfaces;
@ -23,19 +23,19 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -23,19 +23,19 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
{
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly ILocalFileSystem _localFileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
private readonly IMetadataRepository _metadataRepository;
protected MediaServerTelevisionLibraryScanner(
IScannerProxy scannerProxy,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
IMetadataRepository metadataRepository,
ILogger logger)
{
_scannerProxy = scannerProxy;
_localFileSystem = localFileSystem;
_fileSystem = fileSystem;
_localChaptersProvider = localChaptersProvider;
_metadataRepository = metadataRepository;
_logger = logger;
@ -469,7 +469,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -469,7 +469,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
{
await televisionRepository.SetEtag(result.Item, MediaServerEtag(incoming), cancellationToken);
if (_localFileSystem.FileExists(result.LocalPath))
if (_fileSystem.File.Exists(result.LocalPath))
{
Option<int> flagResult = await televisionRepository.FlagNormal(library, result.Item, cancellationToken);
if (flagResult.IsSome)
@ -541,7 +541,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -541,7 +541,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
existingEtag == MediaServerEtag(incoming))
{
// skip scanning unavailable/file not found items that are unchanged and still don't exist locally
if (!_localFileSystem.FileExists(localPath) && !ServerSupportsRemoteStreaming)
if (!_fileSystem.File.Exists(localPath) && !ServerSupportsRemoteStreaming)
{
return false;
}
@ -550,7 +550,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -550,7 +550,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
{
// item is unchanged, but file does not exist
// don't scan, but mark as unavailable
if (!_localFileSystem.FileExists(localPath))
if (!_fileSystem.File.Exists(localPath))
{
if (ServerSupportsRemoteStreaming)
{
@ -741,7 +741,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -741,7 +741,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
if (deepScan || result.IsAdded || MediaServerEtag(existing) != MediaServerEtag(incoming) ||
existing.MediaVersions.Head().Streams.Count == 0)
{
// if (maybeMediaVersion.IsNone && _localFileSystem.FileExists(result.LocalPath))
// if (maybeMediaVersion.IsNone && _fileSystem.File.Exists(result.LocalPath))
// {
// _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", result.LocalPath);
// Either<BaseError, bool> refreshResult =

14
ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -23,6 +24,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -23,6 +24,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@ -32,6 +34,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -32,6 +34,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
public MovieFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
IMovieRepository movieRepository,
ILocalStatisticsProvider localStatisticsProvider,
@ -47,7 +50,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -47,7 +50,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
IClient client,
ILogger<MovieFolderScanner> logger)
: base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -58,6 +61,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -58,6 +61,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_movieRepository = movieRepository;
_localSubtitlesProvider = localSubtitlesProvider;
@ -209,7 +213,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -209,7 +213,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
foreach (string path in await _movieRepository.FindMoviePaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing movie at {Path}", path);
List<int> ids = await FlagFileNotFound(libraryPath, path);
@ -362,7 +366,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -362,7 +366,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
string movieAsNfo = Path.ChangeExtension(path, "nfo");
string movieNfo = Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, "movie.nfo");
return Seq.create(movieAsNfo, movieNfo)
.Filter(s => _localFileSystem.FileExists(s))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
}
@ -380,12 +384,12 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -380,12 +384,12 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
IEnumerable<string> possibleMoviePosters = ImageFileExtensions.Collect(ext =>
new[] { $"{segment}.{ext}", Path.GetFileNameWithoutExtension(path) + $"-{segment}.{ext}" })
.Map(f => Path.Combine(folder, f));
Option<string> result = possibleMoviePosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone();
Option<string> result = possibleMoviePosters.Filter(p => _fileSystem.File.Exists(p)).HeadOrNone();
if (result.IsNone && artworkKind == ArtworkKind.Poster)
{
IEnumerable<string> possibleFolderPosters = ImageFileExtensions.Collect(ext => new[] { $"folder.{ext}" })
.Map(f => Path.Combine(folder, f));
result = possibleFolderPosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone();
result = possibleFolderPosters.Filter(p => _fileSystem.File.Exists(p)).HeadOrNone();
}
return result;

16
ErsatzTV.Scanner/Core/Metadata/MusicVideoFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -23,6 +24,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -23,6 +24,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@ -32,6 +34,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -32,6 +34,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
public MusicVideoFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
@ -47,7 +50,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -47,7 +50,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
ITempFilePool tempFilePool,
IClient client,
ILogger<MusicVideoFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -58,6 +61,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -58,6 +61,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_localMetadataProvider = localMetadataProvider;
_localSubtitlesProvider = localSubtitlesProvider;
@ -173,7 +177,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -173,7 +177,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
foreach (string path in await _musicVideoRepository.FindMusicVideoPaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing music video at {Path}", path);
List<int> musicVideoIds = await FlagFileNotFound(libraryPath, path);
@ -459,7 +463,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -459,7 +463,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
}
private Option<string> LocateNfoFileForArtist(string artistFolder) =>
Optional(Path.Combine(artistFolder, "artist.nfo")).Filter(s => _localFileSystem.FileExists(s));
Optional(Path.Combine(artistFolder, "artist.nfo")).Filter(s => _fileSystem.File.Exists(s));
private Option<string> LocateArtworkForArtist(string artistFolder, ArtworkKind artworkKind)
{
@ -473,7 +477,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -473,7 +477,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
return ImageFileExtensions
.Map(ext => $"{segment}.{ext}")
.Map(f => Path.Combine(artistFolder, f))
.Filter(s => _localFileSystem.FileExists(s))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
}
@ -481,7 +485,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -481,7 +485,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
{
string path = musicVideo.MediaVersions.Head().MediaFiles.Head().Path;
return Optional(Path.ChangeExtension(path, "nfo"))
.Filter(s => _localFileSystem.FileExists(s))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
}
@ -554,7 +558,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -554,7 +558,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
return ImageFileExtensions
.SelectMany(ext => new[] { Path.ChangeExtension(path, ext), Path.ChangeExtension(thumbPath, ext) })
.Filter(f => _localFileSystem.FileExists(f))
.Filter(f => _fileSystem.File.Exists(f))
.HeadOrNone();
}
}

12
ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -22,6 +23,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -22,6 +23,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@ -31,6 +33,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -31,6 +33,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
public OtherVideoFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
@ -45,7 +48,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -45,7 +48,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
ITempFilePool tempFilePool,
IClient client,
ILogger<OtherVideoFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -56,6 +59,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -56,6 +59,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_localMetadataProvider = localMetadataProvider;
_localSubtitlesProvider = localSubtitlesProvider;
@ -220,7 +224,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -220,7 +224,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
foreach (string path in await _otherVideoRepository.FindOtherVideoPaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing other video at {Path}", path);
List<int> otherVideoIds = await FlagFileNotFound(libraryPath, path);
@ -274,7 +278,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -274,7 +278,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
string path = otherVideo.MediaVersions.Head().MediaFiles.Head().Path;
Option<string> maybeNfoFile = new List<string> { Path.ChangeExtension(path, "nfo") }
.Filter(_localFileSystem.FileExists)
.Filter(_fileSystem.File.Exists)
.HeadOrNone();
if (maybeNfoFile.IsNone)
@ -376,7 +380,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -376,7 +380,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
string path = otherVideo.MediaVersions.Head().MediaFiles.Head().Path;
return ImageFileExtensions
.Map(ext => Path.ChangeExtension(path, ext))
.Filter(f => _localFileSystem.FileExists(f))
.Filter(f => _fileSystem.File.Exists(f))
.HeadOrNone();
}
}

8
ErsatzTV.Scanner/Core/Metadata/RemoteStreamFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -24,6 +25,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder @@ -24,6 +25,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder
private readonly IClient _client;
private readonly ILibraryRepository _libraryRepository;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILogger<RemoteStreamFolderScanner> _logger;
@ -32,6 +34,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder @@ -32,6 +34,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder
public RemoteStreamFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
@ -44,7 +47,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder @@ -44,7 +47,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder
ITempFilePool tempFilePool,
IClient client,
ILogger<RemoteStreamFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -55,6 +58,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder @@ -55,6 +58,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_localMetadataProvider = localMetadataProvider;
_remoteStreamRepository = remoteStreamRepository;
@ -213,7 +217,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder @@ -213,7 +217,7 @@ public class RemoteStreamFolderScanner : LocalFolderScanner, IRemoteStreamFolder
foreach (string path in await _remoteStreamRepository.FindRemoteStreamPaths(libraryPath, cancellationToken))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing remote stream at {Path}", path);
List<int> remoteStreamIds = await FlagFileNotFound(libraryPath, path);

10
ErsatzTV.Scanner/Core/Metadata/SongFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -21,6 +22,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -21,6 +22,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
private readonly IClient _client;
private readonly ILibraryRepository _libraryRepository;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILogger<SongFolderScanner> _logger;
@ -29,6 +31,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -29,6 +31,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
public SongFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
@ -41,7 +44,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -41,7 +44,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
ITempFilePool tempFilePool,
IClient client,
ILogger<SongFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -52,6 +55,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -52,6 +55,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_localMetadataProvider = localMetadataProvider;
_songRepository = songRepository;
@ -201,7 +205,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -201,7 +205,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
foreach (string path in await _songRepository.FindSongPaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing song at {Path}", path);
List<int> songIds = await FlagFileNotFound(libraryPath, path);
@ -336,7 +340,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -336,7 +340,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
string coverPath = Path.Combine(di.FullName, "cover.jpg");
return ImageFileExtensions
.Map(ext => Path.ChangeExtension(coverPath, ext))
.Filter(f => _localFileSystem.FileExists(f))
.Filter(f => _fileSystem.File.Exists(f))
.HeadOrNone();
}).Flatten();
}

18
ErsatzTV.Scanner/Core/Metadata/TelevisionFolderScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using Bugsnag;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
@ -23,6 +24,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -23,6 +24,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalChaptersProvider _localChaptersProvider;
private readonly IScannerProxy _scannerProxy;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@ -33,6 +35,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -33,6 +35,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
public TelevisionFolderScanner(
IScannerProxy scannerProxy,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ITelevisionRepository televisionRepository,
ILocalStatisticsProvider localStatisticsProvider,
@ -48,7 +51,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -48,7 +51,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
IClient client,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<TelevisionFolderScanner> logger) : base(
localFileSystem,
fileSystem,
localStatisticsProvider,
metadataRepository,
mediaItemRepository,
@ -59,6 +62,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -59,6 +62,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
logger)
{
_scannerProxy = scannerProxy;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_televisionRepository = televisionRepository;
_localMetadataProvider = localMetadataProvider;
@ -169,7 +173,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -169,7 +173,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
foreach (string path in await _televisionRepository.FindEpisodePaths(libraryPath))
{
if (!_localFileSystem.FileExists(path))
if (!_fileSystem.File.Exists(path))
{
_logger.LogInformation("Flagging missing episode at {Path}", path);
@ -584,12 +588,12 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -584,12 +588,12 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
}
private Option<string> LocateNfoFileForShow(string showFolder) =>
Optional(Path.Combine(showFolder, "tvshow.nfo")).Filter(s => _localFileSystem.FileExists(s));
Optional(Path.Combine(showFolder, "tvshow.nfo")).Filter(s => _fileSystem.File.Exists(s));
private Option<string> LocateNfoFile(Episode episode)
{
string path = episode.MediaVersions.Head().MediaFiles.Head().Path;
return Optional(Path.ChangeExtension(path, "nfo")).Filter(s => _localFileSystem.FileExists(s));
return Optional(Path.ChangeExtension(path, "nfo")).Filter(s => _fileSystem.File.Exists(s));
}
private Option<string> LocateArtworkForShow(string showFolder, ArtworkKind artworkKind)
@ -606,7 +610,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -606,7 +610,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
.Map(ext => segments.Map(segment => $"{segment}.{ext}"))
.Flatten()
.Map(f => Path.Combine(showFolder, f))
.Filter(s => _localFileSystem.FileExists(s))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
}
@ -615,7 +619,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -615,7 +619,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
string folder = Path.GetDirectoryName(seasonFolder) ?? string.Empty;
return ImageFileExtensions
.Map(ext => Path.Combine(folder, $"season{season.SeasonNumber:00}-poster.{ext}"))
.Filter(s => _localFileSystem.FileExists(s))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
}
@ -626,7 +630,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -626,7 +630,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
return ImageFileExtensions
.Map(ext => Path.GetFileNameWithoutExtension(path) + $"-thumb.{ext}")
.Map(f => Path.Combine(folder, f))
.Filter(f => _localFileSystem.FileExists(f))
.Filter(f => _fileSystem.File.Exists(f))
.HeadOrNone();
}
}

8
ErsatzTV.Scanner/Core/Plex/PlexMovieLibraryScanner.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
@ -33,12 +33,12 @@ public class PlexMovieLibraryScanner : @@ -33,12 +33,12 @@ public class PlexMovieLibraryScanner :
IMediaSourceRepository mediaSourceRepository,
IPlexMovieRepository plexMovieRepository,
IPlexPathReplacementService plexPathReplacementService,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
ILogger<PlexMovieLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

6
ErsatzTV.Scanner/Core/Plex/PlexOtherVideoLibraryScanner.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
@ -33,12 +33,12 @@ public class PlexOtherVideoLibraryScanner : @@ -33,12 +33,12 @@ public class PlexOtherVideoLibraryScanner :
IMediaSourceRepository mediaSourceRepository,
IPlexOtherVideoRepository plexOtherVideoRepository,
IPlexPathReplacementService plexPathReplacementService,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
ILogger<PlexOtherVideoLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

8
ErsatzTV.Scanner/Core/Plex/PlexTelevisionLibraryScanner.cs

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
using System.Text.RegularExpressions;
using System.IO.Abstractions;
using System.Text.RegularExpressions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Metadata;
@ -37,12 +37,12 @@ public partial class PlexTelevisionLibraryScanner : @@ -37,12 +37,12 @@ public partial class PlexTelevisionLibraryScanner :
IMediaSourceRepository mediaSourceRepository,
IPlexPathReplacementService plexPathReplacementService,
IPlexTelevisionRepository plexTelevisionRepository,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
ILocalChaptersProvider localChaptersProvider,
ILogger<PlexTelevisionLibraryScanner> logger)
: base(
scannerProxy,
localFileSystem,
fileSystem,
localChaptersProvider,
metadataRepository,
logger)

6
ErsatzTV/Controllers/Api/TroubleshootController.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Application;
using ErsatzTV.Application.MediaItems;
@ -6,7 +7,6 @@ using ErsatzTV.Application.Troubleshooting.Queries; @@ -6,7 +7,6 @@ using ErsatzTV.Application.Troubleshooting.Queries;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Troubleshooting;
using MediatR;
@ -18,7 +18,7 @@ namespace ErsatzTV.Controllers.Api; @@ -18,7 +18,7 @@ namespace ErsatzTV.Controllers.Api;
[ApiController]
public class TroubleshootController(
ChannelWriter<IFFmpegWorkerRequest> channelWriter,
ILocalFileSystem localFileSystem,
IFileSystem fileSystem,
IConfigElementRepository configElementRepository,
ITroubleshootingNotifier notifier,
IMediator mediator) : ControllerBase
@ -104,7 +104,7 @@ public class TroubleshootController( @@ -104,7 +104,7 @@ public class TroubleshootController(
cancellationToken);
string playlistFile = Path.Combine(FileSystemLayout.TranscodeTroubleshootingFolder, "live.m3u8");
while (!localFileSystem.FileExists(playlistFile))
while (!fileSystem.File.Exists(playlistFile))
{
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
if (cancellationToken.IsCancellationRequested || notifier.IsFailed(sessionId))

6
ErsatzTV/Pages/Troubleshooting/PlaybackTroubleshooting.razor

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
@page "/system/troubleshooting/playback"
@using System.Globalization
@using System.IO.Abstractions
@using ErsatzTV.Application.Channels
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.Graphics
@ -7,7 +8,6 @@ @@ -7,7 +8,6 @@
@using ErsatzTV.Application.Troubleshooting
@using ErsatzTV.Application.Troubleshooting.Queries
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Core.Interfaces.Metadata
@using ErsatzTV.Core.Notifications
@using MediatR.Courier
@using Microsoft.AspNetCore.WebUtilities
@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
@inject IEntityLocker Locker
@inject ICourier Courier;
@inject ISnackbar Snackbar;
@inject ILocalFileSystem LocalFileSystem;
@inject IFileSystem FileSystem;
<MudForm Style="max-height: 100%">
<MudPaper Square="true" Style="display: flex; height: 64px; min-height: 64px; width: 100%; z-index: 100; align-items: center">
@ -422,7 +422,7 @@ @@ -422,7 +422,7 @@
}
string logFileName = Path.Combine(FileSystemLayout.TranscodeTroubleshootingFolder, "logs.txt");
if (LocalFileSystem.FileExists(logFileName))
if (FileSystem.File.Exists(logFileName))
{
string text = await File.ReadAllTextAsync(logFileName);
await InvokeAsync(async () => { await _logsField.SetText(text); });

40
ErsatzTV/Services/RunOnce/CacheCleanerService.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core;
using System.IO.Abstractions;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Infrastructure.Data;
@ -6,39 +7,30 @@ using Microsoft.EntityFrameworkCore; @@ -6,39 +7,30 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Services.RunOnce;
public class CacheCleanerService : BackgroundService
public class CacheCleanerService(
IServiceScopeFactory serviceScopeFactory,
SystemStartup systemStartup,
ILogger<CacheCleanerService> logger)
: BackgroundService
{
private readonly ILogger<CacheCleanerService> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly SystemStartup _systemStartup;
public CacheCleanerService(
IServiceScopeFactory serviceScopeFactory,
SystemStartup systemStartup,
ILogger<CacheCleanerService> logger)
{
_serviceScopeFactory = serviceScopeFactory;
_systemStartup = systemStartup;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield();
await _systemStartup.WaitForDatabase(stoppingToken);
await systemStartup.WaitForDatabase(stoppingToken);
if (stoppingToken.IsCancellationRequested)
{
return;
}
using IServiceScope scope = _serviceScopeFactory.CreateScope();
using IServiceScope scope = serviceScopeFactory.CreateScope();
await using TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
ILocalFileSystem localFileSystem = scope.ServiceProvider.GetRequiredService<ILocalFileSystem>();
IFileSystem fileSystem = scope.ServiceProvider.GetRequiredService<IFileSystem>();
if (localFileSystem.FolderExists(FileSystemLayout.LegacyImageCacheFolder))
{
_logger.LogInformation("Migrating channel logos from legacy image cache folder");
logger.LogInformation("Migrating channel logos from legacy image cache folder");
List<string> logos = await dbContext.Channels
.AsNoTracking()
@ -50,7 +42,7 @@ public class CacheCleanerService : BackgroundService @@ -50,7 +42,7 @@ public class CacheCleanerService : BackgroundService
foreach (string logo in logos)
{
string legacyPath = Path.Combine(FileSystemLayout.LegacyImageCacheFolder, logo);
if (localFileSystem.FileExists(legacyPath))
if (fileSystem.File.Exists(legacyPath))
{
string subfolder = logo[..2];
string newPath = Path.Combine(FileSystemLayout.LogoCacheFolder, subfolder, logo);
@ -58,20 +50,20 @@ public class CacheCleanerService : BackgroundService @@ -58,20 +50,20 @@ public class CacheCleanerService : BackgroundService
}
}
_logger.LogInformation("Deleting legacy image cache folder");
logger.LogInformation("Deleting legacy image cache folder");
Directory.Delete(FileSystemLayout.LegacyImageCacheFolder, true);
}
if (localFileSystem.FolderExists(FileSystemLayout.TranscodeFolder))
{
_logger.LogInformation("Emptying transcode cache folder");
logger.LogInformation("Emptying transcode cache folder");
localFileSystem.EmptyFolder(FileSystemLayout.TranscodeFolder);
_logger.LogInformation("Done emptying transcode cache folder");
logger.LogInformation("Done emptying transcode cache folder");
}
if (localFileSystem.FolderExists(FileSystemLayout.ChannelGuideCacheFolder))
{
_logger.LogInformation("Cleaning channel cache");
logger.LogInformation("Cleaning channel cache");
List<string> channelFiles = await dbContext.Channels
.AsNoTracking()

Loading…
Cancel
Save