p115client 0.0.5.10.3__py3-none-any.whl → 0.0.5.10.5__py3-none-any.whl
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.
- p115client/client.py +23 -3
- p115client/tool/iterdir.py +563 -315
- {p115client-0.0.5.10.3.dist-info → p115client-0.0.5.10.5.dist-info}/METADATA +1 -1
- {p115client-0.0.5.10.3.dist-info → p115client-0.0.5.10.5.dist-info}/RECORD +6 -6
- {p115client-0.0.5.10.3.dist-info → p115client-0.0.5.10.5.dist-info}/LICENSE +0 -0
- {p115client-0.0.5.10.3.dist-info → p115client-0.0.5.10.5.dist-info}/WHEEL +0 -0
p115client/tool/iterdir.py
CHANGED
@@ -8,8 +8,8 @@ __all__ = [
|
|
8
8
|
"iter_nodes_skim", "iter_stared_dirs_raw", "iter_stared_dirs", "ensure_attr_path",
|
9
9
|
"ensure_attr_path_by_category_get", "iterdir_raw", "iterdir", "iterdir_limited",
|
10
10
|
"iter_files_raw", "iter_files", "traverse_files", "iter_dirs", "iter_dupfiles",
|
11
|
-
"iter_image_files", "share_iterdir", "share_iter_files", "
|
12
|
-
"iter_selected_nodes_by_pickcode", "iter_selected_nodes_using_category_get",
|
11
|
+
"iter_image_files", "share_iterdir", "share_iter_files", "share_get_id_to_path",
|
12
|
+
"iter_selected_nodes", "iter_selected_nodes_by_pickcode", "iter_selected_nodes_using_category_get",
|
13
13
|
"iter_selected_nodes_using_edit", "iter_selected_nodes_using_star_event",
|
14
14
|
"iter_selected_dirs_using_star", "iter_files_with_dirname", "iter_files_with_path",
|
15
15
|
"iter_files_with_path_by_export_dir", "iter_parents_3_level", "iter_dir_nodes",
|
@@ -59,30 +59,6 @@ from .life import iter_life_behavior_once, life_show
|
|
59
59
|
from .util import posix_escape_name, share_extract_payload, unescape_115_charref
|
60
60
|
|
61
61
|
|
62
|
-
WEBAPI_BASE_URLS = (
|
63
|
-
"http://webapi.115.com",
|
64
|
-
"https://webapi.115.com",
|
65
|
-
"http://webapi.115.com",
|
66
|
-
"http://115cdn.com/webapi",
|
67
|
-
"http://webapi.115.com",
|
68
|
-
"http://115vod.com/webapi",
|
69
|
-
)
|
70
|
-
PROAPI_BASE_URLS = (
|
71
|
-
"http://proapi.115.com",
|
72
|
-
"https://proapi.115.com",
|
73
|
-
"http://proapi.115.com",
|
74
|
-
"https://proapi.115.com",
|
75
|
-
)
|
76
|
-
APS_BASE_URLS = (
|
77
|
-
"http://115cdn.com/aps",
|
78
|
-
"http://aps.115.com",
|
79
|
-
"http://115vod.com/aps",
|
80
|
-
)
|
81
|
-
|
82
|
-
_n_get_ancestors = 0
|
83
|
-
_n_get_count = 0
|
84
|
-
|
85
|
-
|
86
62
|
class DirNode(NamedTuple):
|
87
63
|
name: str
|
88
64
|
parent_id: int
|
@@ -104,7 +80,7 @@ class OverviewAttr:
|
|
104
80
|
|
105
81
|
|
106
82
|
#: 用于缓存每个用户(根据用户 id 区别)的每个目录 id 到所对应的 (名称, 父id) 的元组的字典的字典
|
107
|
-
ID_TO_DIRNODE_CACHE: Final[defaultdict[int, dict[int, tuple[str, int] | DirNode]]] = defaultdict(dict)
|
83
|
+
ID_TO_DIRNODE_CACHE: Final[defaultdict[int | tuple[int, str], dict[int, tuple[str, int] | DirNode]]] = defaultdict(dict)
|
108
84
|
|
109
85
|
|
110
86
|
def _overview_attr(info: Mapping, /) -> OverviewAttr:
|
@@ -117,8 +93,8 @@ def _overview_attr(info: Mapping, /) -> OverviewAttr:
|
|
117
93
|
else:
|
118
94
|
id = int(info["fid"])
|
119
95
|
pid = int(info["cid"])
|
120
|
-
ctime = int(info
|
121
|
-
mtime = int(info
|
96
|
+
ctime = int(info.get("tp") or info["t"])
|
97
|
+
mtime = int(info.get("te") or info["t"])
|
122
98
|
elif "fn" in info:
|
123
99
|
is_dir = info["fc"] == "0"
|
124
100
|
name = info["fn"]
|
@@ -152,7 +128,7 @@ def get_path_to_cid(
|
|
152
128
|
root_id: None | int = None,
|
153
129
|
escape: None | bool | Callable[[str], str] = True,
|
154
130
|
refresh: bool = False,
|
155
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
131
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
156
132
|
app: str = "web",
|
157
133
|
*,
|
158
134
|
async_: Literal[False] = False,
|
@@ -166,7 +142,7 @@ def get_path_to_cid(
|
|
166
142
|
root_id: None | int = None,
|
167
143
|
escape: None | bool | Callable[[str], str] = True,
|
168
144
|
refresh: bool = False,
|
169
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
145
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
170
146
|
app: str = "web",
|
171
147
|
*,
|
172
148
|
async_: Literal[True],
|
@@ -179,7 +155,7 @@ def get_path_to_cid(
|
|
179
155
|
root_id: None | int = None,
|
180
156
|
escape: None | bool | Callable[[str], str] = True,
|
181
157
|
refresh: bool = False,
|
182
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
158
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
183
159
|
app: str = "web",
|
184
160
|
*,
|
185
161
|
async_: Literal[False, True] = False,
|
@@ -215,14 +191,31 @@ def get_path_to_cid(
|
|
215
191
|
escape = cast(None | Callable[[str], str], escape)
|
216
192
|
if id_to_dirnode is None:
|
217
193
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
194
|
+
elif id_to_dirnode is ...:
|
195
|
+
id_to_dirnode = {}
|
218
196
|
def gen_step():
|
219
197
|
nonlocal cid
|
220
198
|
parts: list[str] = []
|
221
199
|
if cid and (refresh or cid not in id_to_dirnode):
|
222
|
-
if
|
223
|
-
resp = yield client.
|
200
|
+
if not isinstance(client, P115Client) or app == "open":
|
201
|
+
resp = yield client.fs_files_open(
|
202
|
+
{"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
|
203
|
+
async_=async_,
|
204
|
+
**request_kwargs,
|
205
|
+
)
|
206
|
+
elif app in ("", "web", "desktop", "harmony"):
|
207
|
+
resp = yield client.fs_files_aps(
|
208
|
+
{"cid": cid, "limit": 1, "nf": 1, "star": 1},
|
209
|
+
async_=async_,
|
210
|
+
**request_kwargs,
|
211
|
+
)
|
224
212
|
else:
|
225
|
-
resp = yield client.fs_files_app(
|
213
|
+
resp = yield client.fs_files_app(
|
214
|
+
{"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
|
215
|
+
app=app,
|
216
|
+
async_=async_,
|
217
|
+
**request_kwargs,
|
218
|
+
)
|
226
219
|
check_response(resp)
|
227
220
|
if cid and int(resp["path"][-1]["cid"]) != cid:
|
228
221
|
raise FileNotFoundError(ENOENT, cid)
|
@@ -252,6 +245,8 @@ def get_file_count(
|
|
252
245
|
client: str | P115Client,
|
253
246
|
cid: int = 0,
|
254
247
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
248
|
+
app: str = "web",
|
249
|
+
use_fs_files: bool = True,
|
255
250
|
*,
|
256
251
|
async_: Literal[False] = False,
|
257
252
|
**request_kwargs,
|
@@ -262,6 +257,8 @@ def get_file_count(
|
|
262
257
|
client: str | P115Client,
|
263
258
|
cid: int = 0,
|
264
259
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
260
|
+
app: str = "web",
|
261
|
+
use_fs_files: bool = True,
|
265
262
|
*,
|
266
263
|
async_: Literal[True],
|
267
264
|
**request_kwargs,
|
@@ -271,6 +268,8 @@ def get_file_count(
|
|
271
268
|
client: str | P115Client,
|
272
269
|
cid: int = 0,
|
273
270
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
271
|
+
app: str = "web",
|
272
|
+
use_fs_files: bool = True,
|
274
273
|
*,
|
275
274
|
async_: Literal[False, True] = False,
|
276
275
|
**request_kwargs,
|
@@ -283,6 +282,8 @@ def get_file_count(
|
|
283
282
|
:param client: 115 客户端或 cookies
|
284
283
|
:param cid: 目录 id
|
285
284
|
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
285
|
+
:param app: 使用某个 app (设备)的接口
|
286
|
+
:param use_fs_files: 使用 `client.fs_files`,否则使用 `client.fs_category_get`
|
286
287
|
:param async_: 是否异步
|
287
288
|
:param request_kwargs: 其它请求参数
|
288
289
|
|
@@ -292,75 +293,78 @@ def get_file_count(
|
|
292
293
|
client = P115Client(client, check_for_relogin=True)
|
293
294
|
if id_to_dirnode is None:
|
294
295
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
_n_get_count += 1
|
296
|
+
def get_resp_of_fs_files(id: int, /):
|
297
|
+
if not isinstance(client, P115Client) or app == "open":
|
298
|
+
return client.fs_files_open(
|
299
|
+
{"cid": id, "hide_data": 1, "show_dir": 0},
|
300
|
+
async_=async_,
|
301
|
+
**request_kwargs,
|
302
|
+
)
|
303
|
+
elif app in ("", "web", "desktop", "harmony"):
|
304
304
|
return client.fs_files(
|
305
|
-
{"cid":
|
306
|
-
base_url=WEBAPI_BASE_URLS[n],
|
305
|
+
{"cid": id, "limit": 1, "show_dir": 0},
|
307
306
|
async_=async_,
|
308
307
|
**request_kwargs,
|
309
308
|
)
|
310
|
-
|
311
|
-
|
312
|
-
|
309
|
+
elif app == "aps":
|
310
|
+
return client.fs_files_aps(
|
311
|
+
{"cid": id, "limit": 1, "show_dir": 0},
|
312
|
+
async_=async_,
|
313
|
+
**request_kwargs,
|
314
|
+
)
|
315
|
+
else:
|
313
316
|
return client.fs_files_app(
|
314
|
-
{"cid":
|
315
|
-
|
317
|
+
{"cid": id, "hide_data": 1, "show_dir": 0},
|
318
|
+
app=app,
|
316
319
|
async_=async_,
|
317
320
|
**request_kwargs,
|
318
321
|
)
|
319
|
-
|
320
|
-
if
|
321
|
-
|
322
|
-
|
323
|
-
{"cid": cid, "limit": 1, "show_dir": 0},
|
324
|
-
base_url=APS_BASE_URLS[n],
|
322
|
+
def get_resp_of_category_get(id: int, /):
|
323
|
+
if not isinstance(client, P115Client) or app == "open":
|
324
|
+
return client.fs_info_open(
|
325
|
+
id,
|
325
326
|
async_=async_,
|
326
327
|
**request_kwargs,
|
327
328
|
)
|
328
|
-
|
329
|
-
if n < n_webapi:
|
330
|
-
_n_get_count += 1
|
329
|
+
elif app in ("", "web", "desktop", "harmony", "aps"):
|
331
330
|
return client.fs_category_get(
|
332
|
-
|
333
|
-
|
331
|
+
id,
|
332
|
+
async_=async_,
|
333
|
+
**request_kwargs,
|
334
|
+
)
|
335
|
+
else:
|
336
|
+
return client.fs_category_get_app(
|
337
|
+
id,
|
338
|
+
app=app,
|
334
339
|
async_=async_,
|
335
340
|
**request_kwargs,
|
336
341
|
)
|
337
|
-
n -= n_webapi
|
338
|
-
_n_get_count += 1
|
339
|
-
return client.fs_category_get_app(
|
340
|
-
cid,
|
341
|
-
base_url=PROAPI_BASE_URLS[n],
|
342
|
-
async_=async_,
|
343
|
-
**request_kwargs,
|
344
|
-
)
|
345
342
|
def gen_step():
|
346
|
-
if cid
|
343
|
+
if not cid:
|
347
344
|
resp = yield client.fs_space_summury(async_=async_, **request_kwargs)
|
348
345
|
check_response(resp)
|
349
346
|
return sum(v["count"] for k, v in resp["type_summury"].items() if k.isupper())
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
check_response(resp)
|
354
|
-
resp["cid"] = cid
|
355
|
-
if "path" in resp:
|
347
|
+
if use_fs_files:
|
348
|
+
resp = yield get_resp_of_fs_files(cid)
|
349
|
+
check_response(resp)
|
356
350
|
if cid != int(resp["path"][-1]["cid"]):
|
351
|
+
resp["cid"] = cid
|
357
352
|
raise NotADirectoryError(ENOTDIR, resp)
|
358
353
|
if id_to_dirnode is not ...:
|
359
354
|
for info in resp["path"][1:]:
|
360
355
|
id_to_dirnode[int(info["cid"])] = DirNode(info["name"], int(info["pid"]))
|
361
356
|
return int(resp["count"])
|
362
357
|
else:
|
358
|
+
resp = yield get_resp_of_category_get(cid)
|
359
|
+
if not resp:
|
360
|
+
raise FileNotFoundError(ENOENT, cid)
|
361
|
+
if "paths" not in resp:
|
362
|
+
check_response(resp)
|
363
|
+
resp = resp["data"]
|
364
|
+
if not resp:
|
365
|
+
raise FileNotFoundError(ENOENT, cid)
|
363
366
|
if int(resp["file_category"]):
|
367
|
+
resp["cid"] = cid
|
364
368
|
raise NotADirectoryError(ENOTDIR, resp)
|
365
369
|
if id_to_dirnode is not ...:
|
366
370
|
pid = 0
|
@@ -374,8 +378,9 @@ def get_file_count(
|
|
374
378
|
@overload
|
375
379
|
def get_ancestors(
|
376
380
|
client: str | P115Client,
|
377
|
-
attr: dict,
|
381
|
+
attr: int | dict,
|
378
382
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
383
|
+
app: str = "web",
|
379
384
|
*,
|
380
385
|
async_: Literal[False] = False,
|
381
386
|
**request_kwargs,
|
@@ -384,8 +389,9 @@ def get_ancestors(
|
|
384
389
|
@overload
|
385
390
|
def get_ancestors(
|
386
391
|
client: str | P115Client,
|
387
|
-
attr: dict,
|
392
|
+
attr: int | dict,
|
388
393
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
394
|
+
app: str = "web",
|
389
395
|
*,
|
390
396
|
async_: Literal[True],
|
391
397
|
**request_kwargs,
|
@@ -393,8 +399,9 @@ def get_ancestors(
|
|
393
399
|
...
|
394
400
|
def get_ancestors(
|
395
401
|
client: str | P115Client,
|
396
|
-
attr: dict,
|
402
|
+
attr: int | dict,
|
397
403
|
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
404
|
+
app: str = "web",
|
398
405
|
*,
|
399
406
|
async_: Literal[False, True] = False,
|
400
407
|
**request_kwargs,
|
@@ -405,8 +412,9 @@ def get_ancestors(
|
|
405
412
|
我通过一些经验,搭配了多个接口的占比和参数分布,可能不够合理,以后会根据实际情况调整
|
406
413
|
|
407
414
|
:param client: 115 客户端或 cookies
|
408
|
-
:param attr:
|
415
|
+
:param attr: 待查询节点 `id` 或信息(必须有 `id`,可选有 `parent_id`)
|
409
416
|
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
417
|
+
:param app: 使用某个 app (设备)的接口
|
410
418
|
:param async_: 是否异步
|
411
419
|
:param request_kwargs: 其它请求参数
|
412
420
|
|
@@ -424,89 +432,168 @@ def get_ancestors(
|
|
424
432
|
client = P115Client(client, check_for_relogin=True)
|
425
433
|
if id_to_dirnode is None:
|
426
434
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
_n_get_ancestors += 1
|
435
|
+
def get_resp_of_fs_files(id: int, /):
|
436
|
+
if not isinstance(client, P115Client) or app == "open":
|
437
|
+
return client.fs_files_open(
|
438
|
+
{"cid": id, "cur": 1, "nf": 1, "hide_data": 1},
|
439
|
+
async_=async_,
|
440
|
+
**request_kwargs,
|
441
|
+
)
|
442
|
+
elif app in ("", "web", "desktop", "harmony"):
|
436
443
|
return client.fs_files(
|
437
|
-
{"cid":
|
438
|
-
base_url=WEBAPI_BASE_URLS[n],
|
444
|
+
{"cid": id, "limit": 1, "nf": 1, "star": 1},
|
439
445
|
async_=async_,
|
440
446
|
**request_kwargs,
|
441
447
|
)
|
442
|
-
|
443
|
-
|
444
|
-
|
448
|
+
elif app == "aps":
|
449
|
+
return client.fs_files_aps(
|
450
|
+
{"cid": id, "limit": 1, "nf": 1, "star": 1},
|
451
|
+
async_=async_,
|
452
|
+
**request_kwargs,
|
453
|
+
)
|
454
|
+
else:
|
445
455
|
return client.fs_files_app(
|
446
|
-
{"cid":
|
447
|
-
|
456
|
+
{"cid": id, "cur": 1, "nf": 1, "hide_data": 1},
|
457
|
+
app=app,
|
448
458
|
async_=async_,
|
449
459
|
**request_kwargs,
|
450
460
|
)
|
451
|
-
|
452
|
-
if
|
453
|
-
|
454
|
-
|
455
|
-
{"cid": attr["parent_id"], "limit": 1},
|
456
|
-
base_url=APS_BASE_URLS[n],
|
461
|
+
def get_resp_of_category_get(id: int, /):
|
462
|
+
if not isinstance(client, P115Client) or app == "open":
|
463
|
+
return client.fs_info_open(
|
464
|
+
id,
|
457
465
|
async_=async_,
|
458
466
|
**request_kwargs,
|
459
467
|
)
|
460
|
-
|
461
|
-
_n_get_ancestors = 0
|
462
|
-
return get_resp()
|
463
|
-
n -= n_apsapi
|
464
|
-
if n < n_webapi:
|
465
|
-
_n_get_ancestors += 1
|
468
|
+
elif app in ("", "web", "desktop", "harmony", "aps"):
|
466
469
|
return client.fs_category_get(
|
467
|
-
|
468
|
-
|
470
|
+
id,
|
471
|
+
async_=async_,
|
472
|
+
**request_kwargs,
|
473
|
+
)
|
474
|
+
else:
|
475
|
+
return client.fs_category_get_app(
|
476
|
+
id,
|
477
|
+
app=app,
|
469
478
|
async_=async_,
|
470
479
|
**request_kwargs,
|
471
480
|
)
|
472
|
-
n -= n_webapi
|
473
|
-
_n_get_ancestors += 1
|
474
|
-
return client.fs_category_get_app(
|
475
|
-
attr["id"],
|
476
|
-
base_url=PROAPI_BASE_URLS[n],
|
477
|
-
async_=async_,
|
478
|
-
**request_kwargs,
|
479
|
-
)
|
480
481
|
def gen_step():
|
481
|
-
if not attr["parent_id"]:
|
482
|
-
return [{"id": 0, "parent_id": 0, "name": ""}]
|
483
|
-
resp = yield get_resp()
|
484
|
-
if not resp:
|
485
|
-
raise FileNotFoundError(ENOENT, attr)
|
486
|
-
check_response(resp)
|
487
|
-
resp["attr"] = attr
|
488
482
|
ancestors: list[dict] = [{"id": 0, "parent_id": 0, "name": ""}]
|
489
483
|
add_ancestor = ancestors.append
|
490
484
|
pid = 0
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
485
|
+
is_completed = False
|
486
|
+
if isinstance(attr, dict):
|
487
|
+
fid = cast(int, attr["id"])
|
488
|
+
if not fid:
|
489
|
+
return ancestors
|
490
|
+
is_dir: None | bool = attr.get("is_dir") or attr.get("is_directory")
|
491
|
+
if is_dir is None:
|
492
|
+
if "parent_id" in attr:
|
493
|
+
cid = cast(int, attr["parent_id"])
|
494
|
+
resp = yield get_resp_of_fs_files(cid)
|
495
|
+
if cid != int(resp["path"][-1]["cid"]):
|
496
|
+
resp["attr"] = attr
|
497
|
+
raise FileNotFoundError(ENOENT, resp)
|
498
|
+
for info in resp["path"][1:]:
|
499
|
+
add_ancestor({
|
500
|
+
"parent_id": pid,
|
501
|
+
"id": (pid := int(info["cid"])),
|
502
|
+
"name": info["name"],
|
503
|
+
})
|
504
|
+
if id_to_dirnode is not ...:
|
505
|
+
for ans in ancestors[1:]:
|
506
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
507
|
+
if "name" in attr:
|
508
|
+
name = attr["name"]
|
509
|
+
is_dir = bool(attr.get("is_dir"))
|
510
|
+
else:
|
511
|
+
resp = yield client.fs_file_skim(attr["id"], async_=async_, **request_kwargs)
|
512
|
+
check_response(resp)
|
513
|
+
name = unescape_115_charref(resp["data"]["file_name"])
|
514
|
+
is_dir = not resp["data"]["sha1"]
|
515
|
+
ans = {"id": fid, "parent_id": pid, "name": name}
|
516
|
+
add_ancestor(ans)
|
517
|
+
if is_dir and id_to_dirnode is not ...:
|
518
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
519
|
+
is_completed = True
|
520
|
+
elif is_dir:
|
521
|
+
resp = yield get_resp_of_fs_files(fid)
|
522
|
+
if fid != int(resp["path"][-1]["cid"]):
|
523
|
+
resp["attr"] = attr
|
524
|
+
raise FileNotFoundError(ENOENT, resp)
|
525
|
+
for info in resp["path"][1:]:
|
526
|
+
add_ancestor({
|
527
|
+
"parent_id": pid,
|
528
|
+
"id": (pid := int(info["cid"])),
|
529
|
+
"name": info["name"],
|
530
|
+
})
|
531
|
+
if id_to_dirnode is not ...:
|
532
|
+
for ans in ancestors[1:]:
|
533
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
534
|
+
is_completed = True
|
535
|
+
else:
|
536
|
+
resp = yield get_resp_of_category_get(fid)
|
537
|
+
if not resp:
|
538
|
+
raise FileNotFoundError(ENOENT, attr)
|
539
|
+
if "paths" not in resp:
|
540
|
+
check_response(resp)
|
541
|
+
resp = resp["data"]
|
542
|
+
if not resp:
|
543
|
+
raise FileNotFoundError(ENOENT, attr)
|
544
|
+
for info in resp["paths"]:
|
545
|
+
add_ancestor({
|
546
|
+
"parent_id": pid,
|
547
|
+
"id": (pid := int(info["file_id"])),
|
548
|
+
"name": info["file_name"],
|
549
|
+
})
|
550
|
+
if id_to_dirnode is not ...:
|
551
|
+
for ans in ancestors[1:]:
|
552
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
553
|
+
ans = {"id": fid, "parent_id": pid, "name": resp["file_name"]}
|
554
|
+
add_ancestor(ans)
|
555
|
+
if not resp.get("sha1") and id_to_dirnode is not ...:
|
556
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
557
|
+
is_completed = True
|
500
558
|
else:
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
559
|
+
fid = attr
|
560
|
+
if not is_completed:
|
561
|
+
if not fid:
|
562
|
+
return ancestors
|
563
|
+
resp = yield get_resp_of_fs_files(fid)
|
564
|
+
check_response(resp)
|
565
|
+
if fid == int(resp["path"][-1]["cid"]):
|
566
|
+
for info in resp["path"][1:]:
|
567
|
+
add_ancestor({
|
568
|
+
"parent_id": pid,
|
569
|
+
"id": (pid := int(info["cid"])),
|
570
|
+
"name": info["name"],
|
571
|
+
})
|
572
|
+
if id_to_dirnode is not ...:
|
573
|
+
for ans in ancestors[1:]:
|
574
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
575
|
+
else:
|
576
|
+
resp = yield get_resp_of_category_get(fid)
|
577
|
+
if not resp:
|
578
|
+
raise FileNotFoundError(ENOENT, fid)
|
579
|
+
if "paths" not in resp:
|
580
|
+
check_response(resp)
|
581
|
+
resp = resp["data"]
|
582
|
+
if not resp:
|
583
|
+
raise FileNotFoundError(ENOENT, fid)
|
584
|
+
for info in resp["paths"]:
|
585
|
+
add_ancestor({
|
586
|
+
"parent_id": pid,
|
587
|
+
"id": (pid := int(info["file_id"])),
|
588
|
+
"name": info["file_name"],
|
589
|
+
})
|
590
|
+
if id_to_dirnode is not ...:
|
591
|
+
for ans in ancestors[1:]:
|
592
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
593
|
+
ans = {"id": fid, "parent_id": pid, "name": resp["file_name"]}
|
594
|
+
add_ancestor(ans)
|
595
|
+
if not resp.get("sha1") and id_to_dirnode is not ...:
|
596
|
+
id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
|
510
597
|
return ancestors
|
511
598
|
return run_gen_step(gen_step, async_=async_)
|
512
599
|
|
@@ -516,7 +603,7 @@ def get_ancestors_to_cid(
|
|
516
603
|
client: str | P115Client,
|
517
604
|
cid: int = 0,
|
518
605
|
refresh: bool = False,
|
519
|
-
id_to_dirnode: None
|
606
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
520
607
|
app: str = "web",
|
521
608
|
*,
|
522
609
|
async_: Literal[False] = False,
|
@@ -528,7 +615,7 @@ def get_ancestors_to_cid(
|
|
528
615
|
client: str | P115Client,
|
529
616
|
cid: int = 0,
|
530
617
|
refresh: bool = False,
|
531
|
-
id_to_dirnode: None
|
618
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
532
619
|
app: str = "web",
|
533
620
|
*,
|
534
621
|
async_: Literal[True],
|
@@ -539,7 +626,7 @@ def get_ancestors_to_cid(
|
|
539
626
|
client: str | P115Client,
|
540
627
|
cid: int = 0,
|
541
628
|
refresh: bool = False,
|
542
|
-
id_to_dirnode: None
|
629
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
543
630
|
app: str = "web",
|
544
631
|
*,
|
545
632
|
async_: Literal[False, True] = False,
|
@@ -569,14 +656,31 @@ def get_ancestors_to_cid(
|
|
569
656
|
client = P115Client(client, check_for_relogin=True)
|
570
657
|
if id_to_dirnode is None:
|
571
658
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
659
|
+
elif id_to_dirnode is ...:
|
660
|
+
id_to_dirnode = {}
|
572
661
|
def gen_step():
|
573
662
|
nonlocal cid
|
574
663
|
parts: list[dict] = []
|
575
664
|
if cid and (refresh or cid not in id_to_dirnode):
|
576
|
-
if
|
577
|
-
resp = yield client.
|
665
|
+
if not isinstance(client, P115Client) or app == "open":
|
666
|
+
resp = yield client.fs_files_open(
|
667
|
+
{"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
|
668
|
+
async_=async_,
|
669
|
+
**request_kwargs,
|
670
|
+
)
|
671
|
+
elif app in ("", "web", "desktop", "harmony"):
|
672
|
+
resp = yield client.fs_files_aps(
|
673
|
+
{"cid": cid, "limit": 1, "nf": 1, "star": 1},
|
674
|
+
async_=async_,
|
675
|
+
**request_kwargs,
|
676
|
+
)
|
578
677
|
else:
|
579
|
-
resp = yield client.fs_files_app(
|
678
|
+
resp = yield client.fs_files_app(
|
679
|
+
{"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
|
680
|
+
app=app,
|
681
|
+
async_=async_,
|
682
|
+
**request_kwargs,
|
683
|
+
)
|
580
684
|
check_response(resp)
|
581
685
|
if cid and int(resp["path"][-1]["cid"]) != cid:
|
582
686
|
raise FileNotFoundError(ENOENT, cid)
|
@@ -596,18 +700,18 @@ def get_ancestors_to_cid(
|
|
596
700
|
return run_gen_step(gen_step, async_=async_)
|
597
701
|
|
598
702
|
|
599
|
-
|
600
|
-
|
601
703
|
# TODO: 使用 search 接口以在特定目录之下搜索某个名字,以便减少风控
|
602
704
|
@overload
|
603
705
|
def get_id_to_path(
|
604
706
|
client: str | P115Client,
|
605
707
|
path: str | Sequence[str],
|
708
|
+
parent_id: int = 0,
|
606
709
|
ensure_file: None | bool = None,
|
607
710
|
is_posixpath: bool = False,
|
608
711
|
refresh: bool = False,
|
609
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
712
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
610
713
|
app: str = "web",
|
714
|
+
dont_use_getid: bool = False,
|
611
715
|
*,
|
612
716
|
async_: Literal[False] = False,
|
613
717
|
**request_kwargs,
|
@@ -617,11 +721,13 @@ def get_id_to_path(
|
|
617
721
|
def get_id_to_path(
|
618
722
|
client: str | P115Client,
|
619
723
|
path: str | Sequence[str],
|
724
|
+
parent_id: int = 0,
|
620
725
|
ensure_file: None | bool = None,
|
621
726
|
is_posixpath: bool = False,
|
622
727
|
refresh: bool = False,
|
623
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
728
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
624
729
|
app: str = "web",
|
730
|
+
dont_use_getid: bool = False,
|
625
731
|
*,
|
626
732
|
async_: Literal[True],
|
627
733
|
**request_kwargs,
|
@@ -630,11 +736,13 @@ def get_id_to_path(
|
|
630
736
|
def get_id_to_path(
|
631
737
|
client: str | P115Client,
|
632
738
|
path: str | Sequence[str],
|
739
|
+
parent_id: int = 0,
|
633
740
|
ensure_file: None | bool = None,
|
634
741
|
is_posixpath: bool = False,
|
635
742
|
refresh: bool = False,
|
636
|
-
id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
|
743
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
637
744
|
app: str = "web",
|
745
|
+
dont_use_getid: bool = False,
|
638
746
|
*,
|
639
747
|
async_: Literal[False, True] = False,
|
640
748
|
**request_kwargs,
|
@@ -643,6 +751,7 @@ def get_id_to_path(
|
|
643
751
|
|
644
752
|
:param client: 115 客户端或 cookies
|
645
753
|
:param path: 路径
|
754
|
+
:param parent_id: 上级目录的 id
|
646
755
|
:param ensure_file: 是否确保为文件
|
647
756
|
|
648
757
|
- True: 必须是文件
|
@@ -653,6 +762,7 @@ def get_id_to_path(
|
|
653
762
|
:param refresh: 是否刷新。如果为 True,则会执行网络请求以查询;如果为 False,则直接从 `id_to_dirnode` 中获取
|
654
763
|
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
655
764
|
:param app: 使用某个 app (设备)的接口
|
765
|
+
:param dont_use_getid: 不要使用 `client.fs_dir_getid` 或 `client.fs_dir_getid_app`,以便 `id_to_dirnode` 有缓存
|
656
766
|
:param async_: 是否异步
|
657
767
|
:param request_kwargs: 其它请求参数
|
658
768
|
|
@@ -664,178 +774,124 @@ def get_id_to_path(
|
|
664
774
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
665
775
|
error = FileNotFoundError(ENOENT, f"no such path: {path!r}")
|
666
776
|
def gen_step():
|
667
|
-
nonlocal
|
668
|
-
if
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
if ensure_file is None and path.endswith("/"):
|
687
|
-
ensure_file = False
|
688
|
-
patht = ["", *filter(None, path.split("/"))]
|
777
|
+
nonlocal ensure_file, parent_id
|
778
|
+
if isinstance(path, str):
|
779
|
+
if path.startswith("/"):
|
780
|
+
parent_id = 0
|
781
|
+
if path in (".", "..", "/"):
|
782
|
+
if ensure_file:
|
783
|
+
raise error
|
784
|
+
return parent_id
|
785
|
+
elif path.startswith("根目录 > "):
|
786
|
+
parent_id = 0
|
787
|
+
patht = path.split(" > ")[1:]
|
788
|
+
elif is_posixpath:
|
789
|
+
if ensure_file is None and path.endswith("/"):
|
790
|
+
ensure_file = False
|
791
|
+
patht = [p for p in path.split("/") if p]
|
792
|
+
else:
|
793
|
+
if ensure_file is None and path_is_dir_form(path):
|
794
|
+
ensure_file = False
|
795
|
+
patht, _ = splits(path.lstrip("/"))
|
689
796
|
else:
|
690
|
-
if
|
691
|
-
|
692
|
-
|
693
|
-
|
797
|
+
if path and not path[0]:
|
798
|
+
parent_id = 0
|
799
|
+
patht = list(path[1:])
|
800
|
+
else:
|
801
|
+
patht = [p for p in path if p]
|
802
|
+
if not patht:
|
803
|
+
return parent_id
|
804
|
+
if not patht:
|
694
805
|
if ensure_file:
|
695
806
|
raise error
|
696
|
-
return
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
if
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
pid = 0
|
706
|
-
if stop > 1 and not refresh and id_to_dirnode:
|
707
|
-
if stop == 2:
|
708
|
-
if is_posixpath:
|
709
|
-
needle = (patht[1].replace("/", "|"), pid)
|
710
|
-
else:
|
711
|
-
needle = (patht[1], pid)
|
712
|
-
for k, t in id_to_dirnode.items():
|
713
|
-
if is_posixpath:
|
714
|
-
t = (t[0].replace("/", "|"), t[1])
|
715
|
-
if t == needle:
|
716
|
-
pid = k
|
717
|
-
j = 2
|
718
|
-
else:
|
719
|
-
if is_posixpath:
|
720
|
-
table = {(n.replace("/", "|"), pid): k for k, (n, pid) in id_to_dirnode.items()}
|
807
|
+
return parent_id
|
808
|
+
i = 0
|
809
|
+
start_parent_id = parent_id
|
810
|
+
if not refresh and id_to_dirnode and id_to_dirnode is not ...:
|
811
|
+
if i := len(patht) - bool(ensure_file):
|
812
|
+
obj = "|" if is_posixpath else "/"
|
813
|
+
for i in range(i):
|
814
|
+
if obj in patht[i]:
|
815
|
+
break
|
721
816
|
else:
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
pid = table[needle]
|
730
|
-
j += 1
|
731
|
-
except KeyError:
|
732
|
-
pass
|
733
|
-
if j >= i:
|
734
|
-
i = j
|
735
|
-
cid = pid
|
736
|
-
else:
|
737
|
-
if ensure_file and len(patht) == i:
|
738
|
-
i -= 1
|
739
|
-
if app in ("", "web", "desktop", "harmony"):
|
740
|
-
fs_dir_getid: Callable = client.fs_dir_getid
|
741
|
-
else:
|
742
|
-
fs_dir_getid = partial(client.fs_dir_getid_app, app=app)
|
743
|
-
cid = 0
|
744
|
-
while i > 1:
|
745
|
-
dirname = "/".join(patht[:i])
|
746
|
-
resp = yield fs_dir_getid(dirname, async_=async_, **request_kwargs)
|
747
|
-
if not (resp["state"] and (cid := resp["id"])):
|
748
|
-
if len(patht) == i and ensure_file is None:
|
749
|
-
ensure_file = True
|
750
|
-
i -= 1
|
751
|
-
continue
|
752
|
-
raise error
|
753
|
-
cid = int(cid)
|
754
|
-
if not refresh and cid not in id_to_dirnode:
|
755
|
-
yield get_path_to_cid(
|
756
|
-
client,
|
757
|
-
cid,
|
758
|
-
id_to_dirnode=id_to_dirnode,
|
759
|
-
app=app,
|
760
|
-
async_=async_,
|
761
|
-
**request_kwargs,
|
762
|
-
)
|
763
|
-
break
|
764
|
-
if len(patht) == i:
|
765
|
-
return cid
|
766
|
-
for name in patht[i:-1]:
|
767
|
-
if async_:
|
768
|
-
async def request():
|
769
|
-
nonlocal cid
|
770
|
-
async for info in iterdir_raw(
|
771
|
-
client,
|
772
|
-
cid,
|
773
|
-
ensure_file=False,
|
774
|
-
app=app,
|
775
|
-
id_to_dirnode=id_to_dirnode,
|
776
|
-
async_=True,
|
777
|
-
**request_kwargs,
|
778
|
-
):
|
779
|
-
attr = _overview_attr(info)
|
780
|
-
if (attr.name.replace("/", "|") if is_posixpath else attr.name) == name:
|
781
|
-
cid = attr.id
|
817
|
+
i += 1
|
818
|
+
if i:
|
819
|
+
for i in range(i):
|
820
|
+
needle = (patht[i], parent_id)
|
821
|
+
for fid, key in id_to_dirnode.items():
|
822
|
+
if needle == key:
|
823
|
+
parent_id = fid
|
782
824
|
break
|
783
825
|
else:
|
784
|
-
raise error
|
785
|
-
yield request
|
786
|
-
else:
|
787
|
-
for info in iterdir_raw(
|
788
|
-
client,
|
789
|
-
cid,
|
790
|
-
ensure_file=False,
|
791
|
-
app=app,
|
792
|
-
id_to_dirnode=id_to_dirnode,
|
793
|
-
**request_kwargs,
|
794
|
-
):
|
795
|
-
attr = _overview_attr(info)
|
796
|
-
if (attr.name.replace("/", "|") if is_posixpath else attr.name) == name:
|
797
|
-
cid = attr.id
|
798
826
|
break
|
799
827
|
else:
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
async_=True,
|
810
|
-
**request_kwargs,
|
811
|
-
):
|
812
|
-
attr = _overview_attr(info)
|
813
|
-
if (attr.name.replace("/", "|") if is_posixpath else attr.name) == name:
|
814
|
-
if ensure_file:
|
815
|
-
if not attr.is_dir:
|
816
|
-
return P115ID(attr.id, info, about="path")
|
817
|
-
elif attr.is_dir:
|
818
|
-
return P115ID(attr.id, info, about="path")
|
828
|
+
i += 1
|
829
|
+
if i == len(patht):
|
830
|
+
return parent_id
|
831
|
+
if not start_parent_id:
|
832
|
+
stop = 0
|
833
|
+
if j := len(patht) - bool(ensure_file):
|
834
|
+
for stop, part in enumerate(patht[:j]):
|
835
|
+
if "/" in part:
|
836
|
+
break
|
819
837
|
else:
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
838
|
+
stop += 1
|
839
|
+
if not dont_use_getid:
|
840
|
+
while stop > i:
|
841
|
+
if app in ("", "web", "desktop", "harmony"):
|
842
|
+
fs_dir_getid: Callable = client.fs_dir_getid
|
843
|
+
else:
|
844
|
+
fs_dir_getid = partial(client.fs_dir_getid_app, app=app)
|
845
|
+
dirname = "/".join(patht[:stop])
|
846
|
+
resp = yield fs_dir_getid(dirname, async_=async_, **request_kwargs)
|
847
|
+
check_response(resp)
|
848
|
+
cid = int(resp["id"])
|
849
|
+
if not cid:
|
850
|
+
if stop == len(patht) and ensure_file is None:
|
851
|
+
stop -= 1
|
852
|
+
continue
|
853
|
+
raise error
|
854
|
+
parent_id = cid
|
855
|
+
i = stop
|
856
|
+
break
|
857
|
+
if i == len(patht):
|
858
|
+
return parent_id
|
859
|
+
for name in patht[i:-1]:
|
860
|
+
if is_posixpath:
|
861
|
+
name = name.replace("/", "|")
|
862
|
+
with with_iter_next(iterdir(
|
824
863
|
client,
|
825
|
-
|
864
|
+
parent_id,
|
865
|
+
ensure_file=False,
|
826
866
|
app=app,
|
827
867
|
id_to_dirnode=id_to_dirnode,
|
868
|
+
async_=async_,
|
828
869
|
**request_kwargs,
|
829
|
-
):
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
870
|
+
)) as get_next:
|
871
|
+
found = False
|
872
|
+
while not found:
|
873
|
+
attr = yield get_next
|
874
|
+
found = (attr["name"].replace("/", "|") if is_posixpath else attr["name"]) == name
|
875
|
+
parent_id = attr["id"]
|
876
|
+
if not found:
|
877
|
+
raise error
|
878
|
+
name = patht[-1]
|
879
|
+
if is_posixpath:
|
880
|
+
name = name.replace("/", "|")
|
881
|
+
with with_iter_next(iterdir(
|
882
|
+
client,
|
883
|
+
parent_id,
|
884
|
+
app=app,
|
885
|
+
id_to_dirnode=id_to_dirnode,
|
886
|
+
async_=async_,
|
887
|
+
**request_kwargs,
|
888
|
+
)) as get_next:
|
889
|
+
while True:
|
890
|
+
attr = yield get_next
|
891
|
+
if (attr["name"].replace("/", "|") if is_posixpath else attr["name"]) == name:
|
892
|
+
if ensure_file is None or ensure_file ^ attr["is_dir"]:
|
893
|
+
return P115ID(attr["id"], attr, about="path")
|
894
|
+
raise error
|
839
895
|
return run_gen_step(gen_step, async_=async_)
|
840
896
|
|
841
897
|
|
@@ -1135,6 +1191,11 @@ def _iter_fs_files(
|
|
1135
1191
|
pid, name = int(info["cid"]), info["name"]
|
1136
1192
|
id_to_dirnode[pid] = DirNode(name, int(info["pid"]))
|
1137
1193
|
if ensure_file is None:
|
1194
|
+
if id_to_dirnode is not ...:
|
1195
|
+
for info in resp["data"]:
|
1196
|
+
attr = _overview_attr(info)
|
1197
|
+
if attr.is_dir:
|
1198
|
+
id_to_dirnode[attr.id] = DirNode(attr.name, attr.parent_id)
|
1138
1199
|
yield YieldFrom(resp["data"], identity=True)
|
1139
1200
|
else:
|
1140
1201
|
for info in resp["data"]:
|
@@ -3118,6 +3179,7 @@ def share_iterdir(
|
|
3118
3179
|
order: Literal["file_name", "file_size", "file_type", "user_utime", "user_ptime", "user_otime"] = "user_ptime",
|
3119
3180
|
asc: Literal[0, 1] = 1,
|
3120
3181
|
normalize_attr: None | Callable[[dict], dict] = normalize_attr,
|
3182
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3121
3183
|
*,
|
3122
3184
|
async_: Literal[False] = False,
|
3123
3185
|
**request_kwargs,
|
@@ -3133,6 +3195,7 @@ def share_iterdir(
|
|
3133
3195
|
order: Literal["file_name", "file_size", "file_type", "user_utime", "user_ptime", "user_otime"] = "user_ptime",
|
3134
3196
|
asc: Literal[0, 1] = 1,
|
3135
3197
|
normalize_attr: None | Callable[[dict], dict] = normalize_attr,
|
3198
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3136
3199
|
*,
|
3137
3200
|
async_: Literal[True],
|
3138
3201
|
**request_kwargs,
|
@@ -3147,6 +3210,7 @@ def share_iterdir(
|
|
3147
3210
|
order: Literal["file_name", "file_size", "file_type", "user_utime", "user_ptime", "user_otime"] = "user_ptime",
|
3148
3211
|
asc: Literal[0, 1] = 1,
|
3149
3212
|
normalize_attr: None | Callable[[dict], dict] = normalize_attr,
|
3213
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3150
3214
|
*,
|
3151
3215
|
async_: Literal[False, True] = False,
|
3152
3216
|
**request_kwargs,
|
@@ -3169,6 +3233,7 @@ def share_iterdir(
|
|
3169
3233
|
|
3170
3234
|
:param asc: 升序排列。0: 否,1: 是
|
3171
3235
|
:param normalize_attr: 把数据进行转换处理,使之便于阅读
|
3236
|
+
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
3172
3237
|
:param async_: 是否异步
|
3173
3238
|
:param request_kwargs: 其它请求参数
|
3174
3239
|
|
@@ -3176,7 +3241,9 @@ def share_iterdir(
|
|
3176
3241
|
"""
|
3177
3242
|
if isinstance(client, str):
|
3178
3243
|
client = P115Client(client, check_for_relogin=True)
|
3179
|
-
if
|
3244
|
+
if id_to_dirnode is None:
|
3245
|
+
id_to_dirnode = ID_TO_DIRNODE_CACHE[(client.user_id, share_code)]
|
3246
|
+
if page_size <= 0:
|
3180
3247
|
page_size = 10_000
|
3181
3248
|
def gen_step():
|
3182
3249
|
nonlocal receive_code
|
@@ -3202,6 +3269,10 @@ def share_iterdir(
|
|
3202
3269
|
for attr in resp["data"]["list"]:
|
3203
3270
|
attr["share_code"] = share_code
|
3204
3271
|
attr["receive_code"] = receive_code
|
3272
|
+
if id_to_dirnode is not ...:
|
3273
|
+
oattr = _overview_attr(attr)
|
3274
|
+
if oattr.is_dir:
|
3275
|
+
id_to_dirnode[oattr.id] = DirNode(oattr.name, oattr.parent_id)
|
3205
3276
|
if normalize_attr is not None:
|
3206
3277
|
attr = normalize_attr(attr)
|
3207
3278
|
yield Yield(attr, identity=True)
|
@@ -3216,6 +3287,7 @@ def share_iter_files(
|
|
3216
3287
|
client: str | P115Client,
|
3217
3288
|
share_link: str,
|
3218
3289
|
receive_code: str = "",
|
3290
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3219
3291
|
*,
|
3220
3292
|
async_: Literal[False] = False,
|
3221
3293
|
**request_kwargs,
|
@@ -3226,6 +3298,7 @@ def share_iter_files(
|
|
3226
3298
|
client: str | P115Client,
|
3227
3299
|
share_link: str,
|
3228
3300
|
receive_code: str = "",
|
3301
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3229
3302
|
*,
|
3230
3303
|
async_: Literal[True],
|
3231
3304
|
**request_kwargs,
|
@@ -3235,6 +3308,7 @@ def share_iter_files(
|
|
3235
3308
|
client: str | P115Client,
|
3236
3309
|
share_link: str,
|
3237
3310
|
receive_code: str = "",
|
3311
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3238
3312
|
*,
|
3239
3313
|
async_: Literal[False, True] = False,
|
3240
3314
|
**request_kwargs,
|
@@ -3274,6 +3348,7 @@ def share_iter_files(
|
|
3274
3348
|
if isinstance(client, str):
|
3275
3349
|
client = P115Client(client, check_for_relogin=True)
|
3276
3350
|
def gen_step():
|
3351
|
+
nonlocal id_to_dirnode
|
3277
3352
|
payload: dict = cast(dict, share_extract_payload(share_link))
|
3278
3353
|
if receive_code:
|
3279
3354
|
payload["receive_code"] = receive_code
|
@@ -3281,7 +3356,10 @@ def share_iter_files(
|
|
3281
3356
|
resp = yield client.share_info(payload["share_code"], async_=async_, **request_kwargs)
|
3282
3357
|
check_response(resp)
|
3283
3358
|
payload["receive_code"] = resp["data"]["receive_code"]
|
3359
|
+
if id_to_dirnode is None:
|
3360
|
+
id_to_dirnode = ID_TO_DIRNODE_CACHE[(client.user_id, payload["share_code"])]
|
3284
3361
|
payload["cid"] = 0
|
3362
|
+
payload["id_to_dirnode"] = id_to_dirnode
|
3285
3363
|
it = share_iterdir(client, **payload, async_=async_, **request_kwargs)
|
3286
3364
|
do_next: Callable = anext if async_ else next
|
3287
3365
|
try:
|
@@ -3307,6 +3385,176 @@ def share_iter_files(
|
|
3307
3385
|
return run_gen_step(gen_step, async_=async_)
|
3308
3386
|
|
3309
3387
|
|
3388
|
+
@overload
|
3389
|
+
def share_get_id_to_path(
|
3390
|
+
client: str | P115Client,
|
3391
|
+
share_code: str,
|
3392
|
+
receive_code: str = "",
|
3393
|
+
path: str | Sequence[str] = "",
|
3394
|
+
parent_id: int = 0,
|
3395
|
+
ensure_file: None | bool = None,
|
3396
|
+
is_posixpath: bool = False,
|
3397
|
+
refresh: bool = False,
|
3398
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3399
|
+
*,
|
3400
|
+
async_: Literal[False] = False,
|
3401
|
+
**request_kwargs,
|
3402
|
+
) -> int:
|
3403
|
+
...
|
3404
|
+
@overload
|
3405
|
+
def share_get_id_to_path(
|
3406
|
+
client: str | P115Client,
|
3407
|
+
share_code: str,
|
3408
|
+
receive_code: str = "",
|
3409
|
+
path: str | Sequence[str] = "",
|
3410
|
+
parent_id: int = 0,
|
3411
|
+
ensure_file: None | bool = None,
|
3412
|
+
is_posixpath: bool = False,
|
3413
|
+
refresh: bool = False,
|
3414
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3415
|
+
*,
|
3416
|
+
async_: Literal[True],
|
3417
|
+
**request_kwargs,
|
3418
|
+
) -> Coroutine[Any, Any, int]:
|
3419
|
+
...
|
3420
|
+
def share_get_id_to_path(
|
3421
|
+
client: str | P115Client,
|
3422
|
+
share_code: str,
|
3423
|
+
receive_code: str = "",
|
3424
|
+
path: str | Sequence[str] = "",
|
3425
|
+
parent_id: int = 0,
|
3426
|
+
ensure_file: None | bool = None,
|
3427
|
+
is_posixpath: bool = False,
|
3428
|
+
refresh: bool = False,
|
3429
|
+
id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
|
3430
|
+
*,
|
3431
|
+
async_: Literal[False, True] = False,
|
3432
|
+
**request_kwargs,
|
3433
|
+
) -> int | Coroutine[Any, Any, int]:
|
3434
|
+
"""对分享链接,获取路径对应的 id
|
3435
|
+
|
3436
|
+
:param client: 115 客户端或 cookies
|
3437
|
+
:param share_code: 分享码
|
3438
|
+
:param receive_code: 密码
|
3439
|
+
:param path: 路径
|
3440
|
+
:param parent_id: 上级目录的 id
|
3441
|
+
:param ensure_file: 是否确保为文件
|
3442
|
+
|
3443
|
+
- True: 必须是文件
|
3444
|
+
- False: 必须是目录
|
3445
|
+
- None: 可以是目录或文件
|
3446
|
+
|
3447
|
+
:param is_posixpath: 使用 posixpath,会把 "/" 转换为 "|",因此解析的时候,会对 "|" 进行特别处理
|
3448
|
+
:param refresh: 是否刷新。如果为 True,则会执行网络请求以查询;如果为 False,则直接从 `id_to_dirnode` 中获取
|
3449
|
+
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
3450
|
+
:param async_: 是否异步
|
3451
|
+
:param request_kwargs: 其它请求参数
|
3452
|
+
|
3453
|
+
:return: 文件或目录的 id
|
3454
|
+
"""
|
3455
|
+
if isinstance(client, str):
|
3456
|
+
client = P115Client(client, check_for_relogin=True)
|
3457
|
+
if id_to_dirnode is None:
|
3458
|
+
id_to_dirnode = ID_TO_DIRNODE_CACHE[(client.user_id, share_code)]
|
3459
|
+
error = FileNotFoundError(ENOENT, f"no such path: {path!r}")
|
3460
|
+
def gen_step():
|
3461
|
+
nonlocal ensure_file, parent_id, receive_code
|
3462
|
+
if isinstance(path, str):
|
3463
|
+
if path.startswith("/"):
|
3464
|
+
parent_id = 0
|
3465
|
+
if path in (".", "..", "/"):
|
3466
|
+
if ensure_file:
|
3467
|
+
raise error
|
3468
|
+
return parent_id
|
3469
|
+
elif path.startswith("根目录 > "):
|
3470
|
+
parent_id = 0
|
3471
|
+
patht = path.split(" > ")[1:]
|
3472
|
+
elif is_posixpath:
|
3473
|
+
if ensure_file is None and path.endswith("/"):
|
3474
|
+
ensure_file = False
|
3475
|
+
patht = [p for p in path.split("/") if p]
|
3476
|
+
else:
|
3477
|
+
if ensure_file is None and path_is_dir_form(path):
|
3478
|
+
ensure_file = False
|
3479
|
+
patht, _ = splits(path.lstrip("/"))
|
3480
|
+
else:
|
3481
|
+
if path and not path[0]:
|
3482
|
+
parent_id = 0
|
3483
|
+
patht = list(path[1:])
|
3484
|
+
else:
|
3485
|
+
patht = [p for p in path if p]
|
3486
|
+
if not patht:
|
3487
|
+
return parent_id
|
3488
|
+
if not patht:
|
3489
|
+
if ensure_file:
|
3490
|
+
raise error
|
3491
|
+
return parent_id
|
3492
|
+
if not receive_code:
|
3493
|
+
resp = yield client.share_info(share_code, async_=async_, **request_kwargs)
|
3494
|
+
check_response(resp)
|
3495
|
+
receive_code = resp["data"]["receive_code"]
|
3496
|
+
i = 0
|
3497
|
+
if not refresh and id_to_dirnode and id_to_dirnode is not ...:
|
3498
|
+
if i := len(patht) - bool(ensure_file):
|
3499
|
+
obj = "|" if is_posixpath else "/"
|
3500
|
+
for i in range(i):
|
3501
|
+
if obj in patht[i]:
|
3502
|
+
break
|
3503
|
+
else:
|
3504
|
+
i += 1
|
3505
|
+
if i:
|
3506
|
+
for i in range(i):
|
3507
|
+
needle = (patht[i], parent_id)
|
3508
|
+
for fid, key in id_to_dirnode.items():
|
3509
|
+
if needle == key:
|
3510
|
+
parent_id = fid
|
3511
|
+
break
|
3512
|
+
else:
|
3513
|
+
break
|
3514
|
+
else:
|
3515
|
+
i += 1
|
3516
|
+
if i == len(patht):
|
3517
|
+
return parent_id
|
3518
|
+
for name in patht[i:-1]:
|
3519
|
+
if is_posixpath:
|
3520
|
+
name = name.replace("/", "|")
|
3521
|
+
with with_iter_next(share_iterdir(
|
3522
|
+
client,
|
3523
|
+
share_code,
|
3524
|
+
receive_code=receive_code,
|
3525
|
+
cid=parent_id,
|
3526
|
+
id_to_dirnode=id_to_dirnode,
|
3527
|
+
async_=async_,
|
3528
|
+
**request_kwargs,
|
3529
|
+
)) as get_next:
|
3530
|
+
found = False
|
3531
|
+
while not found:
|
3532
|
+
attr = yield get_next
|
3533
|
+
found = attr["is_dir"] and (attr["name"].replace("/", "|") if is_posixpath else attr["name"]) == name
|
3534
|
+
parent_id = attr["id"]
|
3535
|
+
if not found:
|
3536
|
+
raise error
|
3537
|
+
name = patht[-1]
|
3538
|
+
if is_posixpath:
|
3539
|
+
name = name.replace("/", "|")
|
3540
|
+
with with_iter_next(share_iterdir(
|
3541
|
+
client,
|
3542
|
+
share_code,
|
3543
|
+
receive_code=receive_code,
|
3544
|
+
cid=parent_id,
|
3545
|
+
id_to_dirnode=id_to_dirnode,
|
3546
|
+
async_=async_,
|
3547
|
+
**request_kwargs,
|
3548
|
+
)) as get_next:
|
3549
|
+
while True:
|
3550
|
+
attr = yield get_next
|
3551
|
+
if (attr["name"].replace("/", "|") if is_posixpath else attr["name"]) == name:
|
3552
|
+
if ensure_file is None or ensure_file ^ attr["is_dir"]:
|
3553
|
+
return P115ID(attr["id"], attr, about="path")
|
3554
|
+
raise error
|
3555
|
+
return run_gen_step(gen_step, async_=async_)
|
3556
|
+
|
3557
|
+
|
3310
3558
|
@overload
|
3311
3559
|
def iter_selected_nodes(
|
3312
3560
|
client: str | P115Client,
|