Clean up dead code, consolidate duplication, fix redundancies
Remove 9 dead methods, 6 unused constants, and redundant ReaderWriterLockSlim from MetadataCache. Consolidate repeated patterns into HasChapters, IsPlayable, and ToLowerString helpers. Extract shared API methods in SRFApiClient. Move variant manifest rewriting from controller to StreamProxyService. Make Auto quality distinct from HD. Update README architecture section.
This commit is contained in:
@@ -46,45 +46,6 @@ public class StreamProxyService : IStreamProxyService
|
||||
_streamMappings = new ConcurrentDictionary<string, StreamInfo>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a stream for proxying.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item ID.</param>
|
||||
/// <param name="authenticatedUrl">The authenticated stream URL.</param>
|
||||
/// <param name="urn">The SRF URN for this content (used for re-fetching fresh URLs).</param>
|
||||
/// <param name="isLiveStream">Whether this is a livestream (livestreams always fetch fresh URLs).</param>
|
||||
public void RegisterStream(string itemId, string authenticatedUrl, string? urn = null, bool isLiveStream = false)
|
||||
{
|
||||
var tokenExpiry = ExtractTokenExpiry(authenticatedUrl);
|
||||
var unauthenticatedUrl = StripAuthenticationFromUrl(authenticatedUrl);
|
||||
|
||||
var streamInfo = new StreamInfo
|
||||
{
|
||||
AuthenticatedUrl = authenticatedUrl,
|
||||
UnauthenticatedUrl = unauthenticatedUrl,
|
||||
RegisteredAt = DateTime.UtcNow,
|
||||
TokenExpiresAt = tokenExpiry,
|
||||
Urn = urn,
|
||||
IsLiveStream = isLiveStream,
|
||||
LastLivestreamFetchAt = isLiveStream ? DateTime.UtcNow : null
|
||||
};
|
||||
|
||||
RegisterWithGuidFormats(itemId, streamInfo);
|
||||
|
||||
if (tokenExpiry.HasValue)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Registered stream for item {ItemId} (token expires at {ExpiresAt} UTC): {Url}",
|
||||
itemId,
|
||||
tokenExpiry.Value,
|
||||
authenticatedUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("Registered stream for item {ItemId}: {Url}", itemId, authenticatedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a stream for deferred authentication (authenticates on first playback request).
|
||||
/// </summary>
|
||||
@@ -442,7 +403,7 @@ public class StreamProxyService : IStreamProxyService
|
||||
// Use short cache duration (5 min) for livestreams
|
||||
var mediaComposition = await _compositionFetcher.GetMediaCompositionAsync(streamInfo.Urn, cancellationToken, 5).ConfigureAwait(false);
|
||||
|
||||
if (mediaComposition?.ChapterList == null || mediaComposition.ChapterList.Count == 0)
|
||||
if (mediaComposition?.HasChapters != true)
|
||||
{
|
||||
_logger.LogWarning("No chapters found when refreshing livestream URL for URN: {Urn}", streamInfo.Urn);
|
||||
return null;
|
||||
@@ -863,6 +824,65 @@ public class StreamProxyService : IStreamProxyService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rewrites URLs in a variant (sub) manifest to point to the proxy.
|
||||
/// </summary>
|
||||
/// <param name="manifestContent">The variant manifest content.</param>
|
||||
/// <param name="baseProxyUrl">The base proxy URL (without query params).</param>
|
||||
/// <param name="queryParams">Query parameters to append to rewritten URLs (e.g., "?token=abc").</param>
|
||||
/// <returns>The rewritten manifest content.</returns>
|
||||
public string RewriteVariantManifestUrls(string manifestContent, string baseProxyUrl, string queryParams)
|
||||
{
|
||||
string RewriteUrl(string url)
|
||||
{
|
||||
if (url.Contains("://", StringComparison.Ordinal))
|
||||
{
|
||||
// Absolute URL - extract filename and rewrite
|
||||
var uri = new Uri(url.Trim());
|
||||
var segments = uri.AbsolutePath.Split('/');
|
||||
var fileName = segments[^1];
|
||||
return $"{baseProxyUrl}/{fileName}{queryParams}";
|
||||
}
|
||||
|
||||
// Relative URL - rewrite to proxy
|
||||
return $"{baseProxyUrl}/{url.Trim()}{queryParams}";
|
||||
}
|
||||
|
||||
var lines = manifestContent.Split('\n');
|
||||
var result = new System.Text.StringBuilder();
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
result.AppendLine(line);
|
||||
}
|
||||
else if (line.StartsWith('#'))
|
||||
{
|
||||
// HLS tag line - check for URI="..." attributes (e.g., #EXT-X-MAP:URI="init.mp4")
|
||||
if (line.Contains("URI=\"", StringComparison.Ordinal))
|
||||
{
|
||||
var rewrittenLine = Regex.Replace(
|
||||
line,
|
||||
@"URI=""([^""]+)""",
|
||||
match => $"URI=\"{RewriteUrl(match.Groups[1].Value)}\"");
|
||||
result.AppendLine(rewrittenLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendLine(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-tag line with URL - rewrite it
|
||||
result.AppendLine(RewriteUrl(line));
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up old and expired stream mappings.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user