p115client 0.0.5.12.3__py3-none-any.whl → 0.0.5.13.1__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 +260 -188
- p115client/tool/attr.py +11 -5
- p115client/tool/download.py +354 -262
- p115client/tool/edit.py +27 -35
- p115client/tool/export_dir.py +24 -42
- p115client/tool/fs_files.py +13 -16
- p115client/tool/history.py +135 -11
- p115client/tool/iterdir.py +2129 -3006
- p115client/tool/life.py +7 -1
- p115client/tool/upload.py +28 -20
- p115client/tool/util.py +23 -20
- p115client/tool/xys.py +0 -1
- p115client/type.py +9 -2
- {p115client-0.0.5.12.3.dist-info → p115client-0.0.5.13.1.dist-info}/METADATA +5 -4
- p115client-0.0.5.13.1.dist-info/RECORD +28 -0
- p115client-0.0.5.12.3.dist-info/RECORD +0 -28
- {p115client-0.0.5.12.3.dist-info → p115client-0.0.5.13.1.dist-info}/LICENSE +0 -0
- {p115client-0.0.5.12.3.dist-info → p115client-0.0.5.13.1.dist-info}/WHEEL +0 -0
p115client/tool/edit.py
CHANGED
@@ -8,14 +8,14 @@ __all__ = [
|
|
8
8
|
]
|
9
9
|
__doc__ = "这个模块提供了一些和修改文件或目录信息有关的函数"
|
10
10
|
|
11
|
-
from collections.abc import AsyncIterable,
|
11
|
+
from collections.abc import AsyncIterable, Coroutine, Iterable
|
12
12
|
from functools import partial
|
13
|
-
from typing import
|
13
|
+
from typing import overload, Any, Literal
|
14
14
|
|
15
|
-
from
|
16
|
-
from
|
17
|
-
from iterutils import chunked, run_gen_step, foreach, through, async_through
|
15
|
+
from concurrenttools import conmap
|
16
|
+
from iterutils import chunked, map as do_map, run_gen_step, through
|
18
17
|
from p115client import check_response, P115Client
|
18
|
+
from p115pickcode import to_id
|
19
19
|
|
20
20
|
|
21
21
|
@overload
|
@@ -61,7 +61,7 @@ def update_abstract(
|
|
61
61
|
"""批量设置文件或目录
|
62
62
|
|
63
63
|
:param client: 115 客户端或 cookies
|
64
|
-
:param ids: 一组文件或目录的 id
|
64
|
+
:param ids: 一组文件或目录的 id 或 pickcode
|
65
65
|
:param method: 方法名
|
66
66
|
:param value: 要设置的值
|
67
67
|
:param batch_size: 批次大小,分批次,每次提交的 id 数
|
@@ -73,24 +73,17 @@ def update_abstract(
|
|
73
73
|
client = P115Client(client, check_for_relogin=True)
|
74
74
|
if max_workers is None or max_workers <= 0:
|
75
75
|
max_workers = 20 if async_ else None
|
76
|
+
ids = do_map(to_id, ids)
|
76
77
|
def gen_step():
|
77
78
|
setter = partial(getattr(client, method), async_=async_, **request_kwargs)
|
78
79
|
def call(batch, /):
|
79
80
|
return check_response(setter(batch, value))
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
max_workers=max_workers,
|
87
|
-
))
|
88
|
-
else:
|
89
|
-
through(threadpool_map(
|
90
|
-
call,
|
91
|
-
chunked(ids, batch_size),
|
92
|
-
max_workers=max_workers
|
93
|
-
))
|
81
|
+
yield through(conmap(
|
82
|
+
call,
|
83
|
+
chunked(ids, batch_size),
|
84
|
+
max_workers=max_workers,
|
85
|
+
async_=async_,
|
86
|
+
))
|
94
87
|
return run_gen_step(gen_step, async_)
|
95
88
|
|
96
89
|
|
@@ -611,28 +604,27 @@ def batch_unstar(
|
|
611
604
|
raise KeyError
|
612
605
|
def gen_step():
|
613
606
|
from .iterdir import _iter_fs_files
|
614
|
-
it = _iter_fs_files(
|
615
|
-
client,
|
616
|
-
payload={"cid": 0, "count_folders": 1, "cur": 0, "fc_mix": 0, "offset": 0, "show_dir": 1, "star": 1},
|
617
|
-
ensure_file=ensure_file,
|
618
|
-
app=app,
|
619
|
-
cooldown=0.5,
|
620
|
-
async_=async_,
|
621
|
-
**request_kwargs,
|
622
|
-
)
|
623
|
-
if async_:
|
624
|
-
ids: list[int] = yield to_list(get_id(info) async for info in cast(AsyncIterator[dict], it))
|
625
|
-
else:
|
626
|
-
ids = [get_id(info) for info in cast(Iterator[dict], it)]
|
627
607
|
yield update_star(
|
628
608
|
client,
|
629
|
-
|
609
|
+
do_map(get_id, _iter_fs_files(
|
610
|
+
client,
|
611
|
+
payload={
|
612
|
+
"cid": 0, "count_folders": 1, "cur": 0, "fc_mix": 0,
|
613
|
+
"offset": 0, "show_dir": 1, "star": 1
|
614
|
+
},
|
615
|
+
ensure_file=ensure_file,
|
616
|
+
app=app,
|
617
|
+
cooldown=0.5,
|
618
|
+
async_=async_,
|
619
|
+
**request_kwargs,
|
620
|
+
)),
|
630
621
|
star=False,
|
631
622
|
batch_size=batch_size,
|
632
623
|
max_workers=max_workers,
|
633
624
|
app=app,
|
634
|
-
async_=async_,
|
625
|
+
async_=async_,
|
635
626
|
**request_kwargs,
|
636
627
|
)
|
637
628
|
return run_gen_step(gen_step, async_)
|
638
629
|
|
630
|
+
# TODO: 上面这些,要支持 open 接口
|
p115client/tool/export_dir.py
CHANGED
@@ -3,13 +3,16 @@
|
|
3
3
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
5
|
__all__ = [
|
6
|
-
"parse_export_dir_as_dict_iter", "parse_export_dir_as_path_iter",
|
7
|
-
"
|
6
|
+
"parse_export_dir_as_dict_iter", "parse_export_dir_as_path_iter",
|
7
|
+
"parse_export_dir_as_patht_iter", "export_dir", "export_dir_result",
|
8
|
+
"export_dir_parse_iter",
|
8
9
|
]
|
9
10
|
__doc__ = "这个模块提供了一些和导出目录树有关的函数"
|
10
11
|
|
11
12
|
from asyncio import sleep as async_sleep
|
12
|
-
from collections.abc import
|
13
|
+
from collections.abc import (
|
14
|
+
AsyncIterable, AsyncIterator, Callable, Coroutine, Iterable, Iterator,
|
15
|
+
)
|
13
16
|
from functools import partial
|
14
17
|
from io import BufferedReader, TextIOWrapper
|
15
18
|
from itertools import count
|
@@ -20,8 +23,12 @@ from typing import cast, overload, Any, Final, IO, Literal
|
|
20
23
|
|
21
24
|
from asynctools import ensure_async, ensure_aiter
|
22
25
|
from filewrap import AsyncBufferedReader, AsyncTextIOWrapper
|
23
|
-
from iterutils import
|
26
|
+
from iterutils import (
|
27
|
+
as_gen_step, backgroud_loop, context, run_gen_step, run_gen_step_iter,
|
28
|
+
Yield, YieldFrom,
|
29
|
+
)
|
24
30
|
from p115client import check_response, P115Client
|
31
|
+
from p115pickcode import to_id, is_valid_pickcode
|
25
32
|
|
26
33
|
|
27
34
|
CRE_TREE_PREFIX_match: Final = re_compile(r"^(?:\| )+\|-(.*)").match
|
@@ -177,7 +184,7 @@ def parse_export_dir_as_path_iter(
|
|
177
184
|
if escape:
|
178
185
|
from posixpatht import escape
|
179
186
|
else:
|
180
|
-
from .
|
187
|
+
from .util import posix_escape_name as escape
|
181
188
|
escape = cast(None | Callable[[str], str], escape)
|
182
189
|
def gen_step():
|
183
190
|
it = ensure_aiter(file, threaded=True) if async_ else file
|
@@ -190,10 +197,12 @@ def parse_export_dir_as_path_iter(
|
|
190
197
|
root = root.removesuffix("\n")[3:]
|
191
198
|
if root == "根目录":
|
192
199
|
stack = [""]
|
200
|
+
root = "/"
|
193
201
|
else:
|
194
202
|
if escape is not None:
|
195
203
|
root = escape(root)
|
196
|
-
|
204
|
+
root = "/" + root
|
205
|
+
stack = [root]
|
197
206
|
push = stack.append
|
198
207
|
try:
|
199
208
|
depth = 0
|
@@ -208,7 +217,7 @@ def parse_export_dir_as_path_iter(
|
|
208
217
|
elif depth:
|
209
218
|
yield Yield(stack[depth])
|
210
219
|
else:
|
211
|
-
yield
|
220
|
+
yield Yield(root)
|
212
221
|
name = m[1]
|
213
222
|
depth = (len(line) - len(name)) // 2 - 1
|
214
223
|
if escape is not None:
|
@@ -354,8 +363,8 @@ def export_dir(
|
|
354
363
|
"""导出目录树
|
355
364
|
|
356
365
|
:param client: 115 客户端或 cookies
|
357
|
-
:param export_file_ids: 待导出的目录 id 或
|
358
|
-
:param target_pid: 导出到的目标目录 id 或
|
366
|
+
:param export_file_ids: 待导出的目录 id 或 pickcode
|
367
|
+
:param target_pid: 导出到的目标目录 id 或 pickcode
|
359
368
|
:param layer_limit: 层级深度,小于等于 0 时不限
|
360
369
|
:param async_: 是否异步
|
361
370
|
:param request_kwargs: 其它请求参数
|
@@ -366,41 +375,14 @@ def export_dir(
|
|
366
375
|
client = P115Client(client, check_for_relogin=True)
|
367
376
|
def gen_step():
|
368
377
|
nonlocal export_file_ids, target_pid
|
369
|
-
from .iterdir import get_id_to_path
|
370
378
|
if isinstance(export_file_ids, int):
|
371
379
|
pass
|
372
380
|
elif isinstance(export_file_ids, str):
|
373
|
-
|
374
|
-
|
375
|
-
export_file_ids,
|
376
|
-
ensure_file=False,
|
377
|
-
async_=async_,
|
378
|
-
**request_kwargs,
|
379
|
-
)
|
381
|
+
if "," not in export_file_ids:
|
382
|
+
export_file_ids = to_id(export_file_ids)
|
380
383
|
else:
|
381
|
-
|
382
|
-
|
383
|
-
for cid in export_file_ids:
|
384
|
-
if isinstance(cid, str):
|
385
|
-
cid = yield get_id_to_path(
|
386
|
-
client,
|
387
|
-
cid,
|
388
|
-
ensure_file=False,
|
389
|
-
async_=async_,
|
390
|
-
**request_kwargs,
|
391
|
-
)
|
392
|
-
add_cid(cast(int, cid))
|
393
|
-
if not cids:
|
394
|
-
raise ValueError("`export_file_ids` is empty")
|
395
|
-
export_file_ids = ",".join(map(str, cids))
|
396
|
-
if isinstance(target_pid, str):
|
397
|
-
target_pid = yield get_id_to_path(
|
398
|
-
client,
|
399
|
-
target_pid,
|
400
|
-
ensure_file=False,
|
401
|
-
async_=async_,
|
402
|
-
**request_kwargs,
|
403
|
-
)
|
384
|
+
export_file_ids = ",".join(str(to_id(eid)) for eid in export_file_ids)
|
385
|
+
target_pid = to_id(target_pid)
|
404
386
|
payload = {"file_ids": export_file_ids, "target": f"U_0_{target_pid}"}
|
405
387
|
if layer_limit > 0:
|
406
388
|
payload["layer_limit"] = layer_limit
|
@@ -544,9 +526,9 @@ def export_dir_parse_iter(
|
|
544
526
|
"""导出目录树到文件,读取文件并解析后返回迭代器,关闭后自动删除导出的文件
|
545
527
|
|
546
528
|
:param client: 115 客户端或 cookies
|
547
|
-
:param export_file_ids: 待导出的目录 id 或 路径(如果有多个,需传入可迭代对象)
|
529
|
+
:param export_file_ids: 待导出的目录 id、pickcode 或 路径(如果有多个,需传入可迭代对象)
|
548
530
|
:param export_id: 优先级高于 `export_file_ids`,之前提交的 `export_dir` 任务的 id,如果是 str,则视为导出的目录树文件的提取码(因此无需导出)
|
549
|
-
:param target_pid: 导出到的目标目录 id 或
|
531
|
+
:param target_pid: 导出到的目标目录 id 或 pickcode
|
550
532
|
:param layer_limit: 层级深度,小于等于 0 时不限
|
551
533
|
:param parse_iter: 解析打开的二进制文件,返回可迭代对象
|
552
534
|
:param delete: 最终删除目录树文件(如果 export_id 为 str(即提取码),则这个值不生效,必不删除)
|
p115client/tool/fs_files.py
CHANGED
@@ -115,20 +115,20 @@ def iter_fs_files(
|
|
115
115
|
"limit": first_page_size, "show_dir": 1, **payload,
|
116
116
|
}
|
117
117
|
cid = int(payload["cid"])
|
118
|
-
|
119
|
-
def get_files(payload: dict, /):
|
118
|
+
def gen_step():
|
120
119
|
nonlocal count
|
121
120
|
while True:
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
payload["limit"]
|
131
|
-
|
121
|
+
while True:
|
122
|
+
try:
|
123
|
+
resp = yield fs_files(payload, async_=async_)
|
124
|
+
check_response(resp)
|
125
|
+
except DataError:
|
126
|
+
if payload["limit"] <= 1150:
|
127
|
+
raise
|
128
|
+
payload["limit"] -= 1_000
|
129
|
+
if payload["limit"] < 1150:
|
130
|
+
payload["limit"] = 1150
|
131
|
+
continue
|
132
132
|
if cid and int(resp["path"][-1]["cid"]) != cid:
|
133
133
|
if count < 0:
|
134
134
|
raise NotADirectoryError(ENOTDIR, cid)
|
@@ -146,10 +146,7 @@ def iter_fs_files(
|
|
146
146
|
count = count_new
|
147
147
|
if callback is not None:
|
148
148
|
resp["callback"] = yield callback(resp)
|
149
|
-
|
150
|
-
def gen_step():
|
151
|
-
while True:
|
152
|
-
resp = yield get_files(payload)
|
149
|
+
break
|
153
150
|
payload["limit"] = page_size
|
154
151
|
yield Yield(resp)
|
155
152
|
payload["offset"] += len(resp["data"])
|
p115client/tool/history.py
CHANGED
@@ -2,26 +2,42 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
|
-
__all__ = [
|
5
|
+
__all__ = [
|
6
|
+
"HISTORY_NAME_TO_TYPE", "HISTORY_TYPE_TO_NAME",
|
7
|
+
"iter_history_once", "iter_history", "iter_history_list",
|
8
|
+
]
|
6
9
|
__doc__ = "这个模块提供了一些和 115 的历史记录有关的函数"
|
7
10
|
|
8
11
|
from asyncio import sleep as async_sleep
|
9
|
-
from collections.abc import AsyncIterator, Iterator
|
12
|
+
from collections.abc import AsyncIterator, Container, Iterator
|
10
13
|
from functools import partial
|
11
14
|
from itertools import cycle
|
12
15
|
from time import time, sleep
|
13
|
-
from typing import overload, Literal
|
16
|
+
from typing import overload, Final, Literal
|
14
17
|
|
15
18
|
from iterutils import run_gen_step_iter, with_iter_next, Yield
|
16
19
|
from p115client import check_response, P115Client
|
17
20
|
|
18
21
|
|
22
|
+
#: 115 生活操作事件名称到类型的映射
|
23
|
+
HISTORY_NAME_TO_TYPE: Final = {
|
24
|
+
"offline_download": 2,
|
25
|
+
"browse_video": 3,
|
26
|
+
"upload": 4,
|
27
|
+
"receive": 7,
|
28
|
+
"move": 8,
|
29
|
+
}
|
30
|
+
#: 115 生活操作事件类型到名称的映射
|
31
|
+
HISTORY_TYPE_TO_NAME: Final = {v: k for k, v in HISTORY_NAME_TO_TYPE.items()}
|
32
|
+
|
33
|
+
|
19
34
|
@overload
|
20
|
-
def
|
35
|
+
def iter_history_once(
|
21
36
|
client: str | P115Client,
|
22
37
|
from_time: int | float = 0,
|
23
38
|
from_id: int = 0,
|
24
39
|
type: int | str = 0,
|
40
|
+
ignore_types: None | Container[int] = None,
|
25
41
|
first_batch_size = 0,
|
26
42
|
app: str = "web",
|
27
43
|
cooldown: int | float = 0,
|
@@ -31,11 +47,12 @@ def iter_history_list_once(
|
|
31
47
|
) -> Iterator[dict]:
|
32
48
|
...
|
33
49
|
@overload
|
34
|
-
def
|
50
|
+
def iter_history_once(
|
35
51
|
client: str | P115Client,
|
36
52
|
from_time: int | float = 0,
|
37
53
|
from_id: int = 0,
|
38
54
|
type: int | str = 0,
|
55
|
+
ignore_types: None | Container[int] = None,
|
39
56
|
first_batch_size = 0,
|
40
57
|
app: str = "web",
|
41
58
|
cooldown: int | float = 0,
|
@@ -44,11 +61,12 @@ def iter_history_list_once(
|
|
44
61
|
**request_kwargs,
|
45
62
|
) -> AsyncIterator[dict]:
|
46
63
|
...
|
47
|
-
def
|
64
|
+
def iter_history_once(
|
48
65
|
client: str | P115Client,
|
49
66
|
from_time: int | float = 0,
|
50
67
|
from_id: int = 0,
|
51
68
|
type: int | str = 0,
|
69
|
+
ignore_types: None | Container[int] = None,
|
52
70
|
first_batch_size = 0,
|
53
71
|
app: str = "web",
|
54
72
|
cooldown: int | float = 0,
|
@@ -73,6 +91,7 @@ def iter_history_list_once(
|
|
73
91
|
- 接收: 7
|
74
92
|
- 移动: 8
|
75
93
|
|
94
|
+
:param ignore_types: 一组要被忽略的操作事件类型代码,仅当 `type` 为空时生效
|
76
95
|
:param first_batch_size: 首批的拉取数目
|
77
96
|
:param app: 使用某个 app (设备)的接口
|
78
97
|
:param cooldown: 冷却时间,大于 0 时,两次接口调用之间至少间隔这么多秒
|
@@ -105,7 +124,8 @@ def iter_history_list_once(
|
|
105
124
|
if from_id and event_id <= from_id or from_time and int(event["update_time"]) < from_time:
|
106
125
|
return
|
107
126
|
if event_id not in seen:
|
108
|
-
|
127
|
+
if type or not ignore_types or event["type"] not in ignore_types:
|
128
|
+
yield Yield(event)
|
109
129
|
seen_add(event_id)
|
110
130
|
offset += len(events)
|
111
131
|
if offset >= int(resp["data"]["total"]):
|
@@ -123,11 +143,12 @@ def iter_history_list_once(
|
|
123
143
|
|
124
144
|
|
125
145
|
@overload
|
126
|
-
def
|
146
|
+
def iter_history(
|
127
147
|
client: str | P115Client,
|
128
148
|
from_time: int | float = 0,
|
129
149
|
from_id: int = 0,
|
130
150
|
type: int | str = 0,
|
151
|
+
ignore_types: None | Container[int] = None,
|
131
152
|
app: str = "web",
|
132
153
|
cooldown: int | float = 0,
|
133
154
|
interval: int | float = 0,
|
@@ -137,11 +158,12 @@ def iter_history_list(
|
|
137
158
|
) -> Iterator[dict]:
|
138
159
|
...
|
139
160
|
@overload
|
140
|
-
def
|
161
|
+
def iter_history(
|
141
162
|
client: str | P115Client,
|
142
163
|
from_time: int | float = 0,
|
143
164
|
from_id: int = 0,
|
144
165
|
type: int | str = 0,
|
166
|
+
ignore_types: None | Container[int] = None,
|
145
167
|
app: str = "web",
|
146
168
|
cooldown: int | float = 0,
|
147
169
|
interval: int | float = 0,
|
@@ -150,11 +172,12 @@ def iter_history_list(
|
|
150
172
|
**request_kwargs,
|
151
173
|
) -> AsyncIterator[dict]:
|
152
174
|
...
|
153
|
-
def
|
175
|
+
def iter_history(
|
154
176
|
client: str | P115Client,
|
155
177
|
from_time: int | float = 0,
|
156
178
|
from_id: int = 0,
|
157
179
|
type: int | str = 0,
|
180
|
+
ignore_types: None | Container[int] = None,
|
158
181
|
app: str = "web",
|
159
182
|
cooldown: int | float = 0,
|
160
183
|
interval: int | float = 0,
|
@@ -179,6 +202,7 @@ def iter_history_list(
|
|
179
202
|
- 接收: 7
|
180
203
|
- 移动: 8
|
181
204
|
|
205
|
+
:param ignore_types: 一组要被忽略的操作事件类型代码,仅当 `type` 为空时生效
|
182
206
|
:param cooldown: 冷却时间,大于 0 时,两次接口调用之间至少间隔这么多秒
|
183
207
|
:param interval: 两个批量拉取之间的睡眠时间间隔,如果小于等于 0,则不睡眠
|
184
208
|
:param app: 使用某个 app (设备)的接口
|
@@ -202,7 +226,7 @@ def iter_history_list(
|
|
202
226
|
yield async_sleep(interval)
|
203
227
|
else:
|
204
228
|
sleep(interval)
|
205
|
-
with with_iter_next(
|
229
|
+
with with_iter_next(iter_history_once(
|
206
230
|
client,
|
207
231
|
from_time,
|
208
232
|
from_id,
|
@@ -219,6 +243,106 @@ def iter_history_list(
|
|
219
243
|
from_id = int(event["id"])
|
220
244
|
from_time = int(event["update_time"])
|
221
245
|
sub_first_loop = False
|
246
|
+
if not type and ignore_types and event["type"] in ignore_types:
|
247
|
+
continue
|
222
248
|
yield Yield(event)
|
223
249
|
return run_gen_step_iter(gen_step, async_)
|
224
250
|
|
251
|
+
|
252
|
+
@overload
|
253
|
+
def iter_history_list(
|
254
|
+
client: str | P115Client,
|
255
|
+
from_time: int | float = 0,
|
256
|
+
from_id: int = 0,
|
257
|
+
type: int | str = 0,
|
258
|
+
ignore_types: None | Container[int] = None,
|
259
|
+
app: str = "web",
|
260
|
+
cooldown: int | float = 0,
|
261
|
+
*,
|
262
|
+
async_: Literal[False] = False,
|
263
|
+
**request_kwargs,
|
264
|
+
) -> Iterator[dict]:
|
265
|
+
...
|
266
|
+
@overload
|
267
|
+
def iter_history_list(
|
268
|
+
client: str | P115Client,
|
269
|
+
from_time: int | float = 0,
|
270
|
+
from_id: int = 0,
|
271
|
+
type: int | str = 0,
|
272
|
+
ignore_types: None | Container[int] = None,
|
273
|
+
app: str = "web",
|
274
|
+
cooldown: int | float = 0,
|
275
|
+
*,
|
276
|
+
async_: Literal[True],
|
277
|
+
**request_kwargs,
|
278
|
+
) -> AsyncIterator[dict]:
|
279
|
+
...
|
280
|
+
def iter_history_list(
|
281
|
+
client: str | P115Client,
|
282
|
+
from_time: int | float = 0,
|
283
|
+
from_id: int = 0,
|
284
|
+
type: int | str = 0,
|
285
|
+
ignore_types: None | Container[int] = None,
|
286
|
+
app: str = "web",
|
287
|
+
cooldown: int | float = 0,
|
288
|
+
*,
|
289
|
+
async_: Literal[False, True] = False,
|
290
|
+
**request_kwargs,
|
291
|
+
) -> AsyncIterator[dict] | Iterator[dict]:
|
292
|
+
"""持续拉取 115 的历史记录
|
293
|
+
|
294
|
+
:param client: 115 客户端或 cookies
|
295
|
+
:param from_time: 开始时间(含),若为 0 则从当前时间开始,若小于 0 则从最早开始
|
296
|
+
:param from_id: 开始的事件 id (不含)
|
297
|
+
:param type: 拉取指定类型的历史记录(??表示还未搞清楚),多个用逗号 "," 隔开
|
298
|
+
|
299
|
+
- 全部: 0
|
300
|
+
- ??: 1
|
301
|
+
- 离线下载: 2
|
302
|
+
- 播放视频: 3
|
303
|
+
- 上传: 4
|
304
|
+
- ??: 5
|
305
|
+
- ??: 6
|
306
|
+
- 接收: 7
|
307
|
+
- 移动: 8
|
308
|
+
|
309
|
+
:param ignore_types: 一组要被忽略的操作事件类型代码,仅当 `type` 为空时生效
|
310
|
+
:param cooldown: 冷却时间,大于 0 时,两次接口调用之间至少间隔这么多秒
|
311
|
+
:param app: 使用某个 app (设备)的接口
|
312
|
+
:param async_: 是否异步
|
313
|
+
:param request_kwargs: 其它请求参数
|
314
|
+
|
315
|
+
:return: 迭代器,产生 115 的历史记录数据字典
|
316
|
+
"""
|
317
|
+
if isinstance(client, str):
|
318
|
+
client = P115Client(client, check_for_relogin=True)
|
319
|
+
def gen_step():
|
320
|
+
nonlocal from_time, from_id
|
321
|
+
if from_time == 0:
|
322
|
+
from_time = time()
|
323
|
+
while True:
|
324
|
+
ls: list[dict] = []
|
325
|
+
push = ls.append
|
326
|
+
with with_iter_next(iter_history_once(
|
327
|
+
client,
|
328
|
+
from_time,
|
329
|
+
from_id,
|
330
|
+
type=type,
|
331
|
+
app=app,
|
332
|
+
cooldown=cooldown,
|
333
|
+
async_=async_,
|
334
|
+
**request_kwargs,
|
335
|
+
)) as get_next:
|
336
|
+
first_loop = True
|
337
|
+
while True:
|
338
|
+
event = yield get_next()
|
339
|
+
if first_loop:
|
340
|
+
from_id = int(event["id"])
|
341
|
+
from_time = int(event["update_time"])
|
342
|
+
first_loop = False
|
343
|
+
if not type and ignore_types and event["type"] in ignore_types:
|
344
|
+
continue
|
345
|
+
push(event)
|
346
|
+
yield Yield(ls)
|
347
|
+
return run_gen_step_iter(gen_step, async_)
|
348
|
+
|