p115client 0.0.5.9.2__py3-none-any.whl → 0.0.5.10__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 +160 -75
- p115client/const.py +183 -1
- p115client/exception.py +42 -18
- p115client/tool/__init__.py +2 -0
- p115client/tool/attr.py +104 -0
- p115client/tool/download.py +7 -22
- p115client/tool/edit.py +1 -2
- p115client/tool/fs_files.py +4 -13
- p115client/tool/iterdir.py +56 -101
- p115client/tool/life.py +1 -1
- p115client/tool/pool.py +6 -29
- p115client/tool/request.py +1 -0
- p115client/tool/util.py +107 -0
- p115client/tool/xys.py +317 -50
- p115client/type.py +16 -1
- {p115client-0.0.5.9.2.dist-info → p115client-0.0.5.10.dist-info}/METADATA +3 -3
- p115client-0.0.5.10.dist-info/RECORD +26 -0
- p115client-0.0.5.9.2.dist-info/RECORD +0 -24
- {p115client-0.0.5.9.2.dist-info → p115client-0.0.5.10.dist-info}/LICENSE +0 -0
- {p115client-0.0.5.9.2.dist-info → p115client-0.0.5.10.dist-info}/WHEEL +0 -0
p115client/const.py
CHANGED
@@ -2,15 +2,25 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
|
-
|
5
|
+
__all__ = [
|
6
|
+
"AVAILABLE_APP_IDS", "AVAILABLE_APPS", "APP_TO_SSOENT",
|
7
|
+
"SSOENT_TO_APP", "CLIENT_API_MAP", "errno",
|
8
|
+
]
|
6
9
|
|
10
|
+
from enum import IntEnum
|
7
11
|
from typing import Final
|
8
12
|
|
13
|
+
|
14
|
+
#: 可用的 AppID 列表
|
15
|
+
AVAILABLE_APP_IDS = range(100195123, 100196837, 2)
|
16
|
+
|
17
|
+
|
9
18
|
#: 目前可用的登录设备
|
10
19
|
AVAILABLE_APPS: Final[tuple[str, ...]] = (
|
11
20
|
"web", "ios", "115ios", "android", "115android", "115ipad", "tv", "qandroid",
|
12
21
|
"windows", "mac", "linux", "wechatmini", "alipaymini", "harmony",
|
13
22
|
)
|
23
|
+
|
14
24
|
#: 目前已知的登录设备和对应的 ssoent
|
15
25
|
APP_TO_SSOENT: Final[dict[str, str]] = {
|
16
26
|
"web": "A1",
|
@@ -33,6 +43,7 @@ APP_TO_SSOENT: Final[dict[str, str]] = {
|
|
33
43
|
"alipaymini": "R2",
|
34
44
|
"harmony": "S1",
|
35
45
|
}
|
46
|
+
|
36
47
|
#: 目前已知的 ssoent 和对应的登录设备,一部分因为不知道具体的设备名,所以使用目前可用的设备名,作为临时代替
|
37
48
|
SSOENT_TO_APP: Final[dict[str, str]] = {
|
38
49
|
"A1": "web",
|
@@ -59,8 +70,10 @@ SSOENT_TO_APP: Final[dict[str, str]] = {
|
|
59
70
|
"R2": "alipaymini",
|
60
71
|
"S1": "harmony",
|
61
72
|
}
|
73
|
+
|
62
74
|
#: 所有已封装的 115 接口以及对应的方法名
|
63
75
|
CLIENT_API_MAP: Final[dict[str, str]] = {}
|
76
|
+
|
64
77
|
#: 文件的 class 属性对应的所属类型的整数代码
|
65
78
|
CLASS_TO_TYPE: Final[dict[str, int]] = {
|
66
79
|
"JG_DOC": 1,
|
@@ -79,6 +92,7 @@ CLASS_TO_TYPE: Final[dict[str, int]] = {
|
|
79
92
|
"JG_BOOK": 7,
|
80
93
|
"BOOK": 7
|
81
94
|
}
|
95
|
+
|
82
96
|
#: 文件后缀对应的所属类型的整数代码(尚需补充)
|
83
97
|
SUFFIX_TO_TYPE: Final[dict[str, int]] = {
|
84
98
|
".ass": 1,
|
@@ -203,3 +217,171 @@ SUFFIX_TO_TYPE: Final[dict[str, int]] = {
|
|
203
217
|
".mobi": 7,
|
204
218
|
".prc": 7,
|
205
219
|
}
|
220
|
+
|
221
|
+
#: OSError 的错误码的枚举,参考:https://docs.python.org/3/library/errno.html
|
222
|
+
class errno(IntEnum):
|
223
|
+
EPERM = 1
|
224
|
+
ENOENT = 2
|
225
|
+
ESRCH = 3
|
226
|
+
EINTR = 4
|
227
|
+
EIO = 5
|
228
|
+
ENXIO = 6
|
229
|
+
E2BIG = 7
|
230
|
+
ENOEXEC = 8
|
231
|
+
EBADF = 9
|
232
|
+
ECHILD = 10
|
233
|
+
EAGAIN = 11
|
234
|
+
ENOMEM = 12
|
235
|
+
EACCES = 13
|
236
|
+
EFAULT = 14
|
237
|
+
ENOTBLK = 15
|
238
|
+
EBUSY = 16
|
239
|
+
EEXIST = 17
|
240
|
+
EXDEV = 18
|
241
|
+
ENODEV = 19
|
242
|
+
ENOTDIR = 20
|
243
|
+
EISDIR = 21
|
244
|
+
EINVAL = 22
|
245
|
+
ENFILE = 23
|
246
|
+
EMFILE = 24
|
247
|
+
ENOTTY = 25
|
248
|
+
ETXTBSY = 26
|
249
|
+
EFBIG = 27
|
250
|
+
ENOSPC = 28
|
251
|
+
ESPIPE = 29
|
252
|
+
EROFS = 30
|
253
|
+
EMLINK = 31
|
254
|
+
EPIPE = 32
|
255
|
+
EDOM = 33
|
256
|
+
ERANGE = 34
|
257
|
+
EDEADLK = 35
|
258
|
+
ENAMETOOLONG = 36
|
259
|
+
ENOLCK = 37
|
260
|
+
ENOSYS = 38
|
261
|
+
ENOTEMPTY = 39
|
262
|
+
ELOOP = 40
|
263
|
+
EWOULDBLOCK = 41
|
264
|
+
ENOMSG = 42
|
265
|
+
EIDRM = 43
|
266
|
+
ECHRNG = 44
|
267
|
+
EL2NSYNC = 45
|
268
|
+
EL3HLT = 46
|
269
|
+
EL3RST = 47
|
270
|
+
ELNRNG = 48
|
271
|
+
EUNATCH = 49
|
272
|
+
ENOCSI = 50
|
273
|
+
EL2HLT = 51
|
274
|
+
EBADE = 52
|
275
|
+
EBADR = 53
|
276
|
+
EXFULL = 54
|
277
|
+
ENOANO = 55
|
278
|
+
EBADRQC = 56
|
279
|
+
EBADSLT = 57
|
280
|
+
EDEADLOCK = 58
|
281
|
+
EBFONT = 59
|
282
|
+
ENOSTR = 60
|
283
|
+
ENODATA = 61
|
284
|
+
ETIME = 62
|
285
|
+
ENOSR = 63
|
286
|
+
ENONET = 64
|
287
|
+
ENOPKG = 65
|
288
|
+
EREMOTE = 66
|
289
|
+
ENOLINK = 67
|
290
|
+
EADV = 68
|
291
|
+
ESRMNT = 69
|
292
|
+
ECOMM = 70
|
293
|
+
EPROTO = 71
|
294
|
+
EMULTIHOP = 72
|
295
|
+
EDOTDOT = 73
|
296
|
+
EBADMSG = 74
|
297
|
+
EOVERFLOW = 75
|
298
|
+
ENOTUNIQ = 76
|
299
|
+
EBADFD = 77
|
300
|
+
EREMCHG = 78
|
301
|
+
ELIBACC = 79
|
302
|
+
ELIBBAD = 80
|
303
|
+
ELIBSCN = 81
|
304
|
+
ELIBMAX = 82
|
305
|
+
ELIBEXEC = 83
|
306
|
+
EILSEQ = 84
|
307
|
+
ERESTART = 85
|
308
|
+
ESTRPIPE = 86
|
309
|
+
EUSERS = 87
|
310
|
+
ENOTSOCK = 88
|
311
|
+
EDESTADDRREQ = 89
|
312
|
+
EMSGSIZE = 90
|
313
|
+
EPROTOTYPE = 91
|
314
|
+
ENOPROTOOPT = 92
|
315
|
+
EPROTONOSUPPORT = 93
|
316
|
+
ESOCKTNOSUPPORT = 94
|
317
|
+
EOPNOTSUPP = 95
|
318
|
+
ENOTSUP = 96
|
319
|
+
EPFNOSUPPORT = 97
|
320
|
+
EAFNOSUPPORT = 98
|
321
|
+
EADDRINUSE = 99
|
322
|
+
EADDRNOTAVAIL = 100
|
323
|
+
ENETDOWN = 101
|
324
|
+
ENETUNREACH = 102
|
325
|
+
ENETRESET = 103
|
326
|
+
ECONNABORTED = 104
|
327
|
+
ECONNRESET = 105
|
328
|
+
ENOBUFS = 106
|
329
|
+
EISCONN = 107
|
330
|
+
ENOTCONN = 108
|
331
|
+
ESHUTDOWN = 109
|
332
|
+
ETOOMANYREFS = 110
|
333
|
+
ETIMEDOUT = 111
|
334
|
+
ECONNREFUSED = 112
|
335
|
+
EHOSTDOWN = 113
|
336
|
+
EHOSTUNREACH = 114
|
337
|
+
EALREADY = 115
|
338
|
+
EINPROGRESS = 116
|
339
|
+
ESTALE = 117
|
340
|
+
EUCLEAN = 118
|
341
|
+
ENOTNAM = 119
|
342
|
+
ENAVAIL = 120
|
343
|
+
EISNAM = 121
|
344
|
+
EREMOTEIO = 122
|
345
|
+
EDQUOT = 123
|
346
|
+
EQFULL = 124
|
347
|
+
ENOMEDIUM = 125
|
348
|
+
EMEDIUMTYPE = 126
|
349
|
+
ENOKEY = 127
|
350
|
+
EKEYEXPIRED = 128
|
351
|
+
EKEYREVOKED = 129
|
352
|
+
EKEYREJECTED = 130
|
353
|
+
ERFKILL = 131
|
354
|
+
ELOCKUNMAPPED = 132
|
355
|
+
ENOTACTIVE = 133
|
356
|
+
EAUTH = 134
|
357
|
+
EBADARCH = 135
|
358
|
+
EBADEXEC = 136
|
359
|
+
EBADMACHO = 137
|
360
|
+
EDEVERR = 138
|
361
|
+
EFTYPE = 139
|
362
|
+
ENEEDAUTH = 140
|
363
|
+
ENOATTR = 141
|
364
|
+
ENOPOLICY = 142
|
365
|
+
EPROCLIM = 143
|
366
|
+
EPROCUNAVAIL = 144
|
367
|
+
EPROGMISMATCH = 145
|
368
|
+
EPROGUNAVAIL = 146
|
369
|
+
EPWROFF = 147
|
370
|
+
EBADRPC = 148
|
371
|
+
ERPCMISMATCH = 149
|
372
|
+
ESHLIBVERS = 150
|
373
|
+
ENOTCAPABLE = 151
|
374
|
+
ECANCELED = 152
|
375
|
+
EOWNERDEAD = 153
|
376
|
+
ENOTRECOVERABLE = 154
|
377
|
+
|
378
|
+
def of(key, /):
|
379
|
+
if isinstance(key, errno):
|
380
|
+
return key
|
381
|
+
if isinstance(key, int):
|
382
|
+
return errno(key)
|
383
|
+
try:
|
384
|
+
return errno[key]
|
385
|
+
except KeyError as e:
|
386
|
+
raise ValueError(key) from e
|
387
|
+
|
p115client/exception.py
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
__all__ = [
|
5
5
|
"P115Warning", "P115OSError", "AuthenticationError", "BusyOSError", "DataError",
|
6
6
|
"LoginError", "MultipartUploadAbort", "NotSupportedError", "OperationalError",
|
7
|
+
"P115FileExistsError", "P115FileNotFoundError", "P115IsADirectoryError",
|
8
|
+
"P115NotADirectoryError", "P115PermissionError", "P115TimeoutError",
|
7
9
|
]
|
8
10
|
|
9
11
|
import warnings
|
@@ -15,44 +17,36 @@ from functools import cached_property
|
|
15
17
|
from .type import MultipartResumeData
|
16
18
|
|
17
19
|
|
20
|
+
warnings.filterwarnings("always", category=UserWarning)
|
21
|
+
setattr(warnings, "formatwarning", lambda message, category, filename, lineno, line=None, _getid=count(1).__next__:
|
22
|
+
f"\r\x1b[K\x1b[1;31;43m{category.__qualname__}\x1b[0m(\x1b[32m{_getid()}\x1b[0m) @ \x1b[3;4;34m{filename}\x1b[0m:\x1b[36m{lineno}\x1b[0m \x1b[5;31m➜\x1b[0m \x1b[1m{message}\x1b[0m\n"
|
23
|
+
)
|
24
|
+
|
18
25
|
class P115Warning(UserWarning):
|
19
26
|
"""本模块的最基础警示类
|
20
27
|
"""
|
21
28
|
|
22
29
|
|
23
|
-
_count = count(1).__next__
|
24
|
-
warnings.filterwarnings("always", category=UserWarning)
|
25
|
-
warnings.formatwarning = lambda message, category, filename, lineno, line=None: f"\r\x1b[K\x1b[1;31;43m{category.__qualname__}\x1b[0m(\x1b[32m{_count()}\x1b[0m) @ \x1b[3;4;34m{filename}\x1b[0m:\x1b[36m{lineno}\x1b[0m \x1b[5;31m➜\x1b[0m \x1b[1m{message}\x1b[0m\n"
|
26
|
-
|
27
|
-
|
28
30
|
class P115OSError(OSError):
|
29
31
|
"""本模块的最基础异常类
|
30
32
|
"""
|
31
|
-
def __init__(self, /, *args):
|
32
|
-
super().__init__(*args)
|
33
|
-
|
34
33
|
def __getattr__(self, attr, /):
|
35
|
-
message = self.message
|
36
34
|
try:
|
37
|
-
|
38
|
-
return message[attr]
|
35
|
+
return self[attr]
|
39
36
|
except KeyError as e:
|
40
37
|
raise AttributeError(attr) from e
|
41
|
-
raise AttributeError(attr)
|
42
38
|
|
43
39
|
def __getitem__(self, key, /):
|
44
40
|
message = self.message
|
45
41
|
if isinstance(message, Mapping):
|
46
42
|
return message[key]
|
47
|
-
|
43
|
+
raise KeyError(key)
|
48
44
|
|
49
45
|
@cached_property
|
50
46
|
def message(self, /):
|
51
|
-
args
|
52
|
-
|
53
|
-
if not isinstance(args[0], int):
|
47
|
+
if args := self.args:
|
48
|
+
if len(args) >= 2 and isinstance(args[0], int):
|
54
49
|
return args[1]
|
55
|
-
if args:
|
56
50
|
return args[0]
|
57
51
|
|
58
52
|
|
@@ -88,7 +82,7 @@ class MultipartUploadAbort(P115OSError):
|
|
88
82
|
|
89
83
|
|
90
84
|
class NotSupportedError(P115OSError):
|
91
|
-
"""
|
85
|
+
"""当调用不存在的接口或者接口不支持此操作时抛出
|
92
86
|
"""
|
93
87
|
|
94
88
|
|
@@ -96,3 +90,33 @@ class OperationalError(P115OSError):
|
|
96
90
|
"""当接口使用方法错误时抛出,例如参数错误、空间不足、超出允许数量范围等
|
97
91
|
"""
|
98
92
|
|
93
|
+
|
94
|
+
class P115FileExistsError(P115OSError, FileExistsError):
|
95
|
+
"""扩展 FileExistsError,同时是 P115OSError 的子类
|
96
|
+
"""
|
97
|
+
|
98
|
+
|
99
|
+
class P115FileNotFoundError(P115OSError, FileNotFoundError):
|
100
|
+
"""扩展 FileNotFoundError,同时是 P115OSError 的子类
|
101
|
+
"""
|
102
|
+
|
103
|
+
|
104
|
+
class P115IsADirectoryError(P115OSError, IsADirectoryError):
|
105
|
+
"""扩展 IsADirectoryError,同时是 P115OSError 的子类
|
106
|
+
"""
|
107
|
+
|
108
|
+
|
109
|
+
class P115NotADirectoryError(P115OSError, NotADirectoryError):
|
110
|
+
"""扩展 NotADirectoryError,同时是 P115OSError 的子类
|
111
|
+
"""
|
112
|
+
|
113
|
+
|
114
|
+
class P115PermissionError(P115OSError, PermissionError):
|
115
|
+
"""扩展 PermissionError,同时是 P115OSError 的子类
|
116
|
+
"""
|
117
|
+
|
118
|
+
|
119
|
+
class P115TimeoutError(P115OSError, TimeoutError):
|
120
|
+
"""扩展 TimeoutError,同时是 P115OSError 的子类
|
121
|
+
"""
|
122
|
+
|
p115client/tool/__init__.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
5
|
|
6
|
+
from .attr import *
|
6
7
|
from .download import *
|
7
8
|
from .edit import *
|
8
9
|
from .export_dir import *
|
@@ -13,4 +14,5 @@ from .life import *
|
|
13
14
|
from .pool import *
|
14
15
|
from .request import *
|
15
16
|
from .upload import *
|
17
|
+
from .util import *
|
16
18
|
from .xys import *
|
p115client/tool/attr.py
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
|
+
__all__ = ["get_attr", "type_of_attr"]
|
6
|
+
__doc__ = "这个模块提供了一些和文件或目录信息有关的函数"
|
7
|
+
|
8
|
+
from collections.abc import Mapping
|
9
|
+
from typing import overload, Literal
|
10
|
+
|
11
|
+
from iterutils import run_gen_step
|
12
|
+
from p115client import check_response, normalize_attr_web, P115Client
|
13
|
+
from p115client.const import CLASS_TO_TYPE, SUFFIX_TO_TYPE
|
14
|
+
from posixpatht import splitext
|
15
|
+
|
16
|
+
|
17
|
+
@overload
|
18
|
+
def get_attr(
|
19
|
+
client: str | P115Client,
|
20
|
+
id: int,
|
21
|
+
skim: bool = False,
|
22
|
+
*,
|
23
|
+
async_: Literal[False] = False,
|
24
|
+
**request_kwargs,
|
25
|
+
) -> dict:
|
26
|
+
...
|
27
|
+
@overload
|
28
|
+
def get_attr(
|
29
|
+
client: str | P115Client,
|
30
|
+
id: int,
|
31
|
+
skim: bool = False,
|
32
|
+
*,
|
33
|
+
async_: Literal[True],
|
34
|
+
**request_kwargs,
|
35
|
+
) -> dict:
|
36
|
+
...
|
37
|
+
def get_attr(
|
38
|
+
client: str | P115Client,
|
39
|
+
id: int,
|
40
|
+
skim: bool = False,
|
41
|
+
*,
|
42
|
+
async_: Literal[False, True] = False,
|
43
|
+
**request_kwargs,
|
44
|
+
) -> dict:
|
45
|
+
"""获取文件或目录的信息
|
46
|
+
|
47
|
+
:param client: 115 客户端或 cookies
|
48
|
+
:param id: 文件或目录的 id
|
49
|
+
:param skim: 是否获取简要信息(可避免风控)
|
50
|
+
:param async_: 是否异步
|
51
|
+
:param request_kwargs: 其它请求参数
|
52
|
+
|
53
|
+
:return: 文件或目录的信息
|
54
|
+
"""
|
55
|
+
if isinstance(client, str):
|
56
|
+
client = P115Client(client, check_for_relogin=True)
|
57
|
+
def gen_step():
|
58
|
+
if skim:
|
59
|
+
from dictattr import AttrDict
|
60
|
+
resp = yield client.fs_file_skim(id, async_=async_, **request_kwargs)
|
61
|
+
check_response(resp)
|
62
|
+
info = resp["data"][0]
|
63
|
+
return AttrDict(
|
64
|
+
id=int(info["file_id"]),
|
65
|
+
name=info["file_name"],
|
66
|
+
pickcode=info["pick_code"],
|
67
|
+
sha1=info["sha1"],
|
68
|
+
size=int(info["file_size"]),
|
69
|
+
)
|
70
|
+
else:
|
71
|
+
resp = yield client.fs_file(id, async_=async_, **request_kwargs)
|
72
|
+
check_response(resp)
|
73
|
+
return normalize_attr_web(resp["data"][0])
|
74
|
+
return run_gen_step(gen_step, async_=async_)
|
75
|
+
|
76
|
+
|
77
|
+
def type_of_attr(attr: Mapping, /) -> int:
|
78
|
+
"""推断文件信息所属类型(试验版,未必准确)
|
79
|
+
|
80
|
+
:param attr: 文件信息
|
81
|
+
|
82
|
+
:return: 返回类型代码
|
83
|
+
|
84
|
+
- 0: 目录
|
85
|
+
- 1: 文档
|
86
|
+
- 2: 图片
|
87
|
+
- 3: 音频
|
88
|
+
- 4: 视频
|
89
|
+
- 5: 压缩包
|
90
|
+
- 6: 应用
|
91
|
+
- 7: 书籍
|
92
|
+
- 99: 其它文件
|
93
|
+
"""
|
94
|
+
if attr.get("is_dir") or attr.get("is_directory"):
|
95
|
+
return 0
|
96
|
+
type: None | int
|
97
|
+
if type := CLASS_TO_TYPE.get(attr.get("class", "")):
|
98
|
+
return type
|
99
|
+
if type := SUFFIX_TO_TYPE.get(splitext(attr["name"])[1].lower()):
|
100
|
+
return type
|
101
|
+
if attr.get("is_video") or "defination" in attr:
|
102
|
+
return 4
|
103
|
+
return 99
|
104
|
+
|
p115client/tool/download.py
CHANGED
@@ -3,58 +3,43 @@
|
|
3
3
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
5
5
|
__all__ = [
|
6
|
-
"
|
6
|
+
"batch_get_url", "iter_url_batches", "iter_files_with_url",
|
7
7
|
"iter_images_with_url", "iter_subtitles_with_url", "iter_subtitle_batches", "make_strm",
|
8
8
|
"iter_download_nodes", "iter_download_files", "get_remaining_open_count",
|
9
9
|
]
|
10
10
|
__doc__ = "这个模块提供了一些和下载有关的函数"
|
11
11
|
|
12
|
-
from asyncio import create_task, to_thread, Queue as AsyncQueue,
|
13
|
-
from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator
|
12
|
+
from asyncio import create_task, to_thread, Queue as AsyncQueue, TaskGroup
|
13
|
+
from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator
|
14
14
|
from concurrent.futures import ThreadPoolExecutor
|
15
|
-
from errno import
|
15
|
+
from errno import ENOTDIR
|
16
16
|
from functools import partial
|
17
17
|
from glob import iglob
|
18
|
-
from inspect import isawaitable
|
19
18
|
from itertools import chain, count, cycle, islice
|
20
|
-
from mimetypes import guess_type
|
21
19
|
from os import fsdecode, makedirs, remove, PathLike
|
22
20
|
from os.path import abspath, dirname, join as joinpath, normpath, splitext
|
23
21
|
from queue import SimpleQueue
|
24
22
|
from shutil import rmtree
|
25
23
|
from threading import Lock
|
26
24
|
from time import time
|
27
|
-
from typing import cast, overload, Any,
|
25
|
+
from typing import cast, overload, Any, Literal
|
28
26
|
from types import EllipsisType
|
29
|
-
from urllib.parse import quote, urlsplit
|
30
27
|
from urllib.request import urlopen, Request
|
31
28
|
from uuid import uuid4
|
32
29
|
from warnings import warn
|
33
30
|
|
34
31
|
from asynctools import async_chain_from_iterable
|
35
|
-
from concurrenttools import
|
32
|
+
from concurrenttools import run_as_thread, thread_batch, async_batch
|
36
33
|
from encode_uri import encode_uri_component_loose
|
37
34
|
from iterutils import chunked, run_gen_step, run_gen_step_iter, with_iter_next, Yield, YieldFrom
|
38
35
|
from p115client import check_response, normalize_attr, normalize_attr_simple, P115Client, P115URL
|
39
36
|
from p115client.exception import P115Warning
|
40
37
|
|
41
|
-
from .export_dir import export_dir_parse_iter
|
42
38
|
from .iterdir import (
|
43
39
|
get_path_to_cid, iterdir, iter_files, iter_files_raw, iter_files_with_path,
|
44
40
|
unescape_115_charref, posix_escape_name, DirNode, ID_TO_DIRNODE_CACHE,
|
45
41
|
)
|
46
|
-
|
47
|
-
|
48
|
-
def reduce_image_url_layers(url: str, /, size: str | int = "") -> str:
|
49
|
-
"""从图片的缩略图链接中提取信息,以减少一次 302 访问
|
50
|
-
"""
|
51
|
-
if not url.startswith(("http://thumb.115.com/", "https://thumb.115.com/")):
|
52
|
-
return url
|
53
|
-
urlp = urlsplit(url)
|
54
|
-
sha1, _, size0 = urlp.path.rsplit("/")[-1].partition("_")
|
55
|
-
if size == "":
|
56
|
-
size = size0 or "0"
|
57
|
-
return f"https://imgjump.115.com/?sha1={sha1}&{urlp.query}&size={size}"
|
42
|
+
from .util import reduce_image_url_layers
|
58
43
|
|
59
44
|
|
60
45
|
@overload
|
p115client/tool/edit.py
CHANGED
@@ -8,9 +8,8 @@ __all__ = [
|
|
8
8
|
]
|
9
9
|
__doc__ = "这个模块提供了一些和修改文件或目录信息有关的函数"
|
10
10
|
|
11
|
-
from collections.abc import AsyncIterable, AsyncIterator, Coroutine, Iterable, Iterator
|
11
|
+
from collections.abc import AsyncIterable, AsyncIterator, Coroutine, Iterable, Iterator
|
12
12
|
from functools import partial
|
13
|
-
from itertools import batched, pairwise
|
14
13
|
from typing import cast, overload, Any, Literal
|
15
14
|
|
16
15
|
from asynctools import to_list
|
p115client/tool/fs_files.py
CHANGED
@@ -15,7 +15,7 @@ from functools import partial
|
|
15
15
|
from inspect import isawaitable
|
16
16
|
from itertools import cycle
|
17
17
|
from time import time
|
18
|
-
from typing import
|
18
|
+
from typing import overload, Any, Final, Literal
|
19
19
|
from warnings import warn
|
20
20
|
|
21
21
|
from iterutils import run_gen_step, run_gen_step_iter, Yield
|
@@ -23,23 +23,13 @@ from p115client import check_response, P115Client, P115OpenClient
|
|
23
23
|
from p115client.client import get_status_code
|
24
24
|
from p115client.exception import BusyOSError, DataError, P115Warning
|
25
25
|
|
26
|
+
from .util import is_timeouterror
|
27
|
+
|
26
28
|
|
27
29
|
get_webapi_origin: Final = cycle(("http://webapi.115.com", "https://webapi.115.com")).__next__
|
28
30
|
get_proapi_origin: Final = cycle(("http://proapi.115.com", "https://proapi.115.com")).__next__
|
29
31
|
|
30
32
|
|
31
|
-
def is_timeouterror(exc: BaseException, /) -> bool:
|
32
|
-
"""通过名字来判断一个异常是不是 Timeout
|
33
|
-
"""
|
34
|
-
exctype = type(exc)
|
35
|
-
for exctype in exctype.mro():
|
36
|
-
if exctype is Exception:
|
37
|
-
break
|
38
|
-
if "Timeout" in exctype.__name__:
|
39
|
-
return True
|
40
|
-
return False
|
41
|
-
|
42
|
-
|
43
33
|
@overload
|
44
34
|
def iter_fs_files(
|
45
35
|
client: str | P115Client | P115OpenClient,
|
@@ -403,4 +393,5 @@ async def iter_fs_files_asynchronized(
|
|
403
393
|
t.cancel()
|
404
394
|
await tg.__aexit__(None, None, None)
|
405
395
|
|
396
|
+
|
406
397
|
# TODO: 以上的数据获取方式某种程度上应该是通用的,只要是涉及到 offset 和 count,因此可以总结出一个更抽象的函数
|