First POC with podcasts library
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.Jellypod.Api;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for proxying podcast audio streams.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("Jellypod/Stream")]
|
||||
public class StreamProxyController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<StreamProxyController> _logger;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StreamProxyController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">Logger instance.</param>
|
||||
/// <param name="httpClientFactory">HTTP client factory.</param>
|
||||
public StreamProxyController(
|
||||
ILogger<StreamProxyController> logger,
|
||||
IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxies an audio stream from a remote URL.
|
||||
/// </summary>
|
||||
/// <param name="url">Base64-encoded URL to stream.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The audio stream.</returns>
|
||||
[HttpGet("{url}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> GetStream([FromRoute] string url, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Decode the URL from base64
|
||||
var decodedUrl = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(url));
|
||||
_logger.LogDebug("Proxying audio stream from: {Url}", decodedUrl);
|
||||
|
||||
var client = _httpClientFactory.CreateClient("Jellypod");
|
||||
|
||||
// Make a streaming request
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, decodedUrl);
|
||||
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogWarning("Failed to fetch audio stream: {StatusCode}", response.StatusCode);
|
||||
return StatusCode((int)response.StatusCode);
|
||||
}
|
||||
|
||||
// Get content type
|
||||
var contentType = response.Content.Headers.ContentType?.MediaType ?? "audio/mpeg";
|
||||
var contentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
// Stream the response
|
||||
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (contentLength.HasValue)
|
||||
{
|
||||
Response.Headers["Content-Length"] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Response.Headers["Accept-Ranges"] = "bytes";
|
||||
|
||||
return File(stream, contentType, enableRangeProcessing: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error proxying audio stream");
|
||||
return StatusCode(500, "Failed to proxy audio stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user