allow multiple watermarks in playback troubleshooting (#2280)
This commit is contained in:
@@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow multiple watermarks on a single playout item
|
- Allow multiple watermarks on a single playout item
|
||||||
|
- Allow multiple watermarks in playback troubleshooting
|
||||||
- YAML playout: `watermark` instruction changes:
|
- YAML playout: `watermark` instruction changes:
|
||||||
- When value is `true`, will add named watermark to list of active watermarks
|
- When value is `true`, will add named watermark to list of active watermarks
|
||||||
- When value is `false` and `name` is specified, will remove named watermark from list of active watermarks
|
- When value is `false` and `name` is specified, will remove named watermark from list of active watermarks
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ namespace ErsatzTV.Application.Troubleshooting;
|
|||||||
public record ArchiveTroubleshootingResults(
|
public record ArchiveTroubleshootingResults(
|
||||||
int MediaItemId,
|
int MediaItemId,
|
||||||
int FFmpegProfileId,
|
int FFmpegProfileId,
|
||||||
int WatermarkId,
|
List<int> WatermarkIds,
|
||||||
bool StartFromBeginning)
|
bool StartFromBeginning)
|
||||||
: IRequest<Option<string>>;
|
: IRequest<Option<string>>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace ErsatzTV.Application.Troubleshooting;
|
|||||||
public record PrepareTroubleshootingPlayback(
|
public record PrepareTroubleshootingPlayback(
|
||||||
int MediaItemId,
|
int MediaItemId,
|
||||||
int FFmpegProfileId,
|
int FFmpegProfileId,
|
||||||
int WatermarkId,
|
List<int> WatermarkIds,
|
||||||
int? SubtitleId,
|
int? SubtitleId,
|
||||||
bool StartFromBeginning)
|
bool StartFromBeginning)
|
||||||
: IRequest<Either<BaseError, PlayoutItemResult>>;
|
: IRequest<Either<BaseError, PlayoutItemResult>>;
|
||||||
|
|||||||
+6
-4
@@ -1,4 +1,3 @@
|
|||||||
using CliWrap;
|
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using ErsatzTV.Core;
|
using ErsatzTV.Core;
|
||||||
using ErsatzTV.Core.Domain;
|
using ErsatzTV.Core.Domain;
|
||||||
@@ -79,10 +78,13 @@ public class PrepareTroubleshootingPlaybackHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ChannelWatermark> watermarks = [];
|
List<ChannelWatermark> watermarks = [];
|
||||||
if (request.WatermarkId > 0)
|
if (request.WatermarkIds.Count > 0)
|
||||||
{
|
{
|
||||||
watermarks.AddRange(await dbContext.ChannelWatermarks
|
var channelWatermarks = await dbContext.ChannelWatermarks
|
||||||
.SelectOneAsync(cw => cw.Id, cw => cw.Id == request.WatermarkId));
|
.Where(w => request.WatermarkIds.Contains(w.Id))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
watermarks.AddRange(channelWatermarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTimeOffset now = DateTimeOffset.Now;
|
DateTimeOffset now = DateTimeOffset.Now;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class TroubleshootController(
|
|||||||
[FromQuery]
|
[FromQuery]
|
||||||
int ffmpegProfile,
|
int ffmpegProfile,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
int watermark,
|
List<int> watermark,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
int? subtitleId,
|
int? subtitleId,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
@@ -63,7 +63,7 @@ public class TroubleshootController(
|
|||||||
troubleshootingInfo.FFmpegProfiles.RemoveAll(p => p.Id != ffmpegProfile);
|
troubleshootingInfo.FFmpegProfiles.RemoveAll(p => p.Id != ffmpegProfile);
|
||||||
|
|
||||||
// filter watermarks
|
// filter watermarks
|
||||||
troubleshootingInfo.Watermarks.RemoveAll(p => p.Id != watermark);
|
troubleshootingInfo.Watermarks.RemoveAll(p => !watermark.Contains(p.Id));
|
||||||
|
|
||||||
await channelWriter.WriteAsync(
|
await channelWriter.WriteAsync(
|
||||||
new StartTroubleshootingPlayback(sessionId, playoutItemResult, mediaInfo,
|
new StartTroubleshootingPlayback(sessionId, playoutItemResult, mediaInfo,
|
||||||
@@ -113,7 +113,7 @@ public class TroubleshootController(
|
|||||||
[FromQuery]
|
[FromQuery]
|
||||||
int ffmpegProfile,
|
int ffmpegProfile,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
int watermark,
|
List<int> watermark,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
bool startFromBeginning,
|
bool startFromBeginning,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
Class="ml-6"
|
Class="ml-6"
|
||||||
StartIcon="@Icons.Material.Filled.Download"
|
StartIcon="@Icons.Material.Filled.Download"
|
||||||
Disabled="@(!_hasPlayed || Locker.IsTroubleshootingPlaybackLocked())"
|
Disabled="@(!_hasPlayed || Locker.IsTroubleshootingPlaybackLocked())"
|
||||||
OnClick="DownloadResults">
|
OnClick="@DownloadResults">
|
||||||
Download Results
|
Download Results
|
||||||
</MudButton>
|
</MudButton>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
@@ -56,13 +56,12 @@
|
|||||||
</MudStack>
|
</MudStack>
|
||||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<MudText>Watermark</MudText>
|
<MudText>Watermarks</MudText>
|
||||||
</div>
|
</div>
|
||||||
<MudSelect @bind-Value="_watermarkId" For="@(() => _watermarkId)" Clearable="true">
|
<MudSelect T="string" @bind-SelectedValues="_watermarkNames" Clearable="true" MultiSelection="true">
|
||||||
<MudSelectItem T="int?" Value="@((int?)null)">(none)</MudSelectItem>
|
|
||||||
@foreach (WatermarkViewModel watermark in _watermarks)
|
@foreach (WatermarkViewModel watermark in _watermarks)
|
||||||
{
|
{
|
||||||
<MudSelectItem T="int?" Value="@watermark.Id">@watermark.Name</MudSelectItem>
|
<MudSelectItem T="string" Value="@watermark.Name">@watermark.Name</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
@@ -119,12 +118,12 @@
|
|||||||
@code {
|
@code {
|
||||||
private readonly CancellationTokenSource _cts = new();
|
private readonly CancellationTokenSource _cts = new();
|
||||||
|
|
||||||
private List<FFmpegProfileViewModel> _ffmpegProfiles = [];
|
private readonly List<FFmpegProfileViewModel> _ffmpegProfiles = [];
|
||||||
private List<WatermarkViewModel> _watermarks = [];
|
private readonly List<WatermarkViewModel> _watermarks = [];
|
||||||
private List<SubtitleViewModel> _subtitleStreams = [];
|
private readonly List<SubtitleViewModel> _subtitleStreams = [];
|
||||||
private MediaItemInfo _info;
|
private MediaItemInfo _info;
|
||||||
private int _ffmpegProfileId;
|
private int _ffmpegProfileId;
|
||||||
private int? _watermarkId;
|
private IEnumerable<string> _watermarkNames = new System.Collections.Generic.HashSet<string>();
|
||||||
private int? _subtitleId;
|
private int? _subtitleId;
|
||||||
private bool _startFromBeginning;
|
private bool _startFromBeginning;
|
||||||
private bool _hasPlayed;
|
private bool _hasPlayed;
|
||||||
@@ -146,13 +145,13 @@
|
|||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
_ffmpegProfiles = await Mediator.Send(new GetAllFFmpegProfiles(), _cts.Token);
|
_ffmpegProfiles.AddRange(await Mediator.Send(new GetAllFFmpegProfiles(), _cts.Token));
|
||||||
if (_ffmpegProfiles.Count > 0)
|
if (_ffmpegProfiles.Count > 0)
|
||||||
{
|
{
|
||||||
_ffmpegProfileId = _ffmpegProfiles.Map(f => f.Id).Head();
|
_ffmpegProfileId = _ffmpegProfiles.Map(f => f.Id).Head();
|
||||||
}
|
}
|
||||||
|
|
||||||
_watermarks = await Mediator.Send(new GetAllWatermarks(), _cts.Token);
|
_watermarks.AddRange(await Mediator.Send(new GetAllWatermarks(), _cts.Token));
|
||||||
|
|
||||||
if (MediaItemId is not null)
|
if (MediaItemId is not null)
|
||||||
{
|
{
|
||||||
@@ -166,7 +165,14 @@
|
|||||||
{
|
{
|
||||||
var uri = new UriBuilder(NavigationManager.ToAbsoluteUri(NavigationManager.Uri));
|
var uri = new UriBuilder(NavigationManager.ToAbsoluteUri(NavigationManager.Uri));
|
||||||
uri.Path = uri.Path.Replace("/system/troubleshooting/playback", "/api/troubleshoot/playback.m3u8");
|
uri.Path = uri.Path.Replace("/system/troubleshooting/playback", "/api/troubleshoot/playback.m3u8");
|
||||||
uri.Query = $"?mediaItem={MediaItemId}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}&startFromBeginning={_startFromBeginning}";
|
uri.Query = $"?mediaItem={MediaItemId}&ffmpegProfile={_ffmpegProfileId}&startFromBeginning={_startFromBeginning}";
|
||||||
|
foreach (var watermarkName in _watermarkNames)
|
||||||
|
{
|
||||||
|
foreach (var watermark in _watermarks.Where(wm => wm.Name == watermarkName))
|
||||||
|
{
|
||||||
|
uri.Query += $"&watermark={watermark.Id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
if (_subtitleId is not null)
|
if (_subtitleId is not null)
|
||||||
{
|
{
|
||||||
uri.Query += $"&subtitleId={_subtitleId.Value}";
|
uri.Query += $"&subtitleId={_subtitleId.Value}";
|
||||||
@@ -207,7 +213,15 @@
|
|||||||
|
|
||||||
private async Task DownloadResults()
|
private async Task DownloadResults()
|
||||||
{
|
{
|
||||||
await JsRuntime.InvokeVoidAsync("window.open", $"api/troubleshoot/playback/archive?mediaItem={MediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}&startFromBeginning={_startFromBeginning}");
|
var uri = $"api/troubleshoot/playback/archive?mediaItem={MediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&startFromBeginning={_startFromBeginning}";
|
||||||
|
foreach (var watermarkName in _watermarkNames)
|
||||||
|
{
|
||||||
|
foreach (var watermark in _watermarks.Where(wm => wm.Name == watermarkName))
|
||||||
|
{
|
||||||
|
uri += $"&watermark={watermark.Id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await JsRuntime.InvokeVoidAsync("window.open", uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleTroubleshootingCompleted(PlaybackTroubleshootingCompletedNotification result)
|
private void HandleTroubleshootingCompleted(PlaybackTroubleshootingCompletedNotification result)
|
||||||
|
|||||||
Reference in New Issue
Block a user