Added sports livestreams
This commit is contained in:
@@ -72,8 +72,14 @@ public class SRFMediaProvider : IMediaSourceProvider
|
||||
return Task.FromResult<IEnumerable<MediaSourceInfo>>(sources);
|
||||
}
|
||||
|
||||
// For scheduled livestreams, use shorter cache TTL (5 minutes) so they refresh when they go live
|
||||
// For regular content, use configured cache duration
|
||||
var cacheDuration = urn.Contains("scheduled_livestream", StringComparison.OrdinalIgnoreCase)
|
||||
? 5
|
||||
: config.CacheDurationMinutes;
|
||||
|
||||
// Try cache first
|
||||
var mediaComposition = _metadataCache.GetMediaComposition(urn, config.CacheDurationMinutes);
|
||||
var mediaComposition = _metadataCache.GetMediaComposition(urn, cacheDuration);
|
||||
|
||||
// If not in cache, fetch from API
|
||||
if (mediaComposition == null)
|
||||
@@ -113,12 +119,72 @@ public class SRFMediaProvider : IMediaSourceProvider
|
||||
// Get stream URL based on quality preference
|
||||
var streamUrl = _streamResolver.GetStreamUrl(chapter, config.QualityPreference);
|
||||
|
||||
if (string.IsNullOrEmpty(streamUrl))
|
||||
// Check if this is an upcoming livestream that hasn't started yet
|
||||
var isUpcomingLivestream = chapter.Type == "SCHEDULED_LIVESTREAM" && string.IsNullOrEmpty(streamUrl);
|
||||
|
||||
if (string.IsNullOrEmpty(streamUrl) && !isUpcomingLivestream)
|
||||
{
|
||||
_logger.LogWarning("Could not resolve stream URL for URN: {Urn}", urn);
|
||||
return Task.FromResult<IEnumerable<MediaSourceInfo>>(sources);
|
||||
}
|
||||
|
||||
// For upcoming livestreams, check if the event has started
|
||||
if (isUpcomingLivestream)
|
||||
{
|
||||
if (chapter.ValidFrom != null)
|
||||
{
|
||||
var eventStart = chapter.ValidFrom.Value.ToUniversalTime();
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
if (eventStart > now)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"URN {Urn}: Livestream '{Title}' hasn't started yet (starts at {ValidFrom}). User should refresh when live.",
|
||||
urn,
|
||||
chapter.Title,
|
||||
chapter.ValidFrom);
|
||||
|
||||
// Return empty sources - event not yet playable
|
||||
return Task.FromResult<IEnumerable<MediaSourceInfo>>(sources);
|
||||
}
|
||||
}
|
||||
|
||||
// Event should be live now - re-fetch media composition without cache
|
||||
using var freshApiClient = new SRFApiClient(_loggerFactory);
|
||||
var freshMediaComposition = freshApiClient.GetMediaCompositionByUrnAsync(urn, cancellationToken).GetAwaiter().GetResult();
|
||||
|
||||
if (freshMediaComposition?.ChapterList != null && freshMediaComposition.ChapterList.Count > 0)
|
||||
{
|
||||
var freshChapter = freshMediaComposition.ChapterList[0];
|
||||
streamUrl = _streamResolver.GetStreamUrl(freshChapter, config.QualityPreference);
|
||||
|
||||
if (!string.IsNullOrEmpty(streamUrl))
|
||||
{
|
||||
// Update cache with fresh data
|
||||
_metadataCache.SetMediaComposition(urn, freshMediaComposition);
|
||||
chapter = freshChapter;
|
||||
_logger.LogInformation("URN {Urn}: Livestream is now live, got fresh stream URL", urn);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("URN {Urn}: Livestream should be live but still no stream URL available", urn);
|
||||
return Task.FromResult<IEnumerable<MediaSourceInfo>>(sources);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("URN {Urn}: Failed to fetch fresh media composition for livestream", urn);
|
||||
return Task.FromResult<IEnumerable<MediaSourceInfo>>(sources);
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate the stream URL (required for all SRF streams, especially livestreams)
|
||||
if (!string.IsNullOrEmpty(streamUrl))
|
||||
{
|
||||
streamUrl = _streamResolver.GetAuthenticatedStreamUrlAsync(streamUrl, cancellationToken).GetAwaiter().GetResult();
|
||||
_logger.LogDebug("Authenticated stream URL for URN: {Urn}", urn);
|
||||
}
|
||||
|
||||
// Create media source
|
||||
var mediaSource = new MediaSourceInfo
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user