Add recording of livestreams
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.SRFPlay.Api.Models;
|
||||
using Jellyfin.Plugin.SRFPlay.Services.Interfaces;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.SRFPlay.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for managing sport livestream recordings.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("Plugins/SRFPlay/Recording")]
|
||||
[Authorize]
|
||||
public class RecordingController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<RecordingController> _logger;
|
||||
private readonly IRecordingService _recordingService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RecordingController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="recordingService">The recording service.</param>
|
||||
public RecordingController(
|
||||
ILogger<RecordingController> logger,
|
||||
IRecordingService recordingService)
|
||||
{
|
||||
_logger = logger;
|
||||
_recordingService = recordingService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets upcoming sport livestreams available for recording.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>List of upcoming livestreams.</returns>
|
||||
[HttpGet("Schedule")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetSchedule(CancellationToken cancellationToken)
|
||||
{
|
||||
var schedule = await _recordingService.GetUpcomingScheduleAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Ok(schedule);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedules a livestream for recording by URN.
|
||||
/// </summary>
|
||||
/// <param name="urn">The SRF URN.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The created recording entry.</returns>
|
||||
[HttpPost("Schedule/{urn}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> ScheduleRecording(
|
||||
[FromRoute] string urn,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(urn))
|
||||
{
|
||||
return BadRequest("URN is required");
|
||||
}
|
||||
|
||||
// URN comes URL-encoded with colons, decode it
|
||||
urn = System.Net.WebUtility.UrlDecode(urn);
|
||||
|
||||
_logger.LogInformation("Scheduling recording for URN: {Urn}", urn);
|
||||
var entry = await _recordingService.ScheduleRecordingAsync(urn, cancellationToken).ConfigureAwait(false);
|
||||
return Ok(entry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels a scheduled recording.
|
||||
/// </summary>
|
||||
/// <param name="id">The recording ID.</param>
|
||||
/// <returns>OK or NotFound.</returns>
|
||||
[HttpDelete("Schedule/{id}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public IActionResult CancelRecording([FromRoute] string id)
|
||||
{
|
||||
return _recordingService.CancelRecording(id) ? Ok() : NotFound();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets currently active recordings.
|
||||
/// </summary>
|
||||
/// <returns>List of active recordings.</returns>
|
||||
[HttpGet("Active")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult GetActiveRecordings()
|
||||
{
|
||||
var active = _recordingService.GetRecordings(RecordingState.Recording);
|
||||
return Ok(active);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops an active recording.
|
||||
/// </summary>
|
||||
/// <param name="id">The recording ID.</param>
|
||||
/// <returns>OK or NotFound.</returns>
|
||||
[HttpPost("Active/{id}/Stop")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public IActionResult StopRecording([FromRoute] string id)
|
||||
{
|
||||
return _recordingService.StopRecording(id) ? Ok() : NotFound();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets completed recordings.
|
||||
/// </summary>
|
||||
/// <returns>List of completed recordings.</returns>
|
||||
[HttpGet("Completed")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult GetCompletedRecordings()
|
||||
{
|
||||
var completed = _recordingService.GetRecordings(RecordingState.Completed);
|
||||
return Ok(completed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all recordings (all states).
|
||||
/// </summary>
|
||||
/// <returns>List of all recordings.</returns>
|
||||
[HttpGet("All")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult GetAllRecordings()
|
||||
{
|
||||
var all = _recordingService.GetRecordings();
|
||||
return Ok(all);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a completed recording and its file.
|
||||
/// </summary>
|
||||
/// <param name="id">The recording ID.</param>
|
||||
/// <param name="deleteFile">Whether to delete the file too.</param>
|
||||
/// <returns>OK or NotFound.</returns>
|
||||
[HttpDelete("Completed/{id}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public IActionResult DeleteRecording(
|
||||
[FromRoute] string id,
|
||||
[FromQuery] bool deleteFile = true)
|
||||
{
|
||||
return _recordingService.DeleteRecording(id, deleteFile) ? Ok() : NotFound();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user