Finaly working version of livestreams
This commit is contained in:
@@ -25,6 +25,7 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
private readonly ContentRefreshService _contentRefreshService;
|
||||
private readonly StreamUrlResolver _streamResolver;
|
||||
private readonly StreamProxyService _proxyService;
|
||||
private readonly CategoryService? _categoryService;
|
||||
|
||||
/// <summary>
|
||||
@@ -33,17 +34,20 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
/// <param name="contentRefreshService">The content refresh service.</param>
|
||||
/// <param name="streamResolver">The stream resolver.</param>
|
||||
/// <param name="proxyService">The stream proxy service.</param>
|
||||
/// <param name="categoryService">The category service (optional).</param>
|
||||
public SRFPlayChannel(
|
||||
ILoggerFactory loggerFactory,
|
||||
ContentRefreshService contentRefreshService,
|
||||
StreamUrlResolver streamResolver,
|
||||
StreamProxyService proxyService,
|
||||
CategoryService? categoryService = null)
|
||||
{
|
||||
_loggerFactory = loggerFactory;
|
||||
_logger = loggerFactory.CreateLogger<SRFPlayChannel>();
|
||||
_contentRefreshService = contentRefreshService;
|
||||
_streamResolver = streamResolver;
|
||||
_proxyService = proxyService;
|
||||
_categoryService = categoryService;
|
||||
|
||||
if (_categoryService == null)
|
||||
@@ -61,7 +65,7 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
public string Description => "Swiss Radio and Television video-on-demand content";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DataVersion => "1.1";
|
||||
public string DataVersion => "2.0"; // Back to authenticating at channel refresh with auto-refresh for fresh tokens
|
||||
|
||||
/// <inheritdoc />
|
||||
public string HomePageUrl => "https://www.srf.ch/play";
|
||||
@@ -433,7 +437,7 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
// Generate deterministic GUID from URN
|
||||
var itemId = UrnToGuid(urn);
|
||||
|
||||
// Get stream URL (unauthenticated - token will be added at playback time by SRFMediaProvider)
|
||||
// Get stream URL and authenticate it
|
||||
var streamUrl = _streamResolver.GetStreamUrl(chapter, config.QualityPreference);
|
||||
|
||||
// Skip scheduled livestreams that haven't started yet (no stream URL available)
|
||||
@@ -447,6 +451,12 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
continue;
|
||||
}
|
||||
|
||||
// Authenticate the stream URL with fresh token
|
||||
if (!string.IsNullOrEmpty(streamUrl))
|
||||
{
|
||||
streamUrl = await _streamResolver.GetAuthenticatedStreamUrlAsync(streamUrl, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Skip items without a valid stream URL
|
||||
if (string.IsNullOrEmpty(streamUrl))
|
||||
{
|
||||
@@ -458,6 +468,13 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register stream with proxy service
|
||||
_proxyService.RegisterStream(itemId, streamUrl);
|
||||
|
||||
// Create proxy URL as absolute HTTP URL (required for ffmpeg)
|
||||
// Use localhost as Jellyfin should be able to access its own endpoints
|
||||
var proxyUrl = $"http://localhost:8096/Plugins/SRFPlay/Proxy/{itemId}/master.m3u8";
|
||||
|
||||
// Build overview
|
||||
var overview = chapter.Description ?? chapter.Lead;
|
||||
|
||||
@@ -477,7 +494,7 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
// Use ValidFrom for premiere date if this is a scheduled livestream, otherwise use Date
|
||||
var premiereDate = chapter.Type == "SCHEDULED_LIVESTREAM" ? chapter.ValidFrom?.ToUniversalTime() : chapter.Date?.ToUniversalTime();
|
||||
|
||||
// Store unauthenticated URL as placeholder - SRFMediaProvider will provide authenticated version at playback
|
||||
// Store authenticated URL - tokens refresh automatically via scheduled channel scans
|
||||
var item = new ChannelItemInfo
|
||||
{
|
||||
Id = itemId,
|
||||
@@ -501,15 +518,38 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
{
|
||||
Id = itemId,
|
||||
Name = chapter.Title,
|
||||
Path = streamUrl, // Unauthenticated URL - placeholder only
|
||||
Path = proxyUrl, // Proxy URL instead of direct Akamai URL
|
||||
Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
|
||||
Container = "m3u8",
|
||||
SupportsDirectPlay = false, // Disable direct play - requires auth from provider
|
||||
SupportsDirectStream = false, // Disable direct stream - requires auth from provider
|
||||
SupportsTranscoding = false, // Force use of IMediaSourceProvider
|
||||
IsRemote = true,
|
||||
Type = MediaBrowser.Model.Dto.MediaSourceType.Placeholder, // Mark as placeholder
|
||||
VideoType = VideoType.VideoFile
|
||||
Container = "hls",
|
||||
SupportsDirectStream = true,
|
||||
SupportsDirectPlay = true, // ✅ Enabled! Proxy handles auth
|
||||
SupportsTranscoding = true,
|
||||
IsRemote = false, // False because it's a local proxy endpoint
|
||||
Type = MediaBrowser.Model.Dto.MediaSourceType.Default,
|
||||
VideoType = VideoType.VideoFile,
|
||||
RequiresOpening = false,
|
||||
RequiresClosing = false,
|
||||
SupportsProbing = false, // Disable probing for proxy URLs
|
||||
ReadAtNativeFramerate = false,
|
||||
MediaStreams = new List<MediaBrowser.Model.Entities.MediaStream>
|
||||
{
|
||||
new MediaBrowser.Model.Entities.MediaStream
|
||||
{
|
||||
Type = MediaBrowser.Model.Entities.MediaStreamType.Video,
|
||||
Codec = "h264",
|
||||
Profile = "high",
|
||||
IsInterlaced = false,
|
||||
IsDefault = true,
|
||||
Index = 0
|
||||
},
|
||||
new MediaBrowser.Model.Entities.MediaStream
|
||||
{
|
||||
Type = MediaBrowser.Model.Entities.MediaStreamType.Audio,
|
||||
Codec = "aac",
|
||||
IsDefault = true,
|
||||
Index = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -523,6 +563,13 @@ public class SRFPlayChannel : IChannel, IHasCacheKey
|
||||
items.Add(item);
|
||||
successCount++;
|
||||
_logger.LogInformation("URN {Urn}: Successfully converted to channel item - {Title}", urn, chapter.Title);
|
||||
_logger.LogInformation(
|
||||
"URN {Urn}: MediaSource configured - DirectStream={DirectStream}, DirectPlay={DirectPlay}, Transcoding={Transcoding}, Container={Container}",
|
||||
urn,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
"hls");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user