Opt: cache type and bilibili cache

pull/40/head
zijiren233 2 years ago
parent 46e470eecb
commit 568efd9623

@ -28,7 +28,7 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/soheilhy/cmux v0.1.5
github.com/spf13/cobra v1.8.0
github.com/synctv-org/vendors v0.1.1-0.20231123042423-562f72cd9f91
github.com/synctv-org/vendors v0.1.1-0.20231203064919-c8eeb877a780
github.com/ulule/limiter/v3 v3.11.2
github.com/zencoder/go-dash/v3 v3.0.3
github.com/zijiren233/gencontainer v0.0.0-20231108115721-8d4bb333a5bc

@ -350,6 +350,10 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/synctv-org/vendors v0.1.1-0.20231123042423-562f72cd9f91 h1:NmpHW9fzZOsbh6oLEbL596eBbEwiqfcCr0uZ3LkYBX0=
github.com/synctv-org/vendors v0.1.1-0.20231123042423-562f72cd9f91/go.mod h1:DQHEXvrsnX9Ke6B0KVJ+w8uMgM/DZKNkvi6cJmRn+zk=
github.com/synctv-org/vendors v0.1.1-0.20231203062458-863dbc08c39d h1:FLjsoPTIUjrwsEKcISzbwmY5/4BUzqydYMaj3lp2aA8=
github.com/synctv-org/vendors v0.1.1-0.20231203062458-863dbc08c39d/go.mod h1:DQHEXvrsnX9Ke6B0KVJ+w8uMgM/DZKNkvi6cJmRn+zk=
github.com/synctv-org/vendors v0.1.1-0.20231203064919-c8eeb877a780 h1:59T2DtbXn8qkW986k+spwTlQlx8Wl1hmD2zZDYWHv5s=
github.com/synctv-org/vendors v0.1.1-0.20231203064919-c8eeb877a780/go.mod h1:DQHEXvrsnX9Ke6B0KVJ+w8uMgM/DZKNkvi6cJmRn+zk=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=

@ -30,23 +30,16 @@ type Movie struct {
}
type BaseCache struct {
lock sync.RWMutex
url map[string]*refreshcache.RefreshCache[string]
mpd map[string]*refreshcache.RefreshCache[*MPDCache]
lock sync.RWMutex
cache map[string]*refreshcache.RefreshCache[any]
}
func newBaseCache() *BaseCache {
return &BaseCache{
url: make(map[string]*refreshcache.RefreshCache[string]),
mpd: make(map[string]*refreshcache.RefreshCache[*MPDCache]),
cache: make(map[string]*refreshcache.RefreshCache[any]),
}
}
type MPDCache struct {
MPDFile string
URLs []string
}
func (b *BaseCache) Clear() {
b.lock.Lock()
defer b.lock.Unlock()
@ -54,13 +47,12 @@ func (b *BaseCache) Clear() {
}
func (b *BaseCache) clear() {
b.mpd = nil
maps.Clear(b.url)
maps.Clear(b.cache)
}
func (b *BaseCache) InitOrLoadURLCache(id string, refreshFunc func() (string, error), maxAge time.Duration) (*refreshcache.RefreshCache[string], error) {
func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), maxAge time.Duration) (*refreshcache.RefreshCache[any], error) {
b.lock.RLock()
c, loaded := b.url[id]
c, loaded := b.cache[id]
if loaded {
b.lock.RUnlock()
return c, nil
@ -69,33 +61,13 @@ func (b *BaseCache) InitOrLoadURLCache(id string, refreshFunc func() (string, er
b.lock.Lock()
defer b.lock.Unlock()
c, loaded = b.url[id]
if loaded {
return c, nil
}
c = refreshcache.NewRefreshCache[string](refreshFunc, maxAge)
b.url[id] = c
return c, nil
}
func (b *BaseCache) InitOrLoadMPDCache(id string, refreshFunc func() (*MPDCache, error), maxAge time.Duration) (*refreshcache.RefreshCache[*MPDCache], error) {
b.lock.RLock()
c, loaded := b.mpd[id]
if loaded {
return c, nil
}
b.lock.RUnlock()
b.lock.Lock()
defer b.lock.Unlock()
c, loaded = b.mpd[id]
c, loaded = b.cache[id]
if loaded {
return c, nil
}
c = refreshcache.NewRefreshCache[*MPDCache](refreshFunc, maxAge)
b.mpd[id] = c
c = refreshcache.NewRefreshCache[any](refreshFunc, maxAge)
b.cache[id] = c
return c, nil
}

@ -468,17 +468,22 @@ func ProxyMovie(ctx *gin.Context) {
switch m.Movie.Base.Type {
case "mpd":
mpdCache, err := m.Cache().InitOrLoadMPDCache("", initDashCache(ctx, &m.Movie), time.Minute*5)
mpdCache, err := m.Cache().InitOrLoadCache("", initDashCache(ctx, &m.Movie), time.Minute*5)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
mpd, err := mpdCache.Get()
mpdI, err := mpdCache.Get()
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
ctx.Data(http.StatusOK, "application/dash+xml", []byte(mpd.MPDFile))
mpd, ok := mpdI.(string)
if !ok {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorStringResp("cache type error"))
return
}
ctx.Data(http.StatusOK, "application/dash+xml", []byte(mpd))
return
default:
err = proxyURL(ctx, m.Movie.Base.Url, m.Movie.Base.Headers)
@ -490,8 +495,8 @@ func ProxyMovie(ctx *gin.Context) {
}
// only cache mpd file
func initDashCache(ctx context.Context, movie *dbModel.Movie) func() (*op.MPDCache, error) {
return func() (*op.MPDCache, error) {
func initDashCache(ctx context.Context, movie *dbModel.Movie) func() (any, error) {
return func() (any, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, movie.Base.Url, nil)
if err != nil {
return nil, err
@ -524,9 +529,7 @@ func initDashCache(ctx context.Context, movie *dbModel.Movie) func() (*op.MPDCac
if err != nil {
return nil, err
}
return &op.MPDCache{
MPDFile: s,
}, nil
return s, nil
}
}
@ -661,20 +664,25 @@ func JoinLive(ctx *gin.Context) {
}
}
func initBilibiliMPDCache(ctx context.Context, hevc bool, roomID, movieID, CreatorID string, info *dbModel.BilibiliVendorInfo) func() (*op.MPDCache, error) {
return func() (*op.MPDCache, error) {
type bilibiliCache struct {
mpd string
hevcMpd string
urls []string
}
func initBilibiliMPDCache(ctx context.Context, roomID, movieID, CreatorID string, info *dbModel.BilibiliVendorInfo) func() (any, error) {
return func() (any, error) {
v, err := db.FirstOrInitVendorByUserIDAndVendor(CreatorID, dbModel.StreamingVendorBilibili)
if err != nil {
return nil, err
}
cli := vendor.BilibiliClient(info.VendorName)
var m *mpd.MPD
var m, hevcM *mpd.MPD
if info.Bvid != "" && info.Cid != 0 {
resp, err := cli.GetDashVideoURL(ctx, &bilibili.GetDashVideoURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Bvid: info.Bvid,
Cid: info.Cid,
Hevc: hevc,
})
if err != nil {
return nil, err
@ -683,11 +691,15 @@ func initBilibiliMPDCache(ctx context.Context, hevc bool, roomID, movieID, Creat
if err != nil {
return nil, err
}
hevcM, err = mpd.ReadFromString(resp.HevcMpd)
if err != nil {
return nil, err
}
} else if info.Epid != 0 {
resp, err := cli.GetDashPGCURL(ctx, &bilibili.GetDashPGCURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Epid: info.Epid,
Hevc: hevc,
})
if err != nil {
return nil, err
@ -696,6 +708,11 @@ func initBilibiliMPDCache(ctx context.Context, hevc bool, roomID, movieID, Creat
if err != nil {
return nil, err
}
hevcM, err = mpd.ReadFromString(resp.HevcMpd)
if err != nil {
return nil, err
}
} else {
return nil, errors.New("bvid and epid are empty")
}
@ -707,11 +724,18 @@ func initBilibiliMPDCache(ctx context.Context, hevc bool, roomID, movieID, Creat
for _, r := range as.Representations {
for i := range r.BaseURL {
movies = append(movies, r.BaseURL[i])
if hevc {
r.BaseURL[i] = fmt.Sprintf("%s?id=%d&t=hevc", movieID, id)
} else {
r.BaseURL[i] = fmt.Sprintf("%s?id=%d", movieID, id)
}
r.BaseURL[i] = fmt.Sprintf("%s?id=%d", movieID, id)
id++
}
}
}
}
for _, p := range hevcM.Periods {
for _, as := range p.AdaptationSets {
for _, r := range as.Representations {
for i := range r.BaseURL {
movies = append(movies, r.BaseURL[i])
r.BaseURL[i] = fmt.Sprintf("%s?id=%d&t=hevc", movieID, id)
id++
}
}
@ -721,15 +745,20 @@ func initBilibiliMPDCache(ctx context.Context, hevc bool, roomID, movieID, Creat
if err != nil {
return nil, err
}
return &op.MPDCache{
URLs: movies,
MPDFile: s,
s2, err := hevcM.WriteToString()
if err != nil {
return nil, err
}
return &bilibiliCache{
urls: movies,
mpd: s,
hevcMpd: s2,
}, nil
}
}
func initBilibiliShareCache(ctx context.Context, CreatorID string, info *dbModel.BilibiliVendorInfo) func() (string, error) {
return func() (string, error) {
func initBilibiliShareCache(ctx context.Context, CreatorID string, info *dbModel.BilibiliVendorInfo) func() (any, error) {
return func() (any, error) {
v, err := db.FirstOrInitVendorByUserIDAndVendor(CreatorID, dbModel.StreamingVendorBilibili)
if err != nil {
return "", err
@ -769,18 +798,27 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) {
if t != "hevc" {
t = ""
}
bvc, err := movie.Cache().InitOrLoadMPDCache(t, initBilibiliMPDCache(ctx, t == "hevc", movie.Movie.RoomID, movie.Movie.ID, movie.Movie.CreatorID, movie.Movie.Base.VendorInfo.Bilibili), time.Minute*119)
bvc, err := movie.Cache().InitOrLoadCache(t, initBilibiliMPDCache(ctx, movie.Movie.RoomID, movie.Movie.ID, movie.Movie.CreatorID, movie.Movie.Base.VendorInfo.Bilibili), time.Minute*119)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
mpd, err := bvc.Get()
mpdI, err := bvc.Get()
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
mpd, ok := mpdI.(*bilibiliCache)
if !ok {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorStringResp("cache type error"))
return
}
if id := ctx.Query("id"); id == "" {
ctx.Data(http.StatusOK, "application/dash+xml", []byte(mpd.MPDFile))
if t == "hevc" {
ctx.Data(http.StatusOK, "application/dash+xml", []byte(mpd.hevcMpd))
} else {
ctx.Data(http.StatusOK, "application/dash+xml", []byte(mpd.mpd))
}
return
} else {
streamId, err := strconv.Atoi(id)
@ -788,11 +826,11 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) {
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
if streamId >= len(mpd.URLs) {
if streamId >= len(mpd.urls) {
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("stream id out of range"))
return
}
proxyURL(ctx, mpd.URLs[streamId], movie.Movie.Base.Headers)
proxyURL(ctx, mpd.urls[streamId], movie.Movie.Base.Headers)
return
}
@ -810,16 +848,21 @@ func parse2VendorMovie(ctx context.Context, userID string, movie *op.Movie) (err
switch movie.Movie.Base.VendorInfo.Vendor {
case dbModel.StreamingVendorBilibili:
if !movie.Movie.Base.Proxy {
c, err := movie.Cache().InitOrLoadURLCache(userID, initBilibiliShareCache(ctx, movie.Movie.CreatorID, movie.Movie.Base.VendorInfo.Bilibili), time.Minute*119)
c, err := movie.Cache().InitOrLoadCache(userID, initBilibiliShareCache(ctx, movie.Movie.CreatorID, movie.Movie.Base.VendorInfo.Bilibili), time.Minute*119)
if err != nil {
return err
}
data, err := c.Get()
dataI, err := c.Get()
if err != nil {
return err
}
data, ok := dataI.(string)
if !ok {
return errors.New("cache type error")
}
movie.Movie.Base.Url = data
} else {
movie.Movie.Base.Type = "mpd"

Loading…
Cancel
Save