From 427244d8d5c1fd4d6c659419d2c80836cba28982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E5=87=89?= <927625802@qq.com> Date: Wed, 14 Apr 2021 13:34:14 +0800 Subject: [PATCH] =?UTF-8?q?:sparkler:=20=E6=8C=87=E5=AE=9A=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E4=B8=8E=E6=B7=B1=E5=BA=A6rebuild?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- alidrive/req_bean.go | 4 +- alidrive/request.go | 4 +- alidrive/resp_bean.go | 8 +++ server/controllers/down.go | 2 +- server/controllers/get.go | 2 +- server/controllers/utils.go | 23 +++++---- server/models/create.go | 98 ++++++++++++++++++++++++++++++++++--- server/models/file.go | 5 ++ server/router.go | 2 +- 9 files changed, 123 insertions(+), 25 deletions(-) diff --git a/alidrive/req_bean.go b/alidrive/req_bean.go index 9143e3fc..ac3a1c9a 100644 --- a/alidrive/req_bean.go +++ b/alidrive/req_bean.go @@ -69,7 +69,7 @@ type OfficePreviewUrlReq struct { // video preview url request bean type VideoPreviewUrlReq struct { - DriveId string `json:"drive_id"` - FileId string `json:"file_id"` + DriveId string `json:"drive_id"` + FileId string `json:"file_id"` ExpireSec int `json:"expire_sec"` } diff --git a/alidrive/request.go b/alidrive/request.go index 4a06e013..d14e622e 100644 --- a/alidrive/request.go +++ b/alidrive/request.go @@ -112,8 +112,8 @@ func GetOfficePreviewUrl(fileId string, drive *conf.Drive) (*OfficePreviewUrlRes func GetVideoPreviewUrl(fileId string, drive *conf.Drive) (*VideoPreviewUrlResp, error) { url := conf.Conf.AliDrive.ApiUrl + "/databox/get_video_play_info" req := VideoPreviewUrlReq{ - DriveId: drive.DefaultDriveId, - FileId: fileId, + DriveId: drive.DefaultDriveId, + FileId: fileId, ExpireSec: 14400, } var resp VideoPreviewUrlResp diff --git a/alidrive/resp_bean.go b/alidrive/resp_bean.go index 5c5118d9..1ff102ef 100644 --- a/alidrive/resp_bean.go +++ b/alidrive/resp_bean.go @@ -68,6 +68,14 @@ type Path struct { FileId string `json:"file_id"` } +/** 秒传 +{ + "name":"mikuclub.mp4", + "content_hash":"C733AC50D1F964C0398D0E403F3A30C37EFC2ADD", + "size":1141068377, + "content_type":"video/mp4" +} + */ // file response bean type File struct { RespError diff --git a/server/controllers/down.go b/server/controllers/down.go index 4ca416db..6a4214f3 100644 --- a/server/controllers/down.go +++ b/server/controllers/down.go @@ -45,7 +45,7 @@ func Down(c *gin.Context) { c.JSON(200, MetaResponse(406, "无法下载目录.")) return } - drive := utils.GetDriveByName(strings.Split(dir, "/")[0]) + drive := utils.GetDriveByName(strings.Split(filePath, "/")[0]) if drive == nil { c.JSON(200, MetaResponse(500, "找不到drive.")) return diff --git a/server/controllers/get.go b/server/controllers/get.go index 727dd140..ccbb2f8d 100644 --- a/server/controllers/get.go +++ b/server/controllers/get.go @@ -42,7 +42,7 @@ func Get(c *gin.Context) { } return } - drive := utils.GetDriveByName(strings.Split(dir, "/")[0]) + drive := utils.GetDriveByName(strings.Split(get.Path, "/")[0]) if drive == nil { c.JSON(200, MetaResponse(500, "找不到drive.")) return diff --git a/server/controllers/utils.go b/server/controllers/utils.go index c19e5772..246aad7c 100644 --- a/server/controllers/utils.go +++ b/server/controllers/utils.go @@ -3,8 +3,8 @@ package controllers import ( "github.com/Xhofe/alist/conf" "github.com/Xhofe/alist/server/models" - "github.com/Xhofe/alist/utils" "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" ) // handle info request @@ -12,14 +12,21 @@ func Info(c *gin.Context) { c.JSON(200, DataResponse(conf.Conf.Info)) } +type RebuildReq struct { + Path string `json:"path" binding:"required"` + Password string `json:"password"` + Depth int `json:"depth"` +} + // rebuild tree func RebuildTree(c *gin.Context) { - drive := utils.GetDriveByName(c.Param("drive")) - if drive == nil { - c.JSON(200, MetaResponse(400, "drive isn't exist.")) + var req RebuildReq + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(200, MetaResponse(400, "Bad Request:"+err.Error())) return } - password := c.Param("password") + log.Debugf("rebuild:%+v", req) + password := req.Password if password != conf.Conf.Server.Password { if password == "" { c.JSON(200, MetaResponse(401, "need password.")) @@ -28,11 +35,7 @@ func RebuildTree(c *gin.Context) { c.JSON(200, MetaResponse(401, "wrong password.")) return } - if err := models.Clear(drive); err != nil { - c.JSON(200, MetaResponse(500, err.Error())) - return - } - if err := models.BuildTree(drive); err != nil { + if err := models.BuildTreeWithPath(req.Path, req.Depth); err != nil { c.JSON(200, MetaResponse(500, err.Error())) return } diff --git a/server/models/create.go b/server/models/create.go index 3b4ea1db..6af4a50e 100644 --- a/server/models/create.go +++ b/server/models/create.go @@ -4,23 +4,25 @@ import ( "fmt" "github.com/Xhofe/alist/alidrive" "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/utils" log "github.com/sirupsen/logrus" "gorm.io/gorm" + "path/filepath" "strings" ) -func BuildTreeAll() { +func BuildTreeAll(depth int) { for i, _ := range conf.Conf.AliDrive.Drives { - if err := BuildTree(&conf.Conf.AliDrive.Drives[i]); err != nil { - log.Errorf("盘[%s]构建目录树失败:%s", err.Error()) + if err := BuildTree(&conf.Conf.AliDrive.Drives[i], depth); err != nil { + log.Errorf("盘[%s]构建目录树失败:%s", conf.Conf.AliDrive.Drives[i].Name, err.Error()) } else { - log.Infof("盘[%s]构建目录树成功") + log.Infof("盘[%s]构建目录树成功", conf.Conf.AliDrive.Drives[i].Name) } } } // build tree -func BuildTree(drive *conf.Drive) error { +func BuildTree(drive *conf.Drive, depth int) error { log.Infof("开始构建目录树...") tx := conf.DB.Begin() defer func() { @@ -42,14 +44,24 @@ func BuildTree(drive *conf.Drive) error { tx.Rollback() return err } - if err := BuildOne(drive.RootFolder, drive.Name+"/", tx, drive.Password, drive); err != nil { + if err := BuildOne(drive.RootFolder, drive.Name+"/", tx, drive.Password, drive, depth); err != nil { tx.Rollback() return err } return tx.Commit().Error } -func BuildOne(parent string, path string, tx *gorm.DB, parentPassword string, drive *conf.Drive) error { +/* +递归构建目录树,插入指定目录下的所有文件 +parent 父目录的file_id +path 指定的目录 +parentPassword 父目录所携带的密码 +drive 要构建的盘 +*/ +func BuildOne(parent string, path string, tx *gorm.DB, parentPassword string, drive *conf.Drive, depth int) error { + if depth == 0 { + return nil + } files, err := alidrive.GetList(parent, conf.Conf.AliDrive.MaxFilesCount, "", "", "", drive) if err != nil { return err @@ -76,16 +88,86 @@ func BuildOne(parent string, path string, tx *gorm.DB, parentPassword string, dr ContentType: file.ContentType, Size: file.Size, Password: password, + ContentHash: file.ContentHash, } log.Debugf("插入file:%+v", newFile) if err := tx.Create(&newFile).Error; err != nil { return err } if file.Type == "folder" { - if err := BuildOne(file.FileId, fmt.Sprintf("%s%s/", path, name), tx, password, drive); err != nil { + if err := BuildOne(file.FileId, fmt.Sprintf("%s%s/", path, name), tx, password, drive, depth-1); err != nil { return err } } } return nil } + +//重建指定路径与深度的目录树: 先删除该目录与该目录下所有文件的model,再重新插入 +func BuildTreeWithPath(path string, depth int) error { + dir, name := filepath.Split(path) + driveName := strings.Split(path, "/")[0] + drive := utils.GetDriveByName(driveName) + if drive == nil { + return fmt.Errorf("找不到drive[%s]", driveName) + } + file := &File{ + Dir: "", + FileId: drive.RootFolder, + Name: drive.Name, + Type: "folder", + Password: drive.Password, + } + var err error + if dir != "" { + file, err = GetFileByDirAndName(dir, name) + if err != nil { + if file == nil { + return fmt.Errorf("path not found") + } + return err + } + } + tx := conf.DB.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + if err = tx.Error; err != nil { + tx.Rollback() + return err + } + if err = tx.Where("dir = ? AND name = ?", file.Dir, file.Name).Delete(file).Error; err != nil{ + tx.Rollback() + return err + } + if err = tx.Where("dir like ?", fmt.Sprintf("%s%%", path)).Delete(&File{}).Error; err != nil{ + tx.Rollback() + return err + } + //if dir != "" { + // aliFile, err := alidrive.GetFile(file.FileId, drive) + // if err != nil { + // tx.Rollback() + // return err + // } + // aliName := aliFile.Name + // if strings.HasSuffix(aliName, ".hide") { + // return nil + // } + // if strings.Contains(aliName, ".password-") { + // index := strings.Index(name, ".password-") + // file.Name = aliName[:index] + // file.Password = aliName[index+10:] + // } + //} + if err = tx.Create(&file).Error; err != nil { + return err + } + if err = BuildOne(file.FileId, path+"/", tx, file.Password, drive, depth); err != nil { + tx.Rollback() + return err + } + return tx.Commit().Error +} diff --git a/server/models/file.go b/server/models/file.go index f0ce0b6f..a5f84510 100644 --- a/server/models/file.go +++ b/server/models/file.go @@ -18,6 +18,7 @@ type File struct { Size int64 `json:"size"` Password string `json:"password"` Url string `json:"url" gorm:"-"` + ContentHash string `json:"content_hash"` } func (file *File) Create() error { @@ -62,3 +63,7 @@ func SearchByNameInDir(keyword string, dir string) (*[]File, error) { } return &files, nil } + +func DeleteWithDir(dir string) error { + return conf.DB.Where("dir like ?", fmt.Sprintf("%s%%", dir)).Delete(&File{}).Error +} \ No newline at end of file diff --git a/server/router.go b/server/router.go index 8b31d819..9e0d6215 100644 --- a/server/router.go +++ b/server/router.go @@ -30,7 +30,7 @@ func InitApiRouter(engine *gin.Engine) { apiV2.POST("/video_preview/:drive", controllers.VideoPreview) apiV2.POST("/local_search", controllers.LocalSearch) apiV2.POST("/global_search", controllers.GlobalSearch) - apiV2.GET("/rebuild/:drive/:password", controllers.RebuildTree) + apiV2.POST("/rebuild", controllers.RebuildTree) } engine.GET("/d/*path", controllers.Down) }