diff --git a/Jellyfin.Plugin.SRFPlay/Controllers/StreamProxyController.cs b/Jellyfin.Plugin.SRFPlay/Controllers/StreamProxyController.cs
index 03e1aea..d4b7df4 100644
--- a/Jellyfin.Plugin.SRFPlay/Controllers/StreamProxyController.cs
+++ b/Jellyfin.Plugin.SRFPlay/Controllers/StreamProxyController.cs
@@ -183,7 +183,8 @@ public class StreamProxyController : ControllerBase
try
{
// 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)
{
@@ -234,7 +235,9 @@ public class StreamProxyController : ControllerBase
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)
{
diff --git a/Jellyfin.Plugin.SRFPlay/Services/Interfaces/IStreamProxyService.cs b/Jellyfin.Plugin.SRFPlay/Services/Interfaces/IStreamProxyService.cs
index b3e7346..9ad0702 100644
--- a/Jellyfin.Plugin.SRFPlay/Services/Interfaces/IStreamProxyService.cs
+++ b/Jellyfin.Plugin.SRFPlay/Services/Interfaces/IStreamProxyService.cs
@@ -56,9 +56,10 @@ public interface IStreamProxyService
///
/// The item ID.
/// The segment path.
+ /// The original query string from the request (preserves segment-specific parameters like timestamps).
/// Cancellation token.
/// The segment content as bytes.
- Task GetSegmentAsync(string itemId, string segmentPath, CancellationToken cancellationToken = default);
+ Task GetSegmentAsync(string itemId, string segmentPath, string? queryString = null, CancellationToken cancellationToken = default);
///
/// Cleans up old and expired stream mappings.
diff --git a/Jellyfin.Plugin.SRFPlay/Services/StreamProxyService.cs b/Jellyfin.Plugin.SRFPlay/Services/StreamProxyService.cs
index 1f3e2ce..1204a11 100644
--- a/Jellyfin.Plugin.SRFPlay/Services/StreamProxyService.cs
+++ b/Jellyfin.Plugin.SRFPlay/Services/StreamProxyService.cs
@@ -701,11 +701,13 @@ public class StreamProxyService : IStreamProxyService
///
/// The item ID.
/// The segment path.
+ /// The original query string from the request (preserves segment-specific parameters like timestamps).
/// Cancellation token.
/// The segment content as bytes.
public async Task GetSegmentAsync(
string itemId,
string segmentPath,
+ string? queryString = null,
CancellationToken cancellationToken = default)
{
var authenticatedUrl = await GetAuthenticatedUrlAsync(itemId, cancellationToken).ConfigureAwait(false);
@@ -720,17 +722,29 @@ public class StreamProxyService : IStreamProxyService
var baseUri = new Uri(authenticatedUrl);
var baseUrl = $"{baseUri.Scheme}://{baseUri.Host}{string.Join('/', baseUri.AbsolutePath.Split('/')[..^1])}";
- // Extract query parameters (auth tokens) from authenticated URL
- var queryParams = baseUri.Query;
+ // Use the original query string from the request (preserves segment-specific params like ?m=timestamp)
+ // 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
var segmentUrl = $"{baseUrl}/{segmentPath}{queryParams}";
_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,
baseUrl,
segmentPath,
+ queryString ?? "(none)",
segmentUrl);
using var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
var segmentData = await httpClient.GetByteArrayAsync(segmentUrl, cancellationToken).ConfigureAwait(false);