diff --git a/drivers/onedrive/driver.go b/drivers/onedrive/driver.go index b460853ee..e62c4008d 100644 --- a/drivers/onedrive/driver.go +++ b/drivers/onedrive/driver.go @@ -7,6 +7,7 @@ import ( "net/url" "path" "sync" + "time" "github.com/OpenListTeam/OpenList/v4/drivers/base" "github.com/OpenListTeam/OpenList/v4/internal/driver" @@ -105,16 +106,28 @@ func (d *Onedrive) List(ctx context.Context, dir model.Obj, args model.ListArgs) } func (d *Onedrive) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - f, err := d.GetFile(file.GetPath()) - if err != nil { - return nil, err - } - if f.File == nil { - return nil, errs.NotFile + var u string + var err error + var duration time.Duration + if d.CreateShareLink { + duration = 365 * 24 * time.Hour // cache 1 year + u, err = d.createLink(file.GetPath()) + if err != nil { + return nil, err + } + } else { + duration = 5 * time.Minute // cache 5 min + f, err := d.GetFile(file.GetPath()) + if err != nil { + return nil, err + } + if f.File == nil { + return nil, errs.NotFile + } + u = f.Url } - u := f.Url if d.CustomHost != "" { - _u, err := url.Parse(f.Url) + _u, err := url.Parse(u) if err != nil { return nil, err } @@ -122,7 +135,8 @@ func (d *Onedrive) Link(ctx context.Context, file model.Obj, args model.LinkArgs u = _u.String() } return &model.Link{ - URL: u, + URL: u, + Expiration: &duration, }, nil } diff --git a/drivers/onedrive/meta.go b/drivers/onedrive/meta.go index 4fd505b9c..83d6aa8d5 100644 --- a/drivers/onedrive/meta.go +++ b/drivers/onedrive/meta.go @@ -20,6 +20,7 @@ type Addition struct { CustomHost string `json:"custom_host" help:"Custom host for onedrive download link"` DisableDiskUsage bool `json:"disable_disk_usage" default:"false"` EnableDirectUpload bool `json:"enable_direct_upload" default:"false" help:"Enable direct upload from client to OneDrive"` + CreateShareLink bool `json:"create_share_link" default:"false" help:"Create share link for file download"` } var config = driver.Config{ diff --git a/drivers/onedrive/util.go b/drivers/onedrive/util.go index ad300af44..c4b94e5b6 100644 --- a/drivers/onedrive/util.go +++ b/drivers/onedrive/util.go @@ -6,7 +6,9 @@ import ( "fmt" "io" "net/http" + "net/url" stdpath "path" + "strings" "time" "github.com/OpenListTeam/OpenList/v4/drivers/base" @@ -185,6 +187,61 @@ func (d *Onedrive) GetFile(path string) (*File, error) { return &file, err } +func (d *Onedrive) createLink(path string) (string, error) { + api := d.GetMetaUrl(false, path) + "/createLink" + data := base.Json{ + "type": "view", + "scope": "anonymous", + } + var resp struct { + Link struct { + WebUrl string `json:"webUrl"` + } `json:"link"` + } + _, err := d.Request(api, http.MethodPost, func(req *resty.Request) { + req.SetBody(data) + }, &resp) + if err != nil { + return "", err + } + + p, err := url.Parse(resp.Link.WebUrl) + if err != nil { + return "", err + } + // Do some transformations + q := url.Values{} + if p.Host == "1drv.ms" { + // For personal + // https://1drv.ms/t/c/{user}/{share} -> + // https://my.microsoftpersonalcontent.com/personal/{user}/_layouts/15/download.aspx?share={share} + paths := strings.Split(p.Path, "/") + if len(paths) < 5 || paths[3] == "" || paths[4] == "" { + return "", fmt.Errorf("invalid onedrive short link") + } + user := paths[3] + share := paths[4] + p.Host = "my.microsoftpersonalcontent.com" + p.Path = fmt.Sprintf("/personal/%s/_layouts/15/download.aspx", user) + q.Set("share", share) + } else if strings.Contains(p.Host, ".sharepoint.com") { + // https://{tenant}-my.sharepoint.com/:u:/g/personal/{user_email}/{share} + // https://{tenant}-my.sharepoint.com/personal/{user_email}/_layouts/15/download.aspx?share={share} + paths := strings.Split(p.Path, "/") + if len(paths) < 6 || paths[5] == "" { + return "", fmt.Errorf("invalid onedrive sharepoint link") + } + user := paths[4] + share := paths[5] + p.Path = fmt.Sprintf("/personal/%s/_layouts/15/download.aspx", user) + q.Set("share", share) + } else { + return "", fmt.Errorf("unsupported onedrive link host: %s", p.Host) + } + p.RawQuery = q.Encode() + return p.String(), nil +} + func (d *Onedrive) upSmall(ctx context.Context, dstDir model.Obj, stream model.FileStreamer) error { filepath := stdpath.Join(dstDir.GetPath(), stream.GetName()) // 1. upload new file