Skip to content

Commit 918ca28

Browse files
committed
feat: add 189cloudPC driver
1 parent 7a12f1b commit 918ca28

7 files changed

Lines changed: 1366 additions & 4 deletions

File tree

drivers/189pc/driver.go

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
package _189pc
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"regexp"
7+
"strconv"
8+
"strings"
9+
"time"
10+
11+
"github.com/alist-org/alist/v3/drivers/base"
12+
"github.com/alist-org/alist/v3/internal/driver"
13+
"github.com/alist-org/alist/v3/internal/errs"
14+
"github.com/alist-org/alist/v3/internal/model"
15+
"github.com/alist-org/alist/v3/pkg/utils"
16+
"github.com/go-resty/resty/v2"
17+
)
18+
19+
type Yun189PC struct {
20+
model.Storage
21+
Addition
22+
23+
identity string
24+
25+
client *resty.Client
26+
putClient *resty.Client
27+
28+
loginParam *LoginParam
29+
tokenInfo *AppSessionResp
30+
}
31+
32+
func (y *Yun189PC) Config() driver.Config {
33+
return config
34+
}
35+
36+
func (y *Yun189PC) GetAddition() driver.Additional {
37+
return y.Addition
38+
}
39+
40+
func (y *Yun189PC) Init(ctx context.Context, storage model.Storage) (err error) {
41+
y.Storage = storage
42+
if err = utils.Json.UnmarshalFromString(y.Storage.Addition, &y.Addition); err != nil {
43+
return err
44+
}
45+
46+
// 处理个人云和家庭云参数
47+
if y.isFamily() && y.RootFolderID == "-11" {
48+
y.RootFolderID = ""
49+
}
50+
if !y.isFamily() && y.RootFolderID == "" {
51+
y.RootFolderID = "-11"
52+
y.FamilyID = ""
53+
}
54+
55+
// 初始化请求客户端
56+
if y.client == nil {
57+
y.client = base.NewRestyClient().SetHeaders(map[string]string{
58+
"Accept": "application/json;charset=UTF-8",
59+
"Referer": WEB_URL,
60+
})
61+
}
62+
if y.putClient == nil {
63+
y.putClient = base.NewRestyClient().SetTimeout(120 * time.Second)
64+
}
65+
66+
// 避免重复登陆
67+
identity := utils.GetMD5Encode(y.Username + y.Password)
68+
if !y.isLogin() || y.identity != identity {
69+
y.identity = identity
70+
if err = y.login(); err != nil {
71+
return
72+
}
73+
}
74+
75+
// 处理家庭云ID
76+
if y.isFamily() && y.FamilyID == "" {
77+
if y.FamilyID, err = y.getFamilyID(); err != nil {
78+
return err
79+
}
80+
}
81+
return
82+
}
83+
84+
func (y *Yun189PC) Drop(ctx context.Context) error {
85+
return nil
86+
}
87+
88+
func (y *Yun189PC) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
89+
return y.getFiles(ctx, dir.GetID())
90+
}
91+
92+
func (y *Yun189PC) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
93+
var downloadUrl struct {
94+
URL string `json:"fileDownloadUrl"`
95+
}
96+
97+
fullUrl := API_URL
98+
if y.isFamily() {
99+
fullUrl += "/family/file"
100+
}
101+
fullUrl += "/getFileDownloadUrl.action"
102+
103+
_, err := y.get(fullUrl, func(r *resty.Request) {
104+
r.SetContext(ctx)
105+
r.SetQueryParam("fileId", file.GetID())
106+
if y.isFamily() {
107+
r.SetQueryParams(map[string]string{
108+
"familyId": y.FamilyID,
109+
})
110+
} else {
111+
r.SetQueryParams(map[string]string{
112+
"dt": "3",
113+
"flag": "1",
114+
})
115+
}
116+
}, &downloadUrl)
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
// 重定向获取真实链接
122+
downloadUrl.URL = strings.Replace(strings.ReplaceAll(downloadUrl.URL, "&", "&"), "http://", "https://", 1)
123+
res, err := base.NoRedirectClient.R().SetContext(ctx).Get(downloadUrl.URL)
124+
if err != nil {
125+
return nil, err
126+
}
127+
if res.StatusCode() == 302 {
128+
downloadUrl.URL = res.Header().Get("location")
129+
}
130+
131+
like := &model.Link{
132+
URL: downloadUrl.URL,
133+
Header: http.Header{
134+
"User-Agent": []string{base.UserAgent},
135+
},
136+
}
137+
138+
// 获取链接有效时常
139+
strs := regexp.MustCompile(`(?i)expire[^=]*=([0-9]*)`).FindStringSubmatch(downloadUrl.URL)
140+
if len(strs) == 2 {
141+
timestamp, err := strconv.ParseInt(strs[1], 10, 64)
142+
if err == nil {
143+
expired := time.Duration(timestamp-time.Now().Unix()) * time.Second
144+
like.Expiration = &expired
145+
}
146+
}
147+
return like, nil
148+
}
149+
150+
func (y *Yun189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
151+
fullUrl := API_URL
152+
if y.isFamily() {
153+
fullUrl += "/family/file"
154+
}
155+
fullUrl += "/createFolder.action"
156+
157+
_, err := y.post(fullUrl, func(req *resty.Request) {
158+
req.SetContext(ctx)
159+
req.SetQueryParams(map[string]string{
160+
"folderName": dirName,
161+
"relativePath": "",
162+
})
163+
if y.isFamily() {
164+
req.SetQueryParams(map[string]string{
165+
"familyId": y.FamilyID,
166+
"parentId": parentDir.GetID(),
167+
})
168+
} else {
169+
req.SetQueryParams(map[string]string{
170+
"parentFolderId": parentDir.GetID(),
171+
})
172+
}
173+
}, nil)
174+
return err
175+
}
176+
177+
func (y *Yun189PC) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
178+
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
179+
req.SetContext(ctx)
180+
req.SetFormData(map[string]string{
181+
"type": "MOVE",
182+
"taskInfos": MustString(utils.Json.MarshalToString(
183+
[]BatchTaskInfo{
184+
{
185+
FileId: srcObj.GetID(),
186+
FileName: srcObj.GetName(),
187+
IsFolder: BoolToNumber(srcObj.IsDir()),
188+
},
189+
})),
190+
"targetFolderId": dstDir.GetID(),
191+
})
192+
if y.isFamily() {
193+
req.SetFormData(map[string]string{
194+
"familyId": y.FamilyID,
195+
})
196+
}
197+
}, nil)
198+
return err
199+
}
200+
201+
func (y *Yun189PC) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
202+
queryParam := make(map[string]string)
203+
fullUrl := API_URL
204+
method := http.MethodPost
205+
if y.isFamily() {
206+
fullUrl += "/family/file"
207+
method = http.MethodGet
208+
queryParam["familyId"] = y.FamilyID
209+
}
210+
if srcObj.IsDir() {
211+
fullUrl += "/renameFolder.action"
212+
queryParam["folderId"] = srcObj.GetID()
213+
queryParam["destFolderName"] = newName
214+
} else {
215+
fullUrl += "/renameFile.action"
216+
queryParam["fileId"] = srcObj.GetID()
217+
queryParam["destFileName"] = newName
218+
}
219+
_, err := y.request(fullUrl, method, func(req *resty.Request) {
220+
req.SetContext(ctx)
221+
req.SetQueryParams(queryParam)
222+
}, nil, nil)
223+
return err
224+
}
225+
226+
func (y *Yun189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
227+
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
228+
req.SetContext(ctx)
229+
req.SetFormData(map[string]string{
230+
"type": "COPY",
231+
"taskInfos": MustString(utils.Json.MarshalToString(
232+
[]BatchTaskInfo{
233+
{
234+
FileId: srcObj.GetID(),
235+
FileName: srcObj.GetName(),
236+
IsFolder: BoolToNumber(srcObj.IsDir()),
237+
},
238+
})),
239+
"targetFolderId": dstDir.GetID(),
240+
"targetFileName": dstDir.GetName(),
241+
})
242+
if y.isFamily() {
243+
req.SetFormData(map[string]string{
244+
"familyId": y.FamilyID,
245+
})
246+
}
247+
}, nil)
248+
return err
249+
}
250+
251+
func (y *Yun189PC) Remove(ctx context.Context, obj model.Obj) error {
252+
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
253+
req.SetContext(ctx)
254+
req.SetFormData(map[string]string{
255+
"type": "DELETE",
256+
"taskInfos": MustString(utils.Json.MarshalToString(
257+
[]*BatchTaskInfo{
258+
{
259+
FileId: obj.GetID(),
260+
FileName: obj.GetName(),
261+
IsFolder: BoolToNumber(obj.IsDir()),
262+
},
263+
})),
264+
})
265+
266+
if y.isFamily() {
267+
req.SetFormData(map[string]string{
268+
"familyId": y.FamilyID,
269+
})
270+
}
271+
}, nil)
272+
return err
273+
}
274+
275+
func (y *Yun189PC) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
276+
if y.RapidUpload {
277+
return y.FastUpload(ctx, dstDir, stream, up)
278+
}
279+
return y.CommonUpload(ctx, dstDir, stream, up)
280+
}
281+
282+
func (y *Yun189PC) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
283+
return nil, errs.NotSupport
284+
}

0 commit comments

Comments
 (0)