Feat: alist subtitle support (#49)

pull/150/head
zijiren233 10 months ago
parent 45d036a36d
commit 2d9f0f2b93

@ -13,6 +13,7 @@ import (
"github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/internal/vendor" "github.com/synctv-org/synctv/internal/vendor"
"github.com/synctv-org/synctv/utils"
"github.com/synctv-org/vendors/api/alist" "github.com/synctv-org/vendors/api/alist"
"github.com/zijiren233/gencontainer/refreshcache" "github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/go-uhc" "github.com/zijiren233/go-uhc"
@ -90,33 +91,34 @@ const (
AlistProvider115 = "115 Cloud" AlistProvider115 = "115 Cloud"
) )
type AlistSubtitle struct {
Name string
URL string
Type string
Cache *SubtitleDataCache
}
type AlistMovieCacheData struct { type AlistMovieCacheData struct {
URL string URL string
Subtitles map[string]string Subtitles []*AlistSubtitle
Provider string Provider string
Ali *AlistAliCache Ali *AlistAliCache
} }
type AlistAliCache struct { type AlistAliCache struct {
M3U8ListFile []byte 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 { func newAliSubtitles(list []*alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscodingSubtitleTaskList) []*AlistSubtitle {
caches := make([]*AliSubtitle, len(list)) caches := make([]*AlistSubtitle, len(list))
for i, v := range list { for i, v := range list {
if v.Status != "finished" { if v.Status != "finished" {
return nil return nil
} }
url := v.Url url := v.Url
caches[i] = &AliSubtitle{ caches[i] = &AlistSubtitle{
Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) { Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) {
r, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) r, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil { if err != nil {
@ -132,7 +134,9 @@ func newAliSubtitlesCacheInitFunc(list []*alist.FsOtherResp_VideoPreviewPlayInfo
} }
return io.ReadAll(resp.Body) return io.ReadAll(resp.Body)
}, 0), }, 0),
Raw: v, Name: v.Language,
URL: v.Url,
Type: utils.GetFileExtension(v.Url),
} }
} }
return caches return caches
@ -216,10 +220,26 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie) func(ctx context.Context, ar
if err != nil { if err != nil {
return nil, err return nil, err
} }
if cache.Subtitles == nil { cache.Subtitles = append(cache.Subtitles, &AlistSubtitle{
cache.Subtitles = make(map[string]string) Name: related.Name,
} URL: resp.RawUrl,
cache.Subtitles[resp.Name] = 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{ cache.Ali = &AlistAliCache{
M3U8ListFile: genAliM3U8ListFile(fo.VideoPreviewPlayInfo.LiveTranscodingTaskList), M3U8ListFile: genAliM3U8ListFile(fo.VideoPreviewPlayInfo.LiveTranscodingTaskList),
Subtitles: newAliSubtitlesCacheInitFunc(fo.VideoPreviewPlayInfo.LiveTranscodingSubtitleTaskList),
} }
cache.Subtitles = append(cache.Subtitles, newAliSubtitles(fo.VideoPreviewPlayInfo.LiveTranscodingSubtitleTaskList)...)
} }
return cache, nil return cache, nil
} }

@ -965,12 +965,12 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) {
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return return
} }
if id >= len(data.Ali.Subtitles) { if id >= len(data.Subtitles) {
log.Errorf("proxy vendor movie error: %v", "id out of range") log.Errorf("proxy vendor movie error: %v", "id out of range")
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("id out of range")) ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("id out of range"))
return return
} }
data, err := data.Ali.Subtitles[id].Cache.Get(ctx) data, err := data.Subtitles[id].Cache.Get(ctx)
if err != nil { if err != nil {
log.Errorf("proxy vendor movie error: %v", err) log.Errorf("proxy vendor movie error: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(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 return nil, err
} }
for name, url := range data.Subtitles { for _, subt := range data.Subtitles {
if movie.Base.Subtitles == nil { if movie.Base.Subtitles == nil {
movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles)) movie.Base.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles))
} }
movie.Base.Subtitles[name] = &dbModel.Subtitle{ movie.Base.Subtitles[subt.Name] = &dbModel.Subtitle{
URL: url, URL: subt.URL,
Type: utils.GetFileExtension(name), 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.Url = u.String()
movie.Base.Type = "m3u8" movie.Base.Type = "m3u8"
for i, s := range data.Ali.Subtitles { for i, subt := range data.Subtitles {
if movie.Base.Subtitles == nil { 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), 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: case cache.AlistProvider115:
if movie.Base.Proxy { if movie.Base.Proxy {
rawPath, err := url.JoinPath("/api/movie/proxy", movie.RoomID, movie.ID) 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.Url = u.String()
movie.Base.Type = utils.GetUrlExtension(data.URL) movie.Base.Type = utils.GetUrlExtension(data.URL)
// TODO: proxy subtitle
} else { } else {
data, err = alistCache.GetRefreshFunc()(ctx, &cache.AlistMovieCacheFuncArgs{ data, err = alistCache.GetRefreshFunc()(ctx, &cache.AlistMovieCacheFuncArgs{
UserCache: creator.Value().AlistCache(), 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) return nil, fmt.Errorf("refresh 115 movie cache error: %w", err)
} }
movie.Base.Url = data.URL 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: default:

Loading…
Cancel
Save