fix: refresh cache and delete movie cache

api-v2
zijiren233 1 year ago
parent cc6e63283d
commit b8fa101412

@ -1,6 +1,6 @@
module github.com/synctv-org/synctv
go 1.22
go 1.22.0
require (
github.com/Boostport/mjml-go v0.14.6
@ -35,15 +35,15 @@ require (
github.com/synctv-org/vendors v0.3.3
github.com/ulule/limiter/v3 v3.11.2
github.com/zencoder/go-dash/v3 v3.0.3
github.com/zijiren233/gencontainer v0.0.0-20240812032827-a8435ce091a6
github.com/zijiren233/gencontainer v0.0.0-20241008162312-0d000427d9f5
github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb
github.com/zijiren233/go-uhc v0.2.5
github.com/zijiren233/livelib v0.3.3
github.com/zijiren233/stream v0.5.2
github.com/zijiren233/yaml-comment v0.2.2
go.etcd.io/etcd/client/v3 v3.5.15
golang.org/x/crypto v0.26.0
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
golang.org/x/crypto v0.28.0
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6
golang.org/x/oauth2 v0.22.0
google.golang.org/grpc v1.66.0
google.golang.org/protobuf v1.34.2
@ -130,12 +130,12 @@ require (
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.9.0 // indirect
golang.org/x/image v0.19.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.24.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect

@ -382,8 +382,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zencoder/go-dash/v3 v3.0.3 h1:xqwGJ2fJCSArwONGx6sY26Z1lxQ7zTURoxdRjCpuodM=
github.com/zencoder/go-dash/v3 v3.0.3/go.mod h1:30R5bKy1aUYY45yesjtZ9l8trNc2TwNqbS17WVQmCzk=
github.com/zijiren233/gencontainer v0.0.0-20240812032827-a8435ce091a6 h1:QoD36S2XLZrmNFuPUJeAYGeJyToUFwToGSo2pwvc0EA=
github.com/zijiren233/gencontainer v0.0.0-20240812032827-a8435ce091a6/go.mod h1:0fOhYRhnuyR/NsECB0NdkQgp2fy4W1TV8pgAYhrW6rY=
github.com/zijiren233/gencontainer v0.0.0-20241008162312-0d000427d9f5 h1:mkxcGD37OjQEaFwYaAHHju8dCQvbilczepNenr/ksuk=
github.com/zijiren233/gencontainer v0.0.0-20241008162312-0d000427d9f5/go.mod h1:bt31/uEP7Eq5qEEW+I/9AzCsueDohCwXLwy/rnLpNPY=
github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb h1:0DyOxf/TbbGodHhOVHNoPk+7v/YBJACs22gKpKlatWw=
github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb/go.mod h1:6TCzjDiQ8+5gWZiwsC3pnA5M0vUy2jV2Y7ciHJh729g=
github.com/zijiren233/go-uhc v0.2.5 h1:oaQmuopsfcARKIb/xyG82NFU6zmWyEl+cqe+tMmCjuM=
@ -418,10 +418,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
@ -431,8 +431,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -448,8 +448,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -495,8 +495,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -512,8 +512,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -525,8 +525,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

@ -20,7 +20,7 @@ import (
"github.com/synctv-org/synctv/internal/provider/providers"
"github.com/synctv-org/synctv/internal/settings"
"github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/gencontainer/refreshcache0"
)
var ProviderGroupSettings = make(map[model.SettingGroup]*ProviderGroupSetting)
@ -34,7 +34,7 @@ type ProviderGroupSetting struct {
SignupNeedReview settings.BoolSetting
}
var Oauth2EnabledCache = refreshcache.NewRefreshCache[[]provider.OAuth2Provider](func(context.Context, ...any) ([]provider.OAuth2Provider, error) {
var Oauth2EnabledCache = refreshcache0.NewRefreshCache[[]provider.OAuth2Provider](func(context.Context) ([]provider.OAuth2Provider, error) {
ps := providers.EnabledProvider()
r := make([]provider.OAuth2Provider, 0, ps.Len())
ps.Range(func(p provider.OAuth2Provider, value struct{}) bool {
@ -53,7 +53,7 @@ var Oauth2EnabledCache = refreshcache.NewRefreshCache[[]provider.OAuth2Provider]
return r, nil
}, 0)
var Oauth2SignupEnabledCache = refreshcache.NewRefreshCache[[]provider.OAuth2Provider](func(ctx context.Context, _ ...any) ([]provider.OAuth2Provider, error) {
var Oauth2SignupEnabledCache = refreshcache0.NewRefreshCache[[]provider.OAuth2Provider](func(ctx context.Context) ([]provider.OAuth2Provider, error) {
ps := providers.EnabledProvider()
r := make([]provider.OAuth2Provider, 0, ps.Len())
ps.Range(func(p provider.OAuth2Provider, value struct{}) bool {

@ -16,7 +16,8 @@ import (
"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/gencontainer/refreshcache0"
"github.com/zijiren233/gencontainer/refreshcache1"
"github.com/zijiren233/go-uhc"
)
@ -79,10 +80,10 @@ func AlistAuthorizationCacheWithConfigInitFunc(ctx context.Context, v *model.Ali
}
}
type AlistMovieCache = refreshcache.RefreshCache[*AlistMovieCacheData, *AlistMovieCacheFuncArgs]
type AlistMovieCache = refreshcache1.RefreshCache[*AlistMovieCacheData, *AlistMovieCacheFuncArgs]
func NewAlistMovieCache(movie *model.Movie, subPath string) *AlistMovieCache {
return refreshcache.NewRefreshCache(NewAlistMovieCacheInitFunc(movie, subPath), time.Minute*14)
return refreshcache1.NewRefreshCache(NewAlistMovieCacheInitFunc(movie, subPath), time.Minute*14)
}
type AlistProvider = string
@ -110,7 +111,7 @@ type AlistAliCache struct {
M3U8ListFile []byte
}
type SubtitleDataCache = refreshcache.RefreshCache[[]byte, struct{}]
type SubtitleDataCache = refreshcache0.RefreshCache[[]byte]
func newAliSubtitles(list []*alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscodingSubtitleTaskList) []*AlistSubtitle {
caches := make([]*AlistSubtitle, len(list))
@ -120,7 +121,7 @@ func newAliSubtitles(list []*alist.FsOtherResp_VideoPreviewPlayInfo_LiveTranscod
}
url := v.Url
caches[i] = &AlistSubtitle{
Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) {
Cache: refreshcache0.NewRefreshCache(func(ctx context.Context) ([]byte, error) {
r, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
@ -162,12 +163,12 @@ type AlistMovieCacheFuncArgs struct {
UserAgent string
}
func NewAlistMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx context.Context, args ...*AlistMovieCacheFuncArgs) (*AlistMovieCacheData, error) {
return func(ctx context.Context, args ...*AlistMovieCacheFuncArgs) (*AlistMovieCacheData, error) {
if len(args) == 0 {
func NewAlistMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx context.Context, args *AlistMovieCacheFuncArgs) (*AlistMovieCacheData, error) {
return func(ctx context.Context, args *AlistMovieCacheFuncArgs) (*AlistMovieCacheData, error) {
if args == nil {
return nil, errors.New("need alist user cache")
}
userCache := args[0].UserCache
userCache := args.UserCache
if userCache == nil {
return nil, errors.New("need alist user cache")
}
@ -204,7 +205,7 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx con
Token: aucd.Token,
Path: truePath,
Password: movie.MovieBase.VendorInfo.Alist.Password,
UserAgent: args[0].UserAgent,
UserAgent: args.UserAgent,
})
if err != nil {
return nil, err
@ -233,7 +234,7 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx con
Token: aucd.Token,
Path: prefix + related.Name,
Password: movie.MovieBase.VendorInfo.Alist.Password,
UserAgent: args[0].UserAgent,
UserAgent: args.UserAgent,
})
if err != nil {
return nil, err
@ -242,7 +243,7 @@ func NewAlistMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx con
Name: related.Name,
URL: resp.RawUrl,
Type: utils.GetFileExtension(resp.Name),
Cache: refreshcache.NewRefreshCache(func(ctx context.Context, args ...struct{}) ([]byte, error) {
Cache: refreshcache0.NewRefreshCache(func(ctx context.Context) ([]byte, error) {
r, err := http.NewRequestWithContext(ctx, http.MethodGet, resp.RawUrl, nil)
if err != nil {
return nil, err

@ -17,6 +17,8 @@ import (
"github.com/synctv-org/vendors/api/bilibili"
"github.com/zencoder/go-dash/v3/mpd"
"github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/gencontainer/refreshcache0"
"github.com/zijiren233/gencontainer/refreshcache1"
"github.com/zijiren233/go-uhc"
)
@ -28,21 +30,21 @@ type BilibiliMpdCache struct {
type BilibiliSubtitleCache map[string]*struct {
Url string
Srt *refreshcache.RefreshCache[[]byte, struct{}]
Srt *refreshcache0.RefreshCache[[]byte]
}
func NewBilibiliSharedMpdCacheInitFunc(movie *model.Movie) func(ctx context.Context, args ...*BilibiliUserCache) (*BilibiliMpdCache, error) {
return func(ctx context.Context, args ...*BilibiliUserCache) (*BilibiliMpdCache, error) {
return BilibiliSharedMpdCacheInitFunc(ctx, movie, args...)
func NewBilibiliSharedMpdCacheInitFunc(movie *model.Movie) func(ctx context.Context, args *BilibiliUserCache) (*BilibiliMpdCache, error) {
return func(ctx context.Context, args *BilibiliUserCache) (*BilibiliMpdCache, error) {
return BilibiliSharedMpdCacheInitFunc(ctx, movie, args)
}
}
func BilibiliSharedMpdCacheInitFunc(ctx context.Context, movie *model.Movie, args ...*BilibiliUserCache) (*BilibiliMpdCache, error) {
if len(args) == 0 {
func BilibiliSharedMpdCacheInitFunc(ctx context.Context, movie *model.Movie, args *BilibiliUserCache) (*BilibiliMpdCache, error) {
if args == nil {
return nil, errors.New("no bilibili user cache data")
}
var cookies []*http.Cookie
vendorInfo, err := args[0].Get(ctx)
vendorInfo, err := args.Get(ctx)
if err != nil {
if !errors.Is(err, db.ErrNotFound("vendor")) {
return nil, err
@ -228,14 +230,14 @@ type bilibiliSubtitleResp struct {
} `json:"body"`
}
func NewBilibiliSubtitleCacheInitFunc(movie *model.Movie) func(ctx context.Context, args ...*BilibiliUserCache) (BilibiliSubtitleCache, error) {
return func(ctx context.Context, args ...*BilibiliUserCache) (BilibiliSubtitleCache, error) {
return BilibiliSubtitleCacheInitFunc(ctx, movie, args...)
func NewBilibiliSubtitleCacheInitFunc(movie *model.Movie) func(ctx context.Context, args *BilibiliUserCache) (BilibiliSubtitleCache, error) {
return func(ctx context.Context, args *BilibiliUserCache) (BilibiliSubtitleCache, error) {
return BilibiliSubtitleCacheInitFunc(ctx, movie, args)
}
}
func BilibiliSubtitleCacheInitFunc(ctx context.Context, movie *model.Movie, args ...*BilibiliUserCache) (BilibiliSubtitleCache, error) {
if len(args) == 0 {
func BilibiliSubtitleCacheInitFunc(ctx context.Context, movie *model.Movie, args *BilibiliUserCache) (BilibiliSubtitleCache, error) {
if args == nil {
return nil, errors.New("no bilibili user cache data")
}
@ -246,7 +248,7 @@ func BilibiliSubtitleCacheInitFunc(ctx context.Context, movie *model.Movie, args
// must login
var cookies []*http.Cookie
vendorInfo, err := args[0].Get(ctx)
vendorInfo, err := args.Get(ctx)
if err != nil {
if errors.Is(err, db.ErrNotFound("vendor")) {
return nil, nil
@ -268,10 +270,10 @@ func BilibiliSubtitleCacheInitFunc(ctx context.Context, movie *model.Movie, args
for k, v := range resp.Subtitles {
subtitleCache[k] = &struct {
Url string
Srt *refreshcache.RefreshCache[[]byte, struct{}]
Srt *refreshcache0.RefreshCache[[]byte]
}{
Url: v,
Srt: refreshcache.NewRefreshCache[[]byte](func(ctx context.Context, args ...struct{}) ([]byte, error) {
Srt: refreshcache0.NewRefreshCache[[]byte](func(ctx context.Context) ([]byte, error) {
return translateBilibiliSubtitleToSrt(ctx, v)
}, 0),
}
@ -326,9 +328,9 @@ func translateBilibiliSubtitleToSrt(ctx context.Context, url string) ([]byte, er
type BilibiliLiveCache struct{}
func NewBilibiliLiveCacheInitFunc(movie *model.Movie) func(ctx context.Context, args ...struct{}) ([]byte, error) {
return func(ctx context.Context, args ...struct{}) ([]byte, error) {
return BilibiliLiveCacheInitFunc(ctx, movie, args...)
func NewBilibiliLiveCacheInitFunc(movie *model.Movie) func(ctx context.Context) ([]byte, error) {
return func(ctx context.Context) ([]byte, error) {
return BilibiliLiveCacheInitFunc(ctx, movie)
}
}
@ -346,7 +348,7 @@ func genBilibiliLiveM3U8ListFile(urls []*bilibili.LiveStream) []byte {
return buf.Bytes()
}
func BilibiliLiveCacheInitFunc(ctx context.Context, movie *model.Movie, args ...struct{}) ([]byte, error) {
func BilibiliLiveCacheInitFunc(ctx context.Context, movie *model.Movie) ([]byte, error) {
cli := vendor.LoadBilibiliClient(movie.MovieBase.VendorInfo.Backend)
resp, err := cli.GetLiveStreams(ctx, &bilibili.GetLiveStreamsReq{
Cid: movie.MovieBase.VendorInfo.Bilibili.Cid,
@ -360,17 +362,17 @@ func BilibiliLiveCacheInitFunc(ctx context.Context, movie *model.Movie, args ...
type BilibiliMovieCache struct {
NoSharedMovie *MapCache[string, *BilibiliUserCache]
SharedMpd *refreshcache.RefreshCache[*BilibiliMpdCache, *BilibiliUserCache]
Subtitle *refreshcache.RefreshCache[BilibiliSubtitleCache, *BilibiliUserCache]
Live *refreshcache.RefreshCache[[]byte, struct{}]
SharedMpd *refreshcache1.RefreshCache[*BilibiliMpdCache, *BilibiliUserCache]
Subtitle *refreshcache1.RefreshCache[BilibiliSubtitleCache, *BilibiliUserCache]
Live *refreshcache0.RefreshCache[[]byte]
}
func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache {
return &BilibiliMovieCache{
NoSharedMovie: newMapCache(NewBilibiliNoSharedMovieCacheInitFunc(movie), time.Minute*60),
SharedMpd: refreshcache.NewRefreshCache(NewBilibiliSharedMpdCacheInitFunc(movie), time.Minute*60),
Subtitle: refreshcache.NewRefreshCache(NewBilibiliSubtitleCacheInitFunc(movie), 0),
Live: refreshcache.NewRefreshCache(NewBilibiliLiveCacheInitFunc(movie), time.Minute*55),
SharedMpd: refreshcache1.NewRefreshCache(NewBilibiliSharedMpdCacheInitFunc(movie), time.Minute*60),
Subtitle: refreshcache1.NewRefreshCache(NewBilibiliSubtitleCacheInitFunc(movie), 0),
Live: refreshcache0.NewRefreshCache(NewBilibiliLiveCacheInitFunc(movie), time.Minute*55),
}
}

@ -0,0 +1,172 @@
package cache
import (
"context"
"sync"
"time"
"github.com/zijiren233/gencontainer/refreshcache0"
"golang.org/x/exp/maps"
)
type MapRefreshFunc0[T any] func(ctx context.Context, key string) (T, error)
type MapCache0[T any] struct {
lock sync.RWMutex
cache map[string]*refreshcache0.RefreshCache[T]
refreshFunc MapRefreshFunc0[T]
maxAge time.Duration
}
func newMapCache0[T any](refreshFunc MapRefreshFunc0[T], maxAge time.Duration) *MapCache0[T] {
return &MapCache0[T]{
cache: make(map[string]*refreshcache0.RefreshCache[T]),
refreshFunc: refreshFunc,
maxAge: maxAge,
}
}
func (b *MapCache0[T]) Clear() {
b.lock.Lock()
defer b.lock.Unlock()
b.clear()
}
func (b *MapCache0[T]) clear() {
maps.Clear(b.cache)
}
func (b *MapCache0[T]) Delete(key string) {
b.lock.Lock()
defer b.lock.Unlock()
delete(b.cache, key)
}
func (b *MapCache0[T]) LoadOrStore(ctx context.Context, key string) (T, error) {
b.lock.RLock()
c, loaded := b.cache[key]
if loaded {
b.lock.RUnlock()
return c.Get(ctx)
}
b.lock.RUnlock()
b.lock.Lock()
c, loaded = b.cache[key]
if loaded {
b.lock.Unlock()
return c.Get(ctx)
}
c = refreshcache0.NewRefreshCache[T](func(ctx context.Context) (T, error) {
return b.refreshFunc(ctx, key)
}, b.maxAge)
b.cache[key] = c
b.lock.Unlock()
return c.Get(ctx)
}
func (b *MapCache0[T]) StoreOrRefresh(ctx context.Context, key string) (T, error) {
b.lock.RLock()
c, ok := b.cache[key]
if ok {
b.lock.RUnlock()
return c.Refresh(ctx)
}
b.lock.RUnlock()
b.lock.Lock()
c, ok = b.cache[key]
if ok {
b.lock.Unlock()
return c.Refresh(ctx)
}
c = refreshcache0.NewRefreshCache[T](func(ctx context.Context) (T, error) {
return b.refreshFunc(ctx, key)
}, b.maxAge)
b.cache[key] = c
b.lock.Unlock()
return c.Refresh(ctx)
}
func (b *MapCache0[T]) LoadCache(key string) (*refreshcache0.RefreshCache[T], bool) {
b.lock.RLock()
c, ok := b.cache[key]
b.lock.RUnlock()
return c, ok
}
func (b *MapCache0[T]) LoadOrNewCache(key string) *refreshcache0.RefreshCache[T] {
b.lock.RLock()
c, ok := b.cache[key]
if ok {
b.lock.RUnlock()
return c
}
b.lock.RUnlock()
b.lock.Lock()
c, ok = b.cache[key]
if ok {
b.lock.Unlock()
return c
}
c = refreshcache0.NewRefreshCache[T](func(ctx context.Context) (T, error) {
return b.refreshFunc(ctx, key)
}, b.maxAge)
b.cache[key] = c
b.lock.Unlock()
return c
}
func (b *MapCache0[T]) LoadOrStoreWithDynamicFunc(ctx context.Context, key string, refreshFunc MapRefreshFunc0[T]) (T, error) {
b.lock.RLock()
c, loaded := b.cache[key]
if loaded {
b.lock.RUnlock()
return c.Data().Get(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}
b.lock.RUnlock()
b.lock.Lock()
c, loaded = b.cache[key]
if loaded {
b.lock.Unlock()
return c.Data().Get(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}
c = refreshcache0.NewRefreshCache[T](func(ctx context.Context) (T, error) {
return b.refreshFunc(ctx, key)
}, b.maxAge)
b.cache[key] = c
b.lock.Unlock()
return c.Data().Get(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}
func (b *MapCache0[T]) StoreOrRefreshWithDynamicFunc(ctx context.Context, key string, refreshFunc MapRefreshFunc0[T]) (T, error) {
b.lock.RLock()
c, ok := b.cache[key]
if ok {
b.lock.RUnlock()
return c.Data().Refresh(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}
b.lock.RUnlock()
b.lock.Lock()
c, ok = b.cache[key]
if ok {
b.lock.Unlock()
return c.Data().Refresh(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}
c = refreshcache0.NewRefreshCache[T](func(ctx context.Context) (T, error) {
return b.refreshFunc(ctx, key)
}, b.maxAge)
b.cache[key] = c
b.lock.Unlock()
return c.Data().Refresh(ctx, func(ctx context.Context) (T, error) {
return refreshFunc(ctx, key)
})
}

@ -15,10 +15,12 @@ import (
"github.com/synctv-org/synctv/utils"
"github.com/synctv-org/vendors/api/emby"
"github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/gencontainer/refreshcache0"
"github.com/zijiren233/gencontainer/refreshcache1"
"github.com/zijiren233/go-uhc"
)
type EmbyUserCache = MapCache[*EmbyUserCacheData, struct{}]
type EmbyUserCache = MapCache0[*EmbyUserCacheData]
type EmbyUserCacheData struct {
Host string
@ -29,7 +31,7 @@ type EmbyUserCacheData struct {
}
func NewEmbyUserCache(userID string) *EmbyUserCache {
return newMapCache(func(ctx context.Context, key string, args ...struct{}) (*EmbyUserCacheData, error) {
return newMapCache0(func(ctx context.Context, key string) (*EmbyUserCacheData, error) {
return EmbyAuthorizationCacheWithUserIDInitFunc(userID, key)
}, -1)
}
@ -62,7 +64,7 @@ type EmbySource struct {
URL string
Type string
Name string
Cache *refreshcache.RefreshCache[[]byte, struct{}]
Cache *refreshcache0.RefreshCache[[]byte]
}
}
@ -71,20 +73,20 @@ type EmbyMovieCacheData struct {
TranscodeSessionID string
}
type EmbyMovieCache = refreshcache.RefreshCache[*EmbyMovieCacheData, *EmbyUserCache]
type EmbyMovieCache = refreshcache1.RefreshCache[*EmbyMovieCacheData, *EmbyUserCache]
func NewEmbyMovieCache(movie *model.Movie, subPath string) *EmbyMovieCache {
cache := refreshcache.NewRefreshCache(NewEmbyMovieCacheInitFunc(movie, subPath), 0)
cache := refreshcache1.NewRefreshCache(NewEmbyMovieCacheInitFunc(movie, subPath), 0)
cache.SetClearFunc(NewEmbyMovieClearCacheFunc(movie, subPath))
return cache
}
func NewEmbyMovieClearCacheFunc(movie *model.Movie, subPath string) func(ctx context.Context, args ...*EmbyUserCache) error {
return func(ctx context.Context, args ...*MapCache[*EmbyUserCacheData, struct{}]) error {
func NewEmbyMovieClearCacheFunc(movie *model.Movie, subPath string) func(ctx context.Context, args *EmbyUserCache) error {
return func(ctx context.Context, args *EmbyUserCache) error {
if !movie.MovieBase.VendorInfo.Emby.Transcode {
return nil
}
if len(args) == 0 {
if args == nil {
return errors.New("need emby user cache")
}
@ -98,7 +100,7 @@ func NewEmbyMovieClearCacheFunc(movie *model.Movie, subPath string) func(ctx con
return nil
}
aucd, err := args[0].LoadOrStore(ctx, serverID)
aucd, err := args.LoadOrStore(ctx, serverID)
if err != nil {
return err
}
@ -118,9 +120,9 @@ func NewEmbyMovieClearCacheFunc(movie *model.Movie, subPath string) func(ctx con
}
}
func NewEmbyMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx context.Context, args ...*EmbyUserCache) (*EmbyMovieCacheData, error) {
return func(ctx context.Context, args ...*EmbyUserCache) (*EmbyMovieCacheData, error) {
if len(args) == 0 {
func NewEmbyMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx context.Context, args *EmbyUserCache) (*EmbyMovieCacheData, error) {
return func(ctx context.Context, args *EmbyUserCache) (*EmbyMovieCacheData, error) {
if args == nil {
return nil, errors.New("need emby user cache")
}
if movie.IsFolder && subPath == "" {
@ -139,7 +141,7 @@ func NewEmbyMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx cont
truePath = subPath
}
aucd, err := args[0].LoadOrStore(ctx, serverID)
aucd, err := args.LoadOrStore(ctx, serverID)
if err != nil {
return nil, err
}
@ -213,12 +215,12 @@ func NewEmbyMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx cont
URL string
Type string
Name string
Cache *refreshcache.RefreshCache[[]byte, struct{}]
Cache *refreshcache0.RefreshCache[[]byte]
}{
URL: url,
Type: subtutleType,
Name: name,
Cache: refreshcache.NewRefreshCache(newEmbySubtitleCacheInitFunc(url), 0),
Cache: refreshcache0.NewRefreshCache(newEmbySubtitleCacheInitFunc(url), 0),
})
}
}
@ -227,8 +229,8 @@ func NewEmbyMovieCacheInitFunc(movie *model.Movie, subPath string) func(ctx cont
}
}
func newEmbySubtitleCacheInitFunc(url string) func(ctx context.Context, args ...struct{}) ([]byte, error) {
return func(ctx context.Context, args ...struct{}) ([]byte, error) {
func newEmbySubtitleCacheInitFunc(url string) func(ctx context.Context) ([]byte, error) {
return func(ctx context.Context) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err

@ -42,36 +42,24 @@ func GetMovieByID(roomID, id string, scopes ...func(*gorm.DB) *gorm.DB) (*model.
}
func DeleteMovieByID(roomID, id string) error {
result := db.Unscoped().Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{})
return HandleUpdateResult(result, "movie")
err := db.Unscoped().Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error
return HandleNotFound(err, "room")
}
func DeleteMoviesByID(roomID string, ids []string) error {
result := db.Unscoped().Where("room_id = ? AND id IN ?", roomID, ids).Delete(&model.Movie{})
return HandleUpdateResult(result, "movie")
}
func LoadAndDeleteMovieByID(roomID, id string, columns []clause.Column) (*model.Movie, error) {
var movie model.Movie
err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", roomID, id).Delete(&movie).Error
return &movie, HandleNotFound(err, "room or movie")
err := db.Unscoped().Where("room_id = ? AND id IN ?", roomID, ids).Delete(&model.Movie{}).Error
return HandleNotFound(err, "room")
}
func DeleteMoviesByRoomID(roomID string, scopes ...func(*gorm.DB) *gorm.DB) error {
result := db.Where("room_id = ?", roomID).Scopes(scopes...).Delete(&model.Movie{})
return HandleUpdateResult(result, "movie")
err := db.Where("room_id = ?", roomID).Scopes(scopes...).Delete(&model.Movie{}).Error
return HandleNotFound(err, "room")
}
func DeleteMoviesByRoomIDAndParentID(roomID string, parentID string) error {
func DeleteMoviesByRoomIDAndParentID(roomID, parentID string) error {
return DeleteMoviesByRoomID(roomID, WithParentMovieID(parentID))
}
func LoadAndDeleteMoviesByRoomID(roomID string, columns ...clause.Column) ([]*model.Movie, error) {
var movies []*model.Movie
err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ?", roomID).Delete(&movies).Error
return movies, HandleNotFound(err, "room")
}
func UpdateMovie(movie *model.Movie, columns ...clause.Column) error {
result := db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie)
return HandleUpdateResult(result, "movie")
@ -94,13 +82,11 @@ func SwapMoviePositions(roomID, movie1ID, movie2ID string) error {
movie1.Position, movie2.Position = movie2.Position, movie1.Position
if err := tx.Model(&movie1).Update("position", movie1.Position).Error; err != nil {
result1 := tx.Model(&movie1).Where("room_id = ? AND id = ?", roomID, movie1ID).Update("position", movie1.Position)
if err := HandleUpdateResult(result1, "movie1"); err != nil {
return err
}
if err := tx.Model(&movie2).Update("position", movie2.Position).Error; err != nil {
return err
}
return nil
result2 := tx.Model(&movie2).Where("room_id = ? AND id = ?", roomID, movie2ID).Update("position", movie2.Position)
return HandleUpdateResult(result2, "movie2")
})
}

@ -18,7 +18,7 @@ type Movie struct {
RoomID string `gorm:"not null;index;type:char(32)" json:"-"`
CreatorID string `gorm:"index;type:char(32)" json:"creatorId"`
MovieBase `gorm:"embedded;embeddedPrefix:base_" json:"base"`
Children []*Movie `gorm:"foreignKey:ParentID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
Childrens []*Movie `gorm:"foreignKey:ParentID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
}
func (m *Movie) Clone() *Movie {
@ -30,7 +30,7 @@ func (m *Movie) Clone() *Movie {
RoomID: m.RoomID,
CreatorID: m.CreatorID,
MovieBase: *m.MovieBase.Clone(),
Children: m.Children,
Childrens: m.Childrens,
}
}

@ -103,8 +103,12 @@ func (m *movies) Clear() error {
return m.DeleteMovieByParentID("")
}
func (m *movies) ClearCache() {
m.cache.Clear()
}
func (m *movies) Close() error {
m.DeleteMovieAndChiledCache("")
m.ClearCache()
return nil
}
@ -113,7 +117,7 @@ func (m *movies) DeleteMovieByParentID(parentID string) error {
if err != nil {
return err
}
m.DeleteMovieAndChiledCache("")
m.DeleteMovieAndChiledCache(parentID)
return nil
}
@ -131,6 +135,10 @@ func (m *movies) DeleteMovieAndChiledCache(id ...string) {
for _, id := range id {
idm[model.EmptyNullString(id)] = struct{}{}
}
if _, ok := idm[model.EmptyNullString("")]; ok {
m.ClearCache()
return
}
m.deleteMovieAndChiledCache(idm)
}
@ -140,9 +148,8 @@ func (m *movies) deleteMovieAndChiledCache(ids map[model.EmptyNullString]struct{
if _, ok := ids[value.ParentID]; ok {
if value.IsFolder {
next[model.EmptyNullString(value.ID)] = struct{}{}
} else {
m.cache.Delete(key)
}
m.cache.Delete(key)
value.Close()
}
return true

@ -18,7 +18,7 @@ import (
"github.com/synctv-org/synctv/server/middlewares"
"github.com/synctv-org/synctv/server/model"
"github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/refreshcache"
"github.com/zijiren233/gencontainer/refreshcache0"
"github.com/zijiren233/gencontainer/synccache"
"gorm.io/gorm"
)
@ -119,7 +119,7 @@ func CreateRoom(ctx *gin.Context) {
}))
}
var roomHotCache = refreshcache.NewRefreshCache(func(context.Context, ...any) ([]*model.RoomListResp, error) {
var roomHotCache = refreshcache0.NewRefreshCache[[]*model.RoomListResp](func(context.Context) ([]*model.RoomListResp, error) {
rooms := make([]*model.RoomListResp, 0)
op.RangeRoomCache(func(key string, value *synccache.Entry[*op.Room]) bool {
v := value.Value()

@ -86,7 +86,7 @@ func Login(ctx *gin.Context) {
return
}
_, err = user.EmbyCache().StoreOrRefreshWithDynamicFunc(ctx, data.ServerId, func(ctx context.Context, key string, args ...struct{}) (*cache.EmbyUserCacheData, error) {
_, err = user.EmbyCache().StoreOrRefreshWithDynamicFunc(ctx, data.ServerId, func(ctx context.Context, key string) (*cache.EmbyUserCacheData, error) {
return &cache.EmbyUserCacheData{
Host: req.Host,
ServerID: key,

Loading…
Cancel
Save