Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for Onedrive Sharelink driver #6793

Merged
merged 2 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
_ "github.com/alist-org/alist/v3/drivers/netease_music"
_ "github.com/alist-org/alist/v3/drivers/onedrive"
_ "github.com/alist-org/alist/v3/drivers/onedrive_app"
_ "github.com/alist-org/alist/v3/drivers/onedrive_sharelink"
_ "github.com/alist-org/alist/v3/drivers/pikpak"
_ "github.com/alist-org/alist/v3/drivers/pikpak_share"
_ "github.com/alist-org/alist/v3/drivers/quark_uc"
Expand Down
131 changes: 131 additions & 0 deletions drivers/onedrive_sharelink/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package onedrive_sharelink

import (
"context"
"strings"
"time"

"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"
log "github.com/sirupsen/logrus"
)

type OnedriveSharelink struct {
model.Storage
cron *cron.Cron
Addition
}

func (d *OnedriveSharelink) Config() driver.Config {
return config
}

func (d *OnedriveSharelink) GetAddition() driver.Additional {
return &d.Addition
}

func (d *OnedriveSharelink) Init(ctx context.Context) error {
// Initialize error variable
var err error

// If there is "-my" in the URL, it is NOT a SharePoint link
d.IsSharepoint = !strings.Contains(d.ShareLinkURL, "-my")

// Initialize cron job to run every hour
d.cron = cron.NewCron(time.Hour * 1)
d.cron.Do(func() {
var err error
d.Headers, err = d.getHeaders()
if err != nil {
log.Errorf("%+v", err)
}
})

// Get initial headers
d.Headers, err = d.getHeaders()
if err != nil {
return err
}

return nil
}

func (d *OnedriveSharelink) Drop(ctx context.Context) error {
return nil
}

func (d *OnedriveSharelink) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
path := dir.GetPath()
files, err := d.getFiles(path)
if err != nil {
return nil, err
}

// Convert the slice of files to the required model.Obj format
return utils.SliceConvert(files, func(src Item) (model.Obj, error) {
return fileToObj(src), nil
})
}

func (d *OnedriveSharelink) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
// Get the unique ID of the file
uniqueId := file.GetID()
// Cut the first char and the last char
uniqueId = uniqueId[1 : len(uniqueId)-1]
url := d.downloadLinkPrefix + uniqueId
header := d.Headers

// If the headers are older than 30 minutes, get new headers
if d.HeaderTime < time.Now().Unix()-1800 {
var err error
log.Debug("headers are older than 30 minutes, get new headers")
header, err = d.getHeaders()
if err != nil {
return nil, err
}
}

return &model.Link{
URL: url,
Header: header,
}, nil
}

func (d *OnedriveSharelink) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
// TODO create folder, optional
return errs.NotImplement
}

func (d *OnedriveSharelink) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
// TODO move obj, optional
return errs.NotImplement
}

func (d *OnedriveSharelink) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
// TODO rename obj, optional
return errs.NotImplement
}

func (d *OnedriveSharelink) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
// TODO copy obj, optional
return errs.NotImplement
}

func (d *OnedriveSharelink) Remove(ctx context.Context, obj model.Obj) error {
// TODO remove obj, optional
return errs.NotImplement
}

func (d *OnedriveSharelink) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
// TODO upload file, optional
return errs.NotImplement
}

//func (d *OnedriveSharelink) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
// return nil, errs.NotSupport
//}

var _ driver.Driver = (*OnedriveSharelink)(nil)
32 changes: 32 additions & 0 deletions drivers/onedrive_sharelink/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package onedrive_sharelink

import (
"net/http"

"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/op"
)

type Addition struct {
driver.RootPath
ShareLinkURL string `json:"url" required:"true"`
ShareLinkPassword string `json:"password"`
IsSharepoint bool
downloadLinkPrefix string
Headers http.Header
HeaderTime int64
}

var config = driver.Config{
Name: "Onedrive Sharelink",
OnlyProxy: true,
NoUpload: true,
DefaultRoot: "/",
CheckStatus: false,
}

func init() {
op.RegisterDriver(func() driver.Driver {
return &OnedriveSharelink{}
})
}
77 changes: 77 additions & 0 deletions drivers/onedrive_sharelink/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package onedrive_sharelink

import (
"strconv"
"time"

"github.com/alist-org/alist/v3/internal/model"
)

// FolderResp represents the structure of the folder response from the OneDrive API.
type FolderResp struct {
// Data holds the nested structure of the response.
Data struct {
Legacy struct {
RenderListData struct {
ListData struct {
Items []Item `json:"Row"` // Items contains the list of items in the folder.
} `json:"ListData"`
} `json:"renderListDataAsStream"`
} `json:"legacy"`
} `json:"data"`
}

// Item represents an individual item in the folder.
type Item struct {
ObjType string `json:"FSObjType"` // ObjType indicates if the item is a file or folder.
Name string `json:"FileLeafRef"` // Name is the name of the item.
ModifiedTime time.Time `json:"Modified."` // ModifiedTime is the last modified time of the item.
Size string `json:"File_x0020_Size"` // Size is the size of the item in string format.
Id string `json:"UniqueId"` // Id is the unique identifier of the item.
}

// fileToObj converts an Item to an ObjThumb.
func fileToObj(f Item) *model.ObjThumb {
// Convert Size from string to int64.
size, _ := strconv.ParseInt(f.Size, 10, 64)
// Convert ObjType from string to int.
objtype, _ := strconv.Atoi(f.ObjType)

// Create a new ObjThumb with the converted values.
file := &model.ObjThumb{
Object: model.Object{
Name: f.Name,
Modified: f.ModifiedTime,
Size: size,
IsFolder: objtype == 1, // Check if the item is a folder.
ID: f.Id,
},
Thumbnail: model.Thumbnail{},
}
return file
}

// GraphQLNEWRequest represents the structure of a new GraphQL request.
type GraphQLNEWRequest struct {
ListData struct {
NextHref string `json:"NextHref"` // NextHref is the link to the next set of data.
Row []Item `json:"Row"` // Row contains the list of items.
} `json:"ListData"`
}

// GraphQLRequest represents the structure of a GraphQL request.
type GraphQLRequest struct {
Data struct {
Legacy struct {
RenderListDataAsStream struct {
ListData struct {
NextHref string `json:"NextHref"` // NextHref is the link to the next set of data.
Row []Item `json:"Row"` // Row contains the list of items.
} `json:"ListData"`
ViewMetadata struct {
ListViewXml string `json:"ListViewXml"` // ListViewXml contains the XML of the list view.
} `json:"ViewMetadata"`
} `json:"renderListDataAsStream"`
} `json:"legacy"`
} `json:"data"`
}
Loading
Loading