commit - 3df4029f13d7c363d034d1c5aed186ba947ab8a6
commit + 62d865db8655e6d23b4fccc3280d73c3cdda8ce9
blob - a71b7f91295d88116f9117e9fd2185a9749e5751
blob + eb9edd1b313d85e154de73ebe1751394c2b0cdc8
--- m3u8/parse.go
+++ m3u8/parse.go
"errors"
"fmt"
"io"
+ "os"
"strconv"
"strings"
"time"
if it.typ != itemTag || it.val != tagHead {
return nil, fmt.Errorf("expected head tag, got %q", it.val)
}
+
p := &Playlist{}
var err error
for it := range lex.items {
switch it.typ {
case itemError:
return p, errors.New(it.val)
- case itemTag:
- switch it.val {
- case tagVersion:
- it = <-lex.items
- if p.Version != 0 {
- return p, fmt.Errorf("parse %s: playlist version already specified", it)
- }
- p.Version, err = strconv.Atoi(it.val)
- if err != nil {
- return p, fmt.Errorf("parse playlist version: %w", err)
- }
- case tagIndependentSegments:
- p.IndependentSegments = true
- case tagVariant:
- variant, err := parseVariant(lex.items)
- if err != nil {
- return p, fmt.Errorf("parse variant: %w", err)
- }
- p.Variants = append(p.Variants, *variant)
- case tagRendition:
- rend, err := parseRendition(lex.items)
- if err != nil {
- return p, fmt.Errorf("parse rendition: %w", err)
- }
- p.Media = append(p.Media, *rend)
- case tagPlaylistType:
- it = <-lex.items
- typ, err := parsePlaylistType(it)
- if err != nil {
- return p, fmt.Errorf("parse playlist type: %w", err)
- }
- p.Type = typ
+ case itemNewline:
+ continue
+ default:
+ if it.typ != itemTag {
+ return p, fmt.Errorf("unexpected %s %q, expected tag", it.typ, it.val)
+ }
+ }
- case tagTargetDuration:
- it = <-lex.items
- dur, err := parseTargetDuration(it)
- if err != nil {
- return p, fmt.Errorf("parse target duration: %w", err)
- }
- p.TargetDuration = dur
+ switch it.val {
+ case tagVersion:
+ it = <-lex.items
+ if p.Version != 0 {
+ return p, fmt.Errorf("parse %s: playlist version already specified", it)
+ }
+ p.Version, err = strconv.Atoi(it.val)
+ if err != nil {
+ return p, fmt.Errorf("parse playlist version: %w", err)
+ }
+ case tagIndependentSegments:
+ p.IndependentSegments = true
+ case tagVariant:
+ variant, err := parseVariant(lex.items)
+ if err != nil {
+ return p, fmt.Errorf("parse variant: %w", err)
+ }
+ p.Variants = append(p.Variants, *variant)
+ case tagRendition:
+ rend, err := parseRendition(lex.items)
+ if err != nil {
+ return p, fmt.Errorf("parse rendition: %w", err)
+ }
+ p.Media = append(p.Media, *rend)
+ case tagPlaylistType:
+ it = <-lex.items
+ typ, err := parsePlaylistType(it)
+ if err != nil {
+ return p, fmt.Errorf("parse playlist type: %w", err)
+ }
+ p.Type = typ
- case tagSegmentDuration, tagByteRange, tagKey:
- segment, err := parseSegment(lex.items, it)
- if err != nil {
- return p, fmt.Errorf("parse segment: %w", err)
- }
- p.Segments = append(p.Segments, *segment)
+ case tagTargetDuration:
+ it = <-lex.items
+ dur, err := parseTargetDuration(it)
+ if err != nil {
+ return p, fmt.Errorf("parse target duration: %w", err)
+ }
+ p.TargetDuration = dur
- case tagEndList:
- p.End = true
- case tagMediaSequence:
- it = <-lex.items
- seq, err := strconv.Atoi(it.val)
- if err != nil {
- return p, fmt.Errorf("parse media sequence: %w", err)
- }
- p.Sequence = seq
+ case tagSegmentDuration, tagByteRange, tagKey:
+ segment, err := parseSegment(lex.items, it)
+ if err != nil {
+ return p, fmt.Errorf("parse segment: %w", err)
}
+ p.Segments = append(p.Segments, *segment)
+
+ case tagEndList:
+ p.End = true
+ case tagMediaSequence:
+ it = <-lex.items
+ seq, err := strconv.Atoi(it.val)
+ if err != nil {
+ return p, fmt.Errorf("parse media sequence: %w", err)
+ }
+ p.Sequence = seq
+ default:
+ if lex.debug {
+ fmt.Fprintln(os.Stderr, "unknown tag", it)
+ }
+ // throw away whatever is next; we don't support it but also don't want to
+ // return errors while this package is in development.
+ <-lex.items
}
}
return p, nil
blob - 0b9fdc9478e2542627b7c7f74521a3c2a8189985
blob + 0a40a92ff5f85cbd5b98a03af439c521889bd4ee
--- m3u8/segment.go
+++ m3u8/segment.go
return key, errors.New(it.val)
case itemNewline:
return key, nil
- case itemAttrName:
- v := <-items
- if v.typ != itemEquals {
- return key, fmt.Errorf("expected %q after %s, got %s", "=", it.typ, v)
+ case itemComma:
+ continue
+ default:
+ if it.typ != itemAttrName {
+ return Key{}, fmt.Errorf("expected attribute name, got %s", it.val)
}
- switch it.val {
- case "METHOD":
- v = <-items
- key.Method = parseEncryptMethod(v.val)
- if key.Method == encryptMethodInvalid {
- return key, fmt.Errorf("bad encrypt method %q", v.val)
- }
- case "URI":
- v = <-items
- key.URI = strings.Trim(v.val, `"`)
- case "IV":
- v = <-items
- b, err := hex.DecodeString(strings.TrimPrefix(v.val, "0x"))
+ }
+ v := <-items
+ if v.typ != itemEquals {
+ return key, fmt.Errorf("expected %q after %s, got %s", "=", it.typ, v)
+ }
+
+ switch it.val {
+ case "METHOD":
+ v = <-items
+ key.Method = parseEncryptMethod(v.val)
+ if key.Method == encryptMethodInvalid {
+ return key, fmt.Errorf("bad encrypt method %q", v.val)
+ }
+ case "URI":
+ v = <-items
+ key.URI = strings.Trim(v.val, `"`)
+ case "IV":
+ v = <-items
+ b, err := hex.DecodeString(strings.TrimPrefix(v.val, "0x"))
+ if err != nil {
+ return key, fmt.Errorf("parse initialisation vector: %w", err)
+ }
+ if len(b) != len(key.IV) {
+ return key, fmt.Errorf("bad initialisation length %d, want %d", len(b), len(key.IV))
+ }
+ copy(key.IV[:], b)
+ case "KEYFORMAT":
+ v = <-items
+ key.Format = strings.Trim(v.val, `"`)
+ case "KEYFORMATVERSIONS":
+ v = <-items
+ ss := strings.Split(v.val, "/")
+ key.FormatVersions = make([]uint32, len(ss))
+ for i := range ss {
+ n, err := strconv.Atoi(ss[i])
if err != nil {
- return key, fmt.Errorf("parse initialisation vector: %w", err)
+ return key, fmt.Errorf("parse key format version: %w", err)
}
- if len(b) != len(key.IV) {
- return key, fmt.Errorf("bad initialisation length %d, want %d", len(b), len(key.IV))
- }
- copy(key.IV[:], b)
- case "KEYFORMAT":
- v = <-items
- key.Format = strings.Trim(v.val, `"`)
- case "KEYFORMATVERSIONS":
- v = <-items
- ss := strings.Split(v.val, "/")
- key.FormatVersions = make([]uint32, len(ss))
- for i := range ss {
- n, err := strconv.Atoi(ss[i])
- if err != nil {
- return key, fmt.Errorf("parse key format version: %w", err)
- }
- key.FormatVersions[i] = uint32(n)
- }
- default:
- return key, fmt.Errorf("unexpected attribute %q", it.val)
+ key.FormatVersions[i] = uint32(n)
}
+ default:
+ return key, fmt.Errorf("unexpected attribute %q", it.val)
}
}
return key, fmt.Errorf("unexpected end of tag")