From 1c02a6c00af4cb4e103abd9a9074ec2fd949b36f Mon Sep 17 00:00:00 2001 From: snowie2000 Date: Thu, 25 Jul 2024 16:12:31 +0800 Subject: [PATCH] added support for CORS request when ts is proxied. improved compatibility of proxied playlist --- handler/api.go | 10 +++++++++ handler/live.go | 6 ++++++ plugin/rtmp.go | 3 +++ route/route.go | 1 + service/m3u8.go | 57 +++++++++++++++++++++++-------------------------- 5 files changed, 47 insertions(+), 30 deletions(-) diff --git a/handler/api.go b/handler/api.go index cf64dcf..9f878bb 100644 --- a/handler/api.go +++ b/handler/api.go @@ -497,6 +497,16 @@ func LogoutHandler(c *gin.Context) { c.String(http.StatusOK, "") } +func CORSHandler(c *gin.Context) { + if strings.HasPrefix(c.Request.URL.Path, "/api") { + c.Status(http.StatusForbidden) + return + } + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "*") + c.Status(http.StatusOK) +} + func ChangePasswordHandler(c *gin.Context) { if sessions.Default(c).Get("logined") != true { c.String(http.StatusUnauthorized, "Unauthorized") diff --git a/handler/live.go b/handler/live.go index 8a65208..83f0a90 100644 --- a/handler/live.go +++ b/handler/live.go @@ -164,6 +164,8 @@ func LiveHandler(c *gin.Context) { global.M3U8Cache.Set(channelCacheKey, m3u8Body, 3*time.Second) } } + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "*") c.Data(http.StatusOK, "application/vnd.apple.mpegurl", []byte(m3u8Body)) } @@ -235,6 +237,8 @@ func M3U8ProxyHandler(c *gin.Context) { // make prefixURL from ourselves prefixUrl, _ := global.GetConfig("base_url") newList := service.M3U8Process(remoteURL, buffer.String(), prefixUrl, global.GetLiveToken(), true, nil) + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "*") c.Data(http.StatusOK, "application/vnd.apple.mpegurl", []byte(newList)) } @@ -299,6 +303,8 @@ func TsProxyHandler(c *gin.Context) { } } defer resp.Body.Close() + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "*") c.Writer.WriteHeader(resp.StatusCode) io.Copy(c.Writer, resp.Body) } diff --git a/plugin/rtmp.go b/plugin/rtmp.go index 5856fb8..ecc734b 100644 --- a/plugin/rtmp.go +++ b/plugin/rtmp.go @@ -28,6 +28,9 @@ func (p *RTMPParser) Host(c *gin.Context, info *model.LiveInfo) error { log.Println("Start transcoding", info.LiveUrl) defer conn.Close() defer log.Println("Transcoding finished") + + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "*") c.Writer.Header().Set("Content-Type", "video/x-flv") c.Writer.Header().Set("Transfer-Encoding", "chunked") c.Writer.WriteHeader(200) diff --git a/route/route.go b/route/route.go index 6e225bd..f089d52 100644 --- a/route/route.go +++ b/route/route.go @@ -6,6 +6,7 @@ import ( ) func Register(r *gin.Engine) { + r.OPTIONS("/", handler.CORSHandler) r.GET("/lives.m3u", handler.M3UHandler) r.GET("/live.m3u8", handler.LiveHandler) r.HEAD("/live.m3u8", handler.LivePreHandler) diff --git a/service/m3u8.go b/service/m3u8.go index 4803b47..534392a 100644 --- a/service/m3u8.go +++ b/service/m3u8.go @@ -1,7 +1,6 @@ package service import ( - "bufio" "bytes" "fmt" "github.com/grafov/m3u8" @@ -54,37 +53,37 @@ func cleanUrl(Url string) string { return cleanURL } -func processMediaPlaylist(playlistUrl string, data string, prefixURL string, proxy bool, fnTransform func(raw string, ts string) string) string { - var sb strings.Builder - scanner := bufio.NewScanner(strings.NewReader(data)) +func processMediaPlaylist(playlistUrl string, pl *m3u8.MediaPlaylist, prefixURL string, proxyToken string, proxy bool, fnTransform func(raw string, ts string) string) string { baseUrl := global.GetBaseURL(playlistUrl) - for scanner.Scan() { - l := strings.TrimSpace(scanner.Text()) - if l == "" { - continue + handleUri := func(uri string) string { + if uri == "" { + return uri } - if strings.HasPrefix(l, "#") { - sb.WriteString(l) - } else { - if !global.IsValidURL(l) { - l = cleanUrl(global.MergeUrl(baseUrl, l)) - } - if proxy { - tsLink := prefixURL + util.CompressString(l) - if fnTransform != nil { - tsLink = fnTransform(l, tsLink) - } - sb.WriteString(tsLink) - } else { - sb.WriteString(l) + if !global.IsValidURL(uri) { + uri = cleanUrl(global.MergeUrl(baseUrl, uri)) + } + if proxy { + tsLink := global.MergeUrl(prefixURL, "/live.ts?token="+proxyToken+"&k="+util.CompressString(uri)) + if fnTransform != nil { + tsLink = fnTransform(uri, tsLink) } + uri = tsLink } - sb.WriteString("\n") + return uri } - return sb.String() + + var i uint + for i = pl.Count() - pl.WinSize(); i < pl.Count(); i++ { + pl.Segments[i].URI = handleUri(pl.Segments[i].URI) + } + // remove unused segments + for pl.Count() > pl.WinSize() { + pl.Remove() + } + return pl.Encode().String() } -func processMasterPlaylist(playlistUrl string, pl *m3u8.MasterPlaylist, prefixURL string, proxy bool, fnTransform func(raw string, ts string) string) string { +func processMasterPlaylist(playlistUrl string, pl *m3u8.MasterPlaylist, prefixURL string, proxyToken string, proxy bool, fnTransform func(raw string, ts string) string) string { baseUrl := global.GetBaseURL(playlistUrl) handleUri := func(uri string) string { if uri == "" { @@ -94,7 +93,7 @@ func processMasterPlaylist(playlistUrl string, pl *m3u8.MasterPlaylist, prefixUR uri = cleanUrl(global.MergeUrl(baseUrl, uri)) } if proxy { - plLink := prefixURL + util.CompressString(uri) + plLink := global.MergeUrl(prefixURL, "/playlist.m3u8?token="+proxyToken+"&k="+util.CompressString(uri)) if fnTransform != nil { plLink = fnTransform(uri, plLink) } @@ -119,11 +118,9 @@ func M3U8Process(playlistUrl string, data string, prefixURL string, proxyToken s if err == nil { switch listType { case m3u8.MASTER: - prefixURL = prefixURL + "/playlist.m3u8?token=" + proxyToken + "&k=" - return processMasterPlaylist(playlistUrl, p.(*m3u8.MasterPlaylist), prefixURL, proxy, fnTransform) + return processMasterPlaylist(playlistUrl, p.(*m3u8.MasterPlaylist), prefixURL, proxyToken, proxy, fnTransform) case m3u8.MEDIA: - prefixURL = prefixURL + "/live.ts?token=" + proxyToken + "&k=" - return processMediaPlaylist(playlistUrl, data, prefixURL, proxy, fnTransform) + return processMediaPlaylist(playlistUrl, p.(*m3u8.MediaPlaylist), prefixURL, proxyToken, proxy, fnTransform) } } return ""