diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d4cc414..a0b904b5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Fixed +- Fix HLS Direct playback with Jellyfin 10.11 ## [25.8.0] - 2025-10-26 ### Added diff --git a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs index 5fb50e674..3bc675cb9 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetHlsPlaylistByChannelNumberHandler.cs @@ -1,5 +1,7 @@ using ErsatzTV.Core; using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Repositories; +using ErsatzTV.FFmpeg.OutputFormat; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; @@ -11,13 +13,16 @@ public class GetHlsPlaylistByChannelNumberHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; + private readonly IConfigElementRepository _configElementRepository; private readonly IMemoryCache _memoryCache; public GetHlsPlaylistByChannelNumberHandler( IDbContextFactory dbContextFactory, + IConfigElementRepository configElementRepository, IMemoryCache memoryCache) { _dbContextFactory = dbContextFactory; + _configElementRepository = configElementRepository; _memoryCache = memoryCache; } @@ -31,7 +36,7 @@ public class GetHlsPlaylistByChannelNumberHandler : return await validation.Apply(parameters => GetPlaylist(dbContext, request, parameters, now)); } - private Task GetPlaylist( + private async Task GetPlaylist( TvContext dbContext, GetHlsPlaylistByChannelNumber request, Parameters parameters, @@ -44,11 +49,25 @@ public class GetHlsPlaylistByChannelNumberHandler : _ => string.Empty }; - string endpoint = request.Mode switch + string endpoint = "ffmpeg/stream"; + string extension = string.Empty; + + if (request.Mode is "hls-direct") { - "hls-direct" => "iptv/hls-direct", - _ => "ffmpeg/stream" - }; + endpoint = "iptv/hls-direct"; + + OutputFormatKind outputFormat = await _configElementRepository + .GetValue(ConfigElementKey.FFmpegHlsDirectOutputFormat, CancellationToken.None) + .IfNoneAsync(OutputFormatKind.MpegTs); + + extension = outputFormat switch + { + OutputFormatKind.MpegTs => ".ts", + OutputFormatKind.Mp4 => ".mp4", + OutputFormatKind.Mkv => ".mkv", + _ => string.Empty + }; + } long index = GetIndexForChannel(parameters.Channel, parameters.PlayoutItem); double timeRemaining = Math.Abs((parameters.PlayoutItem.FinishOffset - now).TotalSeconds); @@ -58,8 +77,8 @@ public class GetHlsPlaylistByChannelNumberHandler : #EXT-X-MEDIA-SEQUENCE:{index} #EXT-X-DISCONTINUITY #EXTINF:{timeRemaining:F2}, -{request.Scheme}://{request.Host}/{endpoint}/{request.ChannelNumber}?index={index}{mode} -".AsTask(); +{request.Scheme}://{request.Host}/{endpoint}/{request.ChannelNumber}{extension}?index={index}{mode} +"; } private static Task> Validate( diff --git a/ErsatzTV/Controllers/IptvController.cs b/ErsatzTV/Controllers/IptvController.cs index 882b823fb..2a73664ba 100644 --- a/ErsatzTV/Controllers/IptvController.cs +++ b/ErsatzTV/Controllers/IptvController.cs @@ -282,6 +282,9 @@ public class IptvController : StreamingControllerBase } [HttpGet("iptv/hls-direct/{channelNumber}")] + [HttpGet("iptv/hls-direct/{channelNumber}.ts")] + [HttpGet("iptv/hls-direct/{channelNumber}.mkv")] + [HttpGet("iptv/hls-direct/{channelNumber}.mp4")] public async Task GetStream(string channelNumber) => await GetHlsDirectStream(channelNumber);