101 lines
2.4 KiB
Go
101 lines
2.4 KiB
Go
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"net/url"
|
||
"path"
|
||
"strings"
|
||
)
|
||
|
||
func rewriteM3U8(raw []byte, id string) []byte {
|
||
// Wir bauen alle URIs so um, dass sie wieder über /api/preview laufen.
|
||
// Wichtig: play=1 bleibt dran, damit Folge-Requests (segments, chunklists) auch ohne Hover gehen.
|
||
base := "/api/preview?id=" + url.QueryEscape(id) + "&file="
|
||
|
||
var out bytes.Buffer
|
||
sc := bufio.NewScanner(bytes.NewReader(raw))
|
||
|
||
// Scanner default token limit 64K – m3u8 ist normalerweise klein, passt.
|
||
// Wenn du riesige Playlists hast, kannst du Buffer erhöhen.
|
||
|
||
for sc.Scan() {
|
||
line := sc.Text()
|
||
trim := strings.TrimSpace(line)
|
||
|
||
if trim == "" {
|
||
out.WriteByte('\n')
|
||
continue
|
||
}
|
||
|
||
// Kommentare/Tags: ggf. URI="..." in Tags rewriten
|
||
if strings.HasPrefix(trim, "#") {
|
||
// EXT-X-KEY:URI="..."
|
||
line = rewriteAttrURI(line, base)
|
||
out.WriteString(line)
|
||
out.WriteByte('\n')
|
||
continue
|
||
}
|
||
|
||
// Nicht-Tag => URI (segment oder child-playlist)
|
||
u := trim
|
||
|
||
// Absolut? dann lassen
|
||
if strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://") {
|
||
out.WriteString(line)
|
||
out.WriteByte('\n')
|
||
continue
|
||
}
|
||
|
||
// Wenn es schon unser API ist, lassen
|
||
if strings.Contains(u, "/api/preview") {
|
||
out.WriteString(line)
|
||
out.WriteByte('\n')
|
||
continue
|
||
}
|
||
|
||
// Nur basename nehmen (ffmpeg schreibt i.d.R. keine Subdirs)
|
||
name := path.Base(u)
|
||
|
||
// Hier play=1 mitschicken:
|
||
out.WriteString(base + url.QueryEscape(name) + "&play=1")
|
||
out.WriteByte('\n')
|
||
}
|
||
|
||
if err := sc.Err(); err != nil {
|
||
// Wenn Scanner aus irgendeinem Grund scheitert: lieber raw zurück (besser als kaputt)
|
||
return raw
|
||
}
|
||
return out.Bytes()
|
||
}
|
||
|
||
func rewriteAttrURI(line, base string) string {
|
||
// Rewritet URI="xyz" in EXT-X-KEY / EXT-X-MAP / EXT-X-MEDIA / EXT-X-I-FRAME-STREAM-INF etc.
|
||
// Nur relative URIs werden angefasst.
|
||
const key = `URI="`
|
||
i := strings.Index(line, key)
|
||
if i < 0 {
|
||
return line
|
||
}
|
||
|
||
j := strings.Index(line[i+len(key):], `"`)
|
||
if j < 0 {
|
||
return line
|
||
}
|
||
|
||
start := i + len(key)
|
||
end := start + j
|
||
val := line[start:end]
|
||
valTrim := strings.TrimSpace(val)
|
||
|
||
// absolut oder schon preview => nix tun
|
||
if strings.HasPrefix(valTrim, "http://") || strings.HasPrefix(valTrim, "https://") || strings.Contains(valTrim, "/api/preview") {
|
||
return line
|
||
}
|
||
|
||
name := path.Base(valTrim)
|
||
repl := base + url.QueryEscape(name) + "&play=1"
|
||
|
||
return line[:start] + repl + line[end:]
|
||
}
|