Browse Source

fix hls playlist filtering (#2435)

* add failing test

* fix hls playlist filtering
pull/2436/head
Jason Dove 4 months ago committed by GitHub
parent
commit
8bc3457de0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 48
      ErsatzTV.Core.Tests/FFmpeg/HlsPlaylistFilterTests.cs
  3. 20
      ErsatzTV.Core/FFmpeg/HlsPlaylistFilter.cs

2
CHANGELOG.md

@ -46,6 +46,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -46,6 +46,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix playback of Jellyfin content with unknown color range
- Block schedules: skip collections (block items) that will never fit in block duration
- Block schedules: skip media items that will never fit in block duration
- Fix HLS playlist generation for clients that actually care about discontinuities (like hls.js)
- This should resolve most playback issues with built-in channel preview
## [25.6.0] - 2025-09-14
### Added

48
ErsatzTV.Core.Tests/FFmpeg/HlsPlaylistFilterTests.cs

@ -551,6 +551,54 @@ live000065.ts @@ -551,6 +551,54 @@ live000065.ts
"));
}
[Test]
public void HlsPlaylistFilter_ShouldHandleDiscontinuitySequenceOnSegmentRemoval()
{
var start = new DateTimeOffset(2025, 9, 17, 10, 11, 5, 31, TimeSpan.FromHours(-5));
string[] input = NormalizeLineEndings(
@"#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:46
#EXT-X-DISCONTINUITY-SEQUENCE:2
#EXT-X-INDEPENDENT-SEGMENTS
#EXTINF:1.734000,
#EXT-X-PROGRAM-DATE-TIME:2025-09-17T10:11:05.031-0500
live000046.ts
#EXT-X-DISCONTINUITY
#EXTINF:4.004000,
#EXT-X-PROGRAM-DATE-TIME:2025-09-17T10:11:06.765-0500
live000047.ts
#EXTINF:4.004000,
#EXT-X-PROGRAM-DATE-TIME:2025-09-17T10:11:10.769-0500
live000048.ts
").Split(Environment.NewLine);
// filter 'live000046.ts'
var filterBefore = start.AddSeconds(2);
TrimPlaylistResult result = _hlsPlaylistFilter.TrimPlaylist(start, filterBefore, input, 2);
result.Sequence.ShouldBe(47);
string expectedPlaylist = NormalizeLineEndings(
@"#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:47
#EXT-X-DISCONTINUITY-SEQUENCE:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXTINF:4.004000,
#EXT-X-PROGRAM-DATE-TIME:2025-09-17T10:11:06.765-0500
live000047.ts
#EXTINF:4.004000,
#EXT-X-PROGRAM-DATE-TIME:2025-09-17T10:11:10.769-0500
live000048.ts
");
result.Playlist.ShouldBe(expectedPlaylist);
}
private static string NormalizeLineEndings(string str) =>
str
.Replace("\r\n", "\n")

20
ErsatzTV.Core/FFmpeg/HlsPlaylistFilter.cs

@ -61,11 +61,11 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter @@ -61,11 +61,11 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter
continue;
}
var duration = TimeSpan.FromSeconds(
double.Parse(
lines[i].TrimEnd(',').Split(':')[1],
NumberStyles.Number,
CultureInfo.InvariantCulture));
var durationDecimal = decimal.Parse(
lines[i].TrimEnd(',').Split(':')[1],
NumberStyles.Number,
CultureInfo.InvariantCulture);
var duration = TimeSpan.FromTicks((long)(durationDecimal * TimeSpan.TicksPerSecond));
items.Add(new PlaylistSegment(currentTime, lines[i], lines[i + 2]));
@ -168,11 +168,17 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter @@ -168,11 +168,17 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter
switch (items[i])
{
case PlaylistDiscontinuity:
if (i == items.Count - 1 || allSegments.Contains(items[i + 1]))
if (i < items.Count - 1 && allSegments.Contains(items[i + 1]))
{
if (items[i + 1] is PlaylistSegment nextSegment && allSegments.Head() != nextSegment)
{
output.AppendLine("#EXT-X-DISCONTINUITY");
}
}
else if (i == items.Count - 1 && allSegments.Count > 0) // discontinuity at the end
{
output.AppendLine("#EXT-X-DISCONTINUITY");
}
break;
case PlaylistSegment segment:
if (allSegments.Contains(segment))

Loading…
Cancel
Save