p115client 0.0.5.13.2__tar.gz → 0.0.5.14.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.
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/PKG-INFO +3 -3
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/client.py +13 -7
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/download.py +18 -9
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/iterdir.py +269 -143
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/pyproject.toml +3 -3
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/LICENSE +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/__init__.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/_upload.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/const.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/exception.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/py.typed +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/__init__.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/attr.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/auth.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/edit.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/export_dir.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/fs_files.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/history.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/life.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/offline.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/pool.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/request.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/upload.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/util.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/tool/xys.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/p115client/type.py +0 -0
- {p115client-0.0.5.13.2 → p115client-0.0.5.14.1}/readme.md +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: p115client
|
3
|
-
Version: 0.0.5.
|
3
|
+
Version: 0.0.5.14.1
|
4
4
|
Summary: Python 115 webdisk client.
|
5
5
|
Home-page: https://github.com/ChenyangGao/p115client
|
6
6
|
License: MIT
|
@@ -29,7 +29,7 @@ Requires-Dist: iter_collect (>=0.0.5.1)
|
|
29
29
|
Requires-Dist: multidict
|
30
30
|
Requires-Dist: orjson
|
31
31
|
Requires-Dist: p115cipher (>=0.0.3)
|
32
|
-
Requires-Dist: p115pickcode (>=0.0.
|
32
|
+
Requires-Dist: p115pickcode (>=0.0.4)
|
33
33
|
Requires-Dist: posixpatht (>=0.0.3)
|
34
34
|
Requires-Dist: python-argtools (>=0.0.1)
|
35
35
|
Requires-Dist: python-asynctools (>=0.1.3)
|
@@ -41,7 +41,7 @@ Requires-Dist: python-filewrap (>=0.2.8)
|
|
41
41
|
Requires-Dist: python-hashtools (>=0.0.3.3)
|
42
42
|
Requires-Dist: python-http_request (>=0.0.6)
|
43
43
|
Requires-Dist: python-httpfile (>=0.0.5.2)
|
44
|
-
Requires-Dist: python-iterutils (>=0.2.5)
|
44
|
+
Requires-Dist: python-iterutils (>=0.2.5.3)
|
45
45
|
Requires-Dist: python-property (>=0.0.3)
|
46
46
|
Requires-Dist: python-startfile (>=0.0.2)
|
47
47
|
Requires-Dist: python-undefined (>=0.0.3)
|
@@ -59,7 +59,7 @@ from orjson import dumps, loads
|
|
59
59
|
from p115cipher.fast import (
|
60
60
|
rsa_encode, rsa_decode, ecdh_encode_token, ecdh_aes_encode, ecdh_aes_decode, make_upload_payload,
|
61
61
|
)
|
62
|
-
from p115pickcode import
|
62
|
+
from p115pickcode import get_stable_point
|
63
63
|
from property import locked_cacheproperty
|
64
64
|
from re import compile as re_compile
|
65
65
|
from startfile import startfile, startfile_async # type: ignore
|
@@ -679,8 +679,6 @@ def normalize_attr_web[D: dict[str, Any]](
|
|
679
679
|
attr["size"] = int(info.get("s") or 0)
|
680
680
|
if "pc" in info:
|
681
681
|
attr["pickcode"] = info["pc"]
|
682
|
-
else:
|
683
|
-
attr["pickcode"] = id_to_pickcode(attr["id"], is_dir=is_dir)
|
684
682
|
if simple:
|
685
683
|
if "c" in info:
|
686
684
|
attr["is_collect"] = int(info["c"])
|
@@ -818,8 +816,6 @@ def normalize_attr_app[D: dict[str, Any]](
|
|
818
816
|
attr["size"] = int(info.get("fs") or 0)
|
819
817
|
if "pc" in info:
|
820
818
|
attr["pickcode"] = info["pc"]
|
821
|
-
else:
|
822
|
-
attr["pickcode"] = id_to_pickcode(attr["id"], is_dir=is_dir)
|
823
819
|
if simple:
|
824
820
|
if "ic" in info:
|
825
821
|
attr["is_collect"] = int(info["ic"])
|
@@ -956,8 +952,6 @@ def normalize_attr_app2[D: dict[str, Any]](
|
|
956
952
|
attr["size"] = int(info.get("file_size") or 0)
|
957
953
|
if "pick_code" in info:
|
958
954
|
attr["pickcode"] = info["pick_code"]
|
959
|
-
else:
|
960
|
-
attr["pickcode"] = id_to_pickcode(attr["id"], is_dir=is_dir)
|
961
955
|
if simple:
|
962
956
|
if "is_collect" in info:
|
963
957
|
attr["is_collect"] = int(info["is_collect"])
|
@@ -3127,6 +3121,18 @@ class P115OpenClient(ClientRequestMixin):
|
|
3127
3121
|
resp = check_response(self.user_info_open())
|
3128
3122
|
return int(resp["data"]["user_id"])
|
3129
3123
|
|
3124
|
+
@locked_cacheproperty
|
3125
|
+
def pickcode_stable_point(self, /) -> str:
|
3126
|
+
"""获取 pickcode 的不动点
|
3127
|
+
|
3128
|
+
.. todo::
|
3129
|
+
不动点可能和用户 id 有某种联系,但目前样本不足,难以推断,以后再尝试分析
|
3130
|
+
"""
|
3131
|
+
resp = self.fs_files({"show_dir": 1, "limit": 1, "cid": 0})
|
3132
|
+
check_response(resp)
|
3133
|
+
info = resp["data"][0]
|
3134
|
+
return get_stable_point(normalize_attr(info)["pickcode"])
|
3135
|
+
|
3130
3136
|
@overload
|
3131
3137
|
def refresh_access_token(
|
3132
3138
|
self,
|
@@ -94,14 +94,15 @@ def batch_get_url(
|
|
94
94
|
"""
|
95
95
|
if isinstance(client, str):
|
96
96
|
client = P115Client(client, check_for_relogin=True)
|
97
|
+
stable_point = client.pickcode_stable_point
|
97
98
|
if headers := request_kwargs.get("headers"):
|
98
99
|
request_kwargs["headers"] = dict(headers, **{"user-agent": user_agent})
|
99
100
|
else:
|
100
101
|
request_kwargs["headers"] = {"user-agent": user_agent}
|
101
102
|
if isinstance(pickcode, (int, str)):
|
102
|
-
pickcode = to_pickcode(pickcode)
|
103
|
+
pickcode = to_pickcode(pickcode, stable_point)
|
103
104
|
elif not isinstance(pickcode, str):
|
104
|
-
pickcode = ",".join(
|
105
|
+
pickcode = ",".join(to_pickcode(pc, stable_point) for pc in pickcode)
|
105
106
|
if not isinstance(client, P115Client) or app == "open":
|
106
107
|
get_download_url: Callable = client.download_url_info_open
|
107
108
|
else:
|
@@ -183,6 +184,7 @@ def iter_url_batches(
|
|
183
184
|
"""
|
184
185
|
if isinstance(client, str):
|
185
186
|
client = P115Client(client, check_for_relogin=True)
|
187
|
+
stable_point = client.pickcode_stable_point
|
186
188
|
if headers := request_kwargs.get("headers"):
|
187
189
|
request_kwargs["headers"] = dict(headers, **{"user-agent": user_agent})
|
188
190
|
else:
|
@@ -194,7 +196,7 @@ def iter_url_batches(
|
|
194
196
|
if batch_size <= 0:
|
195
197
|
batch_size = 1
|
196
198
|
def gen_step():
|
197
|
-
for pcs in batched(
|
199
|
+
for pcs in batched((to_pickcode(pc, stable_point) for pc in pickcodes), batch_size):
|
198
200
|
resp = yield get_download_url(
|
199
201
|
",".join(pcs),
|
200
202
|
async_=async_,
|
@@ -1208,6 +1210,7 @@ def iter_download_nodes(
|
|
1208
1210
|
"""
|
1209
1211
|
if isinstance(client, str):
|
1210
1212
|
client = P115Client(client, check_for_relogin=True)
|
1213
|
+
stable_point = client.pickcode_stable_point
|
1211
1214
|
get_base_url = cycle(("http://proapi.115.com", "https://proapi.115.com")).__next__
|
1212
1215
|
if async_:
|
1213
1216
|
if max_workers is None or max_workers <= 0:
|
@@ -1221,6 +1224,7 @@ def iter_download_nodes(
|
|
1221
1224
|
if id_to_dirnode is None:
|
1222
1225
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
1223
1226
|
file_skim = client.fs_file_skim
|
1227
|
+
need_yield = files and ensure_name
|
1224
1228
|
def normalize_attrs(attrs: list[dict], /):
|
1225
1229
|
if files:
|
1226
1230
|
for i, info in enumerate(attrs):
|
@@ -1243,7 +1247,7 @@ def iter_download_nodes(
|
|
1243
1247
|
for attr in attrs:
|
1244
1248
|
id_to_dirnode[attr["id"]] = DirNode(attr["name"], attr["parent_id"])
|
1245
1249
|
return attrs
|
1246
|
-
if
|
1250
|
+
if need_yield:
|
1247
1251
|
prepare = normalize_attrs
|
1248
1252
|
@as_gen_step
|
1249
1253
|
def normalize_attrs(attrs: list[dict], /):
|
@@ -1262,6 +1266,7 @@ def iter_download_nodes(
|
|
1262
1266
|
attr["sha1"] = node["sha1"]
|
1263
1267
|
attr["name"] = unescape_115_charref(node["file_name"])
|
1264
1268
|
return attrs
|
1269
|
+
need_yield = need_yield and async_
|
1265
1270
|
get_nodes = partial(
|
1266
1271
|
method,
|
1267
1272
|
async_=async_,
|
@@ -1269,7 +1274,7 @@ def iter_download_nodes(
|
|
1269
1274
|
)
|
1270
1275
|
if max_workers == 1:
|
1271
1276
|
def gen_step(pickcode: int | str, /):
|
1272
|
-
pickcode = to_pickcode(pickcode)
|
1277
|
+
pickcode = to_pickcode(pickcode, stable_point)
|
1273
1278
|
for i in count(1):
|
1274
1279
|
payload = {"pickcode": pickcode, "page": i}
|
1275
1280
|
resp = yield get_nodes(payload)
|
@@ -1300,7 +1305,10 @@ def iter_download_nodes(
|
|
1300
1305
|
put(e)
|
1301
1306
|
return
|
1302
1307
|
data = resp["data"]
|
1303
|
-
|
1308
|
+
attrs = normalize_attrs(data["list"])
|
1309
|
+
if need_yield:
|
1310
|
+
attrs = yield attrs
|
1311
|
+
put(attrs)
|
1304
1312
|
if not data["has_next_page"]:
|
1305
1313
|
max_page = page
|
1306
1314
|
def gen_step(pickcode: int | str, /):
|
@@ -1316,7 +1324,7 @@ def iter_download_nodes(
|
|
1316
1324
|
n = executor._max_workers
|
1317
1325
|
submit = executor.submit
|
1318
1326
|
shutdown = lambda: executor.shutdown(False, cancel_futures=True)
|
1319
|
-
pickcode = to_pickcode(pickcode)
|
1327
|
+
pickcode = to_pickcode(pickcode, stable_point)
|
1320
1328
|
try:
|
1321
1329
|
sentinel = object()
|
1322
1330
|
countdown: Callable
|
@@ -1441,6 +1449,7 @@ def iter_download_files(
|
|
1441
1449
|
"""
|
1442
1450
|
if isinstance(client, str):
|
1443
1451
|
client = P115Client(client, check_for_relogin=True)
|
1452
|
+
stable_point = client.pickcode_stable_point
|
1444
1453
|
if id_to_dirnode is None:
|
1445
1454
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
1446
1455
|
elif id_to_dirnode is ...:
|
@@ -1507,7 +1516,7 @@ def iter_download_files(
|
|
1507
1516
|
))
|
1508
1517
|
finally:
|
1509
1518
|
ancestors_loaded = True
|
1510
|
-
def gen_step(pickcode: str
|
1519
|
+
def gen_step(pickcode: str, /):
|
1511
1520
|
nonlocal ancestors_loaded
|
1512
1521
|
if pickcode:
|
1513
1522
|
if cid:
|
@@ -1585,7 +1594,7 @@ def iter_download_files(
|
|
1585
1594
|
for pickcode in pickcodes:
|
1586
1595
|
yield YieldFrom(run_gen_step_iter(gen_step(pickcode), async_))
|
1587
1596
|
ancestors_loaded = False
|
1588
|
-
return run_gen_step_iter(gen_step, async_)
|
1597
|
+
return run_gen_step_iter(gen_step(to_pickcode(cid, stable_point)), async_)
|
1589
1598
|
|
1590
1599
|
|
1591
1600
|
@overload
|
@@ -14,11 +14,13 @@ __all__ = [
|
|
14
14
|
"iter_nodes", "iter_nodes_skim", "iter_nodes_by_pickcode",
|
15
15
|
"iter_nodes_using_update", "iter_nodes_using_info",
|
16
16
|
"iter_nodes_using_star_event", "iter_dir_nodes_using_star",
|
17
|
-
"iter_parents", "
|
18
|
-
"share_iterdir", "share_iter_files", "share_search_iter",
|
17
|
+
"iter_parents", "iter_files_shortcut", "iter_dupfiles", "iter_image_files",
|
18
|
+
"search_iter", "share_iterdir", "share_iter_files", "share_search_iter",
|
19
19
|
]
|
20
20
|
__doc__ = "这个模块提供了一些和目录信息罗列有关的函数"
|
21
21
|
|
22
|
+
# TODO: 再实现 2 个方法,利用 iter_download_nodes,一个有 path,一个没有,可以把某个目录下的所有节点都搞出来,导出时,先导出目录节点,再导出文件节点,但它们是并发执行的,然后必有字段:id, parent_id, pickcode, name, is_dir, sha1 等
|
23
|
+
|
22
24
|
# TODO: 路径表示法,应该支持 / 和 > 开头,而不仅仅是 / 开头
|
23
25
|
# TODO: 对于路径,增加 top_id 和 relpath 字段,表示搜素目录的 id 和相对于搜索路径的相对路径
|
24
26
|
# TODO: get_id* 这类方法,应该放在 attr.py,用来获取某个 id 对应的值(根本还是 get_attr)
|
@@ -2292,6 +2294,7 @@ def iter_files_with_path(
|
|
2292
2294
|
raise ValueError("please set the non-zero value of suffix or type")
|
2293
2295
|
if isinstance(client, str):
|
2294
2296
|
client = P115Client(client, check_for_relogin=True)
|
2297
|
+
stable_point = client.pickcode_stable_point
|
2295
2298
|
if isinstance(escape, bool):
|
2296
2299
|
if escape:
|
2297
2300
|
from posixpatht import escape
|
@@ -2303,36 +2306,6 @@ def iter_files_with_path(
|
|
2303
2306
|
elif id_to_dirnode is ...:
|
2304
2307
|
id_to_dirnode = {}
|
2305
2308
|
path_already = False
|
2306
|
-
_path_already: None | bool = None if path_already else False
|
2307
|
-
if not path_already:
|
2308
|
-
from .download import iter_download_nodes
|
2309
|
-
def set_path_already(*_):
|
2310
|
-
nonlocal _path_already
|
2311
|
-
_path_already = True
|
2312
|
-
@as_gen_step
|
2313
|
-
def fetch_dirs(id: int | str, /):
|
2314
|
-
if id:
|
2315
|
-
yield through(iter_download_nodes(
|
2316
|
-
client,
|
2317
|
-
to_pickcode(id),
|
2318
|
-
files=False,
|
2319
|
-
id_to_dirnode=id_to_dirnode,
|
2320
|
-
max_workers=None,
|
2321
|
-
async_=async_,
|
2322
|
-
**request_kwargs,
|
2323
|
-
))
|
2324
|
-
else:
|
2325
|
-
with with_iter_next(iterdir(
|
2326
|
-
client,
|
2327
|
-
ensure_file=False,
|
2328
|
-
id_to_dirnode=id_to_dirnode,
|
2329
|
-
app=app,
|
2330
|
-
async_=async_,
|
2331
|
-
**request_kwargs,
|
2332
|
-
)) as get_next:
|
2333
|
-
while True:
|
2334
|
-
attr = yield get_next()
|
2335
|
-
yield fetch_dirs(attr["pickcode"])
|
2336
2309
|
if with_ancestors:
|
2337
2310
|
id_to_ancestors: dict[int, list[dict]] = {}
|
2338
2311
|
def get_ancestors(id: int, attr: dict | tuple[str, int] | DirNode, /) -> list[dict]:
|
@@ -2374,17 +2347,8 @@ def iter_files_with_path(
|
|
2374
2347
|
pass
|
2375
2348
|
return attr
|
2376
2349
|
cid = to_id(cid)
|
2377
|
-
|
2378
|
-
|
2379
|
-
cache: list[dict] = []
|
2380
|
-
add_to_cache = cache.append
|
2381
|
-
if not path_already:
|
2382
|
-
if async_:
|
2383
|
-
task: Any = create_task(fetch_dirs(cid))
|
2384
|
-
else:
|
2385
|
-
task = run_as_thread(fetch_dirs, cid)
|
2386
|
-
task.add_done_callback(set_path_already)
|
2387
|
-
with with_iter_next(iter_files(
|
2350
|
+
if path_already:
|
2351
|
+
return do_map(update_path, iter_files(
|
2388
2352
|
client,
|
2389
2353
|
cid,
|
2390
2354
|
page_size=page_size,
|
@@ -2401,30 +2365,88 @@ def iter_files_with_path(
|
|
2401
2365
|
cooldown=cooldown,
|
2402
2366
|
async_=async_, # type: ignore
|
2403
2367
|
**request_kwargs,
|
2404
|
-
))
|
2405
|
-
|
2406
|
-
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2368
|
+
))
|
2369
|
+
else:
|
2370
|
+
_path_already: None | bool = None if path_already else False
|
2371
|
+
from .download import iter_download_nodes
|
2372
|
+
def set_path_already(*_):
|
2373
|
+
nonlocal _path_already
|
2374
|
+
_path_already = True
|
2375
|
+
@as_gen_step
|
2376
|
+
def fetch_dirs(id: int | str, /):
|
2377
|
+
if id:
|
2378
|
+
yield through(iter_download_nodes(
|
2379
|
+
client,
|
2380
|
+
to_pickcode(id, stable_point),
|
2381
|
+
files=False,
|
2382
|
+
id_to_dirnode=id_to_dirnode,
|
2383
|
+
max_workers=None,
|
2384
|
+
async_=async_,
|
2385
|
+
**request_kwargs,
|
2386
|
+
))
|
2387
|
+
else:
|
2388
|
+
with with_iter_next(iterdir(
|
2389
|
+
client,
|
2390
|
+
ensure_file=False,
|
2391
|
+
id_to_dirnode=id_to_dirnode,
|
2392
|
+
app=app,
|
2393
|
+
async_=async_,
|
2394
|
+
**request_kwargs,
|
2395
|
+
)) as get_next:
|
2396
|
+
while True:
|
2397
|
+
attr = yield get_next()
|
2398
|
+
yield fetch_dirs(attr["pickcode"])
|
2399
|
+
def gen_step():
|
2400
|
+
nonlocal _path_already
|
2401
|
+
cache: list[dict] = []
|
2402
|
+
add_to_cache = cache.append
|
2403
|
+
if not path_already:
|
2404
|
+
if async_:
|
2405
|
+
task: Any = create_task(fetch_dirs(cid))
|
2406
|
+
else:
|
2407
|
+
task = run_as_thread(fetch_dirs, cid)
|
2408
|
+
task.add_done_callback(set_path_already)
|
2409
|
+
with with_iter_next(iter_files(
|
2410
|
+
client,
|
2411
|
+
cid,
|
2412
|
+
page_size=page_size,
|
2413
|
+
suffix=suffix,
|
2414
|
+
type=type,
|
2415
|
+
order=order,
|
2416
|
+
asc=asc,
|
2417
|
+
cur=cur,
|
2418
|
+
normalize_attr=normalize_attr,
|
2419
|
+
id_to_dirnode=id_to_dirnode,
|
2420
|
+
raise_for_changed_count=raise_for_changed_count,
|
2421
|
+
max_workers=max_workers,
|
2422
|
+
app=app,
|
2423
|
+
cooldown=cooldown,
|
2424
|
+
async_=async_, # type: ignore
|
2425
|
+
**request_kwargs,
|
2426
|
+
)) as get_next:
|
2427
|
+
while True:
|
2428
|
+
attr = yield get_next()
|
2429
|
+
if _path_already is None:
|
2430
|
+
yield Yield(update_path(attr))
|
2431
|
+
elif _path_already:
|
2432
|
+
if async_:
|
2433
|
+
yield task
|
2434
|
+
else:
|
2435
|
+
task.result()
|
2436
|
+
if cache:
|
2437
|
+
yield YieldFrom(map(update_path, cache))
|
2438
|
+
cache.clear()
|
2439
|
+
yield Yield(update_path(attr))
|
2440
|
+
_path_already = None
|
2412
2441
|
else:
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2417
|
-
yield Yield(update_path(attr))
|
2418
|
-
_path_already = None
|
2442
|
+
add_to_cache(attr)
|
2443
|
+
if cache:
|
2444
|
+
if async_:
|
2445
|
+
yield task
|
2419
2446
|
else:
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
yield task
|
2424
|
-
else:
|
2425
|
-
task.result()
|
2426
|
-
yield YieldFrom(map(update_path, cache))
|
2427
|
-
return run_gen_step_iter(gen_step, async_)
|
2447
|
+
task.result()
|
2448
|
+
yield YieldFrom(map(update_path, cache))
|
2449
|
+
return run_gen_step_iter(gen_step, async_)
|
2428
2450
|
|
2429
2451
|
|
2430
2452
|
@overload
|
@@ -2494,6 +2516,7 @@ def iter_files_with_path_skim(
|
|
2494
2516
|
from .download import iter_download_nodes
|
2495
2517
|
if isinstance(client, str):
|
2496
2518
|
client = P115Client(client, check_for_relogin=True)
|
2519
|
+
stable_point = client.pickcode_stable_point
|
2497
2520
|
if isinstance(escape, bool):
|
2498
2521
|
if escape:
|
2499
2522
|
from posixpatht import escape
|
@@ -2505,45 +2528,6 @@ def iter_files_with_path_skim(
|
|
2505
2528
|
elif id_to_dirnode is ...:
|
2506
2529
|
id_to_dirnode = {}
|
2507
2530
|
path_already = False
|
2508
|
-
_path_already: None | bool = None if path_already else False
|
2509
|
-
if not path_already:
|
2510
|
-
def set_path_already(*_):
|
2511
|
-
nonlocal _path_already
|
2512
|
-
_path_already = True
|
2513
|
-
@as_gen_step
|
2514
|
-
def fetch_dirs(id: int | str, /):
|
2515
|
-
if id:
|
2516
|
-
if cid:
|
2517
|
-
do_next: Callable = anext if async_ else next
|
2518
|
-
yield do_next(_iter_fs_files(
|
2519
|
-
client,
|
2520
|
-
to_id(id),
|
2521
|
-
page_size=1,
|
2522
|
-
id_to_dirnode=id_to_dirnode,
|
2523
|
-
async_=async_,
|
2524
|
-
**request_kwargs,
|
2525
|
-
))
|
2526
|
-
yield through(iter_download_nodes(
|
2527
|
-
client,
|
2528
|
-
to_pickcode(id),
|
2529
|
-
files=False,
|
2530
|
-
id_to_dirnode=id_to_dirnode,
|
2531
|
-
max_workers=max_workers,
|
2532
|
-
async_=async_,
|
2533
|
-
**request_kwargs,
|
2534
|
-
))
|
2535
|
-
else:
|
2536
|
-
with with_iter_next(iterdir(
|
2537
|
-
client,
|
2538
|
-
ensure_file=False,
|
2539
|
-
id_to_dirnode=id_to_dirnode,
|
2540
|
-
app=app,
|
2541
|
-
async_=async_,
|
2542
|
-
**request_kwargs,
|
2543
|
-
)) as get_next:
|
2544
|
-
while True:
|
2545
|
-
attr = yield get_next()
|
2546
|
-
yield fetch_dirs(attr["pickcode"])
|
2547
2531
|
if with_ancestors:
|
2548
2532
|
id_to_ancestors: dict[int, list[dict]] = {}
|
2549
2533
|
def get_ancestors(id: int, attr: dict | tuple[str, int] | DirNode, /) -> list[dict]:
|
@@ -2585,17 +2569,8 @@ def iter_files_with_path_skim(
|
|
2585
2569
|
pass
|
2586
2570
|
return attr
|
2587
2571
|
cid = to_id(cid)
|
2588
|
-
|
2589
|
-
|
2590
|
-
cache: list[dict] = []
|
2591
|
-
add_to_cache = cache.append
|
2592
|
-
if not path_already:
|
2593
|
-
if async_:
|
2594
|
-
task: Any = create_task(fetch_dirs(cid))
|
2595
|
-
else:
|
2596
|
-
task = run_as_thread(fetch_dirs, cid)
|
2597
|
-
task.add_done_callback(set_path_already)
|
2598
|
-
with with_iter_next(iter_download_nodes(
|
2572
|
+
if path_already:
|
2573
|
+
return do_map(update_path, iter_download_nodes(
|
2599
2574
|
client,
|
2600
2575
|
cid,
|
2601
2576
|
files=True,
|
@@ -2604,30 +2579,89 @@ def iter_files_with_path_skim(
|
|
2604
2579
|
app=app,
|
2605
2580
|
async_=async_,
|
2606
2581
|
**request_kwargs,
|
2607
|
-
))
|
2608
|
-
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2582
|
+
))
|
2583
|
+
else:
|
2584
|
+
_path_already: None | bool = None if path_already else False
|
2585
|
+
def set_path_already(*_):
|
2586
|
+
nonlocal _path_already
|
2587
|
+
_path_already = True
|
2588
|
+
@as_gen_step
|
2589
|
+
def fetch_dirs(id: int | str, /):
|
2590
|
+
if id:
|
2591
|
+
if cid:
|
2592
|
+
do_next: Callable = anext if async_ else next
|
2593
|
+
yield do_next(_iter_fs_files(
|
2594
|
+
client,
|
2595
|
+
to_id(id),
|
2596
|
+
page_size=1,
|
2597
|
+
id_to_dirnode=id_to_dirnode,
|
2598
|
+
async_=async_,
|
2599
|
+
**request_kwargs,
|
2600
|
+
))
|
2601
|
+
yield through(iter_download_nodes(
|
2602
|
+
client,
|
2603
|
+
to_pickcode(id, stable_point),
|
2604
|
+
files=False,
|
2605
|
+
id_to_dirnode=id_to_dirnode,
|
2606
|
+
max_workers=max_workers,
|
2607
|
+
async_=async_,
|
2608
|
+
**request_kwargs,
|
2609
|
+
))
|
2610
|
+
else:
|
2611
|
+
with with_iter_next(iterdir(
|
2612
|
+
client,
|
2613
|
+
ensure_file=False,
|
2614
|
+
id_to_dirnode=id_to_dirnode,
|
2615
|
+
app=app,
|
2616
|
+
async_=async_,
|
2617
|
+
**request_kwargs,
|
2618
|
+
)) as get_next:
|
2619
|
+
while True:
|
2620
|
+
attr = yield get_next()
|
2621
|
+
yield fetch_dirs(attr["pickcode"])
|
2622
|
+
def gen_step():
|
2623
|
+
nonlocal _path_already
|
2624
|
+
cache: list[dict] = []
|
2625
|
+
add_to_cache = cache.append
|
2626
|
+
if not path_already:
|
2627
|
+
if async_:
|
2628
|
+
task: Any = create_task(fetch_dirs(cid))
|
2629
|
+
else:
|
2630
|
+
task = run_as_thread(fetch_dirs, cid)
|
2631
|
+
task.add_done_callback(set_path_already)
|
2632
|
+
with with_iter_next(iter_download_nodes(
|
2633
|
+
client,
|
2634
|
+
cid,
|
2635
|
+
files=True,
|
2636
|
+
ensure_name=True,
|
2637
|
+
max_workers=max_workers,
|
2638
|
+
app=app,
|
2639
|
+
async_=async_,
|
2640
|
+
**request_kwargs,
|
2641
|
+
)) as get_next:
|
2642
|
+
while True:
|
2643
|
+
attr = yield get_next()
|
2644
|
+
if _path_already is None:
|
2645
|
+
yield Yield(update_path(attr))
|
2646
|
+
elif _path_already:
|
2647
|
+
if async_:
|
2648
|
+
yield task
|
2649
|
+
else:
|
2650
|
+
task.result()
|
2651
|
+
if cache:
|
2652
|
+
yield YieldFrom(map(update_path, cache))
|
2653
|
+
cache.clear()
|
2654
|
+
yield Yield(update_path(attr))
|
2655
|
+
_path_already = None
|
2615
2656
|
else:
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
yield Yield(update_path(attr))
|
2621
|
-
_path_already = None
|
2657
|
+
add_to_cache(attr)
|
2658
|
+
if cache:
|
2659
|
+
if async_:
|
2660
|
+
yield task
|
2622
2661
|
else:
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
yield task
|
2627
|
-
else:
|
2628
|
-
task.result()
|
2629
|
-
yield YieldFrom(map(update_path, cache))
|
2630
|
-
return run_gen_step_iter(gen_step, async_)
|
2662
|
+
task.result()
|
2663
|
+
yield YieldFrom(map(update_path, cache))
|
2664
|
+
return run_gen_step_iter(gen_step, async_)
|
2631
2665
|
|
2632
2666
|
|
2633
2667
|
@overload
|
@@ -2838,6 +2872,7 @@ def iter_nodes_by_pickcode(
|
|
2838
2872
|
"""
|
2839
2873
|
if isinstance(client, str):
|
2840
2874
|
client = P115Client(client, check_for_relogin=True)
|
2875
|
+
stable_point = client.pickcode_stable_point
|
2841
2876
|
if id_to_dirnode is None:
|
2842
2877
|
id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
|
2843
2878
|
methods: list[Callable] = []
|
@@ -2875,7 +2910,7 @@ def iter_nodes_by_pickcode(
|
|
2875
2910
|
project,
|
2876
2911
|
conmap(
|
2877
2912
|
get_response,
|
2878
|
-
|
2913
|
+
(to_pickcode(pc, stable_point) for pc in pickcodes),
|
2879
2914
|
max_workers=max_workers,
|
2880
2915
|
kwargs=request_kwargs,
|
2881
2916
|
async_=async_,
|
@@ -3426,6 +3461,91 @@ def iter_parents(
|
|
3426
3461
|
))
|
3427
3462
|
|
3428
3463
|
|
3464
|
+
@overload
|
3465
|
+
def iter_files_shortcut(
|
3466
|
+
client: str | P115Client,
|
3467
|
+
cid: int | str = 0,
|
3468
|
+
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3469
|
+
max_workers: None | int = None,
|
3470
|
+
is_skim: bool = True,
|
3471
|
+
with_path: bool = False,
|
3472
|
+
app: str = "android",
|
3473
|
+
*,
|
3474
|
+
async_: Literal[False] = False,
|
3475
|
+
**request_kwargs,
|
3476
|
+
) -> Iterator[dict]:
|
3477
|
+
...
|
3478
|
+
@overload
|
3479
|
+
def iter_files_shortcut(
|
3480
|
+
client: str | P115Client,
|
3481
|
+
cid: int | str = 0,
|
3482
|
+
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3483
|
+
max_workers: None | int = None,
|
3484
|
+
is_skim: bool = True,
|
3485
|
+
with_path: bool = False,
|
3486
|
+
app: str = "android",
|
3487
|
+
*,
|
3488
|
+
async_: Literal[True],
|
3489
|
+
**request_kwargs,
|
3490
|
+
) -> AsyncIterator[dict]:
|
3491
|
+
...
|
3492
|
+
def iter_files_shortcut(
|
3493
|
+
client: str | P115Client,
|
3494
|
+
cid: int | str = 0,
|
3495
|
+
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3496
|
+
max_workers: None | int = None,
|
3497
|
+
is_skim: bool = True,
|
3498
|
+
with_path: bool = False,
|
3499
|
+
app: str = "android",
|
3500
|
+
*,
|
3501
|
+
async_: Literal[False, True] = False,
|
3502
|
+
**request_kwargs,
|
3503
|
+
) -> Iterator[dict] | AsyncIterator[dict]:
|
3504
|
+
"""遍历目录树,获取(仅文件而非目录)文件信息(整合了多个函数的入口)
|
3505
|
+
|
3506
|
+
.. node::
|
3507
|
+
`is_skim` 和 `with_path` 的不同取值组合,会决定采用不同的函数:
|
3508
|
+
|
3509
|
+
1. `iter_download_nodes`: is_skim=True and with_path=False
|
3510
|
+
2. `iter_files_with_path_skim`: is_skim=True and with_path=True
|
3511
|
+
3. `iter_files`: is_skim=False and with_path=False
|
3512
|
+
4. `iter_files_with_path`: is_skim=False and with_path=True
|
3513
|
+
|
3514
|
+
:param client: 115 客户端或 cookies
|
3515
|
+
:param cid: 待被遍历的目录 id 或 pickcode
|
3516
|
+
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
3517
|
+
:param max_workers: 最大并发数,如果为 None 或 <= 0,则自动确定
|
3518
|
+
:param is_skim: 是否拉取简要信息
|
3519
|
+
:param with_path: 是否需要 "path" 和 "ancestors" 字段
|
3520
|
+
:param app: 使用指定 app(设备)的接口
|
3521
|
+
:param async_: 是否异步
|
3522
|
+
:param request_kwargs: 其它请求参数
|
3523
|
+
|
3524
|
+
:return: 迭代器,产生文件信息
|
3525
|
+
"""
|
3526
|
+
if with_path:
|
3527
|
+
request_kwargs.setdefault("with_ancestors", True)
|
3528
|
+
if is_skim:
|
3529
|
+
method: Callable = iter_files_with_path_skim
|
3530
|
+
else:
|
3531
|
+
method = iter_files_with_path
|
3532
|
+
elif is_skim:
|
3533
|
+
request_kwargs.update(files=True, ensure_name=True)
|
3534
|
+
from .download import iter_download_nodes as method
|
3535
|
+
else:
|
3536
|
+
request_kwargs.setdefault("cooldown", 0.5)
|
3537
|
+
method = iter_files
|
3538
|
+
return method(
|
3539
|
+
client,
|
3540
|
+
cid,
|
3541
|
+
id_to_dirnode=id_to_dirnode,
|
3542
|
+
max_workers=max_workers,
|
3543
|
+
app=app,
|
3544
|
+
async_=async_,
|
3545
|
+
**request_kwargs,
|
3546
|
+
)
|
3547
|
+
|
3548
|
+
|
3429
3549
|
@overload
|
3430
3550
|
def iter_dupfiles[K](
|
3431
3551
|
client: str | P115Client,
|
@@ -3434,6 +3554,8 @@ def iter_dupfiles[K](
|
|
3434
3554
|
keep_first: None | bool | Callable[[dict], SupportsLT] = None,
|
3435
3555
|
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3436
3556
|
max_workers: None | int = None,
|
3557
|
+
is_skim: bool = True,
|
3558
|
+
with_path: bool = False,
|
3437
3559
|
app: str = "android",
|
3438
3560
|
*,
|
3439
3561
|
async_: Literal[False] = False,
|
@@ -3448,6 +3570,8 @@ def iter_dupfiles[K](
|
|
3448
3570
|
keep_first: None | bool | Callable[[dict], SupportsLT] = None,
|
3449
3571
|
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3450
3572
|
max_workers: None | int = None,
|
3573
|
+
is_skim: bool = True,
|
3574
|
+
with_path: bool = False,
|
3451
3575
|
app: str = "android",
|
3452
3576
|
*,
|
3453
3577
|
async_: Literal[True],
|
@@ -3461,6 +3585,8 @@ def iter_dupfiles[K](
|
|
3461
3585
|
keep_first: None | bool | Callable[[dict], SupportsLT] = None,
|
3462
3586
|
id_to_dirnode: None | EllipsisType | MutableMapping[int, tuple[str, int] | DirNode] = None,
|
3463
3587
|
max_workers: None | int = None,
|
3588
|
+
is_skim: bool = True,
|
3589
|
+
with_path: bool = False,
|
3464
3590
|
app: str = "android",
|
3465
3591
|
*,
|
3466
3592
|
async_: Literal[False, True] = False,
|
@@ -3480,22 +3606,22 @@ def iter_dupfiles[K](
|
|
3480
3606
|
|
3481
3607
|
:param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
|
3482
3608
|
:param max_workers: 最大并发数,如果为 None 或 <= 0,则自动确定
|
3609
|
+
:param is_skim: 是否拉取简要信息
|
3610
|
+
:param with_path: 是否需要 "path" 和 "ancestors" 字段
|
3483
3611
|
:param app: 使用指定 app(设备)的接口
|
3484
|
-
:param cooldown: 冷却时间,大于 0,则使用此时间间隔执行并发
|
3485
3612
|
:param async_: 是否异步
|
3486
3613
|
:param request_kwargs: 其它请求参数
|
3487
3614
|
|
3488
3615
|
:return: 迭代器,返回 key 和 重复文件信息 的元组
|
3489
3616
|
"""
|
3490
|
-
from .download import iter_download_nodes
|
3491
3617
|
return iter_keyed_dups(
|
3492
|
-
|
3618
|
+
iter_files_shortcut(
|
3493
3619
|
client,
|
3494
3620
|
cid,
|
3495
|
-
files=True,
|
3496
|
-
ensure_name=True,
|
3497
3621
|
id_to_dirnode=id_to_dirnode,
|
3498
3622
|
max_workers=max_workers,
|
3623
|
+
is_skim=is_skim,
|
3624
|
+
with_path=with_path,
|
3499
3625
|
app=app,
|
3500
3626
|
async_=async_, # type: ignore
|
3501
3627
|
**request_kwargs,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "p115client"
|
3
|
-
version = "0.0.5.
|
3
|
+
version = "0.0.5.14.1"
|
4
4
|
description = "Python 115 webdisk client."
|
5
5
|
authors = ["ChenyangGao <wosiwujm@gmail.com>"]
|
6
6
|
license = "MIT"
|
@@ -37,7 +37,7 @@ iter_collect = ">=0.0.5.1"
|
|
37
37
|
multidict = "*"
|
38
38
|
orjson = "*"
|
39
39
|
p115cipher = ">=0.0.3"
|
40
|
-
p115pickcode = ">=0.0.
|
40
|
+
p115pickcode = ">=0.0.4"
|
41
41
|
posixpatht = ">=0.0.3"
|
42
42
|
python-argtools = ">=0.0.1"
|
43
43
|
python-asynctools = ">=0.1.3"
|
@@ -49,7 +49,7 @@ python-filewrap = ">=0.2.8"
|
|
49
49
|
python-hashtools = ">=0.0.3.3"
|
50
50
|
python-httpfile = ">=0.0.5.2"
|
51
51
|
python-http_request = ">=0.0.6"
|
52
|
-
python-iterutils = ">=0.2.5"
|
52
|
+
python-iterutils = ">=0.2.5.3"
|
53
53
|
python-property = ">=0.0.3"
|
54
54
|
python-startfile = ">=0.0.2"
|
55
55
|
python-undefined = ">=0.0.3"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|