From 2d9f0f2b939c5a6ad17fbf3719788879834a3515 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Wed, 8 May 2024 21:53:57 +0800 Subject: [PATCH] Feat: alist subtitle support (#49) --- internal/cache/alist.go | 54 +++++++++++++++++++++++++++------------- server/handlers/movie.go | 30 ++++++++++++++-------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/internal/cache/alist.go b/internal/cache/alist.go index 450bd10..1e37331 100644 --- a/internal/cache/alist.go +++ b/internal/cache/alist.go @@ -13,6 +13,7 @@ import ( "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/vendor" + "github.com/synctv-org/synctv/utils" "github.com/synctv-org/vendors/api/alist" "github.com/zijiren233/gencontainer/refreshcache" "github.com/zijiren233/go-uhc" @@ -90,33 +91,34 @@ const ( AlistProvider115 = "115 Cloud" ) +type AlistSubtitle struct { + Name string + URL string + Type string + Cache *SubtitleDataCache +} + type AlistMovieCacheData struct { URL string - Subtitles map[string]string + Subtitles []*AlistSubtitle Provider string Ali *AlistAliCache } type AlistAliCache struct { M3U8ListFile []byte - Subtitles []*AliSubtitle -} - -type AliSubtitle struct { - Raw *alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscodingSubtitleTaskList - Cache *AliSubtitleCache } -type AliSubtitleCache = refreshcache.RefreshCache[[]byte, struct{}] +type SubtitleDataCache = refreshcache.RefreshCache[[]byte, struct{}] -func newAliSubtitlesCacheInitFunc(list []*alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscodingSubtitleTaskList) []*AliSubtitle { - caches := make([]*AliSubtitle, len(list)) +func newAliSubtitles(list []*alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscodingSubtitleTaskList) []*AlistSubtitle { + caches := make([]*AlistSubtitle, len(list)) for i, v := range list { if v.Status != "finished" { return nil } url := v.Url - caches[i] = &AliSubtitle{ + caches[i] = &AlistSubtitle{ Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) { r, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -132,7 +134,9 @@ func newAliSubtitlesCacheInitFunc(list []*alist.FsOtherResp_VideoPreviewPlayInfo } return io.ReadAll(resp.Body) }, 0), - Raw: v, + Name: v.Language, + URL: v.Url, + Type: utils.GetFileExtension(v.Url), } } return caches @@ -216,10 +220,26 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie) func(ctx context.Context, ar if err != nil { return nil, err } - if cache.Subtitles == nil { - cache.Subtitles = make(map[string]string) - } - cache.Subtitles[resp.Name] = resp.RawUrl + cache.Subtitles = append(cache.Subtitles, &AlistSubtitle{ + Name: related.Name, + URL: resp.RawUrl, + Type: utils.GetFileExtension(resp.Name), + Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) { + r, err := http.NewRequestWithContext(ctx, http.MethodGet, resp.RawUrl, nil) + if err != nil { + return nil, err + } + resp, err := uhc.Do(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("status code: %d", resp.StatusCode) + } + return io.ReadAll(resp.Body) + }, -1), + }) } } @@ -236,8 +256,8 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie) func(ctx context.Context, ar } cache.Ali = &AlistAliCache{ M3U8ListFile: genAliM3U8ListFile(fo.VideoPreviewPlayInfo.LiveTranscodingTaskList), - Subtitles: newAliSubtitlesCacheInitFunc(fo.VideoPreviewPlayInfo.LiveTranscodingSubtitleTaskList), } + cache.Subtitles = append(cache.Subtitles, newAliSubtitles(fo.VideoPreviewPlayInfo.LiveTranscodingSubtitleTaskList)...) } return cache, nil } diff --git a/server/handlers/movie.go b/server/handlers/movie.go index b12bdff..1fb7dcc 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -965,12 +965,12 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } - if id >= len(data.Ali.Subtitles) { + if id >= len(data.Subtitles) { log.Errorf("proxy vendor movie error: %v", "id out of range") ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("id out of range")) return } - data, err := data.Ali.Subtitles[id].Cache.Get(ctx) + data, err := data.Subtitles[id].Cache.Get(ctx) if err != nil { log.Errorf("proxy vendor movie error: %v", err) ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) @@ -1172,13 +1172,13 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA return nil, err } - for name, url := range data.Subtitles { + for _, subt := range data.Subtitles { if movie.Base.Subtitles == nil { movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles)) } - movie.Base.Subtitles[name] = &dbModel.Subtitle{ - URL: url, - Type: utils.GetFileExtension(name), + movie.Base.Subtitles[subt.Name] = &dbModel.Subtitle{ + URL: subt.URL, + Type: subt.Type, } } @@ -1194,15 +1194,16 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA movie.Base.Url = u.String() movie.Base.Type = "m3u8" - for i, s := range data.Ali.Subtitles { + for i, subt := range data.Subtitles { if movie.Base.Subtitles == nil { - movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Ali.Subtitles)) + movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles)) } - movie.Base.Subtitles[s.Raw.Language] = &dbModel.Subtitle{ + movie.Base.Subtitles[subt.Name] = &dbModel.Subtitle{ URL: fmt.Sprintf("/api/movie/proxy/%s/%s?t=subtitle&id=%d", movie.RoomID, movie.ID, i), - Type: utils.GetUrlExtension(s.Raw.Url), + Type: subt.Type, } } + case cache.AlistProvider115: if movie.Base.Proxy { rawPath, err := url.JoinPath("/api/movie/proxy", movie.RoomID, movie.ID) @@ -1214,6 +1215,8 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA } movie.Base.Url = u.String() movie.Base.Type = utils.GetUrlExtension(data.URL) + + // TODO: proxy subtitle } else { data, err = alistCache.GetRefreshFunc()(ctx, &cache.AlistMovieCacheFuncArgs{ UserCache: creator.Value().AlistCache(), @@ -1223,6 +1226,13 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA return nil, fmt.Errorf("refresh 115 movie cache error: %w", err) } movie.Base.Url = data.URL + movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles)) + for _, subt := range data.Subtitles { + movie.Base.Subtitles[subt.Name] = &dbModel.Subtitle{ + URL: subt.URL, + Type: subt.Type, + } + } } default: