Browse Source

add seek seconds to playback troubleshooting (#2300)

pull/2301/head
Jason Dove 6 days ago committed by GitHub
parent
commit
91c4e8f575
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 2
      ErsatzTV.Application/Troubleshooting/Commands/ArchiveTroubleshootingResults.cs
  3. 2
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlayback.cs
  4. 19
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs
  5. 12
      ErsatzTV/Controllers/Api/TroubleshootController.cs
  6. 26
      ErsatzTV/Pages/PlaybackTroubleshooting.razor

1
CHANGELOG.md

@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `graphics_on` requires the name of a graphics element template, e.g. `text/cool_element.yml` - `graphics_on` requires the name of a graphics element template, e.g. `text/cool_element.yml`
- The `variables` property can be used to dynamically replace text from the template - The `variables` property can be used to dynamically replace text from the template
- `graphics_off` will turn off a specific element, or all elements if none are specified - `graphics_off` will turn off a specific element, or all elements if none are specified
- Add `Seek Seconds` to playback troubleshooting to support capturing timing-related issues
### Fix ### Fix
- Fix database operations that were slowing down playout builds - Fix database operations that were slowing down playout builds

2
ErsatzTV.Application/Troubleshooting/Commands/ArchiveTroubleshootingResults.cs

@ -5,5 +5,5 @@ public record ArchiveTroubleshootingResults(
int FFmpegProfileId, int FFmpegProfileId,
List<int> WatermarkIds, List<int> WatermarkIds,
List<int> GraphicsElementIds, List<int> GraphicsElementIds,
bool StartFromBeginning) Option<int> SeekSeconds)
: IRequest<Option<string>>; : IRequest<Option<string>>;

2
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlayback.cs

@ -9,5 +9,5 @@ public record PrepareTroubleshootingPlayback(
List<int> WatermarkIds, List<int> WatermarkIds,
List<int> GraphicsElementIds, List<int> GraphicsElementIds,
int? SubtitleId, int? SubtitleId,
bool StartFromBeginning) Option<int> SeekSeconds)
: IRequest<Either<BaseError, PlayoutItemResult>>; : IRequest<Either<BaseError, PlayoutItemResult>>;

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

@ -103,14 +103,23 @@ public class PrepareTroubleshootingPlaybackHandler(
TimeSpan inPoint = TimeSpan.Zero; TimeSpan inPoint = TimeSpan.Zero;
TimeSpan outPoint = duration; TimeSpan outPoint = duration;
if (!hlsRealtime && !request.StartFromBeginning) if (!hlsRealtime)
{ {
inPoint = TimeSpan.FromSeconds(version.Duration.TotalSeconds / 2.0); foreach (var seekSeconds in request.SeekSeconds)
if (inPoint.TotalSeconds < 30)
{ {
duration = inPoint; inPoint = TimeSpan.FromSeconds(seekSeconds);
if (inPoint > version.Duration)
{
inPoint = version.Duration - duration;
}
if (inPoint + duration > version.Duration)
{
duration = version.Duration - inPoint;
}
outPoint = inPoint + duration;
} }
outPoint = inPoint + duration;
} }
var graphicsElements = await dbContext.GraphicsElements var graphicsElements = await dbContext.GraphicsElements

12
ErsatzTV/Controllers/Api/TroubleshootController.cs

@ -33,13 +33,15 @@ public class TroubleshootController(
[FromQuery] [FromQuery]
int? subtitleId, int? subtitleId,
[FromQuery] [FromQuery]
bool startFromBeginning, int seekSeconds,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
try try
{ {
Option<int> ss = seekSeconds > 0 ? seekSeconds : Option<int>.None;
Either<BaseError, PlayoutItemResult> result = await mediator.Send( Either<BaseError, PlayoutItemResult> result = await mediator.Send(
new PrepareTroubleshootingPlayback(mediaItem, ffmpegProfile, watermark, graphicsElement, subtitleId, startFromBeginning), new PrepareTroubleshootingPlayback(mediaItem, ffmpegProfile, watermark, graphicsElement, subtitleId, ss),
cancellationToken); cancellationToken);
if (result.IsLeft) if (result.IsLeft)
@ -119,11 +121,13 @@ public class TroubleshootController(
[FromQuery] [FromQuery]
List<int> graphicsElement, List<int> graphicsElement,
[FromQuery] [FromQuery]
bool startFromBeginning, int seekSeconds,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
Option<int> ss = seekSeconds > 0 ? seekSeconds : Option<int>.None;
Option<string> maybeArchivePath = await mediator.Send( Option<string> maybeArchivePath = await mediator.Send(
new ArchiveTroubleshootingResults(mediaItem, ffmpegProfile, watermark, graphicsElement, startFromBeginning), new ArchiveTroubleshootingResults(mediaItem, ffmpegProfile, watermark, graphicsElement, ss),
cancellationToken); cancellationToken);
foreach (string archivePath in maybeArchivePath) foreach (string archivePath in maybeArchivePath)

26
ErsatzTV/Pages/PlaybackTroubleshooting.razor

@ -93,7 +93,16 @@
<div class="d-flex"> <div class="d-flex">
<MudText>Start From Beginning</MudText> <MudText>Start From Beginning</MudText>
</div> </div>
<MudCheckBox @bind-Value="_startFromBeginning" Dense="true" Disabled="@(string.Equals(_info?.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase))" /> <MudCheckBox T="bool"
Dense="true"
Disabled="@(string.Equals(_info?.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase))"
ValueChanged="@(c => OnStartFromBeginningChanged(c))" />
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Seek Seconds</MudText>
</div>
<MudTextField @bind-Value="@(_seekSeconds)" Disabled="@(_startFromBeginning)" />
</MudStack> </MudStack>
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Preview</MudText> <MudText Typo="Typo.h5" Class="mt-10 mb-2">Preview</MudText>
<MudDivider Class="mb-6"/> <MudDivider Class="mb-6"/>
@ -138,8 +147,9 @@
private int _ffmpegProfileId; private int _ffmpegProfileId;
private IEnumerable<string> _watermarkNames = new System.Collections.Generic.HashSet<string>(); private IEnumerable<string> _watermarkNames = new System.Collections.Generic.HashSet<string>();
private IEnumerable<string> _graphicsElementNames = new System.Collections.Generic.HashSet<string>(); private IEnumerable<string> _graphicsElementNames = new System.Collections.Generic.HashSet<string>();
private int? _subtitleId;
private bool _startFromBeginning; private bool _startFromBeginning;
private int? _subtitleId;
private int _seekSeconds;
private bool _hasPlayed; private bool _hasPlayed;
[SupplyParameterFromQuery(Name = "mediaItem")] [SupplyParameterFromQuery(Name = "mediaItem")]
@ -178,13 +188,19 @@
} }
} }
private void OnStartFromBeginningChanged(bool value)
{
_startFromBeginning = value;
_seekSeconds = value ? 0 : (int)Math.Round((_info?.Duration.TotalSeconds ?? 0) / 2.0);
}
private void LockChanged(object sender, EventArgs e) => InvokeAsync(StateHasChanged); private void LockChanged(object sender, EventArgs e) => InvokeAsync(StateHasChanged);
private async Task PreviewChannel() private async Task PreviewChannel()
{ {
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}&startFromBeginning={_startFromBeginning}"; uri.Query = $"?mediaItem={MediaItemId}&ffmpegProfile={_ffmpegProfileId}&seekSeconds={_seekSeconds}";
foreach (var watermarkName in _watermarkNames) foreach (var watermarkName in _watermarkNames)
{ {
foreach (var watermark in _watermarks.Where(wm => wm.Name == watermarkName)) foreach (var watermark in _watermarks.Where(wm => wm.Name == watermarkName))
@ -221,7 +237,7 @@
foreach (MediaItemInfo info in maybeInfo.RightToSeq()) foreach (MediaItemInfo info in maybeInfo.RightToSeq())
{ {
_info = info; _info = info;
_startFromBeginning = string.Equals(info.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase); OnStartFromBeginningChanged(string.Equals(info.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase));
_subtitleId = null; _subtitleId = null;
_subtitleStreams.Clear(); _subtitleStreams.Clear();
@ -239,7 +255,7 @@
private async Task DownloadResults() private async Task DownloadResults()
{ {
var uri = $"api/troubleshoot/playback/archive?mediaItem={MediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&startFromBeginning={_startFromBeginning}"; var uri = $"api/troubleshoot/playback/archive?mediaItem={MediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&seekSeconds={_seekSeconds}";
foreach (var watermarkName in _watermarkNames) foreach (var watermarkName in _watermarkNames)
{ {

Loading…
Cancel
Save