Fix: cache and vendor db error

pull/43/head
zijiren233 2 years ago
parent 6ce728381b
commit 2875f44606

@ -286,9 +286,15 @@ func WhereRoomUserStatus(status model.RoomUserStatus) func(db *gorm.DB) *gorm.DB
}
}
type ErrNotFound string
func (e ErrNotFound) Error() string {
return fmt.Sprintf("%s not found", string(e))
}
func HandleNotFound(err error, errMsg ...string) error {
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("%s not found", strings.Join(errMsg, " "))
return ErrNotFound(strings.Join(errMsg, " "))
}
return err
}

@ -12,7 +12,6 @@ import (
"github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/internal/settings"
"github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/livelib/av"
"github.com/zijiren233/livelib/container/flv"
"github.com/zijiren233/livelib/protocol/hls"
@ -31,12 +30,12 @@ type Movie struct {
type BaseCache struct {
lock sync.RWMutex
cache map[string]*refreshcache.RefreshCache[any]
cache map[string]any
}
func newBaseCache() *BaseCache {
return &BaseCache{
cache: make(map[string]*refreshcache.RefreshCache[any]),
cache: make(map[string]any),
}
}
@ -50,7 +49,7 @@ func (b *BaseCache) clear() {
maps.Clear(b.cache)
}
func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), maxAge time.Duration) (*refreshcache.RefreshCache[any], error) {
func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error), maxAge time.Duration) (any, error) {
b.lock.RLock()
c, loaded := b.cache[id]
if loaded {
@ -66,7 +65,10 @@ func (b *BaseCache) InitOrLoadCache(id string, refreshFunc func() (any, error),
return c, nil
}
c = refreshcache.NewRefreshCache[any](refreshFunc, maxAge)
c, err := refreshFunc()
if err != nil {
return nil, err
}
b.cache[id] = c
return c, nil
}

@ -469,12 +469,7 @@ func ProxyMovie(ctx *gin.Context) {
switch m.Movie.Base.Type {
case "mpd":
mpdCache, err := m.Cache().InitOrLoadCache("", initDashCache(ctx, &m.Movie), time.Minute*5)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
mpdI, err := mpdCache.Get()
mpdI, err := m.Cache().InitOrLoadCache("", initDashCache(ctx, &m.Movie), time.Minute*5)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
@ -673,16 +668,21 @@ type bilibiliCache struct {
func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any, error) {
return func() (any, error) {
v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili)
var cookies []*http.Cookie
vendorInfo, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili)
if err != nil {
return nil, err
if !errors.Is(err, db.ErrNotFound("vendor")) {
return nil, err
}
} else {
cookies = vendorInfo.Cookies
}
cli := vendor.BilibiliClient(movie.Base.VendorInfo.Backend)
var m, hevcM *mpd.MPD
biliInfo := movie.Base.VendorInfo.Bilibili
if biliInfo.Bvid != "" && biliInfo.Cid != 0 {
resp, err := cli.GetDashVideoURL(ctx, &bilibili.GetDashVideoURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Bvid: biliInfo.Bvid,
Cid: biliInfo.Cid,
})
@ -700,7 +700,7 @@ func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any,
} else if biliInfo.Epid != 0 {
resp, err := cli.GetDashPGCURL(ctx, &bilibili.GetDashPGCURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Epid: biliInfo.Epid,
})
if err != nil {
@ -761,34 +761,39 @@ func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any,
func initBilibiliShareCache(ctx context.Context, movie dbModel.Movie) func() (any, error) {
return func() (any, error) {
v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili)
var cookies []*http.Cookie
vendorInfo, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili)
if err != nil {
return "", err
if !errors.Is(err, db.ErrNotFound("vendor")) {
return nil, err
}
} else {
cookies = vendorInfo.Cookies
}
cli := vendor.BilibiliClient(movie.Base.VendorInfo.Backend)
var u string
biliInfo := movie.Base.VendorInfo.Bilibili
if biliInfo.Bvid != "" {
resp, err := cli.GetVideoURL(ctx, &bilibili.GetVideoURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Bvid: biliInfo.Bvid,
Cid: biliInfo.Cid,
})
if err != nil {
return "", err
return nil, err
}
u = resp.Url
} else if biliInfo.Epid != 0 {
resp, err := cli.GetPGCURL(ctx, &bilibili.GetPGCURLReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Epid: biliInfo.Epid,
})
if err != nil {
return "", err
return nil, err
}
u = resp.Url
} else {
return "", errors.New("bvid and epid are empty")
return nil, errors.New("bvid and epid are empty")
}
return u, nil
}
@ -800,7 +805,7 @@ type alistCache struct {
func initAlistCache(ctx context.Context, movie dbModel.Movie) func() (any, error) {
return func() (any, error) {
v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorAlist)
v, err := db.GetVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorAlist)
if err != nil {
return nil, err
}
@ -849,12 +854,7 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) {
if t != "hevc" {
t = ""
}
bvc, err := movie.Cache().InitOrLoadCache(t, initBilibiliMPDCache(ctx, movie.Movie), time.Minute*119)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
mpdI, err := bvc.Get()
mpdI, err := movie.Cache().InitOrLoadCache(t, initBilibiliMPDCache(ctx, movie.Movie), time.Minute*119)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
@ -899,12 +899,7 @@ 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 {
cache, err := movie.Cache().InitOrLoadCache(userID, initBilibiliShareCache(ctx, movie.Movie), time.Minute*119)
if err != nil {
return err
}
dataI, err := cache.Get()
dataI, err := movie.Cache().InitOrLoadCache(userID, initBilibiliShareCache(ctx, movie.Movie), time.Minute*119)
if err != nil {
return err
}
@ -921,12 +916,7 @@ func parse2VendorMovie(ctx context.Context, userID string, movie *op.Movie) (err
return nil
case dbModel.StreamingVendorAlist:
cache, err := movie.Cache().InitOrLoadCache("", initAlistCache(ctx, movie.Movie), time.Minute*15)
if err != nil {
return err
}
dataI, err := cache.Get()
dataI, err := movie.Cache().InitOrLoadCache("", initAlistCache(ctx, movie.Movie), time.Minute*15)
if err != nil {
return err
}

@ -1,6 +1,7 @@
package vendorAlist
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
@ -12,10 +13,18 @@ import (
"github.com/synctv-org/vendors/api/alist"
)
type AlistMeResp = model.VendorMeResp[*alist.MeResp]
func Me(ctx *gin.Context) {
user := ctx.MustGet("user").(*op.User)
v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist)
v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist)
if err != nil {
if errors.Is(err, db.ErrNotFound("vendor")) {
ctx.JSON(http.StatusOK, model.NewApiDataResp(&AlistMeResp{
IsLogin: false,
}))
return
}
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
@ -29,5 +38,8 @@ func Me(ctx *gin.Context) {
return
}
ctx.JSON(http.StatusOK, model.NewApiDataResp(resp))
ctx.JSON(http.StatusOK, model.NewApiDataResp(&AlistMeResp{
IsLogin: false,
Info: resp,
}))
}

@ -40,7 +40,7 @@ func List(ctx *gin.Context) {
return
}
v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist)
v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return

@ -50,16 +50,21 @@ func Parse(ctx *gin.Context) {
return
}
v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili)
var cookies []*http.Cookie
vendorInfo, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
if !errors.Is(err, db.ErrNotFound("vendor")) {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
} else {
cookies = vendorInfo.Cookies
}
switch resp.Type {
case "bv":
resp, err := cli.ParseVideoPage(ctx, &bilibili.ParseVideoPageReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Bvid: resp.Id,
Sections: ctx.DefaultQuery("sections", "false") == "true",
})
@ -75,7 +80,7 @@ func Parse(ctx *gin.Context) {
return
}
resp, err := cli.ParseVideoPage(ctx, &bilibili.ParseVideoPageReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Aid: aid,
Sections: ctx.DefaultQuery("sections", "false") == "true",
})
@ -91,7 +96,7 @@ func Parse(ctx *gin.Context) {
return
}
resp, err := cli.ParsePGCPage(ctx, &bilibili.ParsePGCPageReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Epid: epid,
})
if err != nil {
@ -106,7 +111,7 @@ func Parse(ctx *gin.Context) {
return
}
resp, err := cli.ParsePGCPage(ctx, &bilibili.ParsePGCPageReq{
Cookies: utils.HttpCookieToMap(v.Cookies),
Cookies: utils.HttpCookieToMap(cookies),
Ssid: ssid,
})
if err != nil {

@ -1,6 +1,7 @@
package vendorBilibili
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
@ -13,15 +14,23 @@ import (
"github.com/synctv-org/vendors/api/bilibili"
)
type BilibiliMeResp = model.VendorMeResp[*bilibili.UserInfoResp]
func Me(ctx *gin.Context) {
user := ctx.MustGet("user").(*op.User)
v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili)
v, err := db.GetVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili)
if err != nil {
if errors.Is(err, db.ErrNotFound("vendor")) {
ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{
IsLogin: false,
}))
return
}
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
if len(v.Cookies) == 0 {
ctx.JSON(http.StatusOK, model.NewApiDataResp(&bilibili.UserInfoResp{
ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{
IsLogin: false,
}))
return
@ -34,5 +43,8 @@ func Me(ctx *gin.Context) {
return
}
ctx.JSON(http.StatusOK, model.NewApiDataResp(resp))
ctx.JSON(http.StatusOK, model.NewApiDataResp(&BilibiliMeResp{
IsLogin: resp.IsLogin,
Info: resp,
}))
}

@ -0,0 +1,6 @@
package model
type VendorMeResp[T any] struct {
IsLogin bool `json:"isLogin"`
Info T `json:"info,omitempty"`
}

@ -314,7 +314,7 @@ func SortUUID() string {
}
func HttpCookieToMap(c []*http.Cookie) map[string]string {
m := make(map[string]string)
m := make(map[string]string, len(c))
for _, v := range c {
m[v.Name] = v.Value
}

Loading…
Cancel
Save