p115client 0.0.5.10.4__py3-none-any.whl → 0.0.5.11__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.
@@ -13,6 +13,7 @@ __all__ = [
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",
16
+ "search_for_any_file",
16
17
  ]
17
18
  __doc__ = "这个模块提供了一些和目录信息罗列有关的函数"
18
19
 
@@ -59,30 +60,6 @@ from .life import iter_life_behavior_once, life_show
59
60
  from .util import posix_escape_name, share_extract_payload, unescape_115_charref
60
61
 
61
62
 
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
63
  class DirNode(NamedTuple):
87
64
  name: str
88
65
  parent_id: int
@@ -152,7 +129,7 @@ def get_path_to_cid(
152
129
  root_id: None | int = None,
153
130
  escape: None | bool | Callable[[str], str] = True,
154
131
  refresh: bool = False,
155
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
132
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
156
133
  app: str = "web",
157
134
  *,
158
135
  async_: Literal[False] = False,
@@ -166,7 +143,7 @@ def get_path_to_cid(
166
143
  root_id: None | int = None,
167
144
  escape: None | bool | Callable[[str], str] = True,
168
145
  refresh: bool = False,
169
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
146
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
170
147
  app: str = "web",
171
148
  *,
172
149
  async_: Literal[True],
@@ -179,7 +156,7 @@ def get_path_to_cid(
179
156
  root_id: None | int = None,
180
157
  escape: None | bool | Callable[[str], str] = True,
181
158
  refresh: bool = False,
182
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
159
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
183
160
  app: str = "web",
184
161
  *,
185
162
  async_: Literal[False, True] = False,
@@ -215,14 +192,31 @@ def get_path_to_cid(
215
192
  escape = cast(None | Callable[[str], str], escape)
216
193
  if id_to_dirnode is None:
217
194
  id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
195
+ elif id_to_dirnode is ...:
196
+ id_to_dirnode = {}
218
197
  def gen_step():
219
198
  nonlocal cid
220
199
  parts: list[str] = []
221
200
  if cid and (refresh or cid not in id_to_dirnode):
222
- if app in ("", "web", "desktop", "harmony"):
223
- resp = yield client.fs_files({"cid": cid, "limit": 1}, async_=async_, **request_kwargs)
201
+ if not isinstance(client, P115Client) or app == "open":
202
+ resp = yield client.fs_files_open(
203
+ {"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
204
+ async_=async_,
205
+ **request_kwargs,
206
+ )
207
+ elif app in ("", "web", "desktop", "harmony"):
208
+ resp = yield client.fs_files_aps(
209
+ {"cid": cid, "limit": 1, "nf": 1, "star": 1},
210
+ async_=async_,
211
+ **request_kwargs,
212
+ )
224
213
  else:
225
- resp = yield client.fs_files_app({"cid": cid, "hide_data": 1}, async_=async_, **request_kwargs)
214
+ resp = yield client.fs_files_app(
215
+ {"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
216
+ app=app,
217
+ async_=async_,
218
+ **request_kwargs,
219
+ )
226
220
  check_response(resp)
227
221
  if cid and int(resp["path"][-1]["cid"]) != cid:
228
222
  raise FileNotFoundError(ENOENT, cid)
@@ -244,7 +238,7 @@ def get_path_to_cid(
244
238
  return "/" + path
245
239
  else:
246
240
  return path
247
- return run_gen_step(gen_step, async_=async_)
241
+ return run_gen_step(gen_step, simple=True, async_=async_)
248
242
 
249
243
 
250
244
  @overload
@@ -252,6 +246,8 @@ def get_file_count(
252
246
  client: str | P115Client,
253
247
  cid: int = 0,
254
248
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
249
+ app: str = "web",
250
+ use_fs_files: bool = True,
255
251
  *,
256
252
  async_: Literal[False] = False,
257
253
  **request_kwargs,
@@ -262,6 +258,8 @@ def get_file_count(
262
258
  client: str | P115Client,
263
259
  cid: int = 0,
264
260
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
261
+ app: str = "web",
262
+ use_fs_files: bool = True,
265
263
  *,
266
264
  async_: Literal[True],
267
265
  **request_kwargs,
@@ -271,18 +269,19 @@ def get_file_count(
271
269
  client: str | P115Client,
272
270
  cid: int = 0,
273
271
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
272
+ app: str = "web",
273
+ use_fs_files: bool = True,
274
274
  *,
275
275
  async_: Literal[False, True] = False,
276
276
  **request_kwargs,
277
277
  ) -> int | Coroutine[Any, Any, int]:
278
278
  """获取文件总数
279
279
 
280
- .. caution::
281
- 我通过一些经验,搭配了多个接口的占比和参数分布,可能不够合理,以后会根据实际情况调整
282
-
283
280
  :param client: 115 客户端或 cookies
284
281
  :param cid: 目录 id
285
282
  :param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
283
+ :param app: 使用某个 app (设备)的接口
284
+ :param use_fs_files: 使用 `client.fs_files`,否则使用 `client.fs_category_get`
286
285
  :param async_: 是否异步
287
286
  :param request_kwargs: 其它请求参数
288
287
 
@@ -292,75 +291,78 @@ def get_file_count(
292
291
  client = P115Client(client, check_for_relogin=True)
293
292
  if id_to_dirnode is None:
294
293
  id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
295
- n_webapi = len(WEBAPI_BASE_URLS)
296
- n_proapi = len(PROAPI_BASE_URLS)
297
- n_apsapi = len(APS_BASE_URLS)
298
- n_api = n_webapi * 2 + n_proapi * 2 + n_apsapi
299
- def get_resp():
300
- global _n_get_count
301
- n = _n_get_count % n_api
302
- if n < n_webapi:
303
- _n_get_count += 1
294
+ def get_resp_of_fs_files(id: int, /):
295
+ if not isinstance(client, P115Client) or app == "open":
296
+ return client.fs_files_open(
297
+ {"cid": id, "hide_data": 1, "show_dir": 0},
298
+ async_=async_,
299
+ **request_kwargs,
300
+ )
301
+ elif app in ("", "web", "desktop", "harmony"):
304
302
  return client.fs_files(
305
- {"cid": cid, "limit": 1, "show_dir": 0},
306
- base_url=WEBAPI_BASE_URLS[n],
303
+ {"cid": id, "limit": 1, "show_dir": 0},
307
304
  async_=async_,
308
305
  **request_kwargs,
309
306
  )
310
- n -= n_webapi
311
- if n < n_proapi:
312
- _n_get_count += 1
307
+ elif app == "aps":
308
+ return client.fs_files_aps(
309
+ {"cid": id, "limit": 1, "show_dir": 0},
310
+ async_=async_,
311
+ **request_kwargs,
312
+ )
313
+ else:
313
314
  return client.fs_files_app(
314
- {"cid": cid, "hide_data": 1, "show_dir": 0},
315
- base_url=PROAPI_BASE_URLS[n],
315
+ {"cid": id, "hide_data": 1, "show_dir": 0},
316
+ app=app,
316
317
  async_=async_,
317
318
  **request_kwargs,
318
319
  )
319
- n -= n_proapi
320
- if n < n_apsapi:
321
- _n_get_count += 1
322
- return client.fs_files_aps(
323
- {"cid": cid, "limit": 1, "show_dir": 0},
324
- base_url=APS_BASE_URLS[n],
320
+ def get_resp_of_category_get(id: int, /):
321
+ if not isinstance(client, P115Client) or app == "open":
322
+ return client.fs_info_open(
323
+ id,
325
324
  async_=async_,
326
325
  **request_kwargs,
327
326
  )
328
- n -= n_apsapi
329
- if n < n_webapi:
330
- _n_get_count += 1
327
+ elif app in ("", "web", "desktop", "harmony", "aps"):
331
328
  return client.fs_category_get(
332
- cid,
333
- base_url=WEBAPI_BASE_URLS[n],
329
+ id,
330
+ async_=async_,
331
+ **request_kwargs,
332
+ )
333
+ else:
334
+ return client.fs_category_get_app(
335
+ id,
336
+ app=app,
334
337
  async_=async_,
335
338
  **request_kwargs,
336
339
  )
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
340
  def gen_step():
346
- if cid == 0:
341
+ if not cid:
347
342
  resp = yield client.fs_space_summury(async_=async_, **request_kwargs)
348
343
  check_response(resp)
349
344
  return sum(v["count"] for k, v in resp["type_summury"].items() if k.isupper())
350
- resp = yield get_resp()
351
- if not resp:
352
- raise FileNotFoundError(ENOENT, cid)
353
- check_response(resp)
354
- resp["cid"] = cid
355
- if "path" in resp:
345
+ if use_fs_files:
346
+ resp = yield get_resp_of_fs_files(cid)
347
+ check_response(resp)
356
348
  if cid != int(resp["path"][-1]["cid"]):
349
+ resp["cid"] = cid
357
350
  raise NotADirectoryError(ENOTDIR, resp)
358
351
  if id_to_dirnode is not ...:
359
352
  for info in resp["path"][1:]:
360
353
  id_to_dirnode[int(info["cid"])] = DirNode(info["name"], int(info["pid"]))
361
354
  return int(resp["count"])
362
355
  else:
356
+ resp = yield get_resp_of_category_get(cid)
357
+ if not resp:
358
+ raise FileNotFoundError(ENOENT, cid)
359
+ if "paths" not in resp:
360
+ check_response(resp)
361
+ resp = resp["data"]
362
+ if not resp:
363
+ raise FileNotFoundError(ENOENT, cid)
363
364
  if int(resp["file_category"]):
365
+ resp["cid"] = cid
364
366
  raise NotADirectoryError(ENOTDIR, resp)
365
367
  if id_to_dirnode is not ...:
366
368
  pid = 0
@@ -368,14 +370,15 @@ def get_file_count(
368
370
  node = DirNode(info["file_name"], pid)
369
371
  id_to_dirnode[(pid := int(info["file_id"]))] = node
370
372
  return int(resp["count"]) - int(resp.get("folder_count") or 0)
371
- return run_gen_step(gen_step, async_=async_)
373
+ return run_gen_step(gen_step, simple=True, async_=async_)
372
374
 
373
375
 
374
376
  @overload
375
377
  def get_ancestors(
376
378
  client: str | P115Client,
377
- attr: dict,
379
+ attr: int | dict,
378
380
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
381
+ app: str = "web",
379
382
  *,
380
383
  async_: Literal[False] = False,
381
384
  **request_kwargs,
@@ -384,8 +387,9 @@ def get_ancestors(
384
387
  @overload
385
388
  def get_ancestors(
386
389
  client: str | P115Client,
387
- attr: dict,
390
+ attr: int | dict,
388
391
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
392
+ app: str = "web",
389
393
  *,
390
394
  async_: Literal[True],
391
395
  **request_kwargs,
@@ -393,20 +397,19 @@ def get_ancestors(
393
397
  ...
394
398
  def get_ancestors(
395
399
  client: str | P115Client,
396
- attr: dict,
400
+ attr: int | dict,
397
401
  id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
402
+ app: str = "web",
398
403
  *,
399
404
  async_: Literal[False, True] = False,
400
405
  **request_kwargs,
401
406
  ) -> list[dict] | Coroutine[Any, Any, list[dict]]:
402
407
  """获取某个节点对应的祖先节点列表(只有 id、parent_id 和 name 的信息)
403
408
 
404
- .. caution::
405
- 我通过一些经验,搭配了多个接口的占比和参数分布,可能不够合理,以后会根据实际情况调整
406
-
407
409
  :param client: 115 客户端或 cookies
408
- :param attr: 待查询节点的信息(必须有 id parent_id
410
+ :param attr: 待查询节点 `id` 或信息(必须有 `id`,可选有 `parent_id`)
409
411
  :param id_to_dirnode: 字典,保存 id 到对应文件的 `DirNode(name, parent_id)` 命名元组的字典
412
+ :param app: 使用某个 app (设备)的接口
410
413
  :param async_: 是否异步
411
414
  :param request_kwargs: 其它请求参数
412
415
 
@@ -424,91 +427,170 @@ def get_ancestors(
424
427
  client = P115Client(client, check_for_relogin=True)
425
428
  if id_to_dirnode is None:
426
429
  id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
427
- n_webapi = len(WEBAPI_BASE_URLS)
428
- n_proapi = len(PROAPI_BASE_URLS)
429
- n_apsapi = len(APS_BASE_URLS)
430
- n_api = n_webapi * 2 + n_proapi * 2 + n_apsapi
431
- def get_resp():
432
- global _n_get_ancestors
433
- n = _n_get_ancestors % n_api
434
- if n < n_webapi:
435
- _n_get_ancestors += 1
430
+ def get_resp_of_fs_files(id: int, /):
431
+ if not isinstance(client, P115Client) or app == "open":
432
+ return client.fs_files_open(
433
+ {"cid": id, "cur": 1, "nf": 1, "hide_data": 1},
434
+ async_=async_,
435
+ **request_kwargs,
436
+ )
437
+ elif app in ("", "web", "desktop", "harmony"):
436
438
  return client.fs_files(
437
- {"cid": attr["parent_id"], "limit": 1},
438
- base_url=WEBAPI_BASE_URLS[n],
439
+ {"cid": id, "limit": 1, "nf": 1, "star": 1},
439
440
  async_=async_,
440
441
  **request_kwargs,
441
442
  )
442
- n -= n_webapi
443
- if n < n_proapi:
444
- _n_get_ancestors += 1
443
+ elif app == "aps":
444
+ return client.fs_files_aps(
445
+ {"cid": id, "limit": 1, "nf": 1, "star": 1},
446
+ async_=async_,
447
+ **request_kwargs,
448
+ )
449
+ else:
445
450
  return client.fs_files_app(
446
- {"cid": attr["parent_id"], "hide_data": 1},
447
- base_url=PROAPI_BASE_URLS[n],
451
+ {"cid": id, "cur": 1, "nf": 1, "hide_data": 1},
452
+ app=app,
448
453
  async_=async_,
449
454
  **request_kwargs,
450
455
  )
451
- n -= n_proapi
452
- if n < n_apsapi:
453
- _n_get_ancestors += 1
454
- return client.fs_files_aps(
455
- {"cid": attr["parent_id"], "limit": 1},
456
- base_url=APS_BASE_URLS[n],
456
+ def get_resp_of_category_get(id: int, /):
457
+ if not isinstance(client, P115Client) or app == "open":
458
+ return client.fs_info_open(
459
+ id,
457
460
  async_=async_,
458
461
  **request_kwargs,
459
462
  )
460
- if attr.get("is_dir", False) or attr.get("is_directory", False):
461
- _n_get_ancestors = 0
462
- return get_resp()
463
- n -= n_apsapi
464
- if n < n_webapi:
465
- _n_get_ancestors += 1
463
+ elif app in ("", "web", "desktop", "harmony", "aps"):
466
464
  return client.fs_category_get(
467
- attr["id"],
468
- base_url=WEBAPI_BASE_URLS[n],
465
+ id,
466
+ async_=async_,
467
+ **request_kwargs,
468
+ )
469
+ else:
470
+ return client.fs_category_get_app(
471
+ id,
472
+ app=app,
469
473
  async_=async_,
470
474
  **request_kwargs,
471
475
  )
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
476
  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
477
  ancestors: list[dict] = [{"id": 0, "parent_id": 0, "name": ""}]
489
478
  add_ancestor = ancestors.append
490
479
  pid = 0
491
- if "path" in resp:
492
- if attr["parent_id"] != int(resp["path"][-1]["cid"]):
493
- raise FileNotFoundError(ENOENT, resp)
494
- for info in resp["path"][1:]:
495
- add_ancestor({
496
- "parent_id": pid,
497
- "id": (pid := int(info["cid"])),
498
- "name": info["name"],
499
- })
480
+ is_completed = False
481
+ if isinstance(attr, dict):
482
+ fid = cast(int, attr["id"])
483
+ if not fid:
484
+ return ancestors
485
+ is_dir: None | bool = attr.get("is_dir") or attr.get("is_directory")
486
+ if is_dir is None:
487
+ if "parent_id" in attr:
488
+ cid = cast(int, attr["parent_id"])
489
+ resp = yield get_resp_of_fs_files(cid)
490
+ if cid != int(resp["path"][-1]["cid"]):
491
+ resp["attr"] = attr
492
+ raise FileNotFoundError(ENOENT, resp)
493
+ for info in resp["path"][1:]:
494
+ add_ancestor({
495
+ "parent_id": pid,
496
+ "id": (pid := int(info["cid"])),
497
+ "name": info["name"],
498
+ })
499
+ if id_to_dirnode is not ...:
500
+ for ans in ancestors[1:]:
501
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
502
+ if "name" in attr:
503
+ name = attr["name"]
504
+ is_dir = bool(attr.get("is_dir"))
505
+ else:
506
+ resp = yield client.fs_file_skim(attr["id"], async_=async_, **request_kwargs)
507
+ check_response(resp)
508
+ name = unescape_115_charref(resp["data"]["file_name"])
509
+ is_dir = not resp["data"]["sha1"]
510
+ ans = {"id": fid, "parent_id": pid, "name": name}
511
+ add_ancestor(ans)
512
+ if is_dir and id_to_dirnode is not ...:
513
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
514
+ is_completed = True
515
+ elif is_dir:
516
+ resp = yield get_resp_of_fs_files(fid)
517
+ if fid != int(resp["path"][-1]["cid"]):
518
+ resp["attr"] = attr
519
+ raise FileNotFoundError(ENOENT, resp)
520
+ for info in resp["path"][1:]:
521
+ add_ancestor({
522
+ "parent_id": pid,
523
+ "id": (pid := int(info["cid"])),
524
+ "name": info["name"],
525
+ })
526
+ if id_to_dirnode is not ...:
527
+ for ans in ancestors[1:]:
528
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
529
+ is_completed = True
530
+ else:
531
+ resp = yield get_resp_of_category_get(fid)
532
+ if not resp:
533
+ raise FileNotFoundError(ENOENT, attr)
534
+ if "paths" not in resp:
535
+ check_response(resp)
536
+ resp = resp["data"]
537
+ if not resp:
538
+ raise FileNotFoundError(ENOENT, attr)
539
+ for info in resp["paths"]:
540
+ add_ancestor({
541
+ "parent_id": pid,
542
+ "id": (pid := int(info["file_id"])),
543
+ "name": info["file_name"],
544
+ })
545
+ if id_to_dirnode is not ...:
546
+ for ans in ancestors[1:]:
547
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
548
+ ans = {"id": fid, "parent_id": pid, "name": resp["file_name"]}
549
+ add_ancestor(ans)
550
+ if not resp.get("sha1") and id_to_dirnode is not ...:
551
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
552
+ is_completed = True
500
553
  else:
501
- for info in resp["paths"]:
502
- add_ancestor({
503
- "parent_id": pid,
504
- "id": (pid := int(info["file_id"])),
505
- "name": info["file_name"],
506
- })
507
- if id_to_dirnode is not ...:
508
- for ans in ancestors[1:]:
509
- id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
554
+ fid = attr
555
+ if not is_completed:
556
+ if not fid:
557
+ return ancestors
558
+ resp = yield get_resp_of_fs_files(fid)
559
+ check_response(resp)
560
+ if fid == int(resp["path"][-1]["cid"]):
561
+ for info in resp["path"][1:]:
562
+ add_ancestor({
563
+ "parent_id": pid,
564
+ "id": (pid := int(info["cid"])),
565
+ "name": info["name"],
566
+ })
567
+ if id_to_dirnode is not ...:
568
+ for ans in ancestors[1:]:
569
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
570
+ else:
571
+ resp = yield get_resp_of_category_get(fid)
572
+ if not resp:
573
+ raise FileNotFoundError(ENOENT, fid)
574
+ if "paths" not in resp:
575
+ check_response(resp)
576
+ resp = resp["data"]
577
+ if not resp:
578
+ raise FileNotFoundError(ENOENT, fid)
579
+ for info in resp["paths"]:
580
+ add_ancestor({
581
+ "parent_id": pid,
582
+ "id": (pid := int(info["file_id"])),
583
+ "name": info["file_name"],
584
+ })
585
+ if id_to_dirnode is not ...:
586
+ for ans in ancestors[1:]:
587
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
588
+ ans = {"id": fid, "parent_id": pid, "name": resp["file_name"]}
589
+ add_ancestor(ans)
590
+ if not resp.get("sha1") and id_to_dirnode is not ...:
591
+ id_to_dirnode[ans["id"]] = DirNode(ans["name"], ans["parent_id"])
510
592
  return ancestors
511
- return run_gen_step(gen_step, async_=async_)
593
+ return run_gen_step(gen_step, simple=True, async_=async_)
512
594
 
513
595
 
514
596
  @overload
@@ -516,7 +598,7 @@ def get_ancestors_to_cid(
516
598
  client: str | P115Client,
517
599
  cid: int = 0,
518
600
  refresh: bool = False,
519
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
601
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
520
602
  app: str = "web",
521
603
  *,
522
604
  async_: Literal[False] = False,
@@ -528,7 +610,7 @@ def get_ancestors_to_cid(
528
610
  client: str | P115Client,
529
611
  cid: int = 0,
530
612
  refresh: bool = False,
531
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
613
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
532
614
  app: str = "web",
533
615
  *,
534
616
  async_: Literal[True],
@@ -539,7 +621,7 @@ def get_ancestors_to_cid(
539
621
  client: str | P115Client,
540
622
  cid: int = 0,
541
623
  refresh: bool = False,
542
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
624
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
543
625
  app: str = "web",
544
626
  *,
545
627
  async_: Literal[False, True] = False,
@@ -569,14 +651,31 @@ def get_ancestors_to_cid(
569
651
  client = P115Client(client, check_for_relogin=True)
570
652
  if id_to_dirnode is None:
571
653
  id_to_dirnode = ID_TO_DIRNODE_CACHE[client.user_id]
654
+ elif id_to_dirnode is ...:
655
+ id_to_dirnode = {}
572
656
  def gen_step():
573
657
  nonlocal cid
574
658
  parts: list[dict] = []
575
659
  if cid and (refresh or cid not in id_to_dirnode):
576
- if app in ("", "web", "desktop", "harmony"):
577
- resp = yield client.fs_files({"cid": cid, "limit": 1}, async_=async_, **request_kwargs)
660
+ if not isinstance(client, P115Client) or app == "open":
661
+ resp = yield client.fs_files_open(
662
+ {"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
663
+ async_=async_,
664
+ **request_kwargs,
665
+ )
666
+ elif app in ("", "web", "desktop", "harmony"):
667
+ resp = yield client.fs_files_aps(
668
+ {"cid": cid, "limit": 1, "nf": 1, "star": 1},
669
+ async_=async_,
670
+ **request_kwargs,
671
+ )
578
672
  else:
579
- resp = yield client.fs_files_app({"cid": cid, "hide_data": 1}, async_=async_, **request_kwargs)
673
+ resp = yield client.fs_files_app(
674
+ {"cid": cid, "cur": 1, "nf": 1, "hide_data": 1},
675
+ app=app,
676
+ async_=async_,
677
+ **request_kwargs,
678
+ )
580
679
  check_response(resp)
581
680
  if cid and int(resp["path"][-1]["cid"]) != cid:
582
681
  raise FileNotFoundError(ENOENT, cid)
@@ -593,7 +692,7 @@ def get_ancestors_to_cid(
593
692
  parts.append({"id": 0, "name": "", "parent_id": 0})
594
693
  parts.reverse()
595
694
  return parts
596
- return run_gen_step(gen_step, async_=async_)
695
+ return run_gen_step(gen_step, simple=True, async_=async_)
597
696
 
598
697
 
599
698
  # TODO: 使用 search 接口以在特定目录之下搜索某个名字,以便减少风控
@@ -605,7 +704,7 @@ def get_id_to_path(
605
704
  ensure_file: None | bool = None,
606
705
  is_posixpath: bool = False,
607
706
  refresh: bool = False,
608
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
707
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
609
708
  app: str = "web",
610
709
  dont_use_getid: bool = False,
611
710
  *,
@@ -621,7 +720,7 @@ def get_id_to_path(
621
720
  ensure_file: None | bool = None,
622
721
  is_posixpath: bool = False,
623
722
  refresh: bool = False,
624
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
723
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
625
724
  app: str = "web",
626
725
  dont_use_getid: bool = False,
627
726
  *,
@@ -636,7 +735,7 @@ def get_id_to_path(
636
735
  ensure_file: None | bool = None,
637
736
  is_posixpath: bool = False,
638
737
  refresh: bool = False,
639
- id_to_dirnode: None | dict[int, tuple[str, int] | DirNode] = None,
738
+ id_to_dirnode: None | EllipsisType | dict[int, tuple[str, int] | DirNode] = None,
640
739
  app: str = "web",
641
740
  dont_use_getid: bool = False,
642
741
  *,
@@ -788,7 +887,7 @@ def get_id_to_path(
788
887
  if ensure_file is None or ensure_file ^ attr["is_dir"]:
789
888
  return P115ID(attr["id"], attr, about="path")
790
889
  raise error
791
- return run_gen_step(gen_step, async_=async_)
890
+ return run_gen_step(gen_step, simple=True, async_=async_)
792
891
 
793
892
 
794
893
  @overload
@@ -842,7 +941,7 @@ def get_id_to_pickcode(
842
941
  check_response(resp)
843
942
  data = resp["data"]
844
943
  return P115ID(data["file_id"], data, about="pickcode")
845
- return run_gen_step(gen_step, async_=async_)
944
+ return run_gen_step(gen_step, simple=True, async_=async_)
846
945
 
847
946
 
848
947
  @overload
@@ -902,7 +1001,7 @@ def get_id_to_sha1(
902
1001
  else:
903
1002
  raise FileNotFoundError(ENOENT, file_sha1)
904
1003
  return P115ID(data["file_id"], data, about="sha1", file_sha1=file_sha1)
905
- return run_gen_step(gen_step, async_=async_)
1004
+ return run_gen_step(gen_step, simple=True, async_=async_)
906
1005
 
907
1006
 
908
1007
  @overload
@@ -954,8 +1053,8 @@ def iter_nodes_skim(
954
1053
  check_response(resp)
955
1054
  for a in resp["data"]:
956
1055
  a["file_name"] = unescape_115_charref(a["file_name"])
957
- yield YieldFrom(resp["data"], identity=True)
958
- return run_gen_step_iter(gen_step, async_=async_)
1056
+ yield YieldFrom(resp["data"], may_await=False)
1057
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
959
1058
 
960
1059
 
961
1060
  @overload
@@ -1092,7 +1191,7 @@ def _iter_fs_files(
1092
1191
  attr = _overview_attr(info)
1093
1192
  if attr.is_dir:
1094
1193
  id_to_dirnode[attr.id] = DirNode(attr.name, attr.parent_id)
1095
- yield YieldFrom(resp["data"], identity=True)
1194
+ yield YieldFrom(resp["data"], may_await=False)
1096
1195
  else:
1097
1196
  for info in resp["data"]:
1098
1197
  attr = _overview_attr(info)
@@ -1101,10 +1200,10 @@ def _iter_fs_files(
1101
1200
  id_to_dirnode[attr.id] = DirNode(attr.name, attr.parent_id)
1102
1201
  elif ensure_file is False:
1103
1202
  return
1104
- yield Yield(info, identity=True)
1203
+ yield Yield(info, may_await=False)
1105
1204
  except (StopAsyncIteration, StopIteration):
1106
1205
  pass
1107
- return run_gen_step_iter(gen_step, async_=async_)
1206
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
1108
1207
 
1109
1208
 
1110
1209
  @overload
@@ -1493,8 +1592,8 @@ def ensure_attr_path[D: dict](
1493
1592
  warn(f"{type(e).__module__}.{type(e).__qualname__}: {e} of {attr}", category=P115Warning)
1494
1593
  attr.setdefault("ancestors", None)
1495
1594
  attr.setdefault("path", "")
1496
- yield Yield(attr, identity=True)
1497
- return run_gen_step_iter(gen_step, async_=async_)
1595
+ yield Yield(attr, may_await=False)
1596
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
1498
1597
 
1499
1598
 
1500
1599
  @overload
@@ -1976,10 +2075,10 @@ def iterdir(
1976
2075
  name = escape(name)
1977
2076
  attr["path"] = dirname + name
1978
2077
  return attr
1979
- yield YieldFrom(do_map(process, it), identity=True) # type: ignore
2078
+ yield YieldFrom(do_map(process, it), may_await=False) # type: ignore
1980
2079
  else:
1981
- yield YieldFrom(do_map(normalize_attr, it), identity=True) # type: ignore
1982
- return run_gen_step_iter(gen_step, async_=async_)
2080
+ yield YieldFrom(do_map(normalize_attr, it), may_await=False) # type: ignore
2081
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
1983
2082
 
1984
2083
 
1985
2084
  def iterdir_limited(
@@ -2088,8 +2187,8 @@ def iterdir_limited(
2088
2187
  attr["path"] = dirname + name
2089
2188
  yield attr
2090
2189
  def gen_step():
2091
- resp: dict = yield run_gen_step(request, async_=async_)
2092
- yield YieldFrom(iter_attrs(resp), identity=True)
2190
+ resp: dict = yield run_gen_step(request, simple=True, async_=async_)
2191
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2093
2192
  count = int(resp["count"])
2094
2193
  count_fetched = len(resp["data"])
2095
2194
  if count > count_fetched:
@@ -2117,30 +2216,30 @@ def iterdir_limited(
2117
2216
  count_top = count_top_dirs + count_top_files
2118
2217
  if count <= count_fetched * 2 - count_top:
2119
2218
  resp = request({"asc": 0, "offset": count_top, "limit": count - count_fetched})
2120
- yield YieldFrom(iter_attrs(resp), identity=True)
2219
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2121
2220
  return
2122
2221
  if diff := count_dirs - len(seen_dirs):
2123
2222
  if diff > count_fetched - count_top_dirs:
2124
2223
  resp = request({"nf": 1, "offset": len(seen_dirs)})
2125
- yield YieldFrom(iter_attrs(resp), identity=True)
2224
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2126
2225
  diff = count_dirs - len(seen_dirs)
2127
2226
  if diff > 0:
2128
2227
  resp = request({"asc": 0, "nf": 1, "offset": count_top_dirs, "limit": diff})
2129
- yield YieldFrom(iter_attrs(resp), identity=True)
2228
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2130
2229
 
2131
2230
  if diff := count_dirs - len(seen_dirs):
2132
2231
  warn(f"lost {diff} directories: cid={cid}", category=P115Warning)
2133
2232
  if diff := count_files - len(seen_files):
2134
2233
  if diff > count_fetched - count_top_files:
2135
2234
  resp = request({"show_dir": 0, "offset": len(seen_files)})
2136
- yield YieldFrom(iter_attrs(resp), identity=True)
2235
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2137
2236
  diff = count_files - len(seen_files)
2138
2237
  if diff > 0:
2139
2238
  resp = request({"asc": 0, "show_dir": 0, "offset": count_top_files, "limit": diff})
2140
- yield YieldFrom(iter_attrs(resp), identity=True)
2239
+ yield YieldFrom(iter_attrs(resp), may_await=False)
2141
2240
  if diff := count_files - len(seen_files):
2142
2241
  warn(f"lost {diff} files: cid={cid}", category=P115Warning)
2143
- return run_gen_step_iter(gen_step, async_=async_)
2242
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
2144
2243
 
2145
2244
 
2146
2245
  @overload
@@ -2493,9 +2592,9 @@ def iter_files(
2493
2592
  add_to_cache(attr)
2494
2593
  else:
2495
2594
  return attr
2496
- yield YieldFrom(do_filter(bool, do_map(process, it)), identity=True) # type: ignore
2595
+ yield YieldFrom(do_filter(bool, do_map(process, it)), may_await=False) # type: ignore
2497
2596
  else:
2498
- yield YieldFrom(do_map(normalize_attr, it), identity=True) # type: ignore
2597
+ yield YieldFrom(do_map(normalize_attr, it), may_await=False) # type: ignore
2499
2598
  if (with_ancestors or with_path) and cache:
2500
2599
  yield YieldFrom(ensure_attr_path(
2501
2600
  client,
@@ -2509,8 +2608,8 @@ def iter_files(
2509
2608
  app=app,
2510
2609
  async_=async_, # type: ignore
2511
2610
  **request_kwargs,
2512
- ), identity=True)
2513
- return run_gen_step_iter(gen_step, async_=async_)
2611
+ ), may_await=False)
2612
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
2514
2613
 
2515
2614
 
2516
2615
  @overload
@@ -2637,8 +2736,7 @@ def traverse_files(
2637
2736
  def gen_step():
2638
2737
  nonlocal cid
2639
2738
  if auto_splitting_tasks:
2640
- get_count = partial(
2641
- get_file_count,
2739
+ get_count = get_file_count(
2642
2740
  client,
2643
2741
  id_to_dirnode=id_to_dirnode,
2644
2742
  **{**request_kwargs, "timeout": auto_splitting_statistics_timeout}
@@ -2674,7 +2772,7 @@ def traverse_files(
2674
2772
  max_workers=max_workers,
2675
2773
  async_=async_, # type: ignore
2676
2774
  **request_kwargs,
2677
- ), identity=True)
2775
+ ), may_await=False)
2678
2776
  else:
2679
2777
  yield YieldFrom(iter_files(
2680
2778
  client,
@@ -2690,7 +2788,7 @@ def traverse_files(
2690
2788
  max_workers=max_workers,
2691
2789
  async_=async_, # type: ignore
2692
2790
  **request_kwargs,
2693
- ), identity=True)
2791
+ ), may_await=False)
2694
2792
  else:
2695
2793
  with with_iter_next(iterdir(
2696
2794
  client,
@@ -2715,8 +2813,8 @@ def traverse_files(
2715
2813
  type > 7 or
2716
2814
  type_of_attr(attr) == type
2717
2815
  ):
2718
- yield Yield(attr, identity=True)
2719
- return run_gen_step_iter(gen_step, async_=async_)
2816
+ yield Yield(attr, may_await=False)
2817
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
2720
2818
 
2721
2819
 
2722
2820
  @overload
@@ -2809,8 +2907,8 @@ def iter_dirs(
2809
2907
  )) as get_next:
2810
2908
  while True:
2811
2909
  batch = yield get_next
2812
- yield YieldFrom(batch, identity=True)
2813
- it = run_gen_step_iter(gen_step(it), async_=async_)
2910
+ yield YieldFrom(batch, may_await=False)
2911
+ it = run_gen_step_iter(gen_step(it), simple=True, async_=async_)
2814
2912
  return it
2815
2913
 
2816
2914
 
@@ -3057,12 +3155,12 @@ def iter_image_files(
3057
3155
  count = int(resp.get("count") or 0)
3058
3156
  if offset != resp["offset"]:
3059
3157
  break
3060
- yield YieldFrom(map(normalize, resp["data"]), identity=True)
3158
+ yield YieldFrom(map(normalize, resp["data"]), may_await=False)
3061
3159
  offset += len(resp["data"])
3062
3160
  if offset >= count:
3063
3161
  break
3064
3162
  payload["offset"] = offset
3065
- return run_gen_step_iter(gen_step, async_=async_)
3163
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
3066
3164
 
3067
3165
 
3068
3166
  @overload
@@ -3171,11 +3269,11 @@ def share_iterdir(
3171
3269
  id_to_dirnode[oattr.id] = DirNode(oattr.name, oattr.parent_id)
3172
3270
  if normalize_attr is not None:
3173
3271
  attr = normalize_attr(attr)
3174
- yield Yield(attr, identity=True)
3272
+ yield Yield(attr, may_await=False)
3175
3273
  payload["offset"] += page_size # type: ignore
3176
3274
  if payload["offset"] >= count: # type: ignore
3177
3275
  break
3178
- return run_gen_step_iter(gen_step, async_=async_)
3276
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
3179
3277
 
3180
3278
 
3181
3279
  @overload
@@ -3273,12 +3371,12 @@ def share_iter_files(
3273
3371
  "name": info["fn"],
3274
3372
  "size": int(info["si"]),
3275
3373
  "path": f"/{info['pt']}/{info['fn']}",
3276
- }, identity=True)
3374
+ }, may_await=False)
3277
3375
  else:
3278
- yield Yield({k: attr[k] for k in ("id", "sha1", "name", "size", "path")}, identity=True)
3376
+ yield Yield({k: attr[k] for k in ("id", "sha1", "name", "size", "path")}, may_await=False)
3279
3377
  except (StopIteration, StopAsyncIteration):
3280
3378
  pass
3281
- return run_gen_step(gen_step, async_=async_)
3379
+ return run_gen_step(gen_step, simple=True, async_=async_)
3282
3380
 
3283
3381
 
3284
3382
  @overload
@@ -3448,7 +3546,7 @@ def share_get_id_to_path(
3448
3546
  if ensure_file is None or ensure_file ^ attr["is_dir"]:
3449
3547
  return P115ID(attr["id"], attr, about="path")
3450
3548
  raise error
3451
- return run_gen_step(gen_step, async_=async_)
3549
+ return run_gen_step(gen_step, simple=True, async_=async_)
3452
3550
 
3453
3551
 
3454
3552
  @overload
@@ -3960,7 +4058,7 @@ def iter_selected_nodes_using_star_event(
3960
4058
  id_to_dirnode[fid] = DirNode(name, pid)
3961
4059
  if fid in ids:
3962
4060
  if not normalize_attr:
3963
- yield Yield(event, identity=True)
4061
+ yield Yield(event, may_await=False)
3964
4062
  elif normalize_attr is True:
3965
4063
  attr = {
3966
4064
  "id": fid,
@@ -3982,15 +4080,15 @@ def iter_selected_nodes_using_star_event(
3982
4080
  attr["type"] = 3
3983
4081
  else:
3984
4082
  attr["type"] = type_of_attr(attr)
3985
- yield Yield(attr, identity=True)
4083
+ yield Yield(attr, may_await=False)
3986
4084
  else:
3987
- yield Yield(normalize_attr(event), identity=True)
4085
+ yield Yield(normalize_attr(event), may_await=False)
3988
4086
  discard(fid)
3989
4087
  if not ids:
3990
4088
  break
3991
4089
  except (StopIteration, StopAsyncIteration):
3992
4090
  pass
3993
- return run_gen_step_iter(gen_step, async_=async_)
4091
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
3994
4092
 
3995
4093
 
3996
4094
  @overload
@@ -4084,13 +4182,13 @@ def iter_selected_dirs_using_star(
4084
4182
  break
4085
4183
  cid = attr["id"]
4086
4184
  if cid in ids:
4087
- yield Yield(info, identity=True)
4185
+ yield Yield(info, may_await=False)
4088
4186
  discard(cid)
4089
4187
  if not ids:
4090
4188
  break
4091
4189
  except (StopIteration, StopAsyncIteration):
4092
4190
  pass
4093
- return run_gen_step_iter(gen_step, async_=async_)
4191
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
4094
4192
 
4095
4193
 
4096
4194
  @overload
@@ -4251,7 +4349,7 @@ def iter_files_with_dirname(
4251
4349
  resp = yield get_next
4252
4350
  for attr in resp["data"]:
4253
4351
  attr.update(pid_to_info[attr["parent_id"]])
4254
- yield Yield(attr, identity=True)
4352
+ yield Yield(attr, may_await=False)
4255
4353
  except (StopIteration, StopAsyncIteration):
4256
4354
  pass
4257
4355
  if with_parents_4_level:
@@ -4264,7 +4362,7 @@ def iter_files_with_dirname(
4264
4362
  it = iter_parents_3_level(
4265
4363
  client,
4266
4364
  iter_unique((async_map if async_ else map)(
4267
- get_pid, run_gen_step_iter(gen_step, async_=async_))), # type: ignore
4365
+ get_pid, run_gen_step_iter(gen_step, simple=True, async_=async_))), # type: ignore
4268
4366
  async_=async_, # type: ignore
4269
4367
  **request_kwargs,
4270
4368
  )
@@ -4277,9 +4375,9 @@ def iter_files_with_dirname(
4277
4375
  id_to_parents[0] = ("", "", "")
4278
4376
  for attr in files:
4279
4377
  attr["parents"] = (attr["dir_name"], *id_to_parents[attr["parent_id"]])
4280
- yield Yield(attr, identity=True)
4281
- return run_gen_step_iter(gen_step2, async_=async_)
4282
- return run_gen_step_iter(gen_step, async_=async_)
4378
+ yield Yield(attr, may_await=False)
4379
+ return run_gen_step_iter(gen_step2, simple=True, async_=async_)
4380
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
4283
4381
 
4284
4382
 
4285
4383
  @overload
@@ -4419,7 +4517,7 @@ def iter_files_with_path(
4419
4517
  _path_already: None | bool = None if path_already else False
4420
4518
  if not path_already:
4421
4519
  from .download import iter_download_nodes
4422
- def set_path_already(*a):
4520
+ def set_path_already(*_):
4423
4521
  nonlocal _path_already
4424
4522
  _path_already = True
4425
4523
  def fetch_dirs(id: int | str, /):
@@ -4452,7 +4550,7 @@ def iter_files_with_path(
4452
4550
  )) as get_next:
4453
4551
  while True:
4454
4552
  attr = yield get_next
4455
- yield run_gen_step(fetch_dirs(attr["pickcode"]), async_=async_)
4553
+ yield run_gen_step(fetch_dirs(attr["pickcode"]), simple=True, async_=async_)
4456
4554
  if with_ancestors:
4457
4555
  id_to_ancestors: dict[int, list[dict]] = {}
4458
4556
  def get_ancestors(id: int, attr: dict | tuple[str, int] | DirNode, /) -> list[dict]:
@@ -4499,7 +4597,7 @@ def iter_files_with_path(
4499
4597
  add_to_cache = cache.append
4500
4598
  if not path_already:
4501
4599
  if async_:
4502
- task: Any = create_task(run_gen_step(fetch_dirs(cid), async_=True))
4600
+ task: Any = create_task(run_gen_step(fetch_dirs(cid), simple=True, async_=True))
4503
4601
  else:
4504
4602
  task = run_as_thread(run_gen_step, fetch_dirs(cid))
4505
4603
  task.add_done_callback(set_path_already)
@@ -4524,16 +4622,16 @@ def iter_files_with_path(
4524
4622
  while True:
4525
4623
  attr = yield get_next
4526
4624
  if _path_already is None:
4527
- yield Yield(update_path(attr), identity=True)
4625
+ yield Yield(update_path(attr), may_await=False)
4528
4626
  elif _path_already:
4529
4627
  if async_:
4530
4628
  yield task
4531
4629
  else:
4532
4630
  task.result()
4533
4631
  if cache:
4534
- yield YieldFrom(map(update_path, cache), identity=True)
4632
+ yield YieldFrom(map(update_path, cache), may_await=False)
4535
4633
  cache.clear()
4536
- yield Yield(update_path(attr), identity=True)
4634
+ yield Yield(update_path(attr), may_await=False)
4537
4635
  _path_already = None
4538
4636
  else:
4539
4637
  add_to_cache(attr)
@@ -4542,8 +4640,8 @@ def iter_files_with_path(
4542
4640
  yield task
4543
4641
  else:
4544
4642
  task.result()
4545
- yield YieldFrom(map(update_path, cache), identity=True)
4546
- return run_gen_step_iter(gen_step, async_=async_)
4643
+ yield YieldFrom(map(update_path, cache), may_await=False)
4644
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
4547
4645
 
4548
4646
 
4549
4647
  @overload
@@ -4799,8 +4897,8 @@ def iter_files_with_path_by_export_dir(
4799
4897
  if escape is not None:
4800
4898
  name = escape(name)
4801
4899
  attr["path"] = dir_path + name
4802
- yield Yield(attr, identity=True)
4803
- return run_gen_step_iter(gen_step, async_=async_)
4900
+ yield Yield(attr, may_await=False)
4901
+ return run_gen_step_iter(gen_step, simple=True, async_=async_)
4804
4902
 
4805
4903
 
4806
4904
  @overload
@@ -4891,7 +4989,7 @@ def iter_parents_3_level(
4891
4989
  ids = (async_filter if async_ else filter)(None, ids) # type: ignore
4892
4990
  return flatten(
4893
4991
  batch_map(
4894
- lambda ids, /: run_gen_step(get_parents(ids), async_=async_),
4992
+ lambda ids, /: run_gen_step(get_parents(ids), simple=True, async_=async_),
4895
4993
  chunked(ids, 1150),
4896
4994
  max_workers=max_workers,
4897
4995
  ),
@@ -4971,7 +5069,7 @@ def iter_dir_nodes(
4971
5069
  id_to_dirnode[id] = DirNode(name, parent_id)
4972
5070
  yield Yield(
4973
5071
  {"id": id, "parent_id": parent_id, "name": name},
4974
- identity=True,
5072
+ may_await=False,
4975
5073
  )
4976
5074
  else:
4977
5075
  with with_iter_next(iterdir(
@@ -4990,11 +5088,90 @@ def iter_dir_nodes(
4990
5088
  "parent_id": attr["parent_id"],
4991
5089
  "name": attr["name"],
4992
5090
  },
4993
- identity=True,
5091
+ may_await=False,
4994
5092
  )
4995
5093
  yield YieldFrom(
4996
- run_gen_step_iter(gen_step(attr["pickcode"]), async_=async_),
4997
- identity=True,
5094
+ run_gen_step_iter(gen_step(attr["pickcode"]), simple=True, async_=async_),
5095
+ may_await=False,
4998
5096
  )
4999
- return run_gen_step_iter(gen_step(cid or 0), async_=async_)
5097
+ return run_gen_step_iter(gen_step(cid or 0), simple=True, async_=async_)
5098
+
5099
+
5100
+ @overload
5101
+ def search_for_any_file(
5102
+ client: str | P115Client,
5103
+ cid: int = 0,
5104
+ search_value: str = ".",
5105
+ suffix: str = "",
5106
+ type: int = 99,
5107
+ app: str = "web",
5108
+ *,
5109
+ async_: Literal[False] = False,
5110
+ **request_kwargs,
5111
+ ) -> bool:
5112
+ ...
5113
+ @overload
5114
+ def search_for_any_file(
5115
+ client: str | P115Client,
5116
+ cid: int = 0,
5117
+ search_value: str = ".",
5118
+ suffix: str = "",
5119
+ type: int = 99,
5120
+ app: str = "web",
5121
+ *,
5122
+ async_: Literal[True],
5123
+ **request_kwargs,
5124
+ ) -> Coroutine[Any, Any, bool]:
5125
+ ...
5126
+ def search_for_any_file(
5127
+ client: str | P115Client,
5128
+ cid: int = 0,
5129
+ search_value: str = ".",
5130
+ suffix: str = "",
5131
+ type: int = 99,
5132
+ app: str = "web",
5133
+ *,
5134
+ async_: Literal[False, True] = False,
5135
+ **request_kwargs,
5136
+ ) -> bool | Coroutine[Any, Any, bool]:
5137
+ """搜索以判断是否存在某种文件
5138
+
5139
+ :param client: 115 客户端或 cookies
5140
+ :param cid: 目录 id
5141
+ :param search_value: 搜索关键词,搜索到的文件名必须包含这个字符串
5142
+ :param suffix: 后缀名(优先级高于 type)
5143
+ :param type: 文件类型
5144
+
5145
+ - 1: 文档
5146
+ - 2: 图片
5147
+ - 3: 音频
5148
+ - 4: 视频
5149
+ - 5: 压缩包
5150
+ - 6: 应用
5151
+ - 7: 书籍
5152
+ - 99: 仅文件
5153
+
5154
+ :param app: 使用某个 app (设备)的接口
5155
+ :param async_: 是否异步
5156
+ :param request_kwargs: 其它请求参数
5157
+
5158
+ :return: 是否存在某种文件
5159
+ """
5160
+ if isinstance(client, str):
5161
+ client = P115Client(client, check_for_relogin=True)
5162
+ if not isinstance(client, P115Client) or app == "open":
5163
+ fs_search: Callable = client.fs_search_open
5164
+ elif app in ("", "web", "desktop", "harmony"):
5165
+ fs_search = partial(client.fs_search, app=app)
5166
+ else:
5167
+ fs_search = client.fs_search_app
5168
+ def gen_step():
5169
+ resp = yield fs_search(
5170
+ {"cid": cid, "limit": 1, "search_value": search_value, "suffix": suffix, "type": type},
5171
+ async_=async_,
5172
+ **request_kwargs,
5173
+ )
5174
+ check_response(resp)
5175
+ return bool(resp["data"])
5176
+ return run_gen_step(gen_step, simple=True, async_=async_)
5000
5177