Browse Source

add session api endpoints (#1578)

pull/1579/head
Jason Dove 1 year ago committed by GitHub
parent
commit
18deff0b83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 29
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  3. 7
      ErsatzTV.Core/FFmpeg/HlsSessionModel.cs
  4. 2
      ErsatzTV.Core/Interfaces/FFmpeg/IHlsSessionWorker.cs
  5. 27
      ErsatzTV/Controllers/Api/SessionController.cs

5
CHANGELOG.md

@ -29,6 +29,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -29,6 +29,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `Playout Templates` - templates to schedule using the specified criteria. Only one template will be selected each day
- Much more to come on this feature as development continues
- Show chapter markers in movie and episode media info
- Add two new API endpoints for interacting with transcoding sessions (MPEG-TS and HLS Segmenter):
- GET `/api/sessions`
- Show brief info about all active sessions
- DELETE `/api/session/{channel-number}`
- Stop the session for the given channel number
### Fixed
- Fix error loading path replacements when using MySql

29
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -39,6 +39,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -39,6 +39,7 @@ public class HlsSessionWorker : IHlsSessionWorker
private HlsSessionState _state;
private Timer _timer;
private DateTimeOffset _transcodedUntil;
private CancellationTokenSource _cancellationTokenSource;
public HlsSessionWorker(
IServiceScopeFactory serviceScopeFactory,
@ -61,6 +62,21 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -61,6 +62,21 @@ public class HlsSessionWorker : IHlsSessionWorker
public DateTimeOffset PlaylistStart { get; private set; }
public async Task Cancel(CancellationToken cancellationToken)
{
_logger.LogInformation("API termination request for HLS session for channel {Channel}", _channelNumber);
await Slim.WaitAsync(cancellationToken);
try
{
await _cancellationTokenSource.CancelAsync();
}
finally
{
Slim.Release();
}
}
public void Touch()
{
lock (_sync)
@ -121,6 +137,8 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -121,6 +137,8 @@ public class HlsSessionWorker : IHlsSessionWorker
public void PlayoutUpdated() => _state = HlsSessionState.PlayoutUpdated;
public HlsSessionModel GetModel() => new(_channelNumber, _state.ToString(), _transcodedUntil, _lastAccess);
void IDisposable.Dispose()
{
Dispose(true);
@ -129,14 +147,14 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -129,14 +147,14 @@ public class HlsSessionWorker : IHlsSessionWorker
public async Task Run(string channelNumber, TimeSpan idleTimeout, CancellationToken incomingCancellationToken)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(incomingCancellationToken);
_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(incomingCancellationToken);
[SuppressMessage("Usage", "VSTHRD100:Avoid async void methods")]
async void Cancel(object o, ElapsedEventArgs e)
{
try
{
await cts.CancelAsync();
await _cancellationTokenSource.CancelAsync();
}
catch (Exception)
{
@ -154,7 +172,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -154,7 +172,7 @@ public class HlsSessionWorker : IHlsSessionWorker
_timer.Elapsed += Cancel;
}
CancellationToken cancellationToken = cts.Token;
CancellationToken cancellationToken = _cancellationTokenSource.Token;
_logger.LogInformation("Starting HLS session for channel {Channel}", channelNumber);
@ -495,7 +513,10 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -495,7 +513,10 @@ public class HlsSessionWorker : IHlsSessionWorker
// delete old segments
var allSegments = Directory.GetFiles(
Path.Combine(FileSystemLayout.TranscodeFolder, _channelNumber),
"live*.ts")
"live*.ts").Append(
Directory.GetFiles(
Path.Combine(FileSystemLayout.TranscodeFolder, _channelNumber),
"live*.mp4"))
.Map(
file =>
{

7
ErsatzTV.Core/FFmpeg/HlsSessionModel.cs

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
namespace ErsatzTV.Core.FFmpeg;
public record HlsSessionModel(
string ChannelNumber,
string State,
DateTimeOffset TranscodedUntil,
DateTimeOffset LastAccess);

2
ErsatzTV.Core/Interfaces/FFmpeg/IHlsSessionWorker.cs

@ -4,7 +4,9 @@ namespace ErsatzTV.Core.Interfaces.FFmpeg; @@ -4,7 +4,9 @@ namespace ErsatzTV.Core.Interfaces.FFmpeg;
public interface IHlsSessionWorker : IDisposable
{
Task Cancel(CancellationToken cancellationToken);
void Touch();
Task<Option<TrimPlaylistResult>> TrimPlaylist(DateTimeOffset filterBefore, CancellationToken cancellationToken);
void PlayoutUpdated();
HlsSessionModel GetModel();
}

27
ErsatzTV/Controllers/Api/SessionController.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.FFmpeg;
using Microsoft.AspNetCore.Mvc;
namespace ErsatzTV.Controllers.Api;
[ApiController]
public class SessionController(IFFmpegSegmenterService ffmpegSegmenterService)
{
[HttpGet("api/sessions")]
public List<HlsSessionModel> GetSessions()
{
return ffmpegSegmenterService.SessionWorkers.Values.Map(w => w.GetModel()).ToList();
}
[HttpDelete("api/session/{channelNumber}")]
public async Task<IActionResult> StopSession(string channelNumber, CancellationToken cancellationToken)
{
if (ffmpegSegmenterService.SessionWorkers.TryGetValue(channelNumber, out IHlsSessionWorker worker))
{
await worker.Cancel(cancellationToken);
return new NoContentResult();
}
return new NotFoundResult();
}
}
Loading…
Cancel
Save