Browse Source

overdue code cleanup (#1271)

pull/1272/head
Jason Dove 2 years ago committed by GitHub
parent
commit
03df2a6c8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      ErsatzTV.Application/Artists/Queries/GetAllArtistsHandler.cs
  2. 17
      ErsatzTV.Application/Channels/Commands/DeleteChannelHandler.cs
  3. 6
      ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs
  4. 9
      ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs
  5. 2
      ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs
  6. 2
      ErsatzTV.Application/Channels/Queries/GetChannelGuideHandler.cs
  7. 4
      ErsatzTV.Application/Channels/Queries/GetChannelNameByPlayoutIdHandler.cs
  8. 3
      ErsatzTV.Application/Channels/Queries/GetChannelPlaylist.cs
  9. 8
      ErsatzTV.Application/Channels/Queries/GetChannelPlaylistHandler.cs
  10. 4
      ErsatzTV.Application/Configuration/Commands/SaveConfigElementByKeyHandler.cs
  11. 36
      ErsatzTV.Application/Emby/Commands/CallEmbyCollectionScannerHandler.cs
  12. 5
      ErsatzTV.Application/Emby/Commands/CallEmbyLibraryScannerHandler.cs
  13. 2
      ErsatzTV.Application/Emby/Commands/SynchronizeEmbyMediaSourcesHandler.cs
  14. 2
      ErsatzTV.Application/Emby/Queries/GetEmbyConnectionParametersHandler.cs
  15. 2
      ErsatzTV.Application/FFmpegProfiles/Commands/DeleteFFmpegProfileHandler.cs
  16. 2
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs
  17. 2
      ErsatzTV.Application/Filler/Commands/DeleteFillerPresetHandler.cs
  18. 8
      ErsatzTV.Application/Jellyfin/Commands/CallJellyfinLibraryScannerHandler.cs
  19. 6
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinMediaSourcesHandler.cs
  20. 4
      ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs
  21. 2
      ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs
  22. 2
      ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs
  23. 2
      ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs
  24. 6
      ErsatzTV.Application/Libraries/Queries/GetExternalCollectionsHandler.cs
  25. 5
      ErsatzTV.Application/Logs/Queries/GetRecentLogEntriesHandler.cs
  26. 4
      ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedSubtitlesHandler.cs
  27. 4
      ErsatzTV.Application/Maintenance/Commands/ReleaseMemoryHandler.cs
  28. 2
      ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs
  29. 2
      ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollectionHandler.cs
  30. 2
      ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollectionHandler.cs
  31. 2
      ErsatzTV.Application/MediaCollections/Commands/DeleteCollectionHandler.cs
  32. 2
      ErsatzTV.Application/MediaCollections/Commands/DeleteMultiCollectionHandler.cs
  33. 2
      ErsatzTV.Application/MediaCollections/Commands/DeleteSmartCollectionHandler.cs
  34. 4
      ErsatzTV.Application/MediaItems/Queries/GetMediaItemInfoHandler.cs
  35. 2
      ErsatzTV.Application/MediaSources/Commands/CallLocalLibraryScannerHandler.cs
  36. 6
      ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs
  37. 2
      ErsatzTV.Application/Playouts/Commands/CreatePlayoutHandler.cs
  38. 2
      ErsatzTV.Application/Playouts/Commands/DeletePlayoutHandler.cs
  39. 2
      ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs
  40. 2
      ErsatzTV.Application/Playouts/Commands/UpdatePlayoutHandler.cs
  41. 5
      ErsatzTV.Application/Plex/Commands/CallPlexLibraryScannerHandler.cs
  42. 4
      ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs
  43. 2
      ErsatzTV.Application/ProgramSchedules/Commands/DeleteProgramScheduleHandler.cs
  44. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodesHandler.cs
  45. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexMoviesHandler.cs
  46. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideosHandler.cs
  47. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs
  48. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasonsHandler.cs
  49. 2
      ErsatzTV.Application/Search/Queries/QuerySearchIndexShowsHandler.cs
  50. 4
      ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs
  51. 4
      ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs
  52. 4
      ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs
  53. 4
      ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs
  54. 4
      ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs
  55. 4
      ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs
  56. 14
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs
  57. 4
      ErsatzTV.Application/Subtitles/Queries/GetSubtitlePathByIdHandler.cs
  58. 5
      ErsatzTV.Application/Templates/Queries/GetMusicVideoCreditTemplatesHandler.cs
  59. 10
      ErsatzTV.Application/Troubleshooting/Queries/GetTroubleshootingInfoHandler.cs
  60. 2
      ErsatzTV.Application/Watermarks/Commands/CreateWatermarkHandler.cs
  61. 2
      ErsatzTV.Application/Watermarks/Commands/DeleteWatermarkHandler.cs
  62. 2
      ErsatzTV.Core.Tests/Jellyfin/JellyfinPathReplacementServiceTests.cs
  63. 2
      ErsatzTV.Core.Tests/Plex/PlexPathReplacementServiceTests.cs
  64. 9
      ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs
  65. 5
      ErsatzTV.Core.Tests/Scheduling/CustomOrderContentTests.cs
  66. 24
      ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs
  67. 6
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs
  68. 9
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerDurationTests.cs
  69. 9
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerFloodTests.cs
  70. 9
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs
  71. 9
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerOneTests.cs
  72. 9
      ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs
  73. 28
      ErsatzTV.Core.Tests/Scheduling/ScheduleIntegrationTests.cs
  74. 9
      ErsatzTV.Core.Tests/Scheduling/SeasonEpisodeContentTests.cs
  75. 9
      ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs
  76. 9
      ErsatzTV.Core.Tests/Scheduling/ShuffledMediaCollectionEnumeratorTests.cs
  77. 3
      ErsatzTV.Core/Domain/MediaItem/Episode.cs
  78. 20
      ErsatzTV.Core/Domain/ProgramScheduleAlternate.cs
  79. 4
      ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs
  80. 5
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  81. 5
      ErsatzTV.Core/FFmpeg/FFmpegProcess.cs
  82. 9
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  83. 11
      ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs
  84. 2
      ErsatzTV.Core/FFmpeg/SongVideoGenerator.cs
  85. 2
      ErsatzTV.Core/Iptv/ChannelGuide.cs
  86. 4
      ErsatzTV.Core/Iptv/ChannelPlaylist.cs
  87. 6
      ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs
  88. 5
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  89. 2
      ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs
  90. 2
      ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs
  91. 4
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  92. 5
      ErsatzTV.FFmpeg/Capabilities/AmfHardwareCapabilities.cs
  93. 10
      ErsatzTV.FFmpeg/Capabilities/DefaultHardwareCapabilities.cs
  94. 2
      ErsatzTV.FFmpeg/Capabilities/FFmpegCapabilities.cs
  95. 6
      ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs
  96. 11
      ErsatzTV.FFmpeg/Capabilities/IHardwareCapabilities.cs
  97. 10
      ErsatzTV.FFmpeg/Capabilities/NoHardwareCapabilities.cs
  98. 20
      ErsatzTV.FFmpeg/Capabilities/NvidiaHardwareCapabilities.cs
  99. 12
      ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs
  100. 4
      ErsatzTV.FFmpeg/Decoder/Cuvid/CuvidDecoder.cs
  101. Some files were not shown because too many files have changed in this diff Show More

7
ErsatzTV.Application/Artists/Queries/GetAllArtistsHandler.cs

@ -10,10 +10,7 @@ public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMed @@ -10,10 +10,7 @@ public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMed
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetAllArtistsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public GetAllArtistsHandler(IDbContextFactory<TvContext> dbContextFactory) => _dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(
GetAllArtists request,
@ -24,7 +21,7 @@ public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMed @@ -24,7 +21,7 @@ public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMed
List<Artist> allArtists = await dbContext.Artists
.AsNoTracking()
.Include(a => a.ArtistMetadata)
.ToListAsync(cancellationToken: cancellationToken);
.ToListAsync(cancellationToken);
return allArtists.Bind(a => ProjectArtist(a)).ToList();
}

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

@ -1,19 +1,18 @@ @@ -1,19 +1,18 @@
using System.Threading;
using System.Threading.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Channels;
public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public DeleteChannelHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
@ -28,12 +27,12 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr @@ -28,12 +27,12 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr
public async Task<Either<BaseError, Unit>> Handle(DeleteChannel request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Core.Domain.Channel> validation = await ChannelMustExist(dbContext, request);
Validation<BaseError, Channel> validation = await ChannelMustExist(dbContext, request);
return await validation.Apply(c => DoDeletion(dbContext, c, cancellationToken));
return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c, cancellationToken));
}
private async Task<Unit> DoDeletion(TvContext dbContext, Core.Domain.Channel channel, CancellationToken cancellationToken)
private async Task<Unit> DoDeletion(TvContext dbContext, Channel channel, CancellationToken cancellationToken)
{
dbContext.Channels.Remove(channel);
await dbContext.SaveChangesAsync();
@ -51,9 +50,11 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr @@ -51,9 +50,11 @@ public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseEr
return Unit.Default;
}
private static async Task<Validation<BaseError, Core.Domain.Channel>> ChannelMustExist(TvContext dbContext, DeleteChannel deleteChannel)
private static async Task<Validation<BaseError, Channel>> ChannelMustExist(
TvContext dbContext,
DeleteChannel deleteChannel)
{
Option<Core.Domain.Channel> maybeChannel = await dbContext.Channels
Option<Channel> maybeChannel = await dbContext.Channels
.SelectOneAsync(c => c.Id, c => c.Id == deleteChannel.ChannelId);
return maybeChannel.ToValidation<BaseError>($"Channel {deleteChannel.ChannelId} does not exist.");
}

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

@ -14,10 +14,10 @@ namespace ErsatzTV.Application.Channels; @@ -14,10 +14,10 @@ namespace ErsatzTV.Application.Channels;
public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RefreshChannelDataHandler> _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public RefreshChannelDataHandler(
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
@ -499,8 +499,6 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -499,8 +499,6 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
}).Flatten();
}
private record ContentRating(Option<string> System, string Value);
private string GetPrioritizedArtworkPath(Metadata metadata)
{
Option<string> maybeArtwork = Optional(metadata.Artwork).Flatten()
@ -518,4 +516,6 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -518,4 +516,6 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
return maybeArtwork.IfNone(string.Empty);
}
private record ContentRating(Option<string> System, string Value);
}

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

@ -12,9 +12,9 @@ namespace ErsatzTV.Application.Channels; @@ -12,9 +12,9 @@ namespace ErsatzTV.Application.Channels;
public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
{
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public RefreshChannelListHandler(
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
@ -89,11 +89,14 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList> @@ -89,11 +89,14 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
await using var reader = (DbDataReader)await dbContext.Connection.ExecuteReaderAsync(QUERY);
Func<IDataReader, ChannelResult> rowParser = reader.GetRowParser<ChannelResult>();
while (await reader.ReadAsync()) {
while (await reader.ReadAsync())
{
yield return rowParser(reader);
}
while (await reader.NextResultAsync()) {}
while (await reader.NextResultAsync())
{
}
}
private static List<string> GetCategories(string categories) =>

2
ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs

@ -31,7 +31,7 @@ public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseEr @@ -31,7 +31,7 @@ public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseEr
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Channel> validation = await Validate(dbContext, request);
return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request));
return await LanguageExtensions.Apply(validation, c => ApplyUpdateRequest(dbContext, c, request));
}
private async Task<ChannelViewModel> ApplyUpdateRequest(TvContext dbContext, Channel c, UpdateChannel update)

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

@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Channels; @@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Channels;
public class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, Either<BaseError, ChannelGuide>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
private readonly ILocalFileSystem _localFileSystem;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public GetChannelGuideHandler(
IDbContextFactory<TvContext> dbContextFactory,

4
ErsatzTV.Application/Channels/Queries/GetChannelNameByPlayoutIdHandler.cs

@ -8,10 +8,8 @@ public class GetChannelNameByPlayoutIdHandler : IRequestHandler<GetChannelNameBy @@ -8,10 +8,8 @@ public class GetChannelNameByPlayoutIdHandler : IRequestHandler<GetChannelNameBy
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetChannelNameByPlayoutIdHandler(IDbContextFactory<TvContext> dbContextFactory)
{
public GetChannelNameByPlayoutIdHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
}
public async Task<Option<string>> Handle(GetChannelNameByPlayoutId request, CancellationToken cancellationToken)
{

3
ErsatzTV.Application/Channels/Queries/GetChannelPlaylist.cs

@ -2,4 +2,5 @@ using ErsatzTV.Core.Iptv; @@ -2,4 +2,5 @@ using ErsatzTV.Core.Iptv;
namespace ErsatzTV.Application.Channels;
public record GetChannelPlaylist(string Scheme, string Host, string BaseUrl, string Mode, string AccessToken) : IRequest<ChannelPlaylist>;
public record GetChannelPlaylist
(string Scheme, string Host, string BaseUrl, string Mode, string AccessToken) : IRequest<ChannelPlaylist>;

8
ErsatzTV.Application/Channels/Queries/GetChannelPlaylistHandler.cs

@ -14,7 +14,13 @@ public class GetChannelPlaylistHandler : IRequestHandler<GetChannelPlaylist, Cha @@ -14,7 +14,13 @@ public class GetChannelPlaylistHandler : IRequestHandler<GetChannelPlaylist, Cha
public Task<ChannelPlaylist> Handle(GetChannelPlaylist request, CancellationToken cancellationToken) =>
_channelRepository.GetAll()
.Map(channels => EnsureMode(channels, request.Mode))
.Map(channels => new ChannelPlaylist(request.Scheme, request.Host, request.BaseUrl, channels, request.AccessToken));
.Map(
channels => new ChannelPlaylist(
request.Scheme,
request.Host,
request.BaseUrl,
channels,
request.AccessToken));
private static List<Channel> EnsureMode(IEnumerable<Channel> channels, string mode)
{

4
ErsatzTV.Application/Configuration/Commands/SaveConfigElementByKeyHandler.cs

@ -9,8 +9,6 @@ public class SaveConfigElementByKeyHandler : IRequestHandler<SaveConfigElementBy @@ -9,8 +9,6 @@ public class SaveConfigElementByKeyHandler : IRequestHandler<SaveConfigElementBy
public SaveConfigElementByKeyHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public async Task Handle(SaveConfigElementByKey request, CancellationToken cancellationToken)
{
public async Task Handle(SaveConfigElementByKey request, CancellationToken cancellationToken) =>
await _configElementRepository.Upsert(request.Key, request.Value);
}
}

36
ErsatzTV.Application/Emby/Commands/CallEmbyCollectionScannerHandler.cs

@ -22,6 +22,23 @@ public class CallEmbyCollectionScannerHandler : CallLibraryScannerHandler<Synchr @@ -22,6 +22,23 @@ public class CallEmbyCollectionScannerHandler : CallLibraryScannerHandler<Synchr
{
}
public async Task<Either<BaseError, Unit>>
Handle(SynchronizeEmbyCollections request, CancellationToken cancellationToken)
{
Validation<BaseError, string> validation = await Validate(request);
return await validation.Match(
scanner => PerformScan(scanner, request, cancellationToken),
error =>
{
foreach (ScanIsNotRequired scanIsNotRequired in error.OfType<ScanIsNotRequired>())
{
return Task.FromResult<Either<BaseError, Unit>>(scanIsNotRequired);
}
return Task.FromResult<Either<BaseError, Unit>>(error.Join());
});
}
protected override async Task<DateTimeOffset> GetLastScan(TvContext dbContext, SynchronizeEmbyCollections request)
{
DateTime minDateTime = await dbContext.EmbyMediaSources
@ -42,24 +59,7 @@ public class CallEmbyCollectionScannerHandler : CallLibraryScannerHandler<Synchr @@ -42,24 +59,7 @@ public class CallEmbyCollectionScannerHandler : CallLibraryScannerHandler<Synchr
}
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
return request.ForceScan || (libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now);
}
public async Task<Either<BaseError, Unit>>
Handle(SynchronizeEmbyCollections request, CancellationToken cancellationToken)
{
Validation<BaseError, string> validation = await Validate(request);
return await validation.Match(
scanner => PerformScan(scanner, request, cancellationToken),
error =>
{
foreach (ScanIsNotRequired scanIsNotRequired in error.OfType<ScanIsNotRequired>())
{
return Task.FromResult<Either<BaseError, Unit>>(scanIsNotRequired);
}
return Task.FromResult<Either<BaseError, Unit>>(error.Join());
});
return request.ForceScan || libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now;
}
private async Task<Either<BaseError, Unit>> PerformScan(

5
ErsatzTV.Application/Emby/Commands/CallEmbyLibraryScannerHandler.cs

@ -28,7 +28,8 @@ public class CallEmbyLibraryScannerHandler : CallLibraryScannerHandler<ISynchron @@ -28,7 +28,8 @@ public class CallEmbyLibraryScannerHandler : CallLibraryScannerHandler<ISynchron
ForceSynchronizeEmbyLibraryById request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
Task<Either<BaseError, string>> IRequestHandler<SynchronizeEmbyLibraryByIdIfNeeded, Either<BaseError, string>>.Handle(
Task<Either<BaseError, string>> IRequestHandler<SynchronizeEmbyLibraryByIdIfNeeded, Either<BaseError, string>>.
Handle(
SynchronizeEmbyLibraryByIdIfNeeded request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
@ -95,6 +96,6 @@ public class CallEmbyLibraryScannerHandler : CallLibraryScannerHandler<ISynchron @@ -95,6 +96,6 @@ public class CallEmbyLibraryScannerHandler : CallLibraryScannerHandler<ISynchron
}
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
return request.ForceScan || (libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now);
return request.ForceScan || libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now;
}
}

2
ErsatzTV.Application/Emby/Commands/SynchronizeEmbyMediaSourcesHandler.cs

@ -8,8 +8,8 @@ namespace ErsatzTV.Application.Emby; @@ -8,8 +8,8 @@ namespace ErsatzTV.Application.Emby;
public class SynchronizeEmbyMediaSourcesHandler : IRequestHandler<SynchronizeEmbyMediaSources,
Either<BaseError, List<EmbyMediaSource>>>
{
private readonly ChannelWriter<IScannerBackgroundServiceRequest> _scannerWorkerChannel;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ChannelWriter<IScannerBackgroundServiceRequest> _scannerWorkerChannel;
public SynchronizeEmbyMediaSourcesHandler(
IMediaSourceRepository mediaSourceRepository,

2
ErsatzTV.Application/Emby/Queries/GetEmbyConnectionParametersHandler.cs

@ -10,8 +10,8 @@ namespace ErsatzTV.Application.Emby; @@ -10,8 +10,8 @@ namespace ErsatzTV.Application.Emby;
public class GetEmbyConnectionParametersHandler : IRequestHandler<GetEmbyConnectionParameters,
Either<BaseError, EmbyConnectionParametersViewModel>>
{
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IEmbySecretStore _embySecretStore;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMemoryCache _memoryCache;
public GetEmbyConnectionParametersHandler(

2
ErsatzTV.Application/FFmpegProfiles/Commands/DeleteFFmpegProfileHandler.cs

@ -19,7 +19,7 @@ public class DeleteFFmpegProfileHandler : IRequestHandler<DeleteFFmpegProfile, E @@ -19,7 +19,7 @@ public class DeleteFFmpegProfileHandler : IRequestHandler<DeleteFFmpegProfile, E
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, FFmpegProfile> validation = await FFmpegProfileMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, p => DoDeletion(dbContext, p));
return await validation.Apply(p => DoDeletion(dbContext, p));
}
private static async Task<Unit> DoDeletion(TvContext dbContext, FFmpegProfile ffmpegProfile)

2
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs

@ -20,7 +20,7 @@ public class @@ -20,7 +20,7 @@ public class
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, FFmpegProfile> validation = await Validate(dbContext, request);
return await validation.Apply(p => ApplyUpdateRequest(dbContext, p, request));
return await LanguageExtensions.Apply(validation, p => ApplyUpdateRequest(dbContext, p, request));
}
private async Task<UpdateFFmpegProfileResult> ApplyUpdateRequest(

2
ErsatzTV.Application/Filler/Commands/DeleteFillerPresetHandler.cs

@ -19,7 +19,7 @@ public class DeleteFillerPresetHandler : IRequestHandler<DeleteFillerPreset, Eit @@ -19,7 +19,7 @@ public class DeleteFillerPresetHandler : IRequestHandler<DeleteFillerPreset, Eit
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, FillerPreset> validation = await FillerPresetMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, ps => DoDeletion(dbContext, ps));
return await validation.Apply(ps => DoDeletion(dbContext, ps));
}
private static Task<Unit> DoDeletion(TvContext dbContext, FillerPreset fillerPreset)

8
ErsatzTV.Application/Jellyfin/Commands/CallJellyfinLibraryScannerHandler.cs

@ -24,11 +24,13 @@ public class CallJellyfinLibraryScannerHandler : CallLibraryScannerHandler<ISync @@ -24,11 +24,13 @@ public class CallJellyfinLibraryScannerHandler : CallLibraryScannerHandler<ISync
{
}
Task<Either<BaseError, string>> IRequestHandler<ForceSynchronizeJellyfinLibraryById, Either<BaseError, string>>.Handle(
Task<Either<BaseError, string>> IRequestHandler<ForceSynchronizeJellyfinLibraryById, Either<BaseError, string>>.
Handle(
ForceSynchronizeJellyfinLibraryById request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
Task<Either<BaseError, string>> IRequestHandler<SynchronizeJellyfinLibraryByIdIfNeeded, Either<BaseError, string>>.Handle(
Task<Either<BaseError, string>> IRequestHandler<SynchronizeJellyfinLibraryByIdIfNeeded, Either<BaseError, string>>.
Handle(
SynchronizeJellyfinLibraryByIdIfNeeded request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
@ -95,6 +97,6 @@ public class CallJellyfinLibraryScannerHandler : CallLibraryScannerHandler<ISync @@ -95,6 +97,6 @@ public class CallJellyfinLibraryScannerHandler : CallLibraryScannerHandler<ISync
}
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
return request.ForceScan || (libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now);
return request.ForceScan || libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now;
}
}

6
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinMediaSourcesHandler.cs

@ -8,8 +8,8 @@ namespace ErsatzTV.Application.Jellyfin; @@ -8,8 +8,8 @@ namespace ErsatzTV.Application.Jellyfin;
public class SynchronizeJellyfinMediaSourcesHandler : IRequestHandler<SynchronizeJellyfinMediaSources,
Either<BaseError, List<JellyfinMediaSource>>>
{
private readonly ChannelWriter<IScannerBackgroundServiceRequest> _scannerWorkerChannel;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ChannelWriter<IScannerBackgroundServiceRequest> _scannerWorkerChannel;
public SynchronizeJellyfinMediaSourcesHandler(
IMediaSourceRepository mediaSourceRepository,
@ -26,7 +26,9 @@ public class SynchronizeJellyfinMediaSourcesHandler : IRequestHandler<Synchroniz @@ -26,7 +26,9 @@ public class SynchronizeJellyfinMediaSourcesHandler : IRequestHandler<Synchroniz
List<JellyfinMediaSource> mediaSources = await _mediaSourceRepository.GetAllJellyfin();
foreach (JellyfinMediaSource mediaSource in mediaSources)
{
await _scannerWorkerChannel.WriteAsync(new SynchronizeJellyfinAdminUserId(mediaSource.Id), cancellationToken);
await _scannerWorkerChannel.WriteAsync(
new SynchronizeJellyfinAdminUserId(mediaSource.Id),
cancellationToken);
await _scannerWorkerChannel.WriteAsync(new SynchronizeJellyfinLibraries(mediaSource.Id), cancellationToken);
}

4
ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs

@ -20,9 +20,9 @@ namespace ErsatzTV.Application.Libraries; @@ -20,9 +20,9 @@ namespace ErsatzTV.Application.Libraries;
public abstract class CallLibraryScannerHandler<TRequest>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IConfigElementRepository _configElementRepository;
private readonly ChannelWriter<ISearchIndexBackgroundServiceRequest> _channel;
private readonly IConfigElementRepository _configElementRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IMediator _mediator;
private readonly IRuntimeInfo _runtimeInfo;
private string _libraryName;

2
ErsatzTV.Application/Libraries/Commands/CreateLocalLibraryHandler.cs

@ -32,7 +32,7 @@ public class CreateLocalLibraryHandler : LocalLibraryHandlerBase, @@ -32,7 +32,7 @@ public class CreateLocalLibraryHandler : LocalLibraryHandlerBase,
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, LocalLibrary> validation = await Validate(dbContext, request);
return await validation.Apply(localLibrary => PersistLocalLibrary(dbContext, localLibrary));
return await LanguageExtensions.Apply(validation, localLibrary => PersistLocalLibrary(dbContext, localLibrary));
}
private async Task<LocalLibraryViewModel> PersistLocalLibrary(

2
ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs

@ -39,7 +39,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -39,7 +39,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Parameters> validation = await Validate(dbContext, request);
return await validation.Apply(parameters => MovePath(dbContext, parameters));
return await LanguageExtensions.Apply(validation, parameters => MovePath(dbContext, parameters));
}
private async Task<Unit> MovePath(TvContext dbContext, Parameters parameters)

2
ErsatzTV.Application/Libraries/Commands/UpdateLocalLibraryHandler.cs

@ -16,8 +16,8 @@ public class UpdateLocalLibraryHandler : LocalLibraryHandlerBase, @@ -16,8 +16,8 @@ public class UpdateLocalLibraryHandler : LocalLibraryHandlerBase,
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IEntityLocker _entityLocker;
private readonly ISearchIndex _searchIndex;
private readonly ChannelWriter<IScannerBackgroundServiceRequest> _scannerWorkerChannel;
private readonly ISearchIndex _searchIndex;
public UpdateLocalLibraryHandler(
ChannelWriter<IScannerBackgroundServiceRequest> scannerWorkerChannel,

6
ErsatzTV.Application/Libraries/Queries/GetExternalCollectionsHandler.cs

@ -8,10 +8,8 @@ public class GetExternalCollectionsHandler : IRequestHandler<GetExternalCollecti @@ -8,10 +8,8 @@ public class GetExternalCollectionsHandler : IRequestHandler<GetExternalCollecti
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetExternalCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
public GetExternalCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
}
public async Task<List<LibraryViewModel>> Handle(
GetExternalCollections request,
@ -21,7 +19,7 @@ public class GetExternalCollectionsHandler : IRequestHandler<GetExternalCollecti @@ -21,7 +19,7 @@ public class GetExternalCollectionsHandler : IRequestHandler<GetExternalCollecti
List<int> mediaSourceIds = await dbContext.EmbyMediaSources
.Filter(ems => ems.Libraries.Any(l => ((EmbyLibrary)l).ShouldSyncItems))
.Map(ems => ems.Id)
.ToListAsync(cancellationToken: cancellationToken);
.ToListAsync(cancellationToken);
return mediaSourceIds.Map(
id => new LibraryViewModel(

5
ErsatzTV.Application/Logs/Queries/GetRecentLogEntriesHandler.cs

@ -8,10 +8,7 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P @@ -8,10 +8,7 @@ public class GetRecentLogEntriesHandler : IRequestHandler<GetRecentLogEntries, P
{
private readonly ILocalFileSystem _localFileSystem;
public GetRecentLogEntriesHandler(ILocalFileSystem localFileSystem)
{
_localFileSystem = localFileSystem;
}
public GetRecentLogEntriesHandler(ILocalFileSystem localFileSystem) => _localFileSystem = localFileSystem;
public Task<PagedLogEntriesViewModel> Handle(
GetRecentLogEntries request,

4
ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedSubtitlesHandler.cs

@ -9,10 +9,8 @@ public class DeleteOrphanedSubtitlesHandler : IRequestHandler<DeleteOrphanedSubt @@ -9,10 +9,8 @@ public class DeleteOrphanedSubtitlesHandler : IRequestHandler<DeleteOrphanedSubt
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public DeleteOrphanedSubtitlesHandler(IDbContextFactory<TvContext> dbContextFactory)
{
public DeleteOrphanedSubtitlesHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
}
public async Task<Either<BaseError, Unit>> Handle(
DeleteOrphanedSubtitles request,

4
ErsatzTV.Application/Maintenance/Commands/ReleaseMemoryHandler.cs

@ -31,12 +31,12 @@ public class ReleaseMemoryHandler : IRequestHandler<ReleaseMemory> @@ -31,12 +31,12 @@ public class ReleaseMemoryHandler : IRequestHandler<ReleaseMemory>
if (request.ForceAggressive || !hasActiveWorkers)
{
_logger.LogDebug("Starting aggressive garbage collection");
GC.Collect(2, GCCollectionMode.Aggressive, blocking: true, compacting: true);
GC.Collect(2, GCCollectionMode.Aggressive, true, true);
}
else
{
_logger.LogDebug("Starting garbage collection");
GC.Collect(2, GCCollectionMode.Forced, blocking: false);
GC.Collect(2, GCCollectionMode.Forced, false);
}
GC.WaitForPendingFinalizers();

2
ErsatzTV.Application/MediaCollections/Commands/CreateCollectionHandler.cs

@ -20,7 +20,7 @@ public class CreateCollectionHandler : @@ -20,7 +20,7 @@ public class CreateCollectionHandler :
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Collection> validation = await Validate(dbContext, request);
return await LanguageExtensions.Apply(validation, c => PersistCollection(dbContext, c));
return await validation.Apply(c => PersistCollection(dbContext, c));
}
private static async Task<MediaCollectionViewModel> PersistCollection(

2
ErsatzTV.Application/MediaCollections/Commands/CreateMultiCollectionHandler.cs

@ -20,7 +20,7 @@ public class CreateMultiCollectionHandler : @@ -20,7 +20,7 @@ public class CreateMultiCollectionHandler :
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, MultiCollection> validation = await Validate(dbContext, request);
return await LanguageExtensions.Apply(validation, c => PersistCollection(dbContext, c));
return await validation.Apply(c => PersistCollection(dbContext, c));
}
private static async Task<MultiCollectionViewModel> PersistCollection(

2
ErsatzTV.Application/MediaCollections/Commands/CreateSmartCollectionHandler.cs

@ -20,7 +20,7 @@ public class CreateSmartCollectionHandler : @@ -20,7 +20,7 @@ public class CreateSmartCollectionHandler :
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, SmartCollection> validation = await Validate(dbContext, request);
return await LanguageExtensions.Apply(validation, c => PersistCollection(dbContext, c));
return await validation.Apply(c => PersistCollection(dbContext, c));
}
private static async Task<SmartCollectionViewModel> PersistCollection(

2
ErsatzTV.Application/MediaCollections/Commands/DeleteCollectionHandler.cs

@ -20,7 +20,7 @@ public class DeleteCollectionHandler : IRequestHandler<DeleteCollection, Either< @@ -20,7 +20,7 @@ public class DeleteCollectionHandler : IRequestHandler<DeleteCollection, Either<
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Collection> validation = await CollectionMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c));
return await validation.Apply(c => DoDeletion(dbContext, c));
}
private static Task<Unit> DoDeletion(TvContext dbContext, Collection collection)

2
ErsatzTV.Application/MediaCollections/Commands/DeleteMultiCollectionHandler.cs

@ -20,7 +20,7 @@ public class DeleteMultiCollectionHandler : IRequestHandler<DeleteMultiCollectio @@ -20,7 +20,7 @@ public class DeleteMultiCollectionHandler : IRequestHandler<DeleteMultiCollectio
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, MultiCollection> validation = await MultiCollectionMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c));
return await validation.Apply(c => DoDeletion(dbContext, c));
}
private static Task<Unit> DoDeletion(TvContext dbContext, MultiCollection multiCollection)

2
ErsatzTV.Application/MediaCollections/Commands/DeleteSmartCollectionHandler.cs

@ -20,7 +20,7 @@ public class DeleteSmartCollectionHandler : IRequestHandler<DeleteSmartCollectio @@ -20,7 +20,7 @@ public class DeleteSmartCollectionHandler : IRequestHandler<DeleteSmartCollectio
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, SmartCollection> validation = await SmartCollectionMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c));
return await validation.Apply(c => DoDeletion(dbContext, c));
}
private static Task<Unit> DoDeletion(TvContext dbContext, SmartCollection smartCollection)

4
ErsatzTV.Application/MediaItems/Queries/GetMediaItemInfoHandler.cs

@ -11,10 +11,8 @@ public class GetMediaItemInfoHandler : IRequestHandler<GetMediaItemInfo, Either< @@ -11,10 +11,8 @@ public class GetMediaItemInfoHandler : IRequestHandler<GetMediaItemInfo, Either<
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetMediaItemInfoHandler(IDbContextFactory<TvContext> dbContextFactory)
{
public GetMediaItemInfoHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
}
public async Task<Either<BaseError, MediaItemInfo>> Handle(
GetMediaItemInfo request,

2
ErsatzTV.Application/MediaSources/Commands/CallLocalLibraryScannerHandler.cs

@ -90,6 +90,6 @@ public class CallLocalLibraryScannerHandler : CallLibraryScannerHandler<IScanLoc @@ -90,6 +90,6 @@ public class CallLocalLibraryScannerHandler : CallLibraryScannerHandler<IScanLoc
}
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
return request.ForceScan || (libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now);
return request.ForceScan || libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now;
}
}

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

@ -19,8 +19,8 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -19,8 +19,8 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
private readonly IClient _client;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFFmpegSegmenterService _ffmpegSegmenterService;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly IPlayoutBuilder _playoutBuilder;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public BuildPlayoutHandler(
IClient client,
@ -108,7 +108,6 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -108,7 +108,6 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
dbContext.Playouts
.Include(p => p.Channel)
.Include(p => p.Items)
.Include(p => p.ProgramScheduleAlternates)
.ThenInclude(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
@ -137,12 +136,10 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -137,12 +136,10 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
.ThenInclude(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.FallbackFiller)
.Include(p => p.ProgramScheduleAnchors)
.ThenInclude(psa => psa.EnumeratorState)
.Include(p => p.ProgramScheduleAnchors)
.ThenInclude(a => a.MediaItem)
.Include(p => p.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.Collection)
@ -164,7 +161,6 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -164,7 +161,6 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
.Include(p => p.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.FallbackFiller)
.SelectOneAsync(p => p.Id, p => p.Id == buildPlayout.PlayoutId)
.Map(o => o.ToValidation<BaseError>("Playout does not exist."));
}

2
ErsatzTV.Application/Playouts/Commands/CreatePlayoutHandler.cs

@ -29,7 +29,7 @@ public class CreatePlayoutHandler : IRequestHandler<CreatePlayout, Either<BaseEr @@ -29,7 +29,7 @@ public class CreatePlayoutHandler : IRequestHandler<CreatePlayout, Either<BaseEr
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Playout> validation = await Validate(dbContext, request);
return await validation.Apply(playout => PersistPlayout(dbContext, playout));
return await LanguageExtensions.Apply(validation, playout => PersistPlayout(dbContext, playout));
}
private async Task<CreatePlayoutResponse> PersistPlayout(TvContext dbContext, Playout playout)

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

@ -11,9 +11,9 @@ namespace ErsatzTV.Application.Playouts; @@ -11,9 +11,9 @@ namespace ErsatzTV.Application.Playouts;
public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public DeletePlayoutHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,

2
ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs

@ -12,8 +12,8 @@ namespace ErsatzTV.Application.Playouts; @@ -12,8 +12,8 @@ namespace ErsatzTV.Application.Playouts;
public class ReplacePlayoutAlternateScheduleItemsHandler :
IRequestHandler<ReplacePlayoutAlternateScheduleItems, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILogger<ReplacePlayoutAlternateScheduleItemsHandler> _logger;
public ReplacePlayoutAlternateScheduleItemsHandler(

2
ErsatzTV.Application/Playouts/Commands/UpdatePlayoutHandler.cs

@ -19,7 +19,7 @@ public class UpdatePlayoutHandler : IRequestHandler<UpdatePlayout, Either<BaseEr @@ -19,7 +19,7 @@ public class UpdatePlayoutHandler : IRequestHandler<UpdatePlayout, Either<BaseEr
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Playout> validation = await Validate(dbContext, request);
return await LanguageExtensions.Apply(validation, playout => ApplyUpdateRequest(dbContext, request, playout));
return await validation.Apply(playout => ApplyUpdateRequest(dbContext, request, playout));
}
private static async Task<PlayoutNameViewModel> ApplyUpdateRequest(

5
ErsatzTV.Application/Plex/Commands/CallPlexLibraryScannerHandler.cs

@ -28,7 +28,8 @@ public class CallPlexLibraryScannerHandler : CallLibraryScannerHandler<ISynchron @@ -28,7 +28,8 @@ public class CallPlexLibraryScannerHandler : CallLibraryScannerHandler<ISynchron
ForceSynchronizePlexLibraryById request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
Task<Either<BaseError, string>> IRequestHandler<SynchronizePlexLibraryByIdIfNeeded, Either<BaseError, string>>.Handle(
Task<Either<BaseError, string>> IRequestHandler<SynchronizePlexLibraryByIdIfNeeded, Either<BaseError, string>>.
Handle(
SynchronizePlexLibraryByIdIfNeeded request,
CancellationToken cancellationToken) => Handle(request, cancellationToken);
@ -95,6 +96,6 @@ public class CallPlexLibraryScannerHandler : CallLibraryScannerHandler<ISynchron @@ -95,6 +96,6 @@ public class CallPlexLibraryScannerHandler : CallLibraryScannerHandler<ISynchron
}
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(libraryRefreshInterval);
return request.ForceScan || (libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now);
return request.ForceScan || libraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now;
}
}

4
ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs

@ -23,7 +23,9 @@ public class @@ -23,7 +23,9 @@ public class
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, ProgramSchedule> validation = await Validate(dbContext, request);
return await validation.Apply(p => PerformCopy(dbContext, p, request, cancellationToken));
return await LanguageExtensions.Apply(
validation,
p => PerformCopy(dbContext, p, request, cancellationToken));
}
catch (Exception ex)
{

2
ErsatzTV.Application/ProgramSchedules/Commands/DeleteProgramScheduleHandler.cs

@ -19,7 +19,7 @@ public class DeleteProgramScheduleHandler : IRequestHandler<DeleteProgramSchedul @@ -19,7 +19,7 @@ public class DeleteProgramScheduleHandler : IRequestHandler<DeleteProgramSchedul
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, ProgramSchedule> validation = await ProgramScheduleMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, ps => DoDeletion(dbContext, ps));
return await validation.Apply(ps => DoDeletion(dbContext, ps));
}
private static Task<Unit> DoDeletion(TvContext dbContext, ProgramSchedule programSchedule)

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexEpisodesHandler.cs

@ -19,13 +19,13 @@ namespace ErsatzTV.Application.Search; @@ -19,13 +19,13 @@ namespace ErsatzTV.Application.Search;
public class
QuerySearchIndexEpisodesHandler : IRequestHandler<QuerySearchIndexEpisodes, TelevisionEpisodeCardResultsViewModel>
{
private readonly IClient _client;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IEmbyPathReplacementService _embyPathReplacementService;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IPlexPathReplacementService _plexPathReplacementService;
private readonly IClient _client;
private readonly ISearchIndex _searchIndex;
private readonly ITelevisionRepository _televisionRepository;

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexMoviesHandler.cs

@ -10,9 +10,9 @@ namespace ErsatzTV.Application.Search; @@ -10,9 +10,9 @@ namespace ErsatzTV.Application.Search;
public class QuerySearchIndexMoviesHandler : IRequestHandler<QuerySearchIndexMovies, MovieCardResultsViewModel>
{
private readonly IClient _client;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMovieRepository _movieRepository;
private readonly IClient _client;
private readonly ISearchIndex _searchIndex;
public QuerySearchIndexMoviesHandler(

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexMusicVideosHandler.cs

@ -15,11 +15,11 @@ namespace ErsatzTV.Application.Search; @@ -15,11 +15,11 @@ namespace ErsatzTV.Application.Search;
public class
QuerySearchIndexMusicVideosHandler : IRequestHandler<QuerySearchIndexMusicVideos, MusicVideoCardResultsViewModel>
{
private readonly IClient _client;
private readonly IEmbyPathReplacementService _embyPathReplacementService;
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
private readonly IMusicVideoRepository _musicVideoRepository;
private readonly IPlexPathReplacementService _plexPathReplacementService;
private readonly IClient _client;
private readonly ISearchIndex _searchIndex;
public QuerySearchIndexMusicVideosHandler(

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexOtherVideosHandler.cs

@ -11,8 +11,8 @@ public class @@ -11,8 +11,8 @@ public class
QuerySearchIndexOtherVideosHandler : IRequestHandler<QuerySearchIndexOtherVideos,
OtherVideoCardResultsViewModel>
{
private readonly IOtherVideoRepository _otherVideoRepository;
private readonly IClient _client;
private readonly IOtherVideoRepository _otherVideoRepository;
private readonly ISearchIndex _searchIndex;
public QuerySearchIndexOtherVideosHandler(

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexSeasonsHandler.cs

@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Search; @@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Search;
public class
QuerySearchIndexSeasonsHandler : IRequestHandler<QuerySearchIndexSeasons, TelevisionSeasonCardResultsViewModel>
{
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IClient _client;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ISearchIndex _searchIndex;
private readonly ITelevisionRepository _televisionRepository;

2
ErsatzTV.Application/Search/Queries/QuerySearchIndexShowsHandler.cs

@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Search; @@ -11,8 +11,8 @@ namespace ErsatzTV.Application.Search;
public class
QuerySearchIndexShowsHandler : IRequestHandler<QuerySearchIndexShows, TelevisionShowCardResultsViewModel>
{
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IClient _client;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ISearchIndex _searchIndex;
private readonly ITelevisionRepository _televisionRepository;

4
ErsatzTV.Application/Search/Queries/SearchCollectionsHandler.cs

@ -12,7 +12,9 @@ public class SearchCollectionsHandler : IRequestHandler<SearchCollections, List< @@ -12,7 +12,9 @@ public class SearchCollectionsHandler : IRequestHandler<SearchCollections, List<
public SearchCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<MediaCollectionViewModel>> Handle(SearchCollections request, CancellationToken cancellationToken)
public async Task<List<MediaCollectionViewModel>> Handle(
SearchCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Collections.FromSqlRaw(

4
ErsatzTV.Application/Search/Queries/SearchMultiCollectionsHandler.cs

@ -12,7 +12,9 @@ public class SearchMultiCollectionsHandler : IRequestHandler<SearchMultiCollecti @@ -12,7 +12,9 @@ public class SearchMultiCollectionsHandler : IRequestHandler<SearchMultiCollecti
public SearchMultiCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<MultiCollectionViewModel>> Handle(SearchMultiCollections request, CancellationToken cancellationToken)
public async Task<List<MultiCollectionViewModel>> Handle(
SearchMultiCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.MultiCollections.FromSqlRaw(

4
ErsatzTV.Application/Search/Queries/SearchSmartCollectionsHandler.cs

@ -12,7 +12,9 @@ public class SearchSmartCollectionsHandler : IRequestHandler<SearchSmartCollecti @@ -12,7 +12,9 @@ public class SearchSmartCollectionsHandler : IRequestHandler<SearchSmartCollecti
public SearchSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<SmartCollectionViewModel>> Handle(SearchSmartCollections request, CancellationToken cancellationToken)
public async Task<List<SmartCollectionViewModel>> Handle(
SearchSmartCollections request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.SmartCollections.FromSqlRaw(

4
ErsatzTV.Application/Search/Queries/SearchTelevisionSeasonsHandler.cs

@ -12,7 +12,9 @@ public class SearchTelevisionSeasonsHandler : IRequestHandler<SearchTelevisionSe @@ -12,7 +12,9 @@ public class SearchTelevisionSeasonsHandler : IRequestHandler<SearchTelevisionSe
public SearchTelevisionSeasonsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(SearchTelevisionSeasons request, CancellationToken cancellationToken)
public async Task<List<NamedMediaItemViewModel>> Handle(
SearchTelevisionSeasons request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QueryAsync<TelevisionSeason>(

4
ErsatzTV.Application/Search/Queries/SearchTelevisionShowsHandler.cs

@ -12,7 +12,9 @@ public class SearchTelevisionShowsHandler : IRequestHandler<SearchTelevisionShow @@ -12,7 +12,9 @@ public class SearchTelevisionShowsHandler : IRequestHandler<SearchTelevisionShow
public SearchTelevisionShowsHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(SearchTelevisionShows request, CancellationToken cancellationToken)
public async Task<List<NamedMediaItemViewModel>> Handle(
SearchTelevisionShows request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QueryAsync<TelevisionShow>(

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

@ -16,11 +16,11 @@ namespace ErsatzTV.Application.Streaming; @@ -16,11 +16,11 @@ namespace ErsatzTV.Application.Streaming;
public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly IFFmpegSegmenterService _ffmpegSegmenterService;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<StartFFmpegSessionHandler> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public StartFFmpegSessionHandler(
ILocalFileSystem localFileSystem,
@ -104,7 +104,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit @@ -104,7 +104,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit
_logger.LogDebug("Playlist exists");
var segmentCount = 0;
var lastSegmentCount = -1;
int lastSegmentCount = -1;
while (DateTimeOffset.Now < finish && segmentCount < initialSegmentCount)
{
if (segmentCount != lastSegmentCount)

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

@ -20,9 +20,9 @@ namespace ErsatzTV.Application.Subtitles; @@ -20,9 +20,9 @@ namespace ErsatzTV.Application.Subtitles;
public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSubtitles, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<ExtractEmbeddedSubtitlesHandler> _logger;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public ExtractEmbeddedSubtitlesHandler(
IDbContextFactory<TvContext> dbContextFactory,
@ -177,7 +177,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu @@ -177,7 +177,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
.Filter(
em => em.Subtitles.Any(
s => s.SubtitleKind == SubtitleKind.Embedded &&
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" && s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" &&
s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
.Map(em => em.EpisodeId)
.ToListAsync(cancellationToken);
result.AddRange(episodeIds);
@ -188,7 +189,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu @@ -188,7 +189,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
.Filter(
mm => mm.Subtitles.Any(
s => s.SubtitleKind == SubtitleKind.Embedded &&
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" && s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" &&
s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
.Map(mm => mm.MovieId)
.ToListAsync(cancellationToken);
result.AddRange(movieIds);
@ -199,7 +201,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu @@ -199,7 +201,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
.Filter(
mm => mm.Subtitles.Any(
s => s.SubtitleKind == SubtitleKind.Embedded &&
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" && s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" &&
s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
.Map(mm => mm.MusicVideoId)
.ToListAsync(cancellationToken);
result.AddRange(musicVideoIds);
@ -210,7 +213,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu @@ -210,7 +213,8 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
.Filter(
ovm => ovm.Subtitles.Any(
s => s.SubtitleKind == SubtitleKind.Embedded &&
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" && s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
s.Codec != "hdmv_pgs_subtitle" && s.Codec != "dvd_subtitle" && s.Codec != "dvdsub" &&
s.Codec != "vobsub" && s.Codec != "pgssub" && s.Codec != "pgs"))
.Map(ovm => ovm.OtherVideoId)
.ToListAsync(cancellationToken);
result.AddRange(otherVideoIds);

4
ErsatzTV.Application/Subtitles/Queries/GetSubtitlePathByIdHandler.cs

@ -12,10 +12,8 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E @@ -12,10 +12,8 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetSubtitlePathByIdHandler(IDbContextFactory<TvContext> dbContextFactory)
{
public GetSubtitlePathByIdHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
}
public async Task<Either<BaseError, string>> Handle(
GetSubtitlePathById request,

5
ErsatzTV.Application/Templates/Queries/GetMusicVideoCreditTemplatesHandler.cs

@ -7,10 +7,7 @@ public class GetMusicVideoCreditTemplatesHandler : IRequestHandler<GetMusicVideo @@ -7,10 +7,7 @@ public class GetMusicVideoCreditTemplatesHandler : IRequestHandler<GetMusicVideo
{
private readonly ILocalFileSystem _localFileSystem;
public GetMusicVideoCreditTemplatesHandler(ILocalFileSystem localFileSystem)
{
_localFileSystem = localFileSystem;
}
public GetMusicVideoCreditTemplatesHandler(ILocalFileSystem localFileSystem) => _localFileSystem = localFileSystem;
public Task<List<string>> Handle(GetMusicVideoCreditTemplates request, CancellationToken cancellationToken) =>
_localFileSystem.ListFiles(FileSystemLayout.MusicVideoCreditsTemplatesFolder)

10
ErsatzTV.Application/Troubleshooting/Queries/GetTroubleshootingInfoHandler.cs

@ -9,7 +9,6 @@ using ErsatzTV.Core.Interfaces.Repositories; @@ -9,7 +9,6 @@ using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Runtime;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Runtime;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
@ -17,12 +16,12 @@ namespace ErsatzTV.Application.Troubleshooting.Queries; @@ -17,12 +16,12 @@ namespace ErsatzTV.Application.Troubleshooting.Queries;
public class GetTroubleshootingInfoHandler : IRequestHandler<GetTroubleshootingInfo, TroubleshootingInfo>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IHealthCheckService _healthCheckService;
private readonly IHardwareCapabilitiesFactory _hardwareCapabilitiesFactory;
private readonly IConfigElementRepository _configElementRepository;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IHealthCheckService _healthCheckService;
private readonly IMemoryCache _memoryCache;
private readonly IRuntimeInfo _runtimeInfo;
public GetTroubleshootingInfoHandler(
IDbContextFactory<TvContext> dbContextFactory,
@ -105,7 +104,8 @@ public class GetTroubleshootingInfoHandler : IRequestHandler<GetTroubleshootingI @@ -105,7 +104,8 @@ public class GetTroubleshootingInfoHandler : IRequestHandler<GetTroubleshootingI
Optional(GetDriverName(activeDriver)),
vaapiDevice))
{
vaapiCapabilities += $"Checking driver {activeDriver} device {vaapiDevice}{Environment.NewLine}{Environment.NewLine}";
vaapiCapabilities +=
$"Checking driver {activeDriver} device {vaapiDevice}{Environment.NewLine}{Environment.NewLine}";
vaapiCapabilities += output;
vaapiCapabilities += Environment.NewLine + Environment.NewLine;
}

2
ErsatzTV.Application/Watermarks/Commands/CreateWatermarkHandler.cs

@ -18,7 +18,7 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba @@ -18,7 +18,7 @@ public class CreateWatermarkHandler : IRequestHandler<CreateWatermark, Either<Ba
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, ChannelWatermark> validation = Validate(request);
return await LanguageExtensions.Apply(validation, profile => PersistChannelWatermark(dbContext, profile));
return await validation.Apply(profile => PersistChannelWatermark(dbContext, profile));
}
private static async Task<CreateWatermarkResult> PersistChannelWatermark(

2
ErsatzTV.Application/Watermarks/Commands/DeleteWatermarkHandler.cs

@ -19,7 +19,7 @@ public class DeleteWatermarkHandler : IRequestHandler<DeleteWatermark, Either<Ba @@ -19,7 +19,7 @@ public class DeleteWatermarkHandler : IRequestHandler<DeleteWatermark, Either<Ba
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, ChannelWatermark> validation = await WatermarkMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, p => DoDeletion(dbContext, p));
return await validation.Apply(p => DoDeletion(dbContext, p));
}
private static async Task<Unit> DoDeletion(TvContext dbContext, ChannelWatermark watermark)

2
ErsatzTV.Core.Tests/Jellyfin/JellyfinPathReplacementServiceTests.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.Runtime.InteropServices;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.FFmpeg.Runtime;
using ErsatzTV.Core.Jellyfin;
using ErsatzTV.FFmpeg.Runtime;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;

2
ErsatzTV.Core.Tests/Plex/PlexPathReplacementServiceTests.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System.Runtime.InteropServices;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.FFmpeg.Runtime;
using ErsatzTV.Core.Plex;
using ErsatzTV.FFmpeg.Runtime;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;

9
ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs

@ -8,13 +8,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -8,13 +8,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class ChronologicalContentTests
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Episodes_Should_Sort_By_Aired()

5
ErsatzTV.Core.Tests/Scheduling/CustomOrderContentTests.cs

@ -10,10 +10,7 @@ public class CustomOrderContentTests @@ -10,10 +10,7 @@ public class CustomOrderContentTests
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
[Test]
public void MediaItems_Should_Sort_By_CustomOrder()

24
ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs

@ -17,6 +17,9 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -17,6 +17,9 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutBuilderTests
{
[SetUp]
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private readonly ILogger<PlayoutBuilder> _logger;
public PlayoutBuilderTests()
@ -34,12 +37,6 @@ public class PlayoutBuilderTests @@ -34,12 +37,6 @@ public class PlayoutBuilderTests
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
[TestFixture]
public class NewPlayout : PlayoutBuilderTests
{
@ -2369,7 +2366,7 @@ public class PlayoutBuilderTests @@ -2369,7 +2366,7 @@ public class PlayoutBuilderTests
public async Task ShuffleFlood_Should_MaintainRandomSeed_MultipleDays()
{
var mediaItems = new List<MediaItem>();
for (int i = 1; i <= 25; i++)
for (var i = 1; i <= 25; i++)
{
mediaItems.Add(TestMovie(i, TimeSpan.FromMinutes(55), DateTime.Today.AddHours(i)));
}
@ -2392,8 +2389,10 @@ public class PlayoutBuilderTests @@ -2392,8 +2389,10 @@ public class PlayoutBuilderTests
// we need to mess up the ordering to trigger the problematic behavior
// this simulates the way the rows are loaded with EF
PlayoutProgramScheduleAnchor oldest = result.ProgramScheduleAnchors.OrderByDescending(a => a.AnchorDate).Last();
PlayoutProgramScheduleAnchor newest = result.ProgramScheduleAnchors.OrderByDescending(a => a.AnchorDate).First();
PlayoutProgramScheduleAnchor oldest = result.ProgramScheduleAnchors.OrderByDescending(a => a.AnchorDate)
.Last();
PlayoutProgramScheduleAnchor newest = result.ProgramScheduleAnchors.OrderByDescending(a => a.AnchorDate)
.First();
result.ProgramScheduleAnchors = new List<PlayoutProgramScheduleAnchor>
{
@ -2440,7 +2439,8 @@ public class PlayoutBuilderTests @@ -2440,7 +2439,8 @@ public class PlayoutBuilderTests
result.Items.Count.Should().Be(6);
result.ProgramScheduleAnchors.Count.Should().Be(2);
PlayoutProgramScheduleAnchor primaryAnchor = result.ProgramScheduleAnchors.First(a => a.SmartCollectionId == 1);
PlayoutProgramScheduleAnchor primaryAnchor =
result.ProgramScheduleAnchors.First(a => a.SmartCollectionId == 1);
primaryAnchor.EnumeratorState.Seed.Should().BeGreaterThan(0);
primaryAnchor.EnumeratorState.Index.Should().Be(0);
@ -2468,7 +2468,7 @@ public class PlayoutBuilderTests @@ -2468,7 +2468,7 @@ public class PlayoutBuilderTests
public async Task ShuffleFlood_MultipleSmartCollections_Should_MaintainRandomSeed_MultipleDays()
{
var mediaItems = new List<MediaItem>();
for (int i = 1; i <= 100; i++)
for (var i = 1; i <= 100; i++)
{
mediaItems.Add(TestMovie(i, TimeSpan.FromMinutes(55), DateTime.Today.AddHours(i)));
}
@ -2866,7 +2866,7 @@ public class PlayoutBuilderTests @@ -2866,7 +2866,7 @@ public class PlayoutBuilderTests
Collection = mediaCollection,
CollectionId = mediaCollection.Id,
StartTime = null,
PlaybackOrder = playbackOrder,
PlaybackOrder = playbackOrder
};
private static ProgramScheduleItem Flood(

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

@ -13,9 +13,6 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -13,9 +13,6 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerBaseTests : SchedulerTestBase
{
private CancellationToken _cancellationToken;
private PlayoutModeSchedulerBase<ProgramScheduleItem> _scheduler;
[SetUp]
public void SetUp()
{
@ -23,6 +20,9 @@ public class PlayoutModeSchedulerBaseTests : SchedulerTestBase @@ -23,6 +20,9 @@ public class PlayoutModeSchedulerBaseTests : SchedulerTestBase
_scheduler = new TestScheduler();
}
private CancellationToken _cancellationToken;
private PlayoutModeSchedulerBase<ProgramScheduleItem> _scheduler;
[TestFixture]
public class CalculateEndTimeWithFiller : PlayoutModeSchedulerBaseTests
{

9
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerDurationTests.cs

@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Should_Fill_Exact_Duration()

9
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerFloodTests.cs

@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Should_Fill_Exactly_To_Next_Schedule_Item()

9
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs

@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Should_Fill_Exactly_To_Next_Schedule_Item()

9
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerOneTests.cs

@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -11,13 +11,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerOneTests : SchedulerTestBase
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Should_Have_Gap_With_No_Tail_No_Fallback()

9
ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs

@ -8,6 +8,9 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -8,6 +8,9 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class RandomizedContentTests
{
[SetUp]
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private const int KnownSeed = 22295;
private readonly List<int> _expected = new()
@ -19,12 +22,6 @@ public class RandomizedContentTests @@ -19,12 +22,6 @@ public class RandomizedContentTests
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
[Test]
public void Episodes_Should_Randomize()
{

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

@ -30,10 +30,12 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -30,10 +30,12 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[Explicit]
public class ScheduleIntegrationTests
{
[SetUp]
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;
private CancellationToken _cancellationToken;
public ScheduleIntegrationTests()
{
public ScheduleIntegrationTests() =>
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
@ -41,13 +43,6 @@ public class ScheduleIntegrationTests @@ -41,13 +43,6 @@ public class ScheduleIntegrationTests
.WriteTo.Console()
.Destructure.UsingAttributes()
.CreateLogger();
}
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;
}
[Test]
public async Task TestExistingData()
@ -140,7 +135,7 @@ public class ScheduleIntegrationTests @@ -140,7 +135,7 @@ public class ScheduleIntegrationTests
await context.SaveChangesAsync(_cancellationToken);
}
for (var i = 1; i <= (24 * 1); i++)
for (var i = 1; i <= 24 * 1; i++)
{
await using TvContext context = await factory.CreateDbContextAsync(_cancellationToken);
@ -287,7 +282,7 @@ public class ScheduleIntegrationTests @@ -287,7 +282,7 @@ public class ScheduleIntegrationTests
int playoutId = await AddTestData(dbContext, scheduleItems);
DateTimeOffset start = new DateTimeOffset(2022, 7, 26, 8, 0, 5, TimeSpan.FromHours(-5));
var start = new DateTimeOffset(2022, 7, 26, 8, 0, 5, TimeSpan.FromHours(-5));
DateTimeOffset finish = start.AddDays(2);
var builder = new PlayoutBuilder(
@ -299,7 +294,7 @@ public class ScheduleIntegrationTests @@ -299,7 +294,7 @@ public class ScheduleIntegrationTests
new Mock<ILocalFileSystem>().Object,
provider.GetRequiredService<ILogger<PlayoutBuilder>>());
for (var i = 0; i <= (24 * 4); i++)
for (var i = 0; i <= 24 * 4; i++)
{
await using TvContext context = await factory.CreateDbContextAsync(_cancellationToken);
@ -360,12 +355,10 @@ public class ScheduleIntegrationTests @@ -360,12 +355,10 @@ public class ScheduleIntegrationTests
return playout.Id;
}
private static async Task<Option<Playout>> GetPlayout(TvContext dbContext, int playoutId)
{
return await dbContext.Playouts
private static async Task<Option<Playout>> GetPlayout(TvContext dbContext, int playoutId) =>
await dbContext.Playouts
.Include(p => p.Channel)
.Include(p => p.Items)
.Include(p => p.ProgramScheduleAlternates)
.ThenInclude(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
@ -394,12 +387,10 @@ public class ScheduleIntegrationTests @@ -394,12 +387,10 @@ public class ScheduleIntegrationTests
.ThenInclude(a => a.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.FallbackFiller)
.Include(p => p.ProgramScheduleAnchors)
.ThenInclude(a => a.EnumeratorState)
.Include(p => p.ProgramScheduleAnchors)
.ThenInclude(a => a.MediaItem)
.Include(p => p.ProgramSchedule)
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.Collection)
@ -422,5 +413,4 @@ public class ScheduleIntegrationTests @@ -422,5 +413,4 @@ public class ScheduleIntegrationTests
.ThenInclude(ps => ps.Items)
.ThenInclude(psi => psi.FallbackFiller)
.SelectOneAsync(p => p.Id, p => p.Id == playoutId);
}
}

9
ErsatzTV.Core.Tests/Scheduling/SeasonEpisodeContentTests.cs

@ -8,13 +8,10 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -8,13 +8,10 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class SeasonEpisodeContentTests
{
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private CancellationToken _cancellationToken;
[Test]
public void Episodes_Should_Sort_By_EpisodeNumber()

9
ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs

@ -8,17 +8,14 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -8,17 +8,14 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class ShuffledContentTests
{
[SetUp]
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
// this seed will produce (shuffle) 1-10 in order
private const int MagicSeed = 670596;
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
[Test]
public void Episodes_Should_Not_Duplicate_When_Reshuffling()
{

9
ErsatzTV.Core.Tests/Scheduling/ShuffledMediaCollectionEnumeratorTests.cs

@ -9,6 +9,9 @@ namespace ErsatzTV.Core.Tests.Scheduling; @@ -9,6 +9,9 @@ namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class ShuffledMediaCollectionEnumeratorTests
{
[SetUp]
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
private readonly List<GroupedMediaItem> _mediaItems = new()
{
new GroupedMediaItem(new MediaItem { Id = 1 }, new List<MediaItem>()),
@ -18,12 +21,6 @@ public class ShuffledMediaCollectionEnumeratorTests @@ -18,12 +21,6 @@ public class ShuffledMediaCollectionEnumeratorTests
private CancellationToken _cancellationToken;
[SetUp]
public void SetUp()
{
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
}
[Test]
public void Peek_Zero_Should_Match_Current()
{

3
ErsatzTV.Core/Domain/MediaItem/Episode.cs

@ -2,7 +2,8 @@ @@ -2,7 +2,8 @@
namespace ErsatzTV.Core.Domain;
[DebuggerDisplay("{EpisodeMetadata != null && EpisodeMetadata.Count > 0 ? EpisodeMetadata[0].Title : \"[unknown episode]\"}")]
[DebuggerDisplay(
"{EpisodeMetadata != null && EpisodeMetadata.Count > 0 ? EpisodeMetadata[0].Title : \"[unknown episode]\"}")]
public class Episode : MediaItem
{
public int SeasonId { get; set; }

20
ErsatzTV.Core/Domain/ProgramScheduleAlternate.cs

@ -2,6 +2,16 @@ namespace ErsatzTV.Core.Domain; @@ -2,6 +2,16 @@ namespace ErsatzTV.Core.Domain;
public class ProgramScheduleAlternate
{
public int Id { get; set; }
public int PlayoutId { get; set; }
public Playout Playout { get; set; }
public int ProgramScheduleId { get; set; }
public ProgramSchedule ProgramSchedule { get; set; }
public int Index { get; set; }
public ICollection<DayOfWeek> DaysOfWeek { get; set; }
public ICollection<int> DaysOfMonth { get; set; }
public ICollection<int> MonthsOfYear { get; set; }
public static List<DayOfWeek> AllDaysOfWeek() => new()
{
DayOfWeek.Monday,
@ -15,14 +25,4 @@ public class ProgramScheduleAlternate @@ -15,14 +25,4 @@ public class ProgramScheduleAlternate
public static List<int> AllDaysOfMonth() => Enumerable.Range(1, 31).ToList();
public static List<int> AllMonthsOfYear() => Enumerable.Range(1, 12).ToList();
public int Id { get; set; }
public int PlayoutId { get; set; }
public Playout Playout { get; set; }
public int ProgramScheduleId { get; set; }
public ProgramSchedule ProgramSchedule { get; set; }
public int Index { get; set; }
public ICollection<DayOfWeek> DaysOfWeek { get; set; }
public ICollection<int> DaysOfMonth { get; set; }
public ICollection<int> MonthsOfYear { get; set; }
}

4
ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs

@ -96,7 +96,7 @@ public class FFmpegComplexFilterBuilder @@ -96,7 +96,7 @@ public class FFmpegComplexFilterBuilder
var complexFilter = new StringBuilder();
string videoLabel = $"{videoInput}:{(isSong ? "v" : videoStreamIndex.ToString())}";
var videoLabel = $"{videoInput}:{(isSong ? "v" : videoStreamIndex.ToString())}";
string audioLabel = audioStreamIndex.Match(index => $"{audioInput}:{index}", () => "0:a");
var videoFilterQueue = new List<string>();
@ -229,7 +229,7 @@ public class FFmpegComplexFilterBuilder @@ -229,7 +229,7 @@ public class FFmpegComplexFilterBuilder
complexFilter.Append("[vt];");
}
string watermarkLabel = $"[{audioInput + 1}:v]";
var watermarkLabel = $"[{audioInput + 1}:v]";
foreach (int index in _watermarkIndex)
{
watermarkLabel = $"[{audioInput + 1}:{index}]";

5
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -18,9 +18,9 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -18,9 +18,9 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
private readonly FFmpegProcessService _ffmpegProcessService;
private readonly IFFmpegStreamSelector _ffmpegStreamSelector;
private readonly ILogger<FFmpegLibraryProcessService> _logger;
private readonly IPipelineBuilderFactory _pipelineBuilderFactory;
private readonly FFmpegPlaybackSettingsCalculator _playbackSettingsCalculator;
private readonly ITempFilePool _tempFilePool;
private readonly IPipelineBuilderFactory _pipelineBuilderFactory;
public FFmpegLibraryProcessService(
FFmpegProcessService ffmpegProcessService,
@ -154,7 +154,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -154,7 +154,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
videoPath != audioPath || channel.StreamingMode == StreamingMode.HttpLiveStreamingDirect;
ILogger<FFmpegLibraryProcessService> pixelFormatLogger = isUnknownPixelFormatExpected ? null : _logger;
IPixelFormat pixelFormat = await AvailablePixelFormats.ForPixelFormat(videoStream.PixelFormat, pixelFormatLogger)
IPixelFormat pixelFormat = await AvailablePixelFormats
.ForPixelFormat(videoStream.PixelFormat, pixelFormatLogger)
.IfNoneAsync(
() =>
{

5
ErsatzTV.Core/FFmpeg/FFmpegProcess.cs

@ -6,10 +6,7 @@ public class FFmpegProcess : Process @@ -6,10 +6,7 @@ public class FFmpegProcess : Process
{
public static int ProcessCount;
public FFmpegProcess()
{
Interlocked.Increment(ref ProcessCount);
}
public FFmpegProcess() => Interlocked.Increment(ref ProcessCount);
protected override void Dispose(bool disposing)
{

9
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -31,10 +31,7 @@ internal class FFmpegProcessBuilder @@ -31,10 +31,7 @@ internal class FFmpegProcessBuilder
private readonly string _ffmpegPath;
private FFmpegComplexFilterBuilder _complexFilterBuilder = new();
public FFmpegProcessBuilder(string ffmpegPath)
{
_ffmpegPath = ffmpegPath;
}
public FFmpegProcessBuilder(string ffmpegPath) => _ffmpegPath = ffmpegPath;
public FFmpegProcessBuilder WithThreads(int threads)
{
@ -166,8 +163,8 @@ internal class FFmpegProcessBuilder @@ -166,8 +163,8 @@ internal class FFmpegProcessBuilder
audioIndex = 1;
}
string videoLabel = $"{videoIndex}:{videoStreamIndex}";
string audioLabel = $"{audioIndex}:{maybeIndex.Match(i => i.ToString(), () => "a")}";
var videoLabel = $"{videoIndex}:{videoStreamIndex}";
var audioLabel = $"{audioIndex}:{maybeIndex.Match(i => i.ToString(), () => "a")}";
Option<FFmpegComplexFilter> maybeFilter = _complexFilterBuilder.Build(
audioPath.IsNone,

11
ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs

@ -12,12 +12,12 @@ namespace ErsatzTV.Core.FFmpeg; @@ -12,12 +12,12 @@ namespace ErsatzTV.Core.FFmpeg;
public class FFmpegStreamSelector : IFFmpegStreamSelector
{
private readonly IScriptEngine _scriptEngine;
private readonly IStreamSelectorRepository _streamSelectorRepository;
private readonly ISearchRepository _searchRepository;
private readonly IConfigElementRepository _configElementRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<FFmpegStreamSelector> _logger;
private readonly IScriptEngine _scriptEngine;
private readonly ISearchRepository _searchRepository;
private readonly IStreamSelectorRepository _streamSelectorRepository;
public FFmpegStreamSelector(
IScriptEngine scriptEngine,
@ -92,6 +92,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -92,6 +92,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
{
return result;
}
break;
case Movie:
var sw2 = Stopwatch.StartNew();
@ -106,6 +107,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -106,6 +107,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
{
return result2;
}
break;
// let default fall through
}
@ -322,7 +324,8 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -322,7 +324,8 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
_logger.LogDebug("Checking for JS Script at {Path}", jsScriptPath);
if (!_localFileSystem.FileExists(jsScriptPath))
{
_logger.LogInformation("Unable to locate movie audio stream selector script; falling back to built-in logic");
_logger.LogInformation(
"Unable to locate movie audio stream selector script; falling back to built-in logic");
return Option<MediaStream>.None;
}

2
ErsatzTV.Core/FFmpeg/SongVideoGenerator.cs

@ -170,7 +170,7 @@ public class SongVideoGenerator : ISongVideoGenerator @@ -170,7 +170,7 @@ public class SongVideoGenerator : ISongVideoGenerator
Streams = new List<MediaStream>
{
new() { MediaStreamKind = MediaStreamKind.Video, Index = 0 }
},
}
};
string customPath = _imageCache.GetPathForImage(

2
ErsatzTV.Core/Iptv/ChannelGuide.cs

@ -6,8 +6,8 @@ namespace ErsatzTV.Core.Iptv; @@ -6,8 +6,8 @@ namespace ErsatzTV.Core.Iptv;
public class ChannelGuide
{
private readonly string _channelsFragment;
private readonly Dictionary<string, string> _channelDataFragments;
private readonly string _channelsFragment;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public ChannelGuide(

4
ErsatzTV.Core/Iptv/ChannelPlaylist.cs

@ -5,11 +5,11 @@ namespace ErsatzTV.Core.Iptv; @@ -5,11 +5,11 @@ namespace ErsatzTV.Core.Iptv;
public class ChannelPlaylist
{
private readonly string _accessToken;
private readonly string _baseUrl;
private readonly List<Channel> _channels;
private readonly string _host;
private readonly string _baseUrl;
private readonly string _scheme;
private readonly string _accessToken;
public ChannelPlaylist(string scheme, string host, string baseUrl, List<Channel> channels, string accessToken)
{

6
ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs

@ -39,9 +39,6 @@ public partial class FallbackMetadataProvider : IFallbackMetadataProvider @@ -39,9 +39,6 @@ public partial class FallbackMetadataProvider : IFallbackMetadataProvider
return None;
}
[GeneratedRegex(@"s(?:eason)?\s?(\d+)(?![e\d])", RegexOptions.IgnoreCase)]
private static partial Regex SeasonNumber();
public ShowMetadata GetFallbackMetadataForShow(string showFolder)
{
string fileName = Path.GetFileName(showFolder);
@ -156,6 +153,9 @@ public partial class FallbackMetadataProvider : IFallbackMetadataProvider @@ -156,6 +153,9 @@ public partial class FallbackMetadataProvider : IFallbackMetadataProvider
return GetSongMetadata(path, metadata);
}
[GeneratedRegex(@"s(?:eason)?\s?(\d+)(?![e\d])", RegexOptions.IgnoreCase)]
private static partial Regex SeasonNumber();
private List<EpisodeMetadata> GetEpisodeMetadata(string fileName, EpisodeMetadata baseMetadata)
{
var result = new List<EpisodeMetadata> { baseMetadata };

5
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -3,7 +3,6 @@ using ErsatzTV.Core.Extensions; @@ -3,7 +3,6 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using LanguageExt.UnsafeValueAccess;
using Microsoft.Extensions.Logging;
using Map = LanguageExt.Map;
@ -15,11 +14,11 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -15,11 +14,11 @@ public class PlayoutBuilder : IPlayoutBuilder
{
private static readonly Random Random = new();
private readonly IArtistRepository _artistRepository;
private readonly IMultiEpisodeShuffleCollectionEnumeratorFactory _multiEpisodeFactory;
private readonly ILocalFileSystem _localFileSystem;
private readonly IConfigElementRepository _configElementRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<PlayoutBuilder> _logger;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly IMultiEpisodeShuffleCollectionEnumeratorFactory _multiEpisodeFactory;
private readonly ITelevisionRepository _televisionRepository;
public PlayoutBuilder(

2
ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs

@ -5,10 +5,10 @@ namespace ErsatzTV.Core.Scheduling; @@ -5,10 +5,10 @@ namespace ErsatzTV.Core.Scheduling;
public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
{
private readonly CancellationToken _cancellationToken;
private readonly IList<CollectionWithItems> _collections;
private readonly int _mediaItemCount;
private readonly bool _randomStartPoint;
private readonly CancellationToken _cancellationToken;
private Random _random;
private IList<MediaItem> _shuffled;

2
ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs

@ -5,9 +5,9 @@ namespace ErsatzTV.Core.Scheduling; @@ -5,9 +5,9 @@ namespace ErsatzTV.Core.Scheduling;
public class ShuffledMediaCollectionEnumerator : IMediaCollectionEnumerator
{
private readonly CancellationToken _cancellationToken;
private readonly int _mediaItemCount;
private readonly IList<GroupedMediaItem> _mediaItems;
private readonly CancellationToken _cancellationToken;
private CloneableRandom _random;
private IList<MediaItem> _shuffled;

4
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -223,7 +223,9 @@ public class PipelineBuilderBaseTests @@ -223,7 +223,9 @@ public class PipelineBuilderBaseTests
public void Wrap_Segmenter_Test()
{
var resolution = new FrameSize(1920, 1080);
var concatInputFile = new ConcatInputFile("http://localhost:8080/iptv/channel/1.m3u8?mode=segmenter", resolution);
var concatInputFile = new ConcatInputFile(
"http://localhost:8080/iptv/channel/1.m3u8?mode=segmenter",
resolution);
var builder = new SoftwarePipelineBuilder(
new DefaultFFmpegCapabilities(),

5
ErsatzTV.FFmpeg/Capabilities/AmfHardwareCapabilities.cs

@ -9,7 +9,10 @@ public class AmfHardwareCapabilities : IHardwareCapabilities @@ -9,7 +9,10 @@ public class AmfHardwareCapabilities : IHardwareCapabilities
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat) => FFmpegCapability.Software;
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);

10
ErsatzTV.FFmpeg/Capabilities/DefaultHardwareCapabilities.cs

@ -4,7 +4,10 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -4,7 +4,10 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public class DefaultHardwareCapabilities : IHardwareCapabilities
{
public FFmpegCapability CanDecode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);
@ -17,7 +20,10 @@ public class DefaultHardwareCapabilities : IHardwareCapabilities @@ -17,7 +20,10 @@ public class DefaultHardwareCapabilities : IHardwareCapabilities
};
}
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);

2
ErsatzTV.FFmpeg/Capabilities/FFmpegCapabilities.cs

@ -6,8 +6,8 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -6,8 +6,8 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public class FFmpegCapabilities : IFFmpegCapabilities
{
private readonly IReadOnlySet<string> _ffmpegDecoders;
private readonly IReadOnlySet<string> _ffmpegFilters;
private readonly IReadOnlySet<string> _ffmpegEncoders;
private readonly IReadOnlySet<string> _ffmpegFilters;
public FFmpegCapabilities(
IReadOnlySet<string> ffmpegDecoders,

6
ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs

@ -39,16 +39,14 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -39,16 +39,14 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
string ffmpegPath,
HardwareAccelerationMode hardwareAccelerationMode,
Option<string> vaapiDriver,
Option<string> vaapiDevice)
{
return hardwareAccelerationMode switch
Option<string> vaapiDevice) =>
hardwareAccelerationMode switch
{
HardwareAccelerationMode.Nvenc => await GetNvidiaCapabilities(ffmpegPath, ffmpegCapabilities),
HardwareAccelerationMode.Vaapi => await GetVaapiCapabilities(vaapiDriver, vaapiDevice),
HardwareAccelerationMode.Amf => new AmfHardwareCapabilities(),
_ => new DefaultHardwareCapabilities()
};
}
public async Task<string> GetNvidiaOutput(string ffmpegPath)
{

11
ErsatzTV.FFmpeg/Capabilities/IHardwareCapabilities.cs

@ -4,6 +4,13 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -4,6 +4,13 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public interface IHardwareCapabilities
{
public FFmpegCapability CanDecode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat);
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat);
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat);
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat);
}

10
ErsatzTV.FFmpeg/Capabilities/NoHardwareCapabilities.cs

@ -4,9 +4,15 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -4,9 +4,15 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public class NoHardwareCapabilities : IHardwareCapabilities
{
public FFmpegCapability CanDecode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat) =>
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat) =>
FFmpegCapability.Software;
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat) =>
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat) =>
FFmpegCapability.Software;
}

20
ErsatzTV.FFmpeg/Capabilities/NvidiaHardwareCapabilities.cs

@ -6,10 +6,10 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -6,10 +6,10 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public class NvidiaHardwareCapabilities : IHardwareCapabilities
{
private readonly int _architecture;
private readonly List<string> _maxwellGm206 = new() { "GTX 750", "GTX 950", "GTX 960", "GTX 965M" };
private readonly string _model;
private readonly IFFmpegCapabilities _ffmpegCapabilities;
private readonly ILogger _logger;
private readonly List<string> _maxwellGm206 = new() { "GTX 750", "GTX 950", "GTX 960", "GTX 965M" };
private readonly string _model;
public NvidiaHardwareCapabilities(
int architecture,
@ -23,7 +23,13 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities @@ -23,7 +23,13 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities
_logger = logger;
}
public FFmpegCapability CanDecode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
// this fails with some 1650 cards, so let's try greater than 75
public bool HevcBFrames => _architecture > 75;
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);
@ -75,7 +81,10 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities @@ -75,7 +81,10 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities
return FFmpegCapability.Software;
}
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);
@ -96,9 +105,6 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities @@ -96,9 +105,6 @@ public class NvidiaHardwareCapabilities : IHardwareCapabilities
return isHardware ? FFmpegCapability.Hardware : FFmpegCapability.Software;
}
// this fails with some 1650 cards, so let's try greater than 75
public bool HevcBFrames => _architecture > 75;
private FFmpegCapability CheckHardwareCodec(string codec, Func<string, bool> check)
{
if (check(codec))

12
ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs

@ -6,8 +6,8 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -6,8 +6,8 @@ namespace ErsatzTV.FFmpeg.Capabilities;
public class VaapiHardwareCapabilities : IHardwareCapabilities
{
private readonly List<VaapiProfileEntrypoint> _profileEntrypoints;
private readonly ILogger _logger;
private readonly List<VaapiProfileEntrypoint> _profileEntrypoints;
public VaapiHardwareCapabilities(List<VaapiProfileEntrypoint> profileEntrypoints, ILogger logger)
{
@ -15,7 +15,10 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities @@ -15,7 +15,10 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities
_logger = logger;
}
public FFmpegCapability CanDecode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);
@ -106,7 +109,10 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities @@ -106,7 +109,10 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities
return isHardware ? FFmpegCapability.Hardware : FFmpegCapability.Software;
}
public FFmpegCapability CanEncode(string videoFormat, Option<string> videoProfile, Option<IPixelFormat> maybePixelFormat)
public FFmpegCapability CanEncode(
string videoFormat,
Option<string> videoProfile,
Option<IPixelFormat> maybePixelFormat)
{
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);

4
ErsatzTV.FFmpeg/Decoder/Cuvid/CuvidDecoder.cs

@ -2,10 +2,8 @@ namespace ErsatzTV.FFmpeg.Decoder.Cuvid; @@ -2,10 +2,8 @@ namespace ErsatzTV.FFmpeg.Decoder.Cuvid;
public abstract class CuvidDecoder : DecoderBase
{
protected CuvidDecoder(HardwareAccelerationMode hardwareAccelerationMode)
{
protected CuvidDecoder(HardwareAccelerationMode hardwareAccelerationMode) =>
HardwareAccelerationMode = hardwareAccelerationMode;
}
public HardwareAccelerationMode HardwareAccelerationMode { get; set; }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save