commit 2be3531b0dcadd5c29adc1fff94844876de00afe
parent b3f3a7ccc95f08e87b4df8d758c035e4ef5e0fc5
Author: Luiz Henrique Rapatao <rapatao@rapatao.com>
Date: Sun, 20 Apr 2025 21:56:47 +0100
m3u8: add support for parsing media sequence from playlist
Diffstat:
3 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/m3u8/parse.go b/m3u8/parse.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"io"
+ "regexp"
"strconv"
"strings"
"time"
@@ -85,6 +86,12 @@ func Decode(rd io.Reader) (*Playlist, error) {
p.Segments = append(p.Segments, *segment)
case tagEndList:
p.End = true
+ case tagMediaSequence:
+ val, err := parseSequence(lex)
+ if err != nil {
+ return p, fmt.Errorf("parse media sequence: %w", err)
+ }
+ p.Sequence = val
}
}
}
@@ -381,3 +388,14 @@ func parseByteRange(s string) (ByteRange, error) {
}
return ByteRange{n, nn}, nil
}
+
+func parseSequence(lex *lexer) (int, error) {
+ re := regexp.MustCompile(`#EXT-X-MEDIA-SEQUENCE:(\d+)`)
+
+ match := re.FindStringSubmatch(lex.input)
+ if len(match) > 1 {
+ return strconv.Atoi(match[1])
+ }
+
+ return 0, fmt.Errorf("invalid sequence number")
+}
diff --git a/m3u8/parse_test.go b/m3u8/parse_test.go
@@ -135,3 +135,18 @@ func TestFrameRate(t *testing.T) {
}
}
}
+
+func TestParseSequence(t *testing.T) {
+ f, err := os.Open("testdata/sequence.m3u8")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ plist, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if plist.Sequence != 91240 {
+ t.Errorf("want %d, got %d", 91240, plist.Sequence)
+ }
+}
diff --git a/m3u8/testdata/sequence.m3u8 b/m3u8/testdata/sequence.m3u8
@@ -0,0 +1,11 @@
+#EXTM3U
+#EXT-X-VERSION:3
+#EXT-X-TARGETDURATION:3
+#EXT-X-MEDIA-SEQUENCE:91240
+#EXT-X-DISCONTINUITY-SEQUENCE:0
+#EXTINF:2.002,
+media-seg_91240.ts
+#EXTINF:2.002,
+media-seg_91241.ts
+#EXTINF:2.002,
+media-seg_91242.ts