p115client 0.0.5.9.3__tar.gz → 0.0.5.10.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.9.3 → p115client-0.0.5.10.1}/PKG-INFO +4 -4
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/client.py +180 -94
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/const.py +190 -1
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/exception.py +42 -18
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/__init__.py +2 -0
- p115client-0.0.5.10.1/p115client/tool/attr.py +104 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/download.py +7 -22
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/edit.py +1 -2
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/fs_files.py +4 -13
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/iterdir.py +56 -101
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/life.py +1 -1
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/pool.py +6 -29
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/request.py +1 -0
- p115client-0.0.5.10.1/p115client/tool/util.py +107 -0
- p115client-0.0.5.10.1/p115client/tool/xys.py +392 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/type.py +16 -1
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/pyproject.toml +2 -2
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/readme.md +2 -2
- p115client-0.0.5.9.3/p115client/tool/xys.py +0 -125
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/LICENSE +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/__init__.py +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/_upload.py +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/py.typed +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/export_dir.py +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/history.py +0 -0
- {p115client-0.0.5.9.3 → p115client-0.0.5.10.1}/p115client/tool/upload.py +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.10.1
|
4
4
|
Summary: Python 115 webdisk client.
|
5
5
|
Home-page: https://github.com/ChenyangGao/p115client
|
6
6
|
License: MIT
|
@@ -40,7 +40,7 @@ Requires-Dist: python-filewrap (>=0.2.8)
|
|
40
40
|
Requires-Dist: python-hashtools (>=0.0.3.3)
|
41
41
|
Requires-Dist: python-http_request (>=0.0.6)
|
42
42
|
Requires-Dist: python-httpfile (>=0.0.5.2)
|
43
|
-
Requires-Dist: python-iterutils (>=0.1.
|
43
|
+
Requires-Dist: python-iterutils (>=0.1.11)
|
44
44
|
Requires-Dist: python-property (>=0.0.3)
|
45
45
|
Requires-Dist: python-startfile (>=0.0.2)
|
46
46
|
Requires-Dist: python-undefined (>=0.0.3)
|
@@ -108,7 +108,7 @@ client = P115Client(Path("~/115-cookies.txt").expanduser(), check_for_relogin=Tr
|
|
108
108
|
|
109
109
|
如果你有一个申请通过的开放接口的应用,则可以创建开放接口的客户端实例
|
110
110
|
|
111
|
-
你可以直接从一个 `P115Client`
|
111
|
+
你可以直接从一个 `P115Client` 实例拿到授权(自动扫码登录并授权),如果不提供 `app_id`,则使用默认值
|
112
112
|
|
113
113
|
```python
|
114
114
|
app_id = <开放接口应用的 AppID>
|
@@ -143,7 +143,7 @@ from p115client import P115Client, P115OpenClient
|
|
143
143
|
from pathlib import Path
|
144
144
|
|
145
145
|
client = P115Client(Path("~/115-cookies.txt").expanduser(), check_for_relogin=True)
|
146
|
-
client_open = client.login_another_open(
|
146
|
+
client_open = client.login_another_open()
|
147
147
|
```
|
148
148
|
|
149
149
|
### 2. 接口调用
|
@@ -16,23 +16,20 @@ from collections.abc import (
|
|
16
16
|
ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence,
|
17
17
|
)
|
18
18
|
from datetime import date, datetime, timedelta
|
19
|
-
from errno import EBUSY, EEXIST, EFBIG, EINVAL, EIO, EISDIR, ENODATA, ENOENT, ENOSPC, ENOSYS, ENOTSUP
|
20
19
|
from functools import partial
|
21
20
|
from hashlib import md5, sha1
|
22
21
|
from http.cookiejar import Cookie, CookieJar
|
23
22
|
from http.cookies import Morsel
|
24
23
|
from inspect import isawaitable
|
25
|
-
from itertools import count, cycle,
|
24
|
+
from itertools import count, cycle, product, repeat
|
26
25
|
from math import nan
|
27
26
|
from operator import itemgetter
|
28
|
-
from os import fsdecode, fstat, isatty,
|
27
|
+
from os import fsdecode, fstat, isatty, PathLike, path as ospath
|
29
28
|
from pathlib import Path, PurePath
|
30
29
|
from platform import system
|
31
30
|
from posixpath import splitext
|
32
31
|
from re import compile as re_compile, MULTILINE
|
33
32
|
from string import digits
|
34
|
-
from sys import exc_info
|
35
|
-
from _thread import start_new_thread
|
36
33
|
from tempfile import TemporaryFile
|
37
34
|
from threading import Lock
|
38
35
|
from time import time
|
@@ -57,17 +54,20 @@ from http_response import get_total_length
|
|
57
54
|
from httpfile import HTTPFileReader, AsyncHTTPFileReader
|
58
55
|
from iterutils import run_gen_step
|
59
56
|
from orjson import dumps, loads
|
60
|
-
from p115cipher.fast import
|
57
|
+
from p115cipher.fast import (
|
58
|
+
rsa_encode, rsa_decode, ecdh_encode_token, ecdh_aes_encode, ecdh_aes_decode, make_upload_payload,
|
59
|
+
)
|
61
60
|
from property import locked_cacheproperty
|
62
61
|
from re import compile as re_compile
|
63
62
|
from startfile import startfile, startfile_async # type: ignore
|
64
63
|
from undefined import undefined
|
65
64
|
from yarl import URL
|
66
65
|
|
67
|
-
from .const import CLASS_TO_TYPE, CLIENT_API_MAP, SSOENT_TO_APP, SUFFIX_TO_TYPE
|
66
|
+
from .const import CLASS_TO_TYPE, CLIENT_API_MAP, SSOENT_TO_APP, SUFFIX_TO_TYPE, errno
|
68
67
|
from .exception import (
|
69
68
|
AuthenticationError, BusyOSError, DataError, LoginError, NotSupportedError,
|
70
|
-
P115OSError, OperationalError, P115Warning,
|
69
|
+
P115OSError, OperationalError, P115Warning, P115FileExistsError,
|
70
|
+
P115FileNotFoundError, P115IsADirectoryError,
|
71
71
|
)
|
72
72
|
from .type import RequestKeywords, MultipartResumeData, P115Cookies, P115URL
|
73
73
|
from ._upload import buffer_length, make_dataiter, oss_upload, oss_multipart_upload
|
@@ -229,7 +229,7 @@ def json_loads(content: Buffer, /):
|
|
229
229
|
except Exception as e:
|
230
230
|
if isinstance(content, memoryview):
|
231
231
|
content = content.tobytes()
|
232
|
-
raise DataError(ENODATA, content) from e
|
232
|
+
raise DataError(errno.ENODATA, content) from e
|
233
233
|
|
234
234
|
|
235
235
|
def default_parse(resp, content: Buffer, /):
|
@@ -350,7 +350,7 @@ def check_response(resp: dict | Awaitable[dict], /) -> dict | Coroutine[Any, Any
|
|
350
350
|
"""
|
351
351
|
def check(resp, /) -> dict:
|
352
352
|
if not isinstance(resp, dict):
|
353
|
-
raise P115OSError(EIO, resp)
|
353
|
+
raise P115OSError(errno.EIO, resp)
|
354
354
|
if resp.get("state", True):
|
355
355
|
return resp
|
356
356
|
if code := get_first(resp, "errno", "errNo", "errcode", "errCode", "code"):
|
@@ -360,121 +360,206 @@ def check_response(resp: dict | Awaitable[dict], /) -> dict | Coroutine[Any, Any
|
|
360
360
|
match code:
|
361
361
|
# {"state": false, "errno": 99, "error": "请重新登录"}
|
362
362
|
case 99:
|
363
|
-
raise LoginError(
|
363
|
+
raise LoginError(errno.EAUTH, resp)
|
364
364
|
# {"state": false, "errno": 911, "error": "请验证账号"}
|
365
365
|
case 911:
|
366
|
-
raise AuthenticationError(
|
366
|
+
raise AuthenticationError(errno.EAUTH, resp)
|
367
367
|
# {"state": false, "errno": 20001, "error": "目录名称不能为空"}
|
368
368
|
case 20001:
|
369
|
-
raise OperationalError(EINVAL, resp)
|
369
|
+
raise OperationalError(errno.EINVAL, resp)
|
370
370
|
# {"state": false, "errno": 20004, "error": "该目录名称已存在。"}
|
371
371
|
case 20004:
|
372
|
-
raise
|
372
|
+
raise P115FileExistsError(errno.EEXIST, resp)
|
373
373
|
# {"state": false, "errno": 20009, "error": "父目录不存在。"}
|
374
374
|
case 20009:
|
375
|
-
raise
|
375
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
376
376
|
# {"state": false, "errno": 20018, "error": "文件不存在或已删除。"}
|
377
377
|
# {"state": false, "errno": 50015, "error": "文件不存在或已删除。"}
|
378
378
|
# {"state": false, "errno": 90008, "error": "文件(夹)不存在或已经删除。"}
|
379
379
|
# {"state": false, "errno": 430004, "error": "文件(夹)不存在或已删除。"}
|
380
380
|
case 20018 | 50015 | 90008 | 430004:
|
381
|
-
raise
|
381
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
382
382
|
# {"state": false, "errno": 20020, "error": "后缀名不正确,请重新输入"}
|
383
|
-
case 20020:
|
384
|
-
raise OperationalError(ENOTSUP, resp)
|
385
383
|
# {"state": false, "errno": 20021, "error": "后缀名不正确,请重新输入"}
|
386
|
-
case 20021:
|
387
|
-
raise OperationalError(
|
384
|
+
case 20020 | 20021:
|
385
|
+
raise OperationalError(errno.EINVAL, resp)
|
388
386
|
# {"state": false, "errno": 31001, "error": "所预览的文件不存在。"}
|
389
387
|
case 31001:
|
390
|
-
raise
|
388
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
391
389
|
# {"state": false, "errno": 31004, "error": "文档未上传完整,请上传完成后再进行查看。"}
|
392
390
|
case 31004:
|
393
|
-
raise
|
391
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
394
392
|
# {"state": false, "errno": 50003, "error": "很抱歉,该文件提取码不存在。"}
|
395
393
|
case 50003:
|
396
|
-
raise
|
394
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
397
395
|
# {"state": false, "errno": 91002, "error": "不能将文件复制到自身或其子目录下。"}
|
398
396
|
case 91002:
|
399
|
-
raise NotSupportedError(ENOTSUP, resp)
|
397
|
+
raise NotSupportedError(errno.ENOTSUP, resp)
|
400
398
|
# {"state": false, "errno": 91004, "error": "操作的文件(夹)数量超过5万个"}
|
401
399
|
case 91004:
|
402
|
-
raise NotSupportedError(ENOTSUP, resp)
|
400
|
+
raise NotSupportedError(errno.ENOTSUP, resp)
|
403
401
|
# {"state": false, "errno": 91005, "error": "空间不足,复制失败。"}
|
404
402
|
case 91005:
|
405
|
-
raise OperationalError(ENOSPC, resp)
|
403
|
+
raise OperationalError(errno.ENOSPC, resp)
|
406
404
|
# {"state": false, "errno": 231011, "error": "文件已删除,请勿重复操作"}
|
407
405
|
case 231011:
|
408
|
-
raise
|
406
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
409
407
|
# {"state": false, "errno": 300104, "error": "文件超过200MB,暂不支持播放"}
|
410
408
|
case 300104:
|
411
|
-
raise P115OSError(EFBIG, resp)
|
409
|
+
raise P115OSError(errno.EFBIG, resp)
|
412
410
|
# {"state": false, "errno": 590075, "error": "操作太频繁,请稍候再试"}
|
413
411
|
case 590075:
|
414
|
-
raise BusyOSError(EBUSY, resp)
|
412
|
+
raise BusyOSError(errno.EBUSY, resp)
|
415
413
|
# {"state": false, "errno": 800001, "error": "目录不存在。"}
|
416
414
|
case 800001:
|
417
|
-
raise
|
415
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
418
416
|
# {"state": false, "errno": 980006, "error": "404 Not Found"}
|
419
417
|
case 980006:
|
420
|
-
raise NotSupportedError(ENOSYS, resp)
|
418
|
+
raise NotSupportedError(errno.ENOSYS, resp)
|
421
419
|
# {"state": false, "errno": 990001, "error": "登陆超时,请重新登陆。"}
|
422
420
|
case 990001:
|
423
421
|
# NOTE: 可能就是被下线了
|
424
|
-
raise AuthenticationError(
|
422
|
+
raise AuthenticationError(errno.EAUTH, resp)
|
425
423
|
# {"state": false, "errno": 990002, "error": "参数错误。"}
|
426
424
|
case 990002:
|
427
|
-
raise
|
425
|
+
raise OperationalError(errno.EINVAL, resp)
|
428
426
|
# {"state": false, "errno": 990003, "error": "操作失败。"}
|
429
427
|
case 990003:
|
430
|
-
raise OperationalError(EIO, resp)
|
428
|
+
raise OperationalError(errno.EIO, resp)
|
431
429
|
# {"state": false, "errno": 990005, "error": "你的账号有类似任务正在处理,请稍后再试!"}
|
432
430
|
case 990005:
|
433
|
-
raise BusyOSError(EBUSY, resp)
|
431
|
+
raise BusyOSError(errno.EBUSY, resp)
|
434
432
|
# {"state": false, "errno": 990009, "error": "删除[...]操作尚未执行完成,请稍后再试!"}
|
435
433
|
# {"state": false, "errno": 990009, "error": "还原[...]操作尚未执行完成,请稍后再试!"}
|
436
434
|
# {"state": false, "errno": 990009, "error": "复制[...]操作尚未执行完成,请稍后再试!"}
|
437
435
|
# {"state": false, "errno": 990009, "error": "移动[...]操作尚未执行完成,请稍后再试!"}
|
438
436
|
case 990009:
|
439
|
-
raise BusyOSError(EBUSY, resp)
|
437
|
+
raise BusyOSError(errno.EBUSY, resp)
|
440
438
|
# {"state": false, "errno": 990023, "error": "操作的文件(夹)数量超过5万个"}
|
441
439
|
case 990023:
|
442
|
-
raise OperationalError(ENOTSUP, resp)
|
440
|
+
raise OperationalError(errno.ENOTSUP, resp)
|
443
441
|
# {"state": 0, "errno": 40100000, "error": "参数错误!"}
|
442
|
+
# {"state": 0, "errno": 40100000, "error": "参数缺失"}
|
444
443
|
case 40100000:
|
445
|
-
raise OperationalError(EINVAL, resp)
|
444
|
+
raise OperationalError(errno.EINVAL, resp)
|
446
445
|
# {"state": 0, "errno": 40101004, "error": "IP登录异常,请稍候再登录!"}
|
447
446
|
case 40101004:
|
448
|
-
raise LoginError(
|
447
|
+
raise LoginError(errno.EAUTH, resp)
|
449
448
|
# {"state": 0, "errno": 40101017, "error": "用户验证失败!"}
|
450
449
|
case 40101017:
|
451
|
-
raise AuthenticationError(
|
450
|
+
raise AuthenticationError(errno.EAUTH, resp)
|
452
451
|
# {"state": 0, "errno": 40101032, "error": "请重新登录"}
|
453
452
|
case 40101032:
|
454
|
-
raise LoginError(
|
453
|
+
raise LoginError(errno.EAUTH, resp)
|
454
|
+
#################################################################
|
455
|
+
# Reference: https://www.yuque.com/115yun/open/rnq0cbz8tt7cu43i #
|
456
|
+
#################################################################
|
457
|
+
# {"state": 0, "errno": 40110000, "error": "请求异常需要重试"}
|
458
|
+
case 40110000:
|
459
|
+
raise OperationalError(errno.EAGAIN, resp)
|
460
|
+
# {"state": 0, "errno": 40140100, "error": "client_id 错误"}
|
461
|
+
case 40140100:
|
462
|
+
raise OperationalError(errno.EINVAL, resp)
|
463
|
+
# {"state": 0, "errno": 40140101, "error": "code_challenge 必填"}
|
464
|
+
case 40140101:
|
465
|
+
raise OperationalError(errno.EINVAL, resp)
|
466
|
+
# {"state": 0, "errno": 40140102, "error": "code_challenge_method 必须是 sha256、sha1、md5 之一"}
|
467
|
+
case 40140102:
|
468
|
+
raise OperationalError(errno.EINVAL, resp)
|
469
|
+
# {"state": 0, "errno": 40140103, "error": "sign 必填"}
|
470
|
+
case 40140103:
|
471
|
+
raise OperationalError(errno.EINVAL, resp)
|
472
|
+
# {"state": 0, "errno": 40140104, "error": "sign 签名失败"}
|
473
|
+
case 40140104:
|
474
|
+
raise OperationalError(errno.EINVAL, resp)
|
475
|
+
# {"state": 0, "errno": 40140105, "error": "生成二维码失败"}
|
476
|
+
case 40140105:
|
477
|
+
raise OperationalError(errno.EIO, resp)
|
478
|
+
# {"state": 0, "errno": 40140106, "error": "APP ID 无效"}
|
479
|
+
case 40140106:
|
480
|
+
raise OperationalError(errno.EINVAL, resp)
|
481
|
+
# {"state": 0, "errno": 40140107, "error": "应用不存在"}
|
482
|
+
case 40140107:
|
483
|
+
raise OperationalError(errno.EINVAL, resp)
|
484
|
+
# {"state": 0, "errno": 40140108, "error": "应用未审核通过"}
|
485
|
+
case 40140108:
|
486
|
+
raise OperationalError(errno.EINVAL, resp)
|
487
|
+
# {"state": 0, "errno": 40140109, "error": "应用已被停用"}
|
488
|
+
case 40140109:
|
489
|
+
raise OperationalError(errno.EINVAL, resp)
|
490
|
+
# {"state": 0, "errno": 40140110, "error": "应用已过期"}
|
491
|
+
case 40140110:
|
492
|
+
raise OperationalError(errno.EINVAL, resp)
|
493
|
+
# {"state": 0, "errno": 40140111, "error": "APP Secret 错误"}
|
494
|
+
case 40140111:
|
495
|
+
raise OperationalError(errno.EINVAL, resp)
|
496
|
+
# {"state": 0, "errno": 40140112, "error": "code_verifier 长度要求43~128位"}
|
497
|
+
case 40140112:
|
498
|
+
raise OperationalError(errno.EINVAL, resp)
|
499
|
+
# {"state": 0, "errno": 40140113, "error": "code_verifier 验证失败"}
|
500
|
+
case 40140113:
|
501
|
+
raise OperationalError(errno.EINVAL, resp)
|
502
|
+
# {"state": 0, "errno": 40140114, "error": "refresh_token 格式错误(防篡改)"}
|
503
|
+
case 40140114:
|
504
|
+
raise OperationalError(errno.EINVAL, resp)
|
505
|
+
# {"state": 0, "errno": 40140115, "error": "refresh_token 签名校验失败(防篡改)"}
|
506
|
+
case 40140115:
|
507
|
+
raise OperationalError(errno.EINVAL, resp)
|
508
|
+
# {"state": 0, "errno": 40140116, "error": "refresh_token 无效(已解除授权)"}
|
509
|
+
case 40140116:
|
510
|
+
raise OperationalError(errno.EIO, resp)
|
511
|
+
# {"state": 0, "errno": 40140117, "error": "access_token 刷新太频繁"}
|
512
|
+
case 40140117:
|
513
|
+
raise BusyOSError(errno.EBUSY, resp)
|
514
|
+
# {"state": 0, "errno": 40140118, "error": "开发者认证已过期"}
|
515
|
+
case 40140118:
|
516
|
+
raise OperationalError(errno.EINVAL, resp)
|
517
|
+
# {"state": 0, "errno": 40140119, "error": "refresh_token 已过期"}
|
518
|
+
case 40140119:
|
519
|
+
raise OperationalError(errno.EINVAL, resp)
|
520
|
+
# {"state": 0, "errno": 40140120, "error": "refresh_token 检验失败(防篡改)"}
|
521
|
+
case 40140120:
|
522
|
+
raise OperationalError(errno.EINVAL, resp)
|
523
|
+
# {"state": 0, "errno": 40140121, "error": "access_token 刷新失败"}
|
524
|
+
case 40140121:
|
525
|
+
raise OperationalError(errno.EINVAL, resp)
|
526
|
+
# {"state": 0, "errno": 40140122, "error": "超出授权应用个数上限"}
|
527
|
+
case 40140122:
|
528
|
+
raise OperationalError(errno.EINVAL, resp)
|
529
|
+
# {"state": 0, "errno": 40140123, "error": "access_token 格式错误(防篡改)"}
|
530
|
+
case 40140123:
|
531
|
+
raise OperationalError(errno.EINVAL, resp)
|
532
|
+
# {"state": 0, "errno": 40140124, "error": "access_token 签名校验失败(防篡改)"}
|
533
|
+
case 40140124:
|
534
|
+
raise OperationalError(errno.EINVAL, resp)
|
535
|
+
# {"state": 0, "errno": 40140125, "error": "access_token 无效(已过期或者已解除授权)"}
|
536
|
+
case 40140125:
|
537
|
+
raise OperationalError(errno.EINVAL, resp)
|
538
|
+
# {"state": 0, "errno": 40140126, "error": "access_token 校验失败(防篡改)"}
|
539
|
+
case 40140126:
|
540
|
+
raise OperationalError(errno.EINVAL, resp)
|
455
541
|
elif "msg_code" in resp:
|
456
542
|
match resp["msg_code"]:
|
457
543
|
case 50028:
|
458
|
-
raise P115OSError(EFBIG, resp)
|
544
|
+
raise P115OSError(errno.EFBIG, resp)
|
459
545
|
case 70004:
|
460
|
-
raise
|
546
|
+
raise P115IsADirectoryError(errno.EISDIR, resp)
|
461
547
|
case 70005 | 70008:
|
462
|
-
raise
|
548
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
463
549
|
elif "error" in resp:
|
464
550
|
match resp["error"]:
|
465
551
|
case "目录不存在或已转移":
|
466
|
-
raise
|
552
|
+
raise P115FileNotFoundError(errno.ENOENT, resp)
|
467
553
|
case "更新的数据为空":
|
468
|
-
raise OperationalError(EINVAL, resp)
|
469
|
-
raise P115OSError(EIO, resp)
|
554
|
+
raise OperationalError(errno.EINVAL, resp)
|
555
|
+
raise P115OSError(errno.EIO, resp)
|
470
556
|
if isinstance(resp, dict):
|
471
557
|
return check(resp)
|
472
558
|
elif isawaitable(resp):
|
473
559
|
async def check_await() -> dict:
|
474
560
|
return check(await resp)
|
475
561
|
return check_await()
|
476
|
-
|
477
|
-
raise P115OSError(EIO, resp)
|
562
|
+
raise P115OSError(errno.EIO, resp)
|
478
563
|
|
479
564
|
|
480
565
|
def normalize_attr_web(
|
@@ -1278,7 +1363,7 @@ class ClientRequestMixin:
|
|
1278
1363
|
|
1279
1364
|
POST https://qrcodeapi.115.com/open/deviceCodeToToken
|
1280
1365
|
|
1281
|
-
..
|
1366
|
+
.. admonition:: Reference
|
1282
1367
|
https://www.yuque.com/115yun/open/shtpzfhewv5nag11#QCCVQ
|
1283
1368
|
|
1284
1369
|
:payload:
|
@@ -1329,7 +1414,7 @@ class ClientRequestMixin:
|
|
1329
1414
|
|
1330
1415
|
POST https://qrcodeapi.115.com/open/refreshToken
|
1331
1416
|
|
1332
|
-
..
|
1417
|
+
.. admonition:: Reference
|
1333
1418
|
https://www.yuque.com/115yun/open/shtpzfhewv5nag11#ve54x
|
1334
1419
|
|
1335
1420
|
:payload:
|
@@ -1481,7 +1566,7 @@ class ClientRequestMixin:
|
|
1481
1566
|
|
1482
1567
|
GET https://qrcodeapi.115.com/get/status/
|
1483
1568
|
|
1484
|
-
..
|
1569
|
+
.. admonition:: Reference
|
1485
1570
|
https://www.yuque.com/115yun/open/shtpzfhewv5nag11#lAsp2
|
1486
1571
|
|
1487
1572
|
:payload:
|
@@ -1567,9 +1652,10 @@ class ClientRequestMixin:
|
|
1567
1652
|
|
1568
1653
|
POST https://qrcodeapi.115.com/open/authDeviceCode
|
1569
1654
|
|
1570
|
-
..
|
1655
|
+
.. admonition:: Reference
|
1571
1656
|
https://www.yuque.com/115yun/open/shtpzfhewv5nag11#WzRhM
|
1572
1657
|
|
1658
|
+
.. note::
|
1573
1659
|
code_challenge 默认用的字符串为 64 个 0,hash 算法为 md5
|
1574
1660
|
|
1575
1661
|
:payload:
|
@@ -1767,11 +1853,11 @@ class ClientRequestMixin:
|
|
1767
1853
|
print("[status=2] qrcode: signed in")
|
1768
1854
|
break
|
1769
1855
|
case -1:
|
1770
|
-
raise LoginError(
|
1856
|
+
raise LoginError(errno.EAUTH, "[status=-1] qrcode: expired")
|
1771
1857
|
case -2:
|
1772
|
-
raise LoginError(
|
1858
|
+
raise LoginError(errno.EAUTH, "[status=-2] qrcode: canceled")
|
1773
1859
|
case _:
|
1774
|
-
raise LoginError(
|
1860
|
+
raise LoginError(errno.EAUTH, f"qrcode: aborted with {resp!r}")
|
1775
1861
|
if app:
|
1776
1862
|
return cls.login_qrcode_scan_result(
|
1777
1863
|
login_uid,
|
@@ -1865,11 +1951,11 @@ class ClientRequestMixin:
|
|
1865
1951
|
print("[status=2] qrcode: signed in")
|
1866
1952
|
break
|
1867
1953
|
case -1:
|
1868
|
-
raise LoginError(
|
1954
|
+
raise LoginError(errno.EAUTH, "[status=-1] qrcode: expired")
|
1869
1955
|
case -2:
|
1870
|
-
raise LoginError(
|
1956
|
+
raise LoginError(errno.EAUTH, "[status=-2] qrcode: canceled")
|
1871
1957
|
case _:
|
1872
|
-
raise LoginError(
|
1958
|
+
raise LoginError(errno.EAUTH, f"qrcode: aborted with {resp!r}")
|
1873
1959
|
return cls.login_qrcode_access_token_open(
|
1874
1960
|
login_uid,
|
1875
1961
|
async_=async_,
|
@@ -2377,7 +2463,7 @@ class ClientRequestMixin:
|
|
2377
2463
|
class P115OpenClient(ClientRequestMixin):
|
2378
2464
|
"""115 的客户端对象
|
2379
2465
|
|
2380
|
-
..
|
2466
|
+
.. admonition:: Reference
|
2381
2467
|
https://www.yuque.com/115yun/open
|
2382
2468
|
|
2383
2469
|
:param app_id_or_refresh_token: 申请到的 AppID 或 refresh_token
|
@@ -2597,8 +2683,8 @@ class P115OpenClient(ClientRequestMixin):
|
|
2597
2683
|
for fid, info in resp["data"].items():
|
2598
2684
|
url = info["url"]
|
2599
2685
|
if strict and not url:
|
2600
|
-
raise
|
2601
|
-
EISDIR,
|
2686
|
+
raise P115IsADirectoryError(
|
2687
|
+
errno.EISDIR,
|
2602
2688
|
f"{fid} is a directory, with response {resp}",
|
2603
2689
|
)
|
2604
2690
|
return P115URL(
|
@@ -2611,8 +2697,8 @@ class P115OpenClient(ClientRequestMixin):
|
|
2611
2697
|
is_directory=not url,
|
2612
2698
|
headers=resp["headers"],
|
2613
2699
|
)
|
2614
|
-
raise
|
2615
|
-
ENOENT,
|
2700
|
+
raise P115FileNotFoundError(
|
2701
|
+
errno.ENOENT,
|
2616
2702
|
f"no such pickcode: {pickcode!r}, with response {resp}",
|
2617
2703
|
)
|
2618
2704
|
if async_:
|
@@ -2660,7 +2746,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2660
2746
|
.. hint::
|
2661
2747
|
相当于 `P115Client.download_url_app(app="chrome")`
|
2662
2748
|
|
2663
|
-
..
|
2749
|
+
.. admonition:: Reference
|
2664
2750
|
https://www.yuque.com/115yun/open/um8whr91bxb5997o
|
2665
2751
|
|
2666
2752
|
:payload:
|
@@ -2723,7 +2809,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2723
2809
|
|
2724
2810
|
POST https://proapi.115.com/open/ufile/copy
|
2725
2811
|
|
2726
|
-
..
|
2812
|
+
.. admonition:: Reference
|
2727
2813
|
https://www.yuque.com/115yun/open/lvas49ar94n47bbk
|
2728
2814
|
|
2729
2815
|
:payload:
|
@@ -2779,7 +2865,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2779
2865
|
|
2780
2866
|
POST https://proapi.115.com/open/ufile/delete
|
2781
2867
|
|
2782
|
-
..
|
2868
|
+
.. admonition:: Reference
|
2783
2869
|
https://www.yuque.com/115yun/open/kt04fu8vcchd2fnb
|
2784
2870
|
|
2785
2871
|
:payload:
|
@@ -2830,7 +2916,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2830
2916
|
.. hint::
|
2831
2917
|
相当于 `P115Client.fs_files_app`
|
2832
2918
|
|
2833
|
-
..
|
2919
|
+
.. admonition:: Reference
|
2834
2920
|
https://www.yuque.com/115yun/open/kz9ft9a7s57ep868
|
2835
2921
|
|
2836
2922
|
:payload:
|
@@ -2949,7 +3035,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2949
3035
|
.. hint::
|
2950
3036
|
相当于 `P115Client.fs_category_get_app`
|
2951
3037
|
|
2952
|
-
..
|
3038
|
+
.. admonition:: Reference
|
2953
3039
|
https://www.yuque.com/115yun/open/rl8zrhe2nag21dfw
|
2954
3040
|
|
2955
3041
|
:payload:
|
@@ -2998,7 +3084,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
2998
3084
|
|
2999
3085
|
POST https://proapi.115.com/open/folder/add
|
3000
3086
|
|
3001
|
-
..
|
3087
|
+
.. admonition:: Reference
|
3002
3088
|
https://www.yuque.com/115yun/open/qur839kyx9cgxpxi
|
3003
3089
|
|
3004
3090
|
:payload:
|
@@ -3050,7 +3136,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3050
3136
|
|
3051
3137
|
POST https://proapi.115.com/open/ufile/move
|
3052
3138
|
|
3053
|
-
..
|
3139
|
+
.. admonition:: Reference
|
3054
3140
|
https://www.yuque.com/115yun/open/vc6fhi2mrkenmav2
|
3055
3141
|
|
3056
3142
|
:payload:
|
@@ -3108,7 +3194,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3108
3194
|
.. hint::
|
3109
3195
|
相当于 `P115Client.fs_search_app2`
|
3110
3196
|
|
3111
|
-
..
|
3197
|
+
.. admonition:: Reference
|
3112
3198
|
https://www.yuque.com/115yun/open/ft2yelxzopusus38
|
3113
3199
|
|
3114
3200
|
:payload:
|
@@ -3263,7 +3349,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3263
3349
|
.. hint::
|
3264
3350
|
即使文件已经被删除,也可以操作成功
|
3265
3351
|
|
3266
|
-
..
|
3352
|
+
.. admonition:: Reference
|
3267
3353
|
https://www.yuque.com/115yun/open/gyrpw5a0zc4sengm
|
3268
3354
|
|
3269
3355
|
:payload:
|
@@ -3361,7 +3447,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3361
3447
|
|
3362
3448
|
GET https://proapi.115.com/open/rb/list
|
3363
3449
|
|
3364
|
-
..
|
3450
|
+
.. admonition:: Reference
|
3365
3451
|
https://www.yuque.com/115yun/open/bg7l4328t98fwgex
|
3366
3452
|
|
3367
3453
|
:payload:
|
@@ -3410,7 +3496,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3410
3496
|
|
3411
3497
|
POST https://proapi.115.com/open/rb/revert
|
3412
3498
|
|
3413
|
-
..
|
3499
|
+
.. admonition:: Reference
|
3414
3500
|
https://www.yuque.com/115yun/open/gq293z80a3kmxbaq
|
3415
3501
|
|
3416
3502
|
:payload:
|
@@ -3455,7 +3541,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3455
3541
|
|
3456
3542
|
GET https://proapi.115.com/open/upload/get_token
|
3457
3543
|
|
3458
|
-
..
|
3544
|
+
.. admonition:: Reference
|
3459
3545
|
https://www.yuque.com/115yun/open/kzacvzl0g7aiyyn4
|
3460
3546
|
"""
|
3461
3547
|
api = complete_proapi("/open/upload/get_token", base_url)
|
@@ -3496,7 +3582,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3496
3582
|
|
3497
3583
|
POST https://proapi.115.com/open/upload/init
|
3498
3584
|
|
3499
|
-
..
|
3585
|
+
.. admonition:: Reference
|
3500
3586
|
https://www.yuque.com/115yun/open/ul4mrauo5i2uza0q
|
3501
3587
|
|
3502
3588
|
:payload:
|
@@ -3554,7 +3640,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3554
3640
|
|
3555
3641
|
POST https://proapi.115.com/open/upload/resume
|
3556
3642
|
|
3557
|
-
..
|
3643
|
+
.. admonition:: Reference
|
3558
3644
|
https://www.yuque.com/115yun/open/tzvi9sbcg59msddz
|
3559
3645
|
|
3560
3646
|
:payload:
|
@@ -3977,7 +4063,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
3977
4063
|
case 1:
|
3978
4064
|
bucket, object, callback = data["bucket"], data["object"], data["callback"]
|
3979
4065
|
case _:
|
3980
|
-
raise
|
4066
|
+
raise OperationalError(errno.EINVAL, resp)
|
3981
4067
|
url = self.upload_endpoint_url(bucket, object)
|
3982
4068
|
token = self.upload_token
|
3983
4069
|
if partsize <= 0:
|
@@ -4044,7 +4130,7 @@ class P115OpenClient(ClientRequestMixin):
|
|
4044
4130
|
|
4045
4131
|
GET https://proapi.115.com/open/user/info
|
4046
4132
|
|
4047
|
-
..
|
4133
|
+
.. admonition:: Reference
|
4048
4134
|
https://www.yuque.com/115yun/open/ot1litggzxa1czww
|
4049
4135
|
"""
|
4050
4136
|
api = complete_proapi("/open/user/info", base_url)
|
@@ -6530,8 +6616,8 @@ class P115Client(P115OpenClient):
|
|
6530
6616
|
for fid, info in resp["data"].items():
|
6531
6617
|
url = info["url"]
|
6532
6618
|
if strict and not url:
|
6533
|
-
raise
|
6534
|
-
EISDIR,
|
6619
|
+
raise P115IsADirectoryError(
|
6620
|
+
errno.EISDIR,
|
6535
6621
|
f"{fid} is a directory, with response {resp}",
|
6536
6622
|
)
|
6537
6623
|
return P115URL(
|
@@ -6544,8 +6630,8 @@ class P115Client(P115OpenClient):
|
|
6544
6630
|
is_directory=not url,
|
6545
6631
|
headers=resp["headers"],
|
6546
6632
|
)
|
6547
|
-
raise
|
6548
|
-
ENOENT,
|
6633
|
+
raise P115FileNotFoundError(
|
6634
|
+
errno.ENOENT,
|
6549
6635
|
f"no such pickcode: {pickcode!r}, with response {resp}",
|
6550
6636
|
)
|
6551
6637
|
if async_:
|
@@ -17444,7 +17530,7 @@ class P115Client(P115OpenClient):
|
|
17444
17530
|
else:
|
17445
17531
|
payload = dict(payload)
|
17446
17532
|
if url:
|
17447
|
-
from .tool import share_extract_payload
|
17533
|
+
from .tool.util import share_extract_payload
|
17448
17534
|
share_payload = share_extract_payload(url)
|
17449
17535
|
payload["share_code"] = share_payload["share_code"]
|
17450
17536
|
payload["receive_code"] = share_payload["receive_code"] or ""
|
@@ -17456,14 +17542,14 @@ class P115Client(P115OpenClient):
|
|
17456
17542
|
info = check_response(resp)["data"]
|
17457
17543
|
file_id = payload["file_id"]
|
17458
17544
|
if not info:
|
17459
|
-
raise
|
17460
|
-
ENOENT,
|
17545
|
+
raise P115FileNotFoundError(
|
17546
|
+
errno.ENOENT,
|
17461
17547
|
f"no such id: {file_id!r}, with response {resp}",
|
17462
17548
|
)
|
17463
17549
|
url = info["url"]
|
17464
17550
|
if strict and not url:
|
17465
|
-
raise
|
17466
|
-
EISDIR,
|
17551
|
+
raise P115IsADirectoryError(
|
17552
|
+
errno.EISDIR,
|
17467
17553
|
f"{file_id} is a directory, with response {resp}",
|
17468
17554
|
)
|
17469
17555
|
return P115URL(
|
@@ -18208,14 +18294,14 @@ class P115Client(P115OpenClient):
|
|
18208
18294
|
info = check_response(resp)["data"]
|
18209
18295
|
file_id = payload["file_id"]
|
18210
18296
|
if not info:
|
18211
|
-
raise
|
18212
|
-
ENOENT,
|
18297
|
+
raise P115FileNotFoundError(
|
18298
|
+
errno.ENOENT,
|
18213
18299
|
f"no such id: {file_id!r}, with response {resp}",
|
18214
18300
|
)
|
18215
18301
|
url = info["url"]
|
18216
18302
|
if strict and not url:
|
18217
|
-
raise
|
18218
|
-
EISDIR,
|
18303
|
+
raise P115IsADirectoryError(
|
18304
|
+
errno.EISDIR,
|
18219
18305
|
f"{file_id} is a directory, with response {resp}",
|
18220
18306
|
)
|
18221
18307
|
return P115URL(
|
@@ -19939,7 +20025,7 @@ class P115Client(P115OpenClient):
|
|
19939
20025
|
elif status == 1 and statuscode == 0:
|
19940
20026
|
bucket, object, callback = resp["bucket"], resp["object"], resp["callback"]
|
19941
20027
|
else:
|
19942
|
-
raise
|
20028
|
+
raise OperationalError(errno.EINVAL, resp)
|
19943
20029
|
url = self.upload_endpoint_url(bucket, object)
|
19944
20030
|
token = self.upload_token
|
19945
20031
|
if partsize <= 0:
|