Commit Diff


commit - a30e111bb1d9e62aac3810e51749241f488e046a
commit + 9d0a9c380ce962f56c141d6db6fdacd7a41bf831
blob - b524a68ce5470a6e0137bb827ed7145edd7d5f99
blob + cad16cdf5b3e2c9aeaa5df7f69207b3151bc066a
--- m3u8/m3u8.go
+++ m3u8/m3u8.go
@@ -126,6 +126,9 @@ func parseEncryptMethod(s string) EncryptMethod {
 	return encryptMethodInvalid
 }
 
+// Map represents the EXT-X-MAP tag.
+// A Map informs of any byte sequences to initialise readers of
+// some media formats.
 type Map struct {
 	URI       string
 	ByteRange ByteRange
blob - d019ec22dc533455dad16f1fa9b75bc93bb9732f
blob + 0d706d6f50a48b0bc89983ee9fa72a8a9c18b968
--- m3u8/segment.go
+++ m3u8/segment.go
@@ -88,6 +88,12 @@ func parseSegment(items chan item, leading item) (*Seg
 				return nil, fmt.Errorf("parse key: %w", err)
 			}
 			seg.Key = &key
+		case tagMap:
+			m, err := parseMap(items)
+			if err != nil {
+				return nil, fmt.Errorf("parse map: %w", err)
+			}
+			seg.Map = &m
 		default:
 			return nil, fmt.Errorf("parsing %s unsupported", it)
 		}
@@ -184,13 +190,45 @@ func parseKey(items chan item) (Key, error) {
 					key.FormatVersions[i] = uint32(n)
 				}
 			default:
-				return key, fmt.Errorf("TODO %s", it.val)
+				return key, fmt.Errorf("unexpected attribute %q", it.val)
 			}
 		}
 	}
-	return key, fmt.Errorf("TODO")
+	return key, fmt.Errorf("unexpected end of tag")
 }
 
+func parseMap(items chan item) (Map, error) {
+	var mmap Map
+	for it := range items {
+		switch it.typ {
+		case itemError:
+			return mmap, errors.New(it.val)
+		case itemNewline:
+			return mmap, nil
+		case itemAttrName:
+			v := <-items
+			if v.typ != itemEquals {
+				return Map{}, fmt.Errorf("expected %q after %s, got %s", "=", it.typ, v)
+			}
+			switch it.val {
+			case "URI":
+				v = <-items
+				mmap.URI = strings.Trim(it.val, `"`)
+			case "BYTERANGE":
+				v = <-items
+				r, err := parseByteRange(v.val)
+				if err != nil {
+					return Map{}, fmt.Errorf("parse byte range: %w", err)
+				}
+				mmap.ByteRange = r
+			default:
+				return Map{}, fmt.Errorf("unexpected attribute %q", it.val)
+			}
+		}
+	}
+	return Map{}, fmt.Errorf("unexpected end of tag")
+}
+
 func writeSegments(w io.Writer, segments []Segment) (n int, err error) {
 	for i, seg := range segments {
 		b, err := seg.MarshalText()