refactor: split playback proxy logic into separate handler files
This commit is contained in:
98
internal/playback/handler/hls_playlist.go
Normal file
98
internal/playback/handler/hls_playlist.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func isHLSPlaylistResponse(targetURL string, headers http.Header) bool {
|
||||
contentType := strings.ToLower(headers.Get("Content-Type"))
|
||||
if strings.Contains(contentType, "mpegurl") || strings.Contains(contentType, "x-mpegurl") {
|
||||
return true
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
return strings.Contains(strings.ToLower(targetURL), ".m3u8")
|
||||
}
|
||||
return strings.Contains(strings.ToLower(parsed.Path), ".m3u8")
|
||||
}
|
||||
|
||||
func (h *PlaybackHandler) rewriteHLSPlaylist(body string, playlistURL string, referer string) (string, error) {
|
||||
baseURL, err := url.Parse(playlistURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
lines := strings.SplitAfter(body, "\n")
|
||||
var out strings.Builder
|
||||
for _, line := range lines {
|
||||
lineBody := strings.TrimSuffix(line, "\n")
|
||||
newline := ""
|
||||
if strings.HasSuffix(line, "\n") {
|
||||
newline = "\n"
|
||||
lineBody = strings.TrimSuffix(lineBody, "\r")
|
||||
if strings.HasSuffix(line, "\r\n") {
|
||||
newline = "\r\n"
|
||||
}
|
||||
}
|
||||
|
||||
trimmed := strings.TrimSpace(lineBody)
|
||||
rewritten := lineBody
|
||||
if trimmed != "" {
|
||||
if strings.HasPrefix(trimmed, "#") {
|
||||
rewritten, err = h.rewriteHLSQuotedURIs(lineBody, baseURL, referer)
|
||||
} else {
|
||||
rewritten, err = h.proxyPlaylistURI(trimmed, baseURL, referer)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
out.WriteString(rewritten)
|
||||
out.WriteString(newline)
|
||||
}
|
||||
|
||||
return out.String(), nil
|
||||
}
|
||||
|
||||
func (h *PlaybackHandler) rewriteHLSQuotedURIs(line string, baseURL *url.URL, referer string) (string, error) {
|
||||
const marker = `URI="`
|
||||
var out strings.Builder
|
||||
remaining := line
|
||||
for {
|
||||
idx := strings.Index(remaining, marker)
|
||||
if idx < 0 {
|
||||
out.WriteString(remaining)
|
||||
return out.String(), nil
|
||||
}
|
||||
out.WriteString(remaining[:idx+len(marker)])
|
||||
remaining = remaining[idx+len(marker):]
|
||||
end := strings.Index(remaining, `"`)
|
||||
if end < 0 {
|
||||
out.WriteString(remaining)
|
||||
return out.String(), nil
|
||||
}
|
||||
proxied, err := h.proxyPlaylistURI(remaining[:end], baseURL, referer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
out.WriteString(proxied)
|
||||
remaining = remaining[end:]
|
||||
}
|
||||
}
|
||||
|
||||
func (h *PlaybackHandler) proxyPlaylistURI(rawURI string, baseURL *url.URL, referer string) (string, error) {
|
||||
target, err := baseURL.Parse(rawURI)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
token, err := h.svc.SignProxyToken(target.String(), referer, "stream")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("token", token)
|
||||
return "/watch/proxy/stream?" + params.Encode(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user