lurch-dl/core/naive_m3u8_parser.go

68 lines
1.8 KiB
Go
Raw Normal View History

2025-03-08 21:09:32 +01:00
// Copyright (c) 2025, Julian Müller (ChaoticByte)
package core
import (
"regexp"
"strconv"
"strings"
)
var availFormatsRegex = regexp.MustCompile(`NAME="(.+)"`)
func parseAvailFormatsFromM3u8(m3u8 string) []VideoFormat {
foundFormats := []VideoFormat{}
m3u8 = strings.ReplaceAll(m3u8, "\r", "")
parts := strings.Split(m3u8, "#EXT-X-STREAM-INF")
for _, p := range parts {
p := strings.Trim(p, " \n")
if strings.HasPrefix(p, ":") && strings.Contains(p, "RESOLUTION=") && strings.Contains(p, "FRAMERATE=") && strings.Contains(p, "NAME=") {
format := VideoFormat{}
plItem := strings.Split(p, "\n")
if len(plItem) < 2 {
continue
}
formatName := availFormatsRegex.FindStringSubmatch(plItem[0])
if formatName == nil {
continue // didn't find format
}
format.Name = formatName[1]
format.Url = plItem[1]
foundFormats = append(foundFormats, format)
}
}
return foundFormats
}
var targetDurationRegex = regexp.MustCompile(`#EXT-X-TARGETDURATION:(.+)`)
func parseChunkListFromM3u8(m3u8 string, baseurl string) (ChunkList, error) {
chunklist := ChunkList{BaseUrl: baseurl}
m3u8 = strings.ReplaceAll(m3u8, "\r", "")
parts := strings.Split(m3u8, "#EXTINF")
for _, p := range parts {
if strings.HasPrefix(p, "#EXTM3U") {
lines := strings.Split(p, "\n")
for _, l := range lines {
if strings.HasPrefix(l, "#EXT-X-TARGETDURATION") {
targetDuration := targetDurationRegex.FindStringSubmatch(l)
if targetDuration == nil {
continue
}
chunkDuration, err := strconv.ParseFloat(targetDuration[1], 64)
if err != nil {
return chunklist, err
}
chunklist.ChunkDuration = chunkDuration
}
}
} else if strings.HasPrefix(p, ":") {
lines := strings.Split(p, "\n")
if len(lines) > 1 {
chunklist.Chunks = append(chunklist.Chunks, lines[1])
}
}
}
return chunklist, nil
}