package aliyundrive_share import ( "context" "fmt" "net/http" "time" "github.com/Xhofe/rateg" "github.com/alist-org/alist/v3/drivers/base" "github.com/alist-org/alist/v3/internal/driver" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/model" "github.com/alist-org/alist/v3/pkg/cron" "github.com/alist-org/alist/v3/pkg/utils" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) type AliyundriveShare struct { model.Storage Addition AccessToken string ShareToken string DriveId string cron *cron.Cron limitList func(ctx context.Context, dir model.Obj) ([]model.Obj, error) limitLink func(ctx context.Context, file model.Obj) (*model.Link, error) } func (d *AliyundriveShare) Config() driver.Config { return config } func (d *AliyundriveShare) GetAddition() driver.Additional { return &d.Addition } func (d *AliyundriveShare) Init(ctx context.Context) error { err := d.refreshToken() if err != nil { return err } err = d.getShareToken() if err != nil { return err } d.cron = cron.NewCron(time.Hour * 2) d.cron.Do(func() { err := d.refreshToken() if err != nil { log.Errorf("%+v", err) } }) d.limitList = rateg.LimitFnCtx(d.list, rateg.LimitFnOption{ Limit: 4, Bucket: 1, }) d.limitLink = rateg.LimitFnCtx(d.link, rateg.LimitFnOption{ Limit: 1, Bucket: 1, }) return nil } func (d *AliyundriveShare) Drop(ctx context.Context) error { if d.cron != nil { d.cron.Stop() } d.DriveId = "" return nil } func (d *AliyundriveShare) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { if d.limitList == nil { return nil, fmt.Errorf("driver not init") } return d.limitList(ctx, dir) } func (d *AliyundriveShare) list(ctx context.Context, dir model.Obj) ([]model.Obj, error) { files, err := d.getFiles(dir.GetID()) if err != nil { return nil, err } return utils.SliceConvert(files, func(src File) (model.Obj, error) { return fileToObj(src), nil }) } func (d *AliyundriveShare) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { if d.limitLink == nil { return nil, fmt.Errorf("driver not init") } return d.limitLink(ctx, file) } func (d *AliyundriveShare) link(ctx context.Context, file model.Obj) (*model.Link, error) { data := base.Json{ "drive_id": d.DriveId, "file_id": file.GetID(), // // Only ten minutes lifetime "expire_sec": 600, "share_id": d.ShareId, } var resp ShareLinkResp _, err := d.request("https://api.alipan.com/v2/file/get_share_link_download_url", http.MethodPost, func(req *resty.Request) { req.SetHeader(CanaryHeaderKey, CanaryHeaderValue).SetBody(data).SetResult(&resp) }) if err != nil { return nil, err } return &model.Link{ Header: http.Header{ "Referer": []string{"https://www.alipan.com/"}, }, URL: resp.DownloadUrl, }, nil } func (d *AliyundriveShare) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { var resp base.Json var url string data := base.Json{ "share_id": d.ShareId, "file_id": args.Obj.GetID(), } switch args.Method { case "doc_preview": url = "https://api.alipan.com/v2/file/get_office_preview_url" case "video_preview": url = "https://api.alipan.com/v2/file/get_video_preview_play_info" data["category"] = "live_transcoding" default: return nil, errs.NotSupport } _, err := d.request(url, http.MethodPost, func(req *resty.Request) { req.SetBody(data).SetResult(&resp) }) if err != nil { return nil, err } return resp, nil } var _ driver.Driver = (*AliyundriveShare)(nil)