Commit Diff


commit - 440f52398d25a5cddd80cefad5ba8631b5e7eaf7
commit + fdd78130c167098cab14bc621e8d8960de6c6b7c
blob - eb9edd1b313d85e154de73ebe1751394c2b0cdc8
blob + 5a872d7260efb71b4257ea387c78bfdd6dca8ead
--- m3u8/parse.go
+++ m3u8/parse.go
@@ -120,91 +120,97 @@ func parseVariant(items chan item) (*Variant, error) {
 	var v Variant
 	for it := range items {
 		switch it.typ {
-		case itemAttrName:
-			attr := it
-			it = <-items
-			if it.typ != itemEquals {
-				return nil, fmt.Errorf("missing equals after %s", attr)
-			}
-			switch attr.val {
-			case "PROGRAM-ID", "NAME":
-				// parsing PROGRAM-ID attribute unsupported; removed in HLS version 6
-				// NAME is non-standard, should be set in Rendition.
-			case "BANDWIDTH", "AVERAGE-BANDWIDTH":
-				it = <-items
-				if it.typ != itemNumber {
-					return nil, fmt.Errorf("parse bandwidth attribute: unexpected %s", it)
-				}
-				n, err := strconv.Atoi(it.val)
-				if err != nil {
-					return nil, fmt.Errorf("parse bandwidth: %w", err)
-				}
-				if attr.val == "BANDWIDTH" {
-					v.Bandwidth = n
-				} else {
-					v.AverageBandwidth = n
-				}
-			case "CODECS":
-				it = <-items
-				if it.typ != itemString {
-					return nil, fmt.Errorf("parse codecs attribute: unexpected %s", it)
-				}
-				v.Codecs = strings.Split(strings.Trim(it.val, `"`), ",")
-			case "RESOLUTION":
-				it = <-items
-				res, err := parseResolution(it.val)
-				if err != nil {
-					return nil, fmt.Errorf("parse resolution: %w", err)
-				}
-				v.Resolution = res
-			case "FRAME-RATE":
-				it = <-items
-				if it.typ != itemNumber {
-					return nil, fmt.Errorf("parse frame rate: unexpected %s", it)
-				}
-				n, err := strconv.ParseFloat(it.val, 32)
-				if err != nil {
-					return nil, fmt.Errorf("parse frame rate: %w", err)
-				}
-				v.FrameRate = float32(n)
-			case "HDCP-LEVEL":
-				it = <-items
-				l, err := parseHDCPLevel(it.val)
-				if err != nil {
-					return nil, fmt.Errorf("parse HDCP level: %w", err)
-				}
-				v.HDCP = l
-			case "AUDIO", "VIDEO", "SUBTITLES":
-				name := attr.val
-				it = <-items
-				if it.typ != itemString {
-					return nil, fmt.Errorf("parse %s: unexpected %s", name, it)
-				}
-				it.val = strings.Trim(it.val, `"`)
-				if name == "AUDIO" {
-					v.Audio = it.val
-				} else if name == "VIDEO" {
-					v.Video = it.val
-				} else if name == "SUBTITLES" {
-					v.Subtitles = it.val
-				}
-			case "CLOSED-CAPTIONS":
-				it = <-items
-				if it.typ != itemString {
-					return nil, fmt.Errorf("parse closed-captions: unexpected %s", it)
-				}
-				v.ClosedCaptions = strings.Trim(it.val, `"`)
-			default:
-				return nil, fmt.Errorf("unknown attribute %s", attr.val)
-			}
-		case itemComma:
+		case itemError:
+			return nil, errors.New(it.val)
+		case itemComma, itemNewline:
 			continue
 		case itemURL:
 			v.URI = it.val
 			return &v, nil
+		default:
+			if it.typ != itemAttrName {
+				return nil, fmt.Errorf("expected %s, got %s", itemAttrName, it.typ)
+			}
 		}
+		attr := it
+		it = <-items
+		if it.typ != itemEquals {
+			return nil, fmt.Errorf("missing equals after %s", attr)
+		}
+
+		switch attr.val {
+		case "PROGRAM-ID", "NAME":
+			// parsing PROGRAM-ID attribute unsupported; removed in HLS version 6
+			// NAME is non-standard, should be set in Rendition.
+		case "BANDWIDTH", "AVERAGE-BANDWIDTH":
+			it = <-items
+			if it.typ != itemNumber {
+				return nil, fmt.Errorf("parse bandwidth attribute: unexpected %s", it)
+			}
+			n, err := strconv.Atoi(it.val)
+			if err != nil {
+				return nil, fmt.Errorf("parse bandwidth: %w", err)
+			}
+			if attr.val == "BANDWIDTH" {
+				v.Bandwidth = n
+			} else {
+				v.AverageBandwidth = n
+			}
+		case "CODECS":
+			it = <-items
+			if it.typ != itemString {
+				return nil, fmt.Errorf("parse codecs attribute: unexpected %s", it)
+			}
+			v.Codecs = strings.Split(strings.Trim(it.val, `"`), ",")
+		case "RESOLUTION":
+			it = <-items
+			res, err := parseResolution(it.val)
+			if err != nil {
+				return nil, fmt.Errorf("parse resolution: %w", err)
+			}
+			v.Resolution = res
+		case "FRAME-RATE":
+			it = <-items
+			if it.typ != itemNumber {
+				return nil, fmt.Errorf("parse frame rate: unexpected %s", it)
+			}
+			n, err := strconv.ParseFloat(it.val, 32)
+			if err != nil {
+				return nil, fmt.Errorf("parse frame rate: %w", err)
+			}
+			v.FrameRate = float32(n)
+		case "HDCP-LEVEL":
+			it = <-items
+			l, err := parseHDCPLevel(it.val)
+			if err != nil {
+				return nil, fmt.Errorf("parse HDCP level: %w", err)
+			}
+			v.HDCP = l
+		case "AUDIO", "VIDEO", "SUBTITLES":
+			name := attr.val
+			it = <-items
+			if it.typ != itemString {
+				return nil, fmt.Errorf("parse %s: unexpected %s", name, it)
+			}
+			it.val = strings.Trim(it.val, `"`)
+			if name == "AUDIO" {
+				v.Audio = it.val
+			} else if name == "VIDEO" {
+				v.Video = it.val
+			} else if name == "SUBTITLES" {
+				v.Subtitles = it.val
+			}
+		case "CLOSED-CAPTIONS":
+			it = <-items
+			if it.typ != itemString {
+				return nil, fmt.Errorf("parse closed-captions: unexpected %s", it)
+			}
+			v.ClosedCaptions = strings.Trim(it.val, `"`)
+		default:
+			return nil, fmt.Errorf("unknown attribute %s", attr.val)
+		}
 	}
-	return &v, nil
+	return nil, fmt.Errorf("no url")
 }
 
 func parseResolution(s string) (res [2]int, err error) {