91 lines
2.2 KiB
Go
91 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
tvgIDRe = regexp.MustCompile(`tvg-id="([^"]*)"`)
|
|
urlTvgRe = regexp.MustCompile(`url-tvg="([^"]*)"`)
|
|
)
|
|
|
|
// processPlaylist streams in→out, rewriting the #EXTM3U header so url-tvg
|
|
// points at epgURL. Returns the playlist's tvg-ids (in order, with duplicates)
|
|
// and the URL the playlist already declared in url-tvg (empty if absent).
|
|
//
|
|
// If epgURL is empty the header is passed through unchanged. The playlist
|
|
// must start with #EXTM3U after any leading blank lines, otherwise an error
|
|
// is returned without writing the header.
|
|
func processPlaylist(in io.Reader, out io.Writer, epgURL string) (tvgIDs []string, originalEPG string, err error) {
|
|
r := bufio.NewReader(in)
|
|
headerDone := false
|
|
|
|
for {
|
|
line, readErr := r.ReadString('\n')
|
|
|
|
if line != "" {
|
|
switch {
|
|
case !headerDone && strings.TrimSpace(line) == "":
|
|
// leading blank line — write through, keep looking for header
|
|
|
|
case !headerDone:
|
|
if !strings.HasPrefix(strings.TrimSpace(line), "#EXTM3U") {
|
|
return nil, "", errors.New("playlist: missing #EXTM3U header")
|
|
}
|
|
line, originalEPG = rewriteHeader(line, epgURL)
|
|
headerDone = true
|
|
|
|
default:
|
|
if strings.HasPrefix(line, "#EXTINF:") {
|
|
if m := tvgIDRe.FindStringSubmatch(line); m != nil {
|
|
if id := strings.TrimSpace(m[1]); id != "" {
|
|
tvgIDs = append(tvgIDs, id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if _, werr := out.Write([]byte(line)); werr != nil {
|
|
return nil, "", werr
|
|
}
|
|
}
|
|
|
|
if readErr == io.EOF {
|
|
if !headerDone {
|
|
return nil, "", errors.New("playlist: missing #EXTM3U header")
|
|
}
|
|
return tvgIDs, originalEPG, nil
|
|
}
|
|
if readErr != nil {
|
|
return nil, "", readErr
|
|
}
|
|
}
|
|
}
|
|
|
|
func rewriteHeader(line, epgURL string) (rewritten, original string) {
|
|
if m := urlTvgRe.FindStringSubmatch(line); m != nil {
|
|
original = m[1]
|
|
if epgURL != "" {
|
|
line = urlTvgRe.ReplaceAllLiteralString(line, `url-tvg="`+epgURL+`"`)
|
|
}
|
|
return line, original
|
|
}
|
|
if epgURL == "" {
|
|
return line, ""
|
|
}
|
|
body, eol := splitEOL(line)
|
|
return body + ` url-tvg="` + epgURL + `"` + eol, ""
|
|
}
|
|
|
|
func splitEOL(s string) (body, eol string) {
|
|
n := len(s)
|
|
for n > 0 && (s[n-1] == '\n' || s[n-1] == '\r') {
|
|
n--
|
|
}
|
|
return s[:n], s[n:]
|
|
}
|