diff --git a/server/handlers/movie.go b/server/handlers/movie.go index 2fe344e..0e11792 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -600,7 +600,15 @@ func ProxyMovie(ctx *gin.Context) { // TODO: cache mpd file fallthrough default: - err = proxy.AutoProxyURL(ctx, m.Movie.MovieBase.Url, m.Movie.MovieBase.Type, m.Movie.MovieBase.Headers, true, ctx.GetString("token"), room.ID, m.ID) + err = proxy.AutoProxyURL(ctx, + m.Movie.MovieBase.Url, + m.Movie.MovieBase.Type, + m.Movie.MovieBase.Headers, + ctx.GetString("token"), + room.ID, + m.ID, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy movie error: %v", err) return @@ -654,7 +662,15 @@ func ServeM3u8(ctx *gin.Context) { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("invalid token")) return } - err = proxy.ProxyM3u8(ctx, claims.TargetUrl, m.Movie.MovieBase.Headers, true, claims.IsM3u8File, ctx.GetString("token"), room.ID, m.ID) + err = proxy.ProxyM3u8(ctx, + claims.TargetUrl, + m.Movie.MovieBase.Headers, + claims.IsM3u8File, + ctx.GetString("token"), + room.ID, + m.ID, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy m3u8 error: %v", err) } @@ -785,7 +801,15 @@ func JoinHlsLive(ctx *gin.Context) { } if utils.IsM3u8Url(m.Movie.MovieBase.Url) { - err = proxy.ProxyM3u8(ctx, m.Movie.MovieBase.Url, m.Movie.MovieBase.Headers, true, true, ctx.GetString("token"), room.ID, m.ID) + err = proxy.ProxyM3u8(ctx, + m.Movie.MovieBase.Url, + m.Movie.MovieBase.Headers, + true, + ctx.GetString("token"), + room.ID, + m.ID, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy m3u8 hls live error: %v", err) } diff --git a/server/handlers/proxy/m3u8.go b/server/handlers/proxy/m3u8.go index b235e15..c3a09cd 100644 --- a/server/handlers/proxy/m3u8.go +++ b/server/handlers/proxy/m3u8.go @@ -56,9 +56,9 @@ func NewM3u8TargetToken(targetUrl, roomId, movieId string, isM3u8File bool) (str const maxM3u8FileSize = 3 * 1024 * 1024 // // only cache non-m3u8 files -func ProxyM3u8(ctx *gin.Context, u string, headers map[string]string, cache bool, isM3u8File bool, token, roomId, movieId string) error { +func ProxyM3u8(ctx *gin.Context, u string, headers map[string]string, isM3u8File bool, token, roomId, movieId string, opts ...ProxyURLOption) error { if !isM3u8File { - return ProxyURL(ctx, u, headers, cache) + return ProxyURL(ctx, u, headers, opts...) } req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) diff --git a/server/handlers/proxy/proxy.go b/server/handlers/proxy/proxy.go index 4a7e213..fb33e4a 100644 --- a/server/handlers/proxy/proxy.go +++ b/server/handlers/proxy/proxy.go @@ -77,7 +77,35 @@ func getCache() Cache { return defaultCache } -func ProxyURL(ctx *gin.Context, u string, headers map[string]string, cache bool) error { +type ProxyURLOptions struct { + CacheKey string + Cache bool +} + +type ProxyURLOption func(o *ProxyURLOptions) + +func WithProxyURLCache(cache bool) ProxyURLOption { + return func(o *ProxyURLOptions) { + o.Cache = cache + } +} + +func WithProxyURLCacheKey(key string) ProxyURLOption { + return func(o *ProxyURLOptions) { + o.CacheKey = key + } +} + +func NewProxyURLOptions(opts ...ProxyURLOption) *ProxyURLOptions { + o := &ProxyURLOptions{} + for _, opt := range opts { + opt(o) + } + return o +} + +func ProxyURL(ctx *gin.Context, u string, headers map[string]string, opts ...ProxyURLOption) error { + o := NewProxyURLOptions(opts...) if !settings.AllowProxyToLocal.Get() { if l, err := utils.ParseURLIsLocalIP(u); err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, @@ -96,7 +124,7 @@ func ProxyURL(ctx *gin.Context, u string, headers map[string]string, cache bool) } } - if cache && settings.ProxyCacheEnable.Get() { + if o.Cache && settings.ProxyCacheEnable.Get() { c, cancel := context.WithCancel(ctx) defer cancel() rsc := NewHttpReadSeekCloser(u, @@ -105,7 +133,10 @@ func ProxyURL(ctx *gin.Context, u string, headers map[string]string, cache bool) WithNotSupportRange(ctx.GetHeader("Range") == ""), ) defer rsc.Close() - return NewSliceCacheProxy(u, 1024*512, rsc, getCache()). + if o.CacheKey == "" { + o.CacheKey = u + } + return NewSliceCacheProxy(o.CacheKey, 1024*512, rsc, getCache()). Proxy(ctx.Writer, ctx.Request) } @@ -179,9 +210,9 @@ func ProxyURL(ctx *gin.Context, u string, headers map[string]string, cache bool) return nil } -func AutoProxyURL(ctx *gin.Context, u, t string, headers map[string]string, cache bool, token, roomId, movieId string) error { +func AutoProxyURL(ctx *gin.Context, u, t string, headers map[string]string, token, roomId, movieId string, opts ...ProxyURLOption) error { if strings.HasPrefix(t, "m3u") || utils.IsM3u8Url(u) { - return ProxyM3u8(ctx, u, headers, cache, true, token, roomId, movieId) + return ProxyM3u8(ctx, u, headers, true, token, roomId, movieId, opts...) } - return ProxyURL(ctx, u, headers, cache) + return ProxyURL(ctx, u, headers, opts...) } diff --git a/server/handlers/vendors/vendorAlist/alist.go b/server/handlers/vendors/vendorAlist/alist.go index 780f342..509d5cc 100644 --- a/server/handlers/vendors/vendorAlist/alist.go +++ b/server/handlers/vendors/vendorAlist/alist.go @@ -134,7 +134,15 @@ func (s *alistVendorService) ProxyMovie(ctx *gin.Context) { ctx.Data(http.StatusOK, "audio/mpegurl", data.Ali.M3U8ListFile) return case "raw": - err := proxy.AutoProxyURL(ctx, data.URL, s.movie.MovieBase.Type, nil, true, ctx.GetString("token"), s.movie.RoomID, s.movie.ID) + err := proxy.AutoProxyURL(ctx, + data.URL, + s.movie.MovieBase.Type, + nil, + ctx.GetString("token"), + s.movie.RoomID, + s.movie.ID, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy vendor movie error: %v", err) } @@ -173,7 +181,15 @@ func (s *alistVendorService) ProxyMovie(ctx *gin.Context) { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("proxy is not enabled")) return } - err = proxy.AutoProxyURL(ctx, data.URL, s.movie.MovieBase.Type, nil, true, ctx.GetString("token"), s.movie.RoomID, s.movie.ID) + err = proxy.AutoProxyURL(ctx, + data.URL, + s.movie.MovieBase.Type, + nil, + ctx.GetString("token"), + s.movie.RoomID, + s.movie.ID, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy vendor movie error: %v", err) } diff --git a/server/handlers/vendors/vendorBilibili/bilibili.go b/server/handlers/vendors/vendorBilibili/bilibili.go index f8e2b09..64f1c34 100644 --- a/server/handlers/vendors/vendorBilibili/bilibili.go +++ b/server/handlers/vendors/vendorBilibili/bilibili.go @@ -127,7 +127,11 @@ func (s *bilibiliVendorService) ProxyMovie(ctx *gin.Context) { headers["Referer"] = "https://www.bilibili.com" headers["User-Agent"] = utils.UA } - err = proxy.ProxyURL(ctx, mpdC.Urls[streamId], headers, true) + err = proxy.ProxyURL(ctx, + mpdC.Urls[streamId], + headers, + proxy.WithProxyURLCache(true), + ) if err != nil { log.Errorf("proxy vendor movie [%s] error: %v", mpdC.Urls[streamId], err) } diff --git a/server/handlers/vendors/vendorEmby/emby.go b/server/handlers/vendors/vendorEmby/emby.go index dd69cda..a6eda17 100644 --- a/server/handlers/vendors/vendorEmby/emby.go +++ b/server/handlers/vendors/vendorEmby/emby.go @@ -145,7 +145,27 @@ func (s *embyVendorService) ProxyMovie(ctx *gin.Context) { ctx.Redirect(http.StatusFound, embyC.Sources[source].URL) return } - err = proxy.AutoProxyURL(ctx, embyC.Sources[source].URL, "", nil, true, ctx.GetString("token"), s.movie.RoomID, s.movie.ID) + // ignore DeviceId, PlaySessionId as cache key + sourceCacheKey, err := url.Parse(embyC.Sources[source].URL) + if err != nil { + log.Errorf("proxy vendor movie error: %v", err) + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } + query := sourceCacheKey.Query() + query.Del("DeviceId") + query.Del("PlaySessionId") + sourceCacheKey.RawQuery = query.Encode() + err = proxy.AutoProxyURL(ctx, + embyC.Sources[source].URL, + "", + nil, + ctx.GetString("token"), + s.movie.RoomID, + s.movie.ID, + proxy.WithProxyURLCache(true), + proxy.WithProxyURLCacheKey(sourceCacheKey.String()), + ) if err != nil { log.Errorf("proxy vendor movie error: %v", err) }