Browse Source

do not allow deleting default ffmpeg profile (#2490)

* remove dead code

* do not allow deleting default ffmpeg profile
pull/2491/head
Jason Dove 3 months ago committed by GitHub
parent
commit
4cb98242ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 37
      ErsatzTV.Application/FFmpegProfiles/Commands/DeleteFFmpegProfileHandler.cs
  3. 3
      ErsatzTV.Application/Scheduling/BlockTreeBlockGroupViewModel.cs
  4. 3
      ErsatzTV.Application/Scheduling/BlockTreeBlockViewModel.cs
  5. 3
      ErsatzTV.Application/Scheduling/BlockTreeViewModel.cs
  6. 9
      ErsatzTV.Application/Scheduling/Mapper.cs
  7. 3
      ErsatzTV.Application/Scheduling/Queries/GetBlockTree.cs
  8. 21
      ErsatzTV.Application/Scheduling/Queries/GetBlockTreeHandler.cs
  9. 84
      ErsatzTV/ViewModels/BlockTreeItemViewModel.cs

1
CHANGELOG.md

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
- Do not allow deleting ffmpeg profiles that are used by channels
- Do not allow deleting default ffmpeg profile
- Allow ffmpeg profiles using VAAPI accel to set h264 video profile
- Fix HLS Direct playback, and make it accessible on separate streaming port
- Fix playback troubleshooting when using multiple watermarks or multiple graphics elements

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

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -7,7 +8,10 @@ using Microsoft.EntityFrameworkCore; @@ -7,7 +8,10 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.FFmpegProfiles;
public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFactory, ISearchTargets searchTargets)
public class DeleteFFmpegProfileHandler(
IDbContextFactory<TvContext> dbContextFactory,
IConfigElementRepository configElementRepository,
ISearchTargets searchTargets)
: IRequestHandler<DeleteFFmpegProfile, Either<BaseError, Unit>>
{
public async Task<Either<BaseError, Unit>> Handle(
@ -15,9 +19,7 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa @@ -15,9 +19,7 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, FFmpegProfile> validation =
await FFmpegProfileMustNotBeUsed(dbContext, request, cancellationToken)
.BindT(_ => FFmpegProfileMustExist(dbContext, request, cancellationToken));
Validation<BaseError, FFmpegProfile> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(p => DoDeletion(dbContext, p));
}
@ -29,6 +31,15 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa @@ -29,6 +31,15 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa
return Unit.Default;
}
private async Task<Validation<BaseError, FFmpegProfile>> Validate(
TvContext dbContext,
DeleteFFmpegProfile request,
CancellationToken cancellationToken) =>
(await FFmpegProfileMustNotBeUsed(dbContext, request, cancellationToken),
await FFmpegProfileMustNotBeDefault(request, cancellationToken),
await FFmpegProfileMustExist(dbContext, request, cancellationToken))
.Apply((_, _, ffmpegProfile) => ffmpegProfile);
private static Task<Validation<BaseError, FFmpegProfile>> FFmpegProfileMustExist(
TvContext dbContext,
DeleteFFmpegProfile request,
@ -49,7 +60,23 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa @@ -49,7 +60,23 @@ public class DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa
if (count > 0)
{
return BaseError.New($"Cannot delete FFmpegProfile {request.FFmpegProfileId} that is used by {count} {(count > 1 ? "channels" : "channel")}");
return BaseError.New(
$"Cannot delete FFmpeg Profile that is used by {count} {(count > 1 ? "channels" : "channel")}");
}
return Unit.Default;
}
private async Task<Validation<BaseError, Unit>> FFmpegProfileMustNotBeDefault(
DeleteFFmpegProfile request,
CancellationToken cancellationToken)
{
Option<int> defaultFFmpegProfileId =
await configElementRepository.GetValue<int>(ConfigElementKey.FFmpegDefaultProfileId, cancellationToken);
if (defaultFFmpegProfileId.Any(id => id == request.FFmpegProfileId))
{
return BaseError.New("Cannot delete default FFmpeg Profile");
}
return Unit.Default;

3
ErsatzTV.Application/Scheduling/BlockTreeBlockGroupViewModel.cs

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
namespace ErsatzTV.Application.Scheduling;
public record BlockTreeBlockGroupViewModel(int Id, string Name, List<BlockTreeBlockViewModel> Blocks);

3
ErsatzTV.Application/Scheduling/BlockTreeBlockViewModel.cs

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
namespace ErsatzTV.Application.Scheduling;
public record BlockTreeBlockViewModel(int Id, string Name, int Minutes);

3
ErsatzTV.Application/Scheduling/BlockTreeViewModel.cs

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
namespace ErsatzTV.Application.Scheduling;
public record BlockTreeViewModel(List<BlockTreeBlockGroupViewModel> Groups);

9
ErsatzTV.Application/Scheduling/Mapper.cs

@ -28,15 +28,6 @@ internal static class Mapper @@ -28,15 +28,6 @@ internal static class Mapper
tg.Name,
tg.Templates.OrderBy(t => t.Name).Map(t => new TreeItemViewModel(t.Id, t.Name)).ToList())).ToList());
internal static BlockTreeViewModel ProjectToViewModel(List<BlockGroup> blockGroups) =>
new(
blockGroups.OrderBy(bg => bg.Name).Map(bg => new BlockTreeBlockGroupViewModel(
bg.Id,
bg.Name,
bg.Blocks.OrderBy(b => b.Name).Map(b => new BlockTreeBlockViewModel(b.Id, b.Name, b.Minutes))
.ToList()))
.ToList());
internal static BlockGroupViewModel ProjectToViewModel(BlockGroup blockGroup) =>
new(blockGroup.Id, blockGroup.Name);

3
ErsatzTV.Application/Scheduling/Queries/GetBlockTree.cs

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
namespace ErsatzTV.Application.Scheduling;
public record GetBlockTree : IRequest<BlockTreeViewModel>;

21
ErsatzTV.Application/Scheduling/Queries/GetBlockTreeHandler.cs

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Scheduling;
public class GetBlockTreeHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetBlockTree, BlockTreeViewModel>
{
public async Task<BlockTreeViewModel> Handle(GetBlockTree request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
List<BlockGroup> blockGroups = await dbContext.BlockGroups
.AsNoTracking()
.Include(g => g.Blocks)
.ToListAsync(cancellationToken);
return Mapper.ProjectToViewModel(blockGroups);
}
}

84
ErsatzTV/ViewModels/BlockTreeItemViewModel.cs

@ -1,84 +0,0 @@ @@ -1,84 +0,0 @@
using ErsatzTV.Application.Scheduling;
using MudBlazor;
namespace ErsatzTV.ViewModels;
public class BlockTreeItemViewModel
{
public BlockTreeItemViewModel(BlockGroupViewModel blockGroup)
{
Text = blockGroup.Name;
EndText = string.Empty;
TreeItems = [];
BlockGroupId = blockGroup.Id;
Icon = Icons.Material.Filled.Folder;
}
public BlockTreeItemViewModel(BlockTreeBlockGroupViewModel blockGroup)
{
Text = blockGroup.Name;
EndText = string.Empty;
TreeItems = blockGroup.Blocks.Map(b => new TreeItemData<BlockTreeItemViewModel>
{ Value = new BlockTreeItemViewModel(b) }).ToList();
BlockGroupId = blockGroup.Id;
Icon = Icons.Material.Filled.Folder;
}
public BlockTreeItemViewModel(BlockViewModel block)
{
Text = block.Name;
if (block.Minutes / 60 >= 1)
{
string plural = block.Minutes / 60 >= 2 ? "s" : string.Empty;
EndText = $"{block.Minutes / 60} hour{plural}";
if (block.Minutes % 60 != 0)
{
EndText += $", {block.Minutes % 60} minutes";
}
}
else
{
EndText = $"{block.Minutes} minutes";
}
TreeItems = [];
CanExpand = false;
BlockId = block.Id;
}
public BlockTreeItemViewModel(BlockTreeBlockViewModel block)
{
Text = block.Name;
if (block.Minutes / 60 >= 1)
{
string plural = block.Minutes / 60 >= 2 ? "s" : string.Empty;
EndText = $"{block.Minutes / 60} hour{plural}";
if (block.Minutes % 60 != 0)
{
EndText += $", {block.Minutes % 60} minutes";
}
}
else
{
EndText = $"{block.Minutes} minutes";
}
TreeItems = [];
CanExpand = false;
BlockId = block.Id;
}
public string Text { get; }
public string EndText { get; }
public string Icon { get; }
public bool CanExpand { get; }
public int? BlockId { get; }
public int? BlockGroupId { get; }
public List<TreeItemData<BlockTreeItemViewModel>> TreeItems { get; }
}
Loading…
Cancel
Save