diff --git a/go.mod b/go.mod index ecc9dd8..69065b0 100644 --- a/go.mod +++ b/go.mod @@ -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.20231204112116-1882fc1116bf + github.com/synctv-org/vendors v0.1.1-0.20231204154145-d6bf737a7c0b 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 diff --git a/go.sum b/go.sum index 7bc2094..3a76c63 100644 --- a/go.sum +++ b/go.sum @@ -356,6 +356,8 @@ github.com/synctv-org/vendors v0.1.1-0.20231203064919-c8eeb877a780 h1:59T2DtbXn8 github.com/synctv-org/vendors v0.1.1-0.20231203064919-c8eeb877a780/go.mod h1:DQHEXvrsnX9Ke6B0KVJ+w8uMgM/DZKNkvi6cJmRn+zk= github.com/synctv-org/vendors v0.1.1-0.20231204112116-1882fc1116bf h1:E5Mu7mqdWCzjy+kSQBvjvmETfhiLXiTuEhfkGhgBRJk= github.com/synctv-org/vendors v0.1.1-0.20231204112116-1882fc1116bf/go.mod h1:DQHEXvrsnX9Ke6B0KVJ+w8uMgM/DZKNkvi6cJmRn+zk= +github.com/synctv-org/vendors v0.1.1-0.20231204154145-d6bf737a7c0b h1:QsHSl+bzDrY8oiPv/KcoBPjHa7R1VeyDNlChJrEHzus= +github.com/synctv-org/vendors v0.1.1-0.20231204154145-d6bf737a7c0b/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= diff --git a/internal/db/vendor.go b/internal/db/vendor.go index 0287c86..4776491 100644 --- a/internal/db/vendor.go +++ b/internal/db/vendor.go @@ -1,9 +1,11 @@ package db import ( + "errors" "net/http" "github.com/synctv-org/synctv/internal/model" + "gorm.io/gorm" ) func GetVendorByUserID(userID string) ([]*model.StreamingVendorInfo, error) { @@ -62,34 +64,24 @@ func FirstOrCreateVendorByUserIDAndVendor(userID string, vendor model.StreamingV return &vendorInfo, err } -func AssignFirstOrCreateVendorByUserIDAndVendor(userID string, vendor model.StreamingVendor, conf ...CreateVendorConfig) (*model.StreamingVendorInfo, error) { - var vendorInfo model.StreamingVendorInfo - v := &model.StreamingVendorInfo{ +func CreateOrSaveVendorByUserIDAndVendor(userID string, vendor model.StreamingVendor, conf ...CreateVendorConfig) (*model.StreamingVendorInfo, error) { + vendorInfo := model.StreamingVendorInfo{ UserID: userID, Vendor: vendor, } - for _, c := range conf { - c(v) - } - err := db.Where("user_id = ? AND vendor = ?", userID, vendor).Assign( - v, - ).FirstOrCreate(&vendorInfo).Error - return &vendorInfo, err -} - -func FirstOrInitVendorByUserIDAndVendor(userID string, vendor model.StreamingVendor, conf ...CreateVendorConfig) (*model.StreamingVendorInfo, error) { - var vendorInfo model.StreamingVendorInfo - v := &model.StreamingVendorInfo{ - UserID: userID, - Vendor: vendor, - } - for _, c := range conf { - c(v) - } - err := db.Where("user_id = ? AND vendor = ?", userID, vendor).Attrs( - v, - ).FirstOrInit(&vendorInfo).Error - return &vendorInfo, err + return &vendorInfo, Transactional(func(tx *gorm.DB) error { + if errors.Is(tx.First(&vendorInfo).Error, gorm.ErrRecordNotFound) { + for _, c := range conf { + c(&vendorInfo) + } + return tx.Create(&vendorInfo).Error + } else { + for _, c := range conf { + c(&vendorInfo) + } + return tx.Save(&vendorInfo).Error + } + }) } func DeleteVendorByUserIDAndVendor(userID string, vendor model.StreamingVendor) error { diff --git a/internal/vendor/alist.go b/internal/vendor/alist.go index 4a0b0f5..2871677 100644 --- a/internal/vendor/alist.go +++ b/internal/vendor/alist.go @@ -282,6 +282,10 @@ func (a *grpcAlist) Login(ctx context.Context, req *alist.LoginReq) (*alist.Logi return a.client.Login(ctx, req) } +func (a *grpcAlist) Me(ctx context.Context, req *alist.MeReq) (*alist.MeResp, error) { + return a.client.Me(ctx, req) +} + var _ AlistInterface = (*httpAlist)(nil) type httpAlist struct { @@ -309,3 +313,7 @@ func (a *httpAlist) FsOther(ctx context.Context, req *alist.FsOtherReq) (*alist. func (a *httpAlist) Login(ctx context.Context, req *alist.LoginReq) (*alist.LoginResp, error) { return a.client.Login(ctx, req) } + +func (a *httpAlist) Me(ctx context.Context, req *alist.MeReq) (*alist.MeResp, error) { + return a.client.Me(ctx, req) +} diff --git a/server/handlers/init.go b/server/handlers/init.go index b0617f9..4cb7cfa 100644 --- a/server/handlers/init.go +++ b/server/handlers/init.go @@ -204,6 +204,8 @@ func Init(e *gin.Engine) { alist.POST("/login", vendorAlist.Login) alist.POST("/list", vendorAlist.List) + + alist.GET("/me", vendorAlist.Me) } } } diff --git a/server/handlers/movie.go b/server/handlers/movie.go index 2e322a8..5f1503d 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -673,7 +673,7 @@ type bilibiliCache struct { func initBilibiliMPDCache(ctx context.Context, movie dbModel.Movie) func() (any, error) { return func() (any, error) { - v, err := db.FirstOrInitVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) + v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) if err != nil { return nil, err } @@ -761,7 +761,7 @@ 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.FirstOrInitVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) + v, err := db.FirstOrCreateVendorByUserIDAndVendor(movie.CreatorID, dbModel.StreamingVendorBilibili) if err != nil { return "", err } diff --git a/server/handlers/vendors/vendorAlist/login.go b/server/handlers/vendors/vendorAlist/login.go index 9c0f0f8..a76b67b 100644 --- a/server/handlers/vendors/vendorAlist/login.go +++ b/server/handlers/vendors/vendorAlist/login.go @@ -40,14 +40,22 @@ func Login(ctx *gin.Context) { return } + cli := vendor.AlistClient("") + if req.Username == "" { - _, err := db.AssignFirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist, db.WithHost(req.Host)) + _, err := cli.Me(ctx, &alist.MeReq{ + Host: req.Host, + }) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) + } + _, err = db.CreateOrSaveVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist, db.WithHost(req.Host), db.WithAuthorization("")) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return } } else { - resp, err := vendor.AlistClient("").Login(ctx, &alist.LoginReq{ + resp, err := cli.Login(ctx, &alist.LoginReq{ Host: req.Host, Username: req.Username, Password: req.Password, @@ -57,7 +65,7 @@ func Login(ctx *gin.Context) { return } - _, err = db.AssignFirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist, db.WithAuthorization(resp.Token), db.WithHost(req.Host)) + _, err = db.CreateOrSaveVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist, db.WithAuthorization(resp.Token), db.WithHost(req.Host)) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return diff --git a/server/handlers/vendors/vendorAlist/me.go b/server/handlers/vendors/vendorAlist/me.go new file mode 100644 index 0000000..80b3d32 --- /dev/null +++ b/server/handlers/vendors/vendorAlist/me.go @@ -0,0 +1,33 @@ +package vendorAlist + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/synctv-org/synctv/internal/db" + dbModel "github.com/synctv-org/synctv/internal/model" + "github.com/synctv-org/synctv/internal/op" + "github.com/synctv-org/synctv/internal/vendor" + "github.com/synctv-org/synctv/server/model" + "github.com/synctv-org/vendors/api/alist" +) + +func Me(ctx *gin.Context) { + user := ctx.MustGet("user").(*op.User) + v, err := db.FirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorAlist) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } + + resp, err := vendor.AlistClient("").Me(ctx, &alist.MeReq{ + Host: v.Host, + Token: v.Authorization, + }) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } + + ctx.JSON(http.StatusOK, model.NewApiDataResp(resp)) +} diff --git a/server/handlers/vendors/vendorAlist/parse.go b/server/handlers/vendors/vendorAlist/parse.go index 2f1d0b5..d3d8205 100644 --- a/server/handlers/vendors/vendorAlist/parse.go +++ b/server/handlers/vendors/vendorAlist/parse.go @@ -1,6 +1,7 @@ package vendorAlist import ( + "fmt" "net/http" "github.com/gin-gonic/gin" @@ -16,6 +17,7 @@ import ( type ListReq struct { Path string `json:"path"` Password string `json:"password"` + Refresh bool `json:"refresh"` } func (r *ListReq) Validate() error { @@ -44,10 +46,7 @@ func List(ctx *gin.Context) { return } - if v.Authorization == "" { - ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("unauthorized")) - return - } + fmt.Printf("v.Authorization: %v\n", v.Authorization) var cli = vendor.AlistClient(ctx.Query("backend")) @@ -56,7 +55,7 @@ func List(ctx *gin.Context) { Password: req.Password, Path: req.Path, Host: v.Host, - Refresh: true, + Refresh: req.Refresh, }) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) diff --git a/server/handlers/vendors/vendorBilibili/login.go b/server/handlers/vendors/vendorBilibili/login.go index 239be5d..39c25b2 100644 --- a/server/handlers/vendors/vendorBilibili/login.go +++ b/server/handlers/vendors/vendorBilibili/login.go @@ -73,7 +73,7 @@ func LoginWithQR(ctx *gin.Context) { })) return case bilibili.QRCodeStatus_SUCCESS: - _, err = db.AssignFirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili, db.WithCookie(utils.MapToHttpCookie(resp.Cookies))) + _, err = db.CreateOrSaveVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili, db.WithCookie(utils.MapToHttpCookie(resp.Cookies))) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return @@ -185,7 +185,7 @@ func LoginWithSMS(ctx *gin.Context) { return } user := ctx.MustGet("user").(*op.User) - _, err = db.AssignFirstOrCreateVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili, db.WithCookie(utils.MapToHttpCookie(c.Cookies))) + _, err = db.CreateOrSaveVendorByUserIDAndVendor(user.ID, dbModel.StreamingVendorBilibili, db.WithCookie(utils.MapToHttpCookie(c.Cookies))) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return