fundrive-quark 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fundrive-quark might be problematic. Click here for more details.
- fundrive_quark-1.0.1/PKG-INFO +10 -0
- fundrive_quark-1.0.1/README.md +1 -0
- fundrive_quark-1.0.1/pyproject.toml +13 -0
- fundrive_quark-1.0.1/setup.cfg +4 -0
- fundrive_quark-1.0.1/src/fundrive_quark.egg-info/PKG-INFO +10 -0
- fundrive_quark-1.0.1/src/fundrive_quark.egg-info/SOURCES.txt +10 -0
- fundrive_quark-1.0.1/src/fundrive_quark.egg-info/dependency_links.txt +1 -0
- fundrive_quark-1.0.1/src/fundrive_quark.egg-info/requires.txt +1 -0
- fundrive_quark-1.0.1/src/fundrive_quark.egg-info/top_level.txt +1 -0
- fundrive_quark-1.0.1/src/fundrives/__init__.py +0 -0
- fundrive_quark-1.0.1/src/fundrives/quark/__init__.py +0 -0
- fundrive_quark-1.0.1/src/fundrives/quark/manage.py +619 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# fardrive-quark
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fundrive-quark"
|
|
3
|
+
version = "1.0.1"
|
|
4
|
+
description = "fundrive-quark"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.8"
|
|
7
|
+
dependencies = [ "funutil>=1.0.46",]
|
|
8
|
+
[[project.authors]]
|
|
9
|
+
name = "niuliangtao"
|
|
10
|
+
email = "farfarfun@qq.com"
|
|
11
|
+
|
|
12
|
+
[tool.setuptools]
|
|
13
|
+
license-files = []
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/fundrive_quark.egg-info/PKG-INFO
|
|
4
|
+
src/fundrive_quark.egg-info/SOURCES.txt
|
|
5
|
+
src/fundrive_quark.egg-info/dependency_links.txt
|
|
6
|
+
src/fundrive_quark.egg-info/requires.txt
|
|
7
|
+
src/fundrive_quark.egg-info/top_level.txt
|
|
8
|
+
src/fundrives/__init__.py
|
|
9
|
+
src/fundrives/quark/__init__.py
|
|
10
|
+
src/fundrives/quark/manage.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
funutil>=1.0.46
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fundrives
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import random
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
import string
|
|
8
|
+
import time
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import List, Dict, Tuple, Any, Union
|
|
11
|
+
|
|
12
|
+
import requests
|
|
13
|
+
from funutil import getLogger, deep_get
|
|
14
|
+
|
|
15
|
+
logger = getLogger("fundrive")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_id_from_url(url) -> str:
|
|
19
|
+
"""pwd_id"""
|
|
20
|
+
pattern = r"/s/(\w+)"
|
|
21
|
+
match = re.search(pattern, url)
|
|
22
|
+
if match:
|
|
23
|
+
return match.group(1)
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def safe_copy(src, dst):
|
|
28
|
+
if not os.path.exists(src):
|
|
29
|
+
print(f"源文件不存在,跳过复制:{src}")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
if os.path.exists(dst):
|
|
33
|
+
os.remove(dst)
|
|
34
|
+
print(f"目标文件已存在,已删除:{dst}")
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
shutil.copy(src, dst)
|
|
38
|
+
print(f"文件已复制到:{dst}")
|
|
39
|
+
except Exception as e:
|
|
40
|
+
print("备份share_url.txt文件错误,", e)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def generate_random_code(length=4):
|
|
44
|
+
characters = string.ascii_letters + string.digits
|
|
45
|
+
random_code = "".join(random.choice(characters) for _ in range(length))
|
|
46
|
+
return random_code
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_datetime(
|
|
50
|
+
timestamp: Union[int, float, None] = None, fmt: str = "%Y-%m-%d %H:%M:%S"
|
|
51
|
+
) -> str:
|
|
52
|
+
if timestamp is None or not isinstance(timestamp, (int, float)):
|
|
53
|
+
return datetime.today().strftime(fmt)
|
|
54
|
+
else:
|
|
55
|
+
dt = datetime.fromtimestamp(timestamp)
|
|
56
|
+
formatted_time = dt.strftime(fmt)
|
|
57
|
+
return formatted_time
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class QuarkPanManage:
|
|
61
|
+
def __init__(self, cookies, *args, **kwargs) -> None:
|
|
62
|
+
# self.base_url = 'https://drive.quark.cn/1/clouddrive'
|
|
63
|
+
self.base_url = "https://drive-pc.quark.cn/1/clouddrive"
|
|
64
|
+
|
|
65
|
+
self.headers: Dict[str, str] = {
|
|
66
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)"
|
|
67
|
+
" Chrome/94.0.4606.71 Safari/537.36 Core/1.94.225.400 QQBrowser/12.2.5544.400",
|
|
68
|
+
"origin": "https://pan.quark.cn",
|
|
69
|
+
"referer": "https://pan.quark.cn/",
|
|
70
|
+
"accept-language": "zh-CN,zh;q=0.9",
|
|
71
|
+
"cookie": cookies,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def get_pwd_id(share_url: str) -> str:
|
|
76
|
+
return share_url.split("?")[0].split("/s/")[1]
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def extract_urls(text: str) -> list:
|
|
80
|
+
url_pattern = r'https?://[^\s<>"]+|www\.[^\s<>"]+'
|
|
81
|
+
return re.findall(url_pattern, text)[0]
|
|
82
|
+
|
|
83
|
+
def request(
|
|
84
|
+
self,
|
|
85
|
+
uri,
|
|
86
|
+
method="GET",
|
|
87
|
+
params=None,
|
|
88
|
+
headers=None,
|
|
89
|
+
data=None,
|
|
90
|
+
timeout=10,
|
|
91
|
+
*args,
|
|
92
|
+
**kwargs,
|
|
93
|
+
):
|
|
94
|
+
url = f"{self.base_url}/{uri}"
|
|
95
|
+
params = params or {}
|
|
96
|
+
params.update(
|
|
97
|
+
{
|
|
98
|
+
"pr": "ucpro",
|
|
99
|
+
"fr": "pc",
|
|
100
|
+
"uc_param_str": "",
|
|
101
|
+
"__dt": random.randint(100, 9999),
|
|
102
|
+
"__t": int(time.time()) * 1000,
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
return requests.request(
|
|
106
|
+
method,
|
|
107
|
+
url,
|
|
108
|
+
params=params,
|
|
109
|
+
headers=headers or self.headers,
|
|
110
|
+
json=data,
|
|
111
|
+
timeout=timeout,
|
|
112
|
+
*args,
|
|
113
|
+
**kwargs,
|
|
114
|
+
).json()
|
|
115
|
+
|
|
116
|
+
def get_stoken(self, pwd_id: str) -> str:
|
|
117
|
+
data = {"pwd_id": pwd_id, "passcode": ""}
|
|
118
|
+
json_data = self.request(
|
|
119
|
+
"share/sharepage/token",
|
|
120
|
+
"post",
|
|
121
|
+
data=data,
|
|
122
|
+
)
|
|
123
|
+
if json_data["status"] == 200 and json_data["data"]:
|
|
124
|
+
stoken = json_data["data"]["stoken"]
|
|
125
|
+
else:
|
|
126
|
+
stoken = ""
|
|
127
|
+
logger.info(f"文件转存失败,{json_data['message']}")
|
|
128
|
+
return stoken
|
|
129
|
+
|
|
130
|
+
def get_detail(
|
|
131
|
+
self,
|
|
132
|
+
pwd_id: str,
|
|
133
|
+
stoken: str,
|
|
134
|
+
pdir_fid: str = "0",
|
|
135
|
+
size=50,
|
|
136
|
+
sort="file_type:asc,updated_at:desc",
|
|
137
|
+
) -> Tuple[str, List[Dict[str, Union[int, str]]]]:
|
|
138
|
+
file_list: List[Dict[str, Union[int, str]]] = []
|
|
139
|
+
for page in range(1, 100):
|
|
140
|
+
params = {
|
|
141
|
+
"pwd_id": pwd_id,
|
|
142
|
+
"stoken": stoken,
|
|
143
|
+
"pdir_fid": pdir_fid,
|
|
144
|
+
"force": "0",
|
|
145
|
+
"_page": page,
|
|
146
|
+
"_size": size,
|
|
147
|
+
"_sort": sort,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
json_data = self.request("share/sharepage/detail", "get", params=params)
|
|
151
|
+
is_owner = json_data["data"]["is_owner"]
|
|
152
|
+
_total = json_data["metadata"]["_total"]
|
|
153
|
+
if _total < 1:
|
|
154
|
+
return is_owner, file_list
|
|
155
|
+
|
|
156
|
+
_size = json_data["metadata"]["_size"] # 每页限制数量
|
|
157
|
+
_count = json_data["metadata"]["_count"] # 当前页数量
|
|
158
|
+
|
|
159
|
+
_list = json_data["data"]["list"]
|
|
160
|
+
|
|
161
|
+
for file in _list:
|
|
162
|
+
file_list.append(
|
|
163
|
+
{
|
|
164
|
+
"fid": file["fid"],
|
|
165
|
+
"file_name": file["file_name"],
|
|
166
|
+
"file_type": file["file_type"],
|
|
167
|
+
"dir": file["dir"],
|
|
168
|
+
"pdir_fid": file["pdir_fid"],
|
|
169
|
+
"include_items": file["include_items"]
|
|
170
|
+
if "include_items" in file
|
|
171
|
+
else "",
|
|
172
|
+
"share_fid_token": file["share_fid_token"],
|
|
173
|
+
"status": file["status"],
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
if _total <= _size or _count < _size:
|
|
177
|
+
return is_owner, file_list
|
|
178
|
+
|
|
179
|
+
def get_user_info(self) -> str:
|
|
180
|
+
params = {
|
|
181
|
+
"fr": "pc",
|
|
182
|
+
"platform": "pc",
|
|
183
|
+
}
|
|
184
|
+
return requests.get(
|
|
185
|
+
"https://pan.quark.cn/account/info", params=params, headers=self.headers
|
|
186
|
+
).json()
|
|
187
|
+
|
|
188
|
+
def create_dir(self, pdir_name="新建文件夹", pdir_fid="") -> None:
|
|
189
|
+
json_data = {
|
|
190
|
+
"pdir_fid": pdir_fid,
|
|
191
|
+
"file_name": pdir_name,
|
|
192
|
+
"dir_path": "",
|
|
193
|
+
"dir_init_lock": False,
|
|
194
|
+
}
|
|
195
|
+
return self.request("file", "post", data=json_data)
|
|
196
|
+
|
|
197
|
+
def save_shared(
|
|
198
|
+
self,
|
|
199
|
+
share_url: str,
|
|
200
|
+
folder_id: Union[str, None] = None,
|
|
201
|
+
) -> None:
|
|
202
|
+
logger.info(f"文件分享链接:{share_url}")
|
|
203
|
+
pwd_id = self.get_pwd_id(share_url)
|
|
204
|
+
stoken = self.get_stoken(pwd_id)
|
|
205
|
+
if not stoken:
|
|
206
|
+
return
|
|
207
|
+
is_owner, data_list = self.get_detail(pwd_id, stoken)
|
|
208
|
+
files_count = 0
|
|
209
|
+
folders_count = 0
|
|
210
|
+
files_list: List[str] = []
|
|
211
|
+
folders_list: List[str] = []
|
|
212
|
+
files_id_list = []
|
|
213
|
+
|
|
214
|
+
if data_list:
|
|
215
|
+
total_files_count = len(data_list)
|
|
216
|
+
for data in data_list:
|
|
217
|
+
if data["dir"]:
|
|
218
|
+
folders_count += 1
|
|
219
|
+
folders_list.append(data["file_name"])
|
|
220
|
+
else:
|
|
221
|
+
files_count += 1
|
|
222
|
+
files_list.append(data["file_name"])
|
|
223
|
+
files_id_list.append((data["fid"], data["file_name"]))
|
|
224
|
+
|
|
225
|
+
logger.info(
|
|
226
|
+
f"转存总数:{total_files_count},文件数:{files_count},文件夹数:{folders_count} | 支持嵌套"
|
|
227
|
+
)
|
|
228
|
+
logger.info(f"文件转存列表:{files_list}")
|
|
229
|
+
logger.info(f"文件夹转存列表:{folders_list}")
|
|
230
|
+
|
|
231
|
+
fid_list = [i["fid"] for i in data_list]
|
|
232
|
+
share_fid_token_list = [i["share_fid_token"] for i in data_list]
|
|
233
|
+
|
|
234
|
+
if not folder_id:
|
|
235
|
+
logger.info(
|
|
236
|
+
"保存目录ID不合法,请重新获取,如果无法获取,请输入0作为文件夹ID"
|
|
237
|
+
)
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
if is_owner == 1:
|
|
241
|
+
logger.info("网盘中已经存在该文件,无需再次转存")
|
|
242
|
+
return
|
|
243
|
+
task_id = self.get_share_save_task_id(
|
|
244
|
+
pwd_id, stoken, fid_list, share_fid_token_list, to_pdir_fid=folder_id
|
|
245
|
+
)
|
|
246
|
+
self.submit_task(task_id)
|
|
247
|
+
|
|
248
|
+
def get_file_download_url(self, fid: str) -> None:
|
|
249
|
+
data = {"fids": [fid]}
|
|
250
|
+
json_data = self.request("file/download", "post", data=data)
|
|
251
|
+
data_list = json_data.get("data", None)
|
|
252
|
+
|
|
253
|
+
if json_data["status"] != 200:
|
|
254
|
+
logger.info(
|
|
255
|
+
f"文件下载地址列表获取失败, {json_data['message']}", error_msg=True
|
|
256
|
+
)
|
|
257
|
+
return
|
|
258
|
+
elif data_list:
|
|
259
|
+
logger.info("文件下载地址列表获取成功")
|
|
260
|
+
return data_list[0]["download_url"]
|
|
261
|
+
|
|
262
|
+
def get_share_save_task_id(
|
|
263
|
+
self,
|
|
264
|
+
pwd_id: str,
|
|
265
|
+
stoken: str,
|
|
266
|
+
first_ids: List[str],
|
|
267
|
+
share_fid_tokens: List[str],
|
|
268
|
+
to_pdir_fid: str = "0",
|
|
269
|
+
) -> str:
|
|
270
|
+
data = {
|
|
271
|
+
"fid_list": first_ids,
|
|
272
|
+
"fid_token_list": share_fid_tokens,
|
|
273
|
+
"to_pdir_fid": to_pdir_fid,
|
|
274
|
+
"pwd_id": pwd_id,
|
|
275
|
+
"stoken": stoken,
|
|
276
|
+
"pdir_fid": "0",
|
|
277
|
+
"scene": "link",
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
response = self.request("share/sharepage/save", "post", data=data)
|
|
281
|
+
json_data = response.json()
|
|
282
|
+
task_id = json_data["data"]["task_id"]
|
|
283
|
+
logger.info(f"获取任务ID:{task_id}")
|
|
284
|
+
return task_id
|
|
285
|
+
|
|
286
|
+
def submit_task(
|
|
287
|
+
self, task_id: str, retry: int = 50
|
|
288
|
+
) -> Union[bool, Dict[str, Union[str, Dict[str, Union[int, str]]]]]:
|
|
289
|
+
for i in range(retry):
|
|
290
|
+
# 随机暂停100-50毫秒
|
|
291
|
+
time.sleep(random.randint(500, 1000) / 1000)
|
|
292
|
+
logger.info(f"第{i + 1}次提交任务")
|
|
293
|
+
params = {"task_id": task_id, "retry_index": i}
|
|
294
|
+
json_data = self.request("task", "get", headers=self.headers, params=params)
|
|
295
|
+
|
|
296
|
+
if json_data["message"] != "ok":
|
|
297
|
+
if (
|
|
298
|
+
json_data["code"] == 32003
|
|
299
|
+
and "capacity limit" in json_data["message"]
|
|
300
|
+
):
|
|
301
|
+
logger.info(
|
|
302
|
+
"转存失败,网盘容量不足!请注意当前已成功保存的个数,避免重复保存",
|
|
303
|
+
)
|
|
304
|
+
elif json_data["code"] == 41013:
|
|
305
|
+
logger.info(
|
|
306
|
+
f"网盘文件夹不存在,请重新运行按3切换保存目录后重试!",
|
|
307
|
+
)
|
|
308
|
+
else:
|
|
309
|
+
logger.info(
|
|
310
|
+
f"错误信息:{json_data['message']}",
|
|
311
|
+
)
|
|
312
|
+
continue
|
|
313
|
+
|
|
314
|
+
if json_data["data"]["status"] != 2:
|
|
315
|
+
continue
|
|
316
|
+
|
|
317
|
+
if json_data["data"]["task_title"] == "分享-转存":
|
|
318
|
+
logger.info(f"结束任务ID:{task_id}")
|
|
319
|
+
logger.info(
|
|
320
|
+
f"文件保存位置:{deep_get(json_data, 'data', 'save_as', 'to_pdir_name') or '根目录'} 文件夹"
|
|
321
|
+
)
|
|
322
|
+
return json_data
|
|
323
|
+
|
|
324
|
+
def get_share_task_id(
|
|
325
|
+
self,
|
|
326
|
+
fid: str,
|
|
327
|
+
file_name: str,
|
|
328
|
+
url_type: int = 1,
|
|
329
|
+
expired_type: int = 2,
|
|
330
|
+
password: str = "",
|
|
331
|
+
) -> str:
|
|
332
|
+
json_data = {
|
|
333
|
+
"fid_list": [fid],
|
|
334
|
+
"title": file_name,
|
|
335
|
+
"url_type": url_type,
|
|
336
|
+
"expired_type": expired_type,
|
|
337
|
+
}
|
|
338
|
+
if url_type == 2:
|
|
339
|
+
json_data["passcode"] = password or generate_random_code()
|
|
340
|
+
json_data = self.request("share", "post", json=json_data)
|
|
341
|
+
return json_data["data"]["task_id"]
|
|
342
|
+
|
|
343
|
+
def get_share_id(self, task_id: str) -> str:
|
|
344
|
+
params = {
|
|
345
|
+
"task_id": task_id,
|
|
346
|
+
"retry_index": "0",
|
|
347
|
+
}
|
|
348
|
+
json_data = self.request("task", "get", params=params)
|
|
349
|
+
return json_data["data"]["share_id"]
|
|
350
|
+
|
|
351
|
+
def submit_share(self, share_id: str) -> None:
|
|
352
|
+
json_data = {
|
|
353
|
+
"share_id": share_id,
|
|
354
|
+
}
|
|
355
|
+
json_data = self.request(
|
|
356
|
+
"share/password",
|
|
357
|
+
"post",
|
|
358
|
+
data=json_data,
|
|
359
|
+
)
|
|
360
|
+
share_url = json_data["data"]["share_url"]
|
|
361
|
+
if "passcode" in json_data["data"]:
|
|
362
|
+
share_url = share_url + f"?pwd={json_data['data']['passcode']}"
|
|
363
|
+
return share_url
|
|
364
|
+
|
|
365
|
+
def share(
|
|
366
|
+
self,
|
|
367
|
+
share_url: str,
|
|
368
|
+
folder_id: Union[str, None] = None,
|
|
369
|
+
url_type: int = 1,
|
|
370
|
+
expired_type: int = 2,
|
|
371
|
+
password: str = "",
|
|
372
|
+
) -> None:
|
|
373
|
+
first_dir = ""
|
|
374
|
+
second_dir = ""
|
|
375
|
+
try:
|
|
376
|
+
logger.info(f"文件夹网页地址:{share_url}")
|
|
377
|
+
pwd_id = share_url.rsplit("/", maxsplit=1)[1].split("-")[0]
|
|
378
|
+
|
|
379
|
+
first_page = 1
|
|
380
|
+
n = 0
|
|
381
|
+
error = 0
|
|
382
|
+
os.makedirs("share", exist_ok=True)
|
|
383
|
+
|
|
384
|
+
while True:
|
|
385
|
+
json_data = self.get_file_list(
|
|
386
|
+
pwd_id, page=first_page, size=50, fetch_total=True
|
|
387
|
+
)
|
|
388
|
+
for i1 in json_data["data"]["list"]:
|
|
389
|
+
if not i1["dir"]:
|
|
390
|
+
continue
|
|
391
|
+
|
|
392
|
+
first_dir = i1["file_name"]
|
|
393
|
+
second_page = 1
|
|
394
|
+
while True:
|
|
395
|
+
logger.info(
|
|
396
|
+
f"正在获取{first_dir}第{first_page}页,二级目录第{second_page}页,目前共分享{n}文件"
|
|
397
|
+
)
|
|
398
|
+
json_data2 = self.get_file_list(
|
|
399
|
+
i1["fid"],
|
|
400
|
+
page=second_page,
|
|
401
|
+
size=50,
|
|
402
|
+
fetch_total=True,
|
|
403
|
+
)
|
|
404
|
+
for i2 in json_data2["data"]["list"]:
|
|
405
|
+
if not i2["dir"]:
|
|
406
|
+
continue
|
|
407
|
+
|
|
408
|
+
n += 1
|
|
409
|
+
share_success = False
|
|
410
|
+
|
|
411
|
+
fid = ""
|
|
412
|
+
for i in range(3):
|
|
413
|
+
try:
|
|
414
|
+
second_dir = i2["file_name"]
|
|
415
|
+
logger.info(
|
|
416
|
+
f"{n}.开始分享 {first_dir}/{second_dir} 文件夹"
|
|
417
|
+
)
|
|
418
|
+
random_time = random.choice([0.5, 1, 1.5, 2])
|
|
419
|
+
time.sleep(random_time)
|
|
420
|
+
# print('获取到文件夹ID:', i2['fid'])
|
|
421
|
+
fid = i2["fid"]
|
|
422
|
+
task_id = self.get_share_task_id(
|
|
423
|
+
fid,
|
|
424
|
+
second_dir,
|
|
425
|
+
url_type=url_type,
|
|
426
|
+
expired_type=expired_type,
|
|
427
|
+
password=password,
|
|
428
|
+
)
|
|
429
|
+
share_id = self.get_share_id(task_id)
|
|
430
|
+
share_url = self.submit_share(share_id)
|
|
431
|
+
logger.info(
|
|
432
|
+
f"{n} | {first_dir} | {second_dir} | {share_url}"
|
|
433
|
+
)
|
|
434
|
+
logger.info(
|
|
435
|
+
f"{n}.分享成功 {first_dir}/{second_dir} 文件夹"
|
|
436
|
+
)
|
|
437
|
+
share_success = True
|
|
438
|
+
break
|
|
439
|
+
|
|
440
|
+
except Exception as e:
|
|
441
|
+
share_error_msg = e
|
|
442
|
+
error += 1
|
|
443
|
+
|
|
444
|
+
if not share_success:
|
|
445
|
+
logger.error("分享失败:", share_error_msg)
|
|
446
|
+
logger.error(
|
|
447
|
+
f"{error}.{first_dir}/{second_dir} 文件夹"
|
|
448
|
+
)
|
|
449
|
+
logger.error(
|
|
450
|
+
f"{n} | {first_dir} | {second_dir} | {fid}"
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
second_total = json_data2["metadata"]["_total"]
|
|
454
|
+
second_size = json_data2["metadata"]["_size"]
|
|
455
|
+
second_page = json_data2["metadata"]["_page"]
|
|
456
|
+
if second_size * second_page >= second_total:
|
|
457
|
+
break
|
|
458
|
+
second_page += 1
|
|
459
|
+
|
|
460
|
+
second_total = json_data["metadata"]["_total"]
|
|
461
|
+
second_size = json_data["metadata"]["_size"]
|
|
462
|
+
second_page = json_data["metadata"]["_page"]
|
|
463
|
+
if second_size * second_page >= second_total:
|
|
464
|
+
break
|
|
465
|
+
first_page += 1
|
|
466
|
+
logger.info(f"总共分享了 {n} 个文件夹")
|
|
467
|
+
|
|
468
|
+
except Exception as e:
|
|
469
|
+
print("分享失败:", e)
|
|
470
|
+
logger.error(f"{first_dir}/{second_dir} 文件夹")
|
|
471
|
+
|
|
472
|
+
def share_retry(
|
|
473
|
+
self,
|
|
474
|
+
retry_url: str,
|
|
475
|
+
url_type: int = 1,
|
|
476
|
+
expired_type: int = 2,
|
|
477
|
+
password: str = "",
|
|
478
|
+
):
|
|
479
|
+
data_list = retry_url.split("\n")
|
|
480
|
+
|
|
481
|
+
error = 0
|
|
482
|
+
error_data = []
|
|
483
|
+
for n, i1 in enumerate(data_list):
|
|
484
|
+
data = i1.split(" | ")
|
|
485
|
+
if data and len(data) == 4:
|
|
486
|
+
first_dir = data[-3]
|
|
487
|
+
second_dir = data[-2]
|
|
488
|
+
fid = data[-1]
|
|
489
|
+
share_success = False
|
|
490
|
+
for i in range(3):
|
|
491
|
+
try:
|
|
492
|
+
task_id = self.get_share_task_id(
|
|
493
|
+
fid,
|
|
494
|
+
second_dir,
|
|
495
|
+
url_type=url_type,
|
|
496
|
+
expired_type=expired_type,
|
|
497
|
+
password=password,
|
|
498
|
+
)
|
|
499
|
+
logger.debug("获取到任务ID:", task_id)
|
|
500
|
+
share_id = self.get_share_id(task_id)
|
|
501
|
+
logger.debug("获取到分享ID:", share_id)
|
|
502
|
+
share_url = self.submit_share(share_id)
|
|
503
|
+
logger.info(f"{n} | {first_dir} | {second_dir} | {share_url}")
|
|
504
|
+
logger.info(f"{n}.分享成功 {first_dir}/{second_dir} 文件夹")
|
|
505
|
+
share_success = True
|
|
506
|
+
break
|
|
507
|
+
except Exception as e:
|
|
508
|
+
logger.error("分享失败:", e)
|
|
509
|
+
error += 1
|
|
510
|
+
|
|
511
|
+
if not share_success:
|
|
512
|
+
error_data.append(i1)
|
|
513
|
+
error_content = "\n".join(error_data)
|
|
514
|
+
logger.error(error_content)
|
|
515
|
+
|
|
516
|
+
def search_file(
|
|
517
|
+
self, file_name, page=1, size=50, sort="file_type:desc,updated_at:desc"
|
|
518
|
+
):
|
|
519
|
+
logger.info("正在从网盘搜索文件🔍")
|
|
520
|
+
params = {
|
|
521
|
+
"q": file_name,
|
|
522
|
+
"_page": page,
|
|
523
|
+
"_size": size,
|
|
524
|
+
"_sort": sort,
|
|
525
|
+
"_fetch_total": 1,
|
|
526
|
+
"_is_hl": "1",
|
|
527
|
+
}
|
|
528
|
+
return self.request("file/search", params=params)
|
|
529
|
+
|
|
530
|
+
def get_file_list(
|
|
531
|
+
self,
|
|
532
|
+
pdir_fid="0",
|
|
533
|
+
page=1,
|
|
534
|
+
size=100,
|
|
535
|
+
fetch_total=False,
|
|
536
|
+
sort="file_type:asc,file_name:asc",
|
|
537
|
+
) -> Dict[str, Any]:
|
|
538
|
+
params = {
|
|
539
|
+
"pdir_fid": pdir_fid,
|
|
540
|
+
"_page": page,
|
|
541
|
+
"_size": size,
|
|
542
|
+
"_fetch_total": fetch_total,
|
|
543
|
+
"_fetch_sub_dirs": "1",
|
|
544
|
+
"_sort": sort,
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return self.request("file/sort", "get", params=params)
|
|
548
|
+
|
|
549
|
+
def del_file(self, file_id):
|
|
550
|
+
logger.debug("正在删除文件")
|
|
551
|
+
data = {"action_type": 2, "filelist": [file_id], "exclude_fids": []}
|
|
552
|
+
return self.request("file/delete", "post", data=data)
|
|
553
|
+
|
|
554
|
+
def store(self, url: str):
|
|
555
|
+
pwd_id = get_id_from_url(url)
|
|
556
|
+
stoken = self.get_stoken(pwd_id)
|
|
557
|
+
detail = self.get_detail(pwd_id, stoken)[1][0]
|
|
558
|
+
file_name = detail.get("title")
|
|
559
|
+
|
|
560
|
+
first_id, share_fid_token, file_type = (
|
|
561
|
+
detail.get("fid"),
|
|
562
|
+
detail.get("share_fid_token"),
|
|
563
|
+
detail.get("file_type"),
|
|
564
|
+
)
|
|
565
|
+
task = self.save_task_id(pwd_id, stoken, first_id, share_fid_token)
|
|
566
|
+
data = self.task(task)
|
|
567
|
+
file_id = data.get("data").get("save_as").get("save_as_top_fids")[0]
|
|
568
|
+
share_task_id = self.share_task_id(file_id, file_name)
|
|
569
|
+
share_id = self.task(share_task_id).get("data").get("share_id")
|
|
570
|
+
share_link = self.get_share_link(share_id)
|
|
571
|
+
logger.info(file_id, file_name, file_type, share_link)
|
|
572
|
+
|
|
573
|
+
def save_task_id(self, pwd_id, stoken, first_id, share_fid_token, to_pdir_fid=0):
|
|
574
|
+
logger.info("获取保存文件的TASKID")
|
|
575
|
+
|
|
576
|
+
data = {
|
|
577
|
+
"fid_list": [first_id],
|
|
578
|
+
"fid_token_list": [share_fid_token],
|
|
579
|
+
"to_pdir_fid": to_pdir_fid,
|
|
580
|
+
"pwd_id": pwd_id,
|
|
581
|
+
"stoken": stoken,
|
|
582
|
+
"pdir_fid": "0",
|
|
583
|
+
"scene": "link",
|
|
584
|
+
}
|
|
585
|
+
response = self.request("share/sharepage/save", "POST", data=data)
|
|
586
|
+
logger.info(response.json())
|
|
587
|
+
task_id = response.json().get("data").get("task_id")
|
|
588
|
+
return task_id
|
|
589
|
+
|
|
590
|
+
def task(self, task_id, trice=10):
|
|
591
|
+
"""根据task_id进行任务"""
|
|
592
|
+
logger.info("根据TASKID执行任务")
|
|
593
|
+
trys = 0
|
|
594
|
+
for i in range(trice):
|
|
595
|
+
url = f"task"
|
|
596
|
+
trys += 1
|
|
597
|
+
data = {"task_id": task_id, "retry_index": "range"}
|
|
598
|
+
response = self.request(url, "get", headers=self.headers, data=data)
|
|
599
|
+
logger.info(response)
|
|
600
|
+
if response.get("data").get("status"):
|
|
601
|
+
return response
|
|
602
|
+
return False
|
|
603
|
+
|
|
604
|
+
def share_task_id(self, file_id, file_name):
|
|
605
|
+
"""创建分享任务ID"""
|
|
606
|
+
data = {
|
|
607
|
+
"fid_list": [file_id],
|
|
608
|
+
"title": file_name,
|
|
609
|
+
"url_type": 1,
|
|
610
|
+
"expired_type": 1,
|
|
611
|
+
}
|
|
612
|
+
response = self.request("share", "POST", data=data)
|
|
613
|
+
return response.get("data").get("task_id")
|
|
614
|
+
|
|
615
|
+
def get_share_link(self, share_id):
|
|
616
|
+
url = "https://drive-pc.quark.cn/1/clouddrive/share/password?pr=ucpro&fr=pc&uc_param_str="
|
|
617
|
+
data = {"share_id": share_id}
|
|
618
|
+
response = requests.post(url=url, json=data, headers=self.headers)
|
|
619
|
+
return response.json().get("data").get("share_url")
|