fix: change in server side API for live stream
All checks were successful
🏗️ Build Plugin / build (push) Successful in 4m12s
🧪 Test Plugin / test (push) Successful in 1m24s
🚀 Release Plugin / build-and-release (push) Successful in 2m49s

This commit is contained in:
Duncan Tourolle 2026-01-17 10:46:11 +01:00
parent d313b68975
commit 92dc6d8203
3 changed files with 24 additions and 6 deletions

View File

@ -183,7 +183,8 @@ public class StreamProxyController : ControllerBase
try try
{ {
// Fetch the variant manifest as a segment // Fetch the variant manifest as a segment
var manifestData = await _proxyService.GetSegmentAsync(actualItemId, fullPath, cancellationToken).ConfigureAwait(false); var queryString = Request.QueryString.HasValue ? Request.QueryString.Value : null;
var manifestData = await _proxyService.GetSegmentAsync(actualItemId, fullPath, queryString, cancellationToken).ConfigureAwait(false);
if (manifestData == null) if (manifestData == null)
{ {
@ -234,7 +235,9 @@ public class StreamProxyController : ControllerBase
try try
{ {
var segmentData = await _proxyService.GetSegmentAsync(actualItemId, segmentPath, cancellationToken).ConfigureAwait(false); // Pass the original query string to preserve segment-specific parameters (e.g., ?m=timestamp)
var queryString = Request.QueryString.HasValue ? Request.QueryString.Value : null;
var segmentData = await _proxyService.GetSegmentAsync(actualItemId, segmentPath, queryString, cancellationToken).ConfigureAwait(false);
if (segmentData == null) if (segmentData == null)
{ {

View File

@ -56,9 +56,10 @@ public interface IStreamProxyService
/// </summary> /// </summary>
/// <param name="itemId">The item ID.</param> /// <param name="itemId">The item ID.</param>
/// <param name="segmentPath">The segment path.</param> /// <param name="segmentPath">The segment path.</param>
/// <param name="queryString">The original query string from the request (preserves segment-specific parameters like timestamps).</param>
/// <param name="cancellationToken">Cancellation token.</param> /// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The segment content as bytes.</returns> /// <returns>The segment content as bytes.</returns>
Task<byte[]?> GetSegmentAsync(string itemId, string segmentPath, CancellationToken cancellationToken = default); Task<byte[]?> GetSegmentAsync(string itemId, string segmentPath, string? queryString = null, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Cleans up old and expired stream mappings. /// Cleans up old and expired stream mappings.

View File

@ -701,11 +701,13 @@ public class StreamProxyService : IStreamProxyService
/// </summary> /// </summary>
/// <param name="itemId">The item ID.</param> /// <param name="itemId">The item ID.</param>
/// <param name="segmentPath">The segment path.</param> /// <param name="segmentPath">The segment path.</param>
/// <param name="queryString">The original query string from the request (preserves segment-specific parameters like timestamps).</param>
/// <param name="cancellationToken">Cancellation token.</param> /// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The segment content as bytes.</returns> /// <returns>The segment content as bytes.</returns>
public async Task<byte[]?> GetSegmentAsync( public async Task<byte[]?> GetSegmentAsync(
string itemId, string itemId,
string segmentPath, string segmentPath,
string? queryString = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var authenticatedUrl = await GetAuthenticatedUrlAsync(itemId, cancellationToken).ConfigureAwait(false); var authenticatedUrl = await GetAuthenticatedUrlAsync(itemId, cancellationToken).ConfigureAwait(false);
@ -720,17 +722,29 @@ public class StreamProxyService : IStreamProxyService
var baseUri = new Uri(authenticatedUrl); var baseUri = new Uri(authenticatedUrl);
var baseUrl = $"{baseUri.Scheme}://{baseUri.Host}{string.Join('/', baseUri.AbsolutePath.Split('/')[..^1])}"; var baseUrl = $"{baseUri.Scheme}://{baseUri.Host}{string.Join('/', baseUri.AbsolutePath.Split('/')[..^1])}";
// Extract query parameters (auth tokens) from authenticated URL // Use the original query string from the request (preserves segment-specific params like ?m=timestamp)
var queryParams = baseUri.Query; // If no query string is provided, check if we need to add auth params from the master manifest
var queryParams = string.Empty;
if (!string.IsNullOrEmpty(queryString))
{
// Use the original query string from the segment request
queryParams = queryString.StartsWith('?') ? queryString : $"?{queryString}";
}
else if (!segmentPath.Contains("hdntl=", StringComparison.OrdinalIgnoreCase))
{
// Only append master manifest query params if segment doesn't have path-based auth
queryParams = baseUri.Query;
}
// Build full segment URL // Build full segment URL
var segmentUrl = $"{baseUrl}/{segmentPath}{queryParams}"; var segmentUrl = $"{baseUrl}/{segmentPath}{queryParams}";
_logger.LogDebug( _logger.LogDebug(
"Fetching segment - BaseUri: {BaseUri}, BaseUrl: {BaseUrl}, SegmentPath: {SegmentPath}, FullUrl: {FullUrl}", "Fetching segment - BaseUri: {BaseUri}, BaseUrl: {BaseUrl}, SegmentPath: {SegmentPath}, QueryString: {QueryString}, FullUrl: {FullUrl}",
authenticatedUrl, authenticatedUrl,
baseUrl, baseUrl,
segmentPath, segmentPath,
queryString ?? "(none)",
segmentUrl); segmentUrl);
using var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); using var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
var segmentData = await httpClient.GetByteArrayAsync(segmentUrl, cancellationToken).ConfigureAwait(false); var segmentData = await httpClient.GetByteArrayAsync(segmentUrl, cancellationToken).ConfigureAwait(false);