76 lines
2.2 KiB
Go
76 lines
2.2 KiB
Go
package playback
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func (s *Service) ProxyStream(ctx context.Context, targetURL string, referer string, rangeHeader string) (int, http.Header, []byte, io.ReadCloser, error) {
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, nil)
|
|
if err != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("invalid upstream url: %w", err)
|
|
}
|
|
|
|
if referer != "" {
|
|
req.Header.Set("Referer", referer)
|
|
}
|
|
req.Header.Set("User-Agent", defaultUserAgent)
|
|
if rangeHeader != "" {
|
|
req.Header.Set("Range", rangeHeader)
|
|
}
|
|
|
|
resp, err := s.httpClient.Do(req)
|
|
if err != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("upstream request failed: %w", err)
|
|
}
|
|
|
|
if isM3U8(targetURL, resp.Header.Get("Content-Type")) {
|
|
defer resp.Body.Close()
|
|
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1024))
|
|
if readErr != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("read playlist failed: %w", readErr)
|
|
}
|
|
|
|
rewritten, rewriteErr := s.rewritePlaylistWithTokens(ctx, string(body), targetURL, referer)
|
|
if rewriteErr != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("rewrite playlist failed: %w", rewriteErr)
|
|
}
|
|
|
|
headers := cloneHeaders(resp.Header)
|
|
headers.Set("Content-Type", "application/vnd.apple.mpegurl")
|
|
return resp.StatusCode, headers, []byte(rewritten), nil, nil
|
|
}
|
|
|
|
headers := cloneHeaders(resp.Header)
|
|
return resp.StatusCode, headers, nil, resp.Body, nil
|
|
}
|
|
|
|
func isM3U8(targetURL string, contentType string) bool {
|
|
lowerURL := strings.ToLower(targetURL)
|
|
lowerType := strings.ToLower(contentType)
|
|
if strings.Contains(lowerURL, ".m3u8") {
|
|
return true
|
|
}
|
|
|
|
return strings.Contains(lowerType, "application/vnd.apple.mpegurl") || strings.Contains(lowerType, "application/x-mpegurl")
|
|
}
|
|
|
|
func cloneHeaders(src http.Header) http.Header {
|
|
dst := make(http.Header)
|
|
for key, values := range src {
|
|
lower := strings.ToLower(key)
|
|
if lower == "connection" || lower == "transfer-encoding" || lower == "keep-alive" || lower == "proxy-authenticate" || lower == "proxy-authorization" || lower == "te" || lower == "trailers" || lower == "upgrade" {
|
|
continue
|
|
}
|
|
|
|
for _, value := range values {
|
|
dst.Add(key, value)
|
|
}
|
|
}
|
|
|
|
return dst
|
|
}
|