p123client 0.0.6.4__py3-none-any.whl → 0.0.6.9__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.
- p123client/client.py +317 -25
- p123client/tool/__init__.py +70 -29
- {p123client-0.0.6.4.dist-info → p123client-0.0.6.9.dist-info}/METADATA +2 -2
- {p123client-0.0.6.4.dist-info → p123client-0.0.6.9.dist-info}/RECORD +6 -6
- {p123client-0.0.6.4.dist-info → p123client-0.0.6.9.dist-info}/LICENSE +0 -0
- {p123client-0.0.6.4.dist-info → p123client-0.0.6.9.dist-info}/WHEEL +0 -0
p123client/client.py
CHANGED
@@ -40,6 +40,9 @@ from .exception import P123OSError, P123BrokenUpload
|
|
40
40
|
|
41
41
|
|
42
42
|
# 默认使用的域名
|
43
|
+
# "https://www.123pan.com"
|
44
|
+
# "https://www.123pan.com/a"
|
45
|
+
# "https://www.123pan.com/b"
|
43
46
|
DEFAULT_BASE_URL = "https://www.123pan.com/b"
|
44
47
|
DEFAULT_LOGIN_BASE_URL = "https://login.123pan.com"
|
45
48
|
DEFAULT_OPEN_BASE_URL = "https://open-api.123pan.com"
|
@@ -371,7 +374,7 @@ class P123OpenClient:
|
|
371
374
|
check_response(resp)
|
372
375
|
self.token = resp["data"]["accessToken"]
|
373
376
|
return resp
|
374
|
-
return run_gen_step(gen_step, async_
|
377
|
+
return run_gen_step(gen_step, async_)
|
375
378
|
|
376
379
|
@overload
|
377
380
|
@staticmethod
|
@@ -1212,6 +1215,8 @@ class P123OpenClient:
|
|
1212
1215
|
})
|
1213
1216
|
return self.request(api, params=payload, async_=async_, **request_kwargs)
|
1214
1217
|
|
1218
|
+
fs_list_v2 = fs_list
|
1219
|
+
|
1215
1220
|
@overload
|
1216
1221
|
def fs_list_v1(
|
1217
1222
|
self,
|
@@ -1258,7 +1263,7 @@ class P123OpenClient:
|
|
1258
1263
|
:payload:
|
1259
1264
|
- limit: int = 100 💡 分页大小,最多 100
|
1260
1265
|
- orderBy: str = "file_id" 💡 排序依据
|
1261
|
-
|
1266
|
+
|
1262
1267
|
- "file_id": 文件 id
|
1263
1268
|
- "file_name": 文件名
|
1264
1269
|
- "size": 文件大小
|
@@ -2857,7 +2862,7 @@ class P123OpenClient:
|
|
2857
2862
|
"duplicate": duplicate,
|
2858
2863
|
"slice_size": slice_size,
|
2859
2864
|
}) from e
|
2860
|
-
return run_gen_step(gen_step, async_
|
2865
|
+
return run_gen_step(gen_step, async_)
|
2861
2866
|
|
2862
2867
|
@overload
|
2863
2868
|
def share_create(
|
@@ -4213,7 +4218,7 @@ class P123OpenClient:
|
|
4213
4218
|
"duplicate": duplicate,
|
4214
4219
|
"slice_size": slice_size,
|
4215
4220
|
}) from e
|
4216
|
-
return run_gen_step(gen_step, async_
|
4221
|
+
return run_gen_step(gen_step, async_)
|
4217
4222
|
|
4218
4223
|
@overload
|
4219
4224
|
def user_info(
|
@@ -4285,6 +4290,7 @@ class P123OpenClient:
|
|
4285
4290
|
fs_detail_open = fs_detail
|
4286
4291
|
fs_info_open = fs_info
|
4287
4292
|
fs_list_open = fs_list
|
4293
|
+
fs_list_v2_open = fs_list_v2
|
4288
4294
|
fs_list_v1_open = fs_list_v1
|
4289
4295
|
fs_mkdir_open = fs_mkdir
|
4290
4296
|
fs_move_open = fs_move
|
@@ -4415,7 +4421,7 @@ class P123Client(P123OpenClient):
|
|
4415
4421
|
check_response(resp)
|
4416
4422
|
self.token = resp["data"]["token"]
|
4417
4423
|
return resp
|
4418
|
-
return run_gen_step(gen_step, async_
|
4424
|
+
return run_gen_step(gen_step, async_)
|
4419
4425
|
|
4420
4426
|
@overload
|
4421
4427
|
@staticmethod
|
@@ -4456,6 +4462,45 @@ class P123Client(P123OpenClient):
|
|
4456
4462
|
request_kwargs["async_"] = async_
|
4457
4463
|
return request(**request_kwargs)
|
4458
4464
|
|
4465
|
+
@overload
|
4466
|
+
@staticmethod
|
4467
|
+
def app_server_time(
|
4468
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
4469
|
+
request: None | Callable = None,
|
4470
|
+
*,
|
4471
|
+
async_: Literal[False] = False,
|
4472
|
+
**request_kwargs,
|
4473
|
+
) -> dict:
|
4474
|
+
...
|
4475
|
+
@overload
|
4476
|
+
@staticmethod
|
4477
|
+
def app_server_time(
|
4478
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
4479
|
+
request: None | Callable = None,
|
4480
|
+
*,
|
4481
|
+
async_: Literal[True],
|
4482
|
+
**request_kwargs,
|
4483
|
+
) -> Coroutine[Any, Any, dict]:
|
4484
|
+
...
|
4485
|
+
@staticmethod
|
4486
|
+
def app_server_time(
|
4487
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
4488
|
+
request: None | Callable = None,
|
4489
|
+
*,
|
4490
|
+
async_: Literal[False, True] = False,
|
4491
|
+
**request_kwargs,
|
4492
|
+
) -> dict | Coroutine[Any, Any, dict]:
|
4493
|
+
"""获取 123 网盘的服务器时间戳
|
4494
|
+
|
4495
|
+
GET https://www.123pan.com/api/get/server/time
|
4496
|
+
"""
|
4497
|
+
request_kwargs["url"] = complete_url("/api/get/server/time", base_url)
|
4498
|
+
request_kwargs.setdefault("parse", default_parse)
|
4499
|
+
if request is None:
|
4500
|
+
request = get_default_request()
|
4501
|
+
request_kwargs["async_"] = async_
|
4502
|
+
return request(**request_kwargs)
|
4503
|
+
|
4459
4504
|
@overload
|
4460
4505
|
def download_info(
|
4461
4506
|
self,
|
@@ -4531,8 +4576,7 @@ class P123Client(P123OpenClient):
|
|
4531
4576
|
)
|
4532
4577
|
resp["payload"] = payload
|
4533
4578
|
check_response(resp)
|
4534
|
-
info_list
|
4535
|
-
if not info_list:
|
4579
|
+
if not (info_list := resp["data"]["infoList"]):
|
4536
4580
|
raise FileNotFoundError(ENOENT, resp)
|
4537
4581
|
payload = cast(dict, info_list[0])
|
4538
4582
|
if payload["Type"]:
|
@@ -4549,7 +4593,7 @@ class P123Client(P123OpenClient):
|
|
4549
4593
|
async_=async_,
|
4550
4594
|
**request_kwargs,
|
4551
4595
|
)
|
4552
|
-
return run_gen_step(gen_step, async_
|
4596
|
+
return run_gen_step(gen_step, async_)
|
4553
4597
|
|
4554
4598
|
@overload
|
4555
4599
|
def download_info_batch(
|
@@ -4641,12 +4685,22 @@ class P123Client(P123OpenClient):
|
|
4641
4685
|
) -> str | Coroutine[Any, Any, str]:
|
4642
4686
|
"""获取下载链接
|
4643
4687
|
|
4688
|
+
.. note::
|
4689
|
+
`payload` 支持多种格式的输入,按下面的规则按顺序进行判断:
|
4690
|
+
|
4691
|
+
1. 如果是 `int` 或 `str`,则视为文件 id,必须在你的网盘中存在此文件
|
4692
|
+
2. 如果是 `dict`(不区分大小写),有 "S3KeyFlag", "Etag" 和 "Size" 的值,则直接获取链接,文件不必在你网盘中
|
4693
|
+
3. 如果是 `dict`(不区分大小写),有 "Etag" 和 "Size" 的值,则会先秒传(临时文件路径为 /.tempfile)再获取链接,文件不必在你网盘中
|
4694
|
+
4. 如果是 `dict`(不区分大小写),有 "FileID",则会先获取信息,再获取链接,必须在你的网盘中存在此文件
|
4695
|
+
5. 否则会报错 ValueError
|
4696
|
+
|
4644
4697
|
:params payload: 文件 id 或者文件信息,文件信息必须包含的信息如下:
|
4645
4698
|
|
4646
|
-
-
|
4647
|
-
-
|
4648
|
-
-
|
4649
|
-
-
|
4699
|
+
- FileID: int | str 💡 下载链接
|
4700
|
+
- S3KeyFlag: str 💡 s3 存储名
|
4701
|
+
- Etag: str 💡 文件的 MD5 散列值
|
4702
|
+
- Size: int 💡 文件大小
|
4703
|
+
- FileName: str 💡 默认用 Etag(即 MD5)作为文件名,可以省略
|
4650
4704
|
|
4651
4705
|
:params async_: 是否异步
|
4652
4706
|
:params request_kwargs: 其它请求参数
|
@@ -4654,7 +4708,37 @@ class P123Client(P123OpenClient):
|
|
4654
4708
|
:return: 下载链接
|
4655
4709
|
"""
|
4656
4710
|
def gen_step():
|
4711
|
+
nonlocal payload
|
4657
4712
|
if isinstance(payload, dict):
|
4713
|
+
payload = dict_to_lower(payload)
|
4714
|
+
if not ("size" in payload and "etag" in payload):
|
4715
|
+
if fileid := payload.get("fileid"):
|
4716
|
+
resp = yield self.fs_info(fileid, async_=async_, **request_kwargs)
|
4717
|
+
check_response(resp)
|
4718
|
+
if not (info_list := resp["data"]["infoList"]):
|
4719
|
+
raise P123OSError(ENOENT, resp)
|
4720
|
+
info = info_list[0]
|
4721
|
+
if info["Type"]:
|
4722
|
+
raise IsADirectoryError(EISDIR, resp)
|
4723
|
+
payload = dict_to_lower_merge(payload, info)
|
4724
|
+
else:
|
4725
|
+
raise ValueError("`Size` and `Etag` must be provided")
|
4726
|
+
if "s3keyflag" not in payload:
|
4727
|
+
resp = yield self.upload_request(
|
4728
|
+
{
|
4729
|
+
"filename": ".tempfile",
|
4730
|
+
"duplicate": 2,
|
4731
|
+
"etag": payload["etag"],
|
4732
|
+
"size": payload["size"],
|
4733
|
+
"type": 0,
|
4734
|
+
},
|
4735
|
+
async_=async_,
|
4736
|
+
**request_kwargs,
|
4737
|
+
)
|
4738
|
+
check_response(resp)
|
4739
|
+
if not resp["data"]["Reuse"]:
|
4740
|
+
raise P123OSError(ENOENT, resp)
|
4741
|
+
payload["s3keyflag"] = resp["data"]["Info"]["S3KeyFlag"]
|
4658
4742
|
resp = yield self.download_info(
|
4659
4743
|
payload,
|
4660
4744
|
async_=async_,
|
@@ -4670,7 +4754,7 @@ class P123Client(P123OpenClient):
|
|
4670
4754
|
)
|
4671
4755
|
check_response(resp)
|
4672
4756
|
return resp["data"]["downloadUrl"]
|
4673
|
-
return run_gen_step(gen_step, async_
|
4757
|
+
return run_gen_step(gen_step, async_)
|
4674
4758
|
|
4675
4759
|
@overload
|
4676
4760
|
def fs_copy(
|
@@ -4746,7 +4830,7 @@ class P123Client(P123OpenClient):
|
|
4746
4830
|
async_=async_,
|
4747
4831
|
**request_kwargs,
|
4748
4832
|
)
|
4749
|
-
return run_gen_step(gen_step, async_
|
4833
|
+
return run_gen_step(gen_step, async_)
|
4750
4834
|
|
4751
4835
|
@overload
|
4752
4836
|
def fs_detail(
|
@@ -5013,7 +5097,7 @@ class P123Client(P123OpenClient):
|
|
5013
5097
|
- next: int = 0 💡 下一批拉取开始的 id
|
5014
5098
|
- orderBy: str = "file_id" 💡 排序依据
|
5015
5099
|
|
5016
|
-
- "file_id": 文件 id
|
5100
|
+
- "file_id": 文件 id,也可以写作 "fileId"
|
5017
5101
|
- "file_name": 文件名
|
5018
5102
|
- "size": 文件大小
|
5019
5103
|
- "create_at": 创建时间
|
@@ -5109,7 +5193,7 @@ class P123Client(P123OpenClient):
|
|
5109
5193
|
- next: int = 0 💡 下一批拉取开始的 id
|
5110
5194
|
- orderBy: str = "file_id" 💡 排序依据
|
5111
5195
|
|
5112
|
-
- "file_id": 文件 id
|
5196
|
+
- "file_id": 文件 id,也可以写作 "fileId"
|
5113
5197
|
- "file_name": 文件名
|
5114
5198
|
- "size": 文件大小
|
5115
5199
|
- "create_at": 创建时间
|
@@ -5118,7 +5202,7 @@ class P123Client(P123OpenClient):
|
|
5118
5202
|
- ...
|
5119
5203
|
|
5120
5204
|
- orderDirection: "asc" | "desc" = "asc" 💡 排序顺序
|
5121
|
-
- Page: int =
|
5205
|
+
- Page: int = 1 💡 第几页,从 1 开始
|
5122
5206
|
- parentFileId: int | str = 0 💡 父目录 id
|
5123
5207
|
- trashed: "false" | "true" = <default> 💡 是否查看回收站的文件
|
5124
5208
|
- inDirectSpace: "false" | "true" = "false"
|
@@ -5129,8 +5213,13 @@ class P123Client(P123OpenClient):
|
|
5129
5213
|
- "syncFileList": 同步空间
|
5130
5214
|
|
5131
5215
|
- operateType: int | str = <default> 💡 操作类型,如果在同步空间,则需要指定为 "SyncSpacePage"
|
5216
|
+
|
5217
|
+
.. note::
|
5218
|
+
这个值似乎不影响结果,所以可以忽略。我在浏览器中,看到罗列根目录为 1,搜索(指定 `SearchData`)为 2,同步空间的根目录为 3,罗列其它目录大多为 4,偶尔为 8,也可能是其它值
|
5219
|
+
|
5132
5220
|
- SearchData: str = <default> 💡 搜索关键字(将无视 `parentFileId` 参数)
|
5133
|
-
- OnlyLookAbnormalFile: int =
|
5221
|
+
- OnlyLookAbnormalFile: int = 0 💡 大概可传入 0 或 1
|
5222
|
+
- RequestSource: int = <default> 💡 浏览器中,在同步空间中为 1
|
5134
5223
|
"""
|
5135
5224
|
if isinstance(payload, (int, str)):
|
5136
5225
|
payload = {"parentFileId": payload}
|
@@ -5143,6 +5232,8 @@ class P123Client(P123OpenClient):
|
|
5143
5232
|
"parentFileId": 0,
|
5144
5233
|
"inDirectSpace": "false",
|
5145
5234
|
"event": event,
|
5235
|
+
"OnlyLookAbnormalFile": 0,
|
5236
|
+
"Page": 1,
|
5146
5237
|
})
|
5147
5238
|
if not payload.get("trashed"):
|
5148
5239
|
match payload["event"]:
|
@@ -5280,6 +5371,50 @@ class P123Client(P123OpenClient):
|
|
5280
5371
|
**request_kwargs,
|
5281
5372
|
)
|
5282
5373
|
|
5374
|
+
@overload
|
5375
|
+
def fs_fresh(
|
5376
|
+
self,
|
5377
|
+
payload: dict = {},
|
5378
|
+
/,
|
5379
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5380
|
+
*,
|
5381
|
+
async_: Literal[False] = False,
|
5382
|
+
**request_kwargs,
|
5383
|
+
) -> dict:
|
5384
|
+
...
|
5385
|
+
@overload
|
5386
|
+
def fs_fresh(
|
5387
|
+
self,
|
5388
|
+
payload: dict = {},
|
5389
|
+
/,
|
5390
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5391
|
+
*,
|
5392
|
+
async_: Literal[True],
|
5393
|
+
**request_kwargs,
|
5394
|
+
) -> Coroutine[Any, Any, dict]:
|
5395
|
+
...
|
5396
|
+
def fs_fresh(
|
5397
|
+
self,
|
5398
|
+
payload: dict = {},
|
5399
|
+
/,
|
5400
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5401
|
+
*,
|
5402
|
+
async_: Literal[False, True] = False,
|
5403
|
+
**request_kwargs,
|
5404
|
+
) -> dict | Coroutine[Any, Any, dict]:
|
5405
|
+
"""刷新列表和直链缓存
|
5406
|
+
|
5407
|
+
POST https://www.123pan.com/api/restful/goapi/v1/cdnLink/cache/refresh
|
5408
|
+
"""
|
5409
|
+
return self.request(
|
5410
|
+
"restful/goapi/v1/cdnLink/cache/refresh",
|
5411
|
+
"POST",
|
5412
|
+
json=payload,
|
5413
|
+
base_url=base_url,
|
5414
|
+
async_=async_,
|
5415
|
+
**request_kwargs,
|
5416
|
+
)
|
5417
|
+
|
5283
5418
|
@overload # type: ignore
|
5284
5419
|
def fs_rename(
|
5285
5420
|
self,
|
@@ -5336,6 +5471,56 @@ class P123Client(P123OpenClient):
|
|
5336
5471
|
**request_kwargs,
|
5337
5472
|
)
|
5338
5473
|
|
5474
|
+
@overload
|
5475
|
+
def fs_sync_log(
|
5476
|
+
self,
|
5477
|
+
payload: dict | int = 1,
|
5478
|
+
/,
|
5479
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5480
|
+
*,
|
5481
|
+
async_: Literal[False] = False,
|
5482
|
+
**request_kwargs,
|
5483
|
+
) -> dict:
|
5484
|
+
...
|
5485
|
+
@overload
|
5486
|
+
def fs_sync_log(
|
5487
|
+
self,
|
5488
|
+
payload: dict | int = 1,
|
5489
|
+
/,
|
5490
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5491
|
+
*,
|
5492
|
+
async_: Literal[True],
|
5493
|
+
**request_kwargs,
|
5494
|
+
) -> Coroutine[Any, Any, dict]:
|
5495
|
+
...
|
5496
|
+
def fs_sync_log(
|
5497
|
+
self,
|
5498
|
+
payload: dict | int = 1,
|
5499
|
+
/,
|
5500
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
5501
|
+
*,
|
5502
|
+
async_: Literal[False, True] = False,
|
5503
|
+
**request_kwargs,
|
5504
|
+
) -> dict | Coroutine[Any, Any, dict]:
|
5505
|
+
"""获取同步空间的操作记录
|
5506
|
+
|
5507
|
+
GET https://www.123pan.com/api/restful/goapi/v1/sync-disk/file/log
|
5508
|
+
|
5509
|
+
:payload:
|
5510
|
+
- page: int = 1 💡 第几页
|
5511
|
+
- pageSize: int = 100 💡 每页大小
|
5512
|
+
- searchData: str = <default> 💡 搜索关键字
|
5513
|
+
"""
|
5514
|
+
if not isinstance(payload, dict):
|
5515
|
+
payload = {"page": payload, "pageSize": 100}
|
5516
|
+
return self.request(
|
5517
|
+
"restful/goapi/v1/sync-disk/file/log",
|
5518
|
+
params=payload,
|
5519
|
+
base_url=base_url,
|
5520
|
+
async_=async_,
|
5521
|
+
**request_kwargs,
|
5522
|
+
)
|
5523
|
+
|
5339
5524
|
@overload # type: ignore
|
5340
5525
|
def fs_trash(
|
5341
5526
|
self,
|
@@ -5391,6 +5576,8 @@ class P123Client(P123OpenClient):
|
|
5391
5576
|
- "recycleRestore": 移出回收站
|
5392
5577
|
|
5393
5578
|
- operation: bool = <default>
|
5579
|
+
- operatePlace: int = <default>
|
5580
|
+
- RequestSource: int = <default>
|
5394
5581
|
"""
|
5395
5582
|
if isinstance(payload, (int, str)):
|
5396
5583
|
payload = {"fileTrashInfoList": [{"FileId": payload}]}
|
@@ -7004,8 +7191,10 @@ class P123Client(P123OpenClient):
|
|
7004
7191
|
if async_:
|
7005
7192
|
async def request():
|
7006
7193
|
chunks = bio_chunk_async_iter(file, chunksize=slice_size) # type: ignore
|
7007
|
-
|
7194
|
+
slice_no = 1
|
7008
7195
|
async for chunk in chunks:
|
7196
|
+
upload_data["partNumberStart"] = slice_no
|
7197
|
+
upload_data["partNumberEnd"] = slice_no + 1
|
7009
7198
|
resp = await self.upload_prepare(
|
7010
7199
|
upload_data,
|
7011
7200
|
base_url=base_url,
|
@@ -7014,17 +7203,18 @@ class P123Client(P123OpenClient):
|
|
7014
7203
|
)
|
7015
7204
|
check_response(resp)
|
7016
7205
|
await self.request(
|
7017
|
-
resp["data"]["presignedUrls"][
|
7206
|
+
resp["data"]["presignedUrls"][str(slice_no)],
|
7018
7207
|
data=chunk,
|
7019
7208
|
async_=True,
|
7020
7209
|
**upload_request_kwargs,
|
7021
7210
|
)
|
7022
|
-
|
7211
|
+
slice_no += 1
|
7023
7212
|
yield request()
|
7024
7213
|
else:
|
7025
7214
|
chunks = bio_chunk_iter(file, chunksize=slice_size) # type: ignore
|
7026
7215
|
for slice_no, chunk in enumerate(chunks, 1):
|
7027
7216
|
upload_data["partNumberStart"] = slice_no
|
7217
|
+
upload_data["partNumberEnd"] = slice_no + 1
|
7028
7218
|
resp = self.upload_prepare(
|
7029
7219
|
upload_data,
|
7030
7220
|
base_url=base_url,
|
@@ -7032,7 +7222,7 @@ class P123Client(P123OpenClient):
|
|
7032
7222
|
)
|
7033
7223
|
check_response(resp)
|
7034
7224
|
self.request(
|
7035
|
-
resp["data"]["presignedUrls"][
|
7225
|
+
resp["data"]["presignedUrls"][str(slice_no)],
|
7036
7226
|
data=chunk,
|
7037
7227
|
**upload_request_kwargs,
|
7038
7228
|
)
|
@@ -7057,7 +7247,7 @@ class P123Client(P123OpenClient):
|
|
7057
7247
|
async_=async_,
|
7058
7248
|
**request_kwargs,
|
7059
7249
|
)
|
7060
|
-
return run_gen_step(gen_step, async_
|
7250
|
+
return run_gen_step(gen_step, async_)
|
7061
7251
|
|
7062
7252
|
@overload
|
7063
7253
|
def upload_file_fast(
|
@@ -7218,7 +7408,56 @@ class P123Client(P123OpenClient):
|
|
7218
7408
|
async_=async_,
|
7219
7409
|
**request_kwargs,
|
7220
7410
|
)
|
7221
|
-
return run_gen_step(gen_step, async_
|
7411
|
+
return run_gen_step(gen_step, async_)
|
7412
|
+
|
7413
|
+
@overload
|
7414
|
+
def user_device_list(
|
7415
|
+
self,
|
7416
|
+
payload: dict | str = "deviceManagement",
|
7417
|
+
/,
|
7418
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7419
|
+
*,
|
7420
|
+
async_: Literal[False] = False,
|
7421
|
+
**request_kwargs,
|
7422
|
+
) -> dict:
|
7423
|
+
...
|
7424
|
+
@overload
|
7425
|
+
def user_device_list(
|
7426
|
+
self,
|
7427
|
+
payload: dict | str = "deviceManagement",
|
7428
|
+
/,
|
7429
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7430
|
+
*,
|
7431
|
+
async_: Literal[True],
|
7432
|
+
**request_kwargs,
|
7433
|
+
) -> Coroutine[Any, Any, dict]:
|
7434
|
+
...
|
7435
|
+
def user_device_list(
|
7436
|
+
self,
|
7437
|
+
payload: dict | str = "deviceManagement",
|
7438
|
+
/,
|
7439
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7440
|
+
*,
|
7441
|
+
async_: Literal[False, True] = False,
|
7442
|
+
**request_kwargs,
|
7443
|
+
) -> dict | Coroutine[Any, Any, dict]:
|
7444
|
+
"""用户设备列表
|
7445
|
+
|
7446
|
+
GET https://www.123pan.com/api/user/device_list
|
7447
|
+
|
7448
|
+
:payload:
|
7449
|
+
- event: str = "deviceManagement" 💡 事件类型,"deviceManagement" 为管理登录设备列表
|
7450
|
+
- operateType: int = <default>
|
7451
|
+
"""
|
7452
|
+
if not isinstance(payload, dict):
|
7453
|
+
payload = {"event": payload}
|
7454
|
+
return self.request(
|
7455
|
+
"user/device_list",
|
7456
|
+
params=payload,
|
7457
|
+
base_url=base_url,
|
7458
|
+
async_=async_,
|
7459
|
+
**request_kwargs,
|
7460
|
+
)
|
7222
7461
|
|
7223
7462
|
@overload
|
7224
7463
|
def user_info(
|
@@ -7312,4 +7551,57 @@ class P123Client(P123OpenClient):
|
|
7312
7551
|
request_kwargs["async_"] = async_
|
7313
7552
|
return request(url=api, method="POST", json=payload, **request_kwargs)
|
7314
7553
|
|
7315
|
-
|
7554
|
+
@overload
|
7555
|
+
def user_use_history(
|
7556
|
+
self,
|
7557
|
+
payload: dict | str = "loginRecord",
|
7558
|
+
/,
|
7559
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7560
|
+
*,
|
7561
|
+
async_: Literal[False] = False,
|
7562
|
+
**request_kwargs,
|
7563
|
+
) -> dict:
|
7564
|
+
...
|
7565
|
+
@overload
|
7566
|
+
def user_use_history(
|
7567
|
+
self,
|
7568
|
+
payload: dict | str = "loginRecord",
|
7569
|
+
/,
|
7570
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7571
|
+
*,
|
7572
|
+
async_: Literal[True],
|
7573
|
+
**request_kwargs,
|
7574
|
+
) -> Coroutine[Any, Any, dict]:
|
7575
|
+
...
|
7576
|
+
def user_use_history(
|
7577
|
+
self,
|
7578
|
+
payload: dict | str = "loginRecord",
|
7579
|
+
/,
|
7580
|
+
base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
|
7581
|
+
*,
|
7582
|
+
async_: Literal[False, True] = False,
|
7583
|
+
**request_kwargs,
|
7584
|
+
) -> dict | Coroutine[Any, Any, dict]:
|
7585
|
+
"""用户使用记录
|
7586
|
+
|
7587
|
+
GET https://www.123pan.com/api/user/use_history
|
7588
|
+
|
7589
|
+
:payload:
|
7590
|
+
- event: str = "loginRecord" 💡 事件类型,"loginRecord" 为登录记录
|
7591
|
+
"""
|
7592
|
+
if not isinstance(payload, dict):
|
7593
|
+
payload = {"event": payload}
|
7594
|
+
return self.request(
|
7595
|
+
"user/use_history",
|
7596
|
+
params=payload,
|
7597
|
+
base_url=base_url,
|
7598
|
+
async_=async_,
|
7599
|
+
**request_kwargs,
|
7600
|
+
)
|
7601
|
+
|
7602
|
+
# TODO: 添加扫码登录接口,以及通过扫码登录的方法,特别是用已登录的设备扫描一个新的 token 出来
|
7603
|
+
# TODO: 添加 同步空间 和 直链空间 的操作接口
|
7604
|
+
# TODO: 添加 图床 的操作接口
|
7605
|
+
# TODO: 添加 视频转码 的操作接口
|
7606
|
+
# TODO: 对于某些工具的接口封装,例如 重复文件清理
|
7607
|
+
# TODO: 开放接口有更新了,从此开始 https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/xogi45g7okqk7svr
|
p123client/tool/__init__.py
CHANGED
@@ -6,14 +6,14 @@ __all__ = ["make_uri", "upload_uri", "get_downurl", "iterdir", "share_iterdir"]
|
|
6
6
|
|
7
7
|
from asyncio import sleep as async_sleep
|
8
8
|
from collections import deque
|
9
|
-
from collections.abc import AsyncIterator, Callable, Coroutine, Iterator
|
9
|
+
from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator, Mapping
|
10
10
|
from errno import EISDIR, ENOENT
|
11
11
|
from functools import partial
|
12
12
|
from itertools import count
|
13
13
|
from time import sleep, time
|
14
14
|
from typing import Literal
|
15
15
|
from typing import overload, Any, Literal
|
16
|
-
from urllib.parse import unquote
|
16
|
+
from urllib.parse import unquote, urlsplit
|
17
17
|
|
18
18
|
from encode_uri import encode_uri_component_loose
|
19
19
|
from iterutils import run_gen_step, run_gen_step_iter, Yield
|
@@ -73,7 +73,7 @@ def make_uri(
|
|
73
73
|
size = info["Size"]
|
74
74
|
s3_key_flag = info["S3KeyFlag"]
|
75
75
|
return f"123://{name}|{size}|{md5}?{s3_key_flag}"
|
76
|
-
return run_gen_step(gen_step, async_
|
76
|
+
return run_gen_step(gen_step, async_)
|
77
77
|
|
78
78
|
|
79
79
|
@overload
|
@@ -194,19 +194,16 @@ def get_downurl(
|
|
194
194
|
size = int(size_s)
|
195
195
|
if s3_key_flag:
|
196
196
|
payload = {
|
197
|
-
"S3KeyFlag": s3_key_flag,
|
198
197
|
"FileName": name,
|
199
198
|
"Etag": md5,
|
200
199
|
"Size": size,
|
200
|
+
"S3KeyFlag": s3_key_flag,
|
201
201
|
}
|
202
202
|
else:
|
203
|
-
resp = yield client.fs_mkdir("我的秒传", async_=async_, **request_kwargs)
|
204
|
-
check_response(resp)
|
205
203
|
resp = yield client.upload_file_fast(
|
204
|
+
file_name=".tempfile",
|
206
205
|
file_md5=md5,
|
207
|
-
file_name=f"{md5}-{size}",
|
208
206
|
file_size=size,
|
209
|
-
parent_id=resp["data"]["Info"]["FileId"],
|
210
207
|
duplicate=2,
|
211
208
|
async_=async_,
|
212
209
|
**request_kwargs,
|
@@ -216,9 +213,12 @@ def get_downurl(
|
|
216
213
|
resp = yield client.download_info(payload, async_=async_, **request_kwargs)
|
217
214
|
check_response(resp)
|
218
215
|
return resp["data"]["DownloadUrl"]
|
219
|
-
return run_gen_step(gen_step, async_
|
216
|
+
return run_gen_step(gen_step, async_)
|
220
217
|
|
221
218
|
|
219
|
+
# TODO: _iterdir 支持广度优先遍历
|
220
|
+
# TODO: 失败时,报错信息支持返回已经成功和未成功的列表,并且形式上也要利于断点重试
|
221
|
+
# TODO: 支持传入其它自定义的查询参数
|
222
222
|
@overload
|
223
223
|
def _iterdir(
|
224
224
|
fs_files: Callable,
|
@@ -227,7 +227,9 @@ def _iterdir(
|
|
227
227
|
min_depth: int = 1,
|
228
228
|
max_depth: int = 1,
|
229
229
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
230
|
-
|
230
|
+
cooldown: int | float = 0,
|
231
|
+
base_url: None | str | Callable[[], str] = None,
|
232
|
+
extra_data: None | Mapping | Iterable[tuple[str, Any]] = None,
|
231
233
|
*,
|
232
234
|
async_: Literal[False] = False,
|
233
235
|
**request_kwargs,
|
@@ -241,7 +243,9 @@ def _iterdir(
|
|
241
243
|
min_depth: int = 1,
|
242
244
|
max_depth: int = 1,
|
243
245
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
244
|
-
|
246
|
+
cooldown: int | float = 0,
|
247
|
+
base_url: None | str | Callable[[], str] = None,
|
248
|
+
extra_data: None | Mapping | Iterable[tuple[str, Any]] = None,
|
245
249
|
*,
|
246
250
|
async_: Literal[True],
|
247
251
|
**request_kwargs,
|
@@ -254,7 +258,9 @@ def _iterdir(
|
|
254
258
|
min_depth: int = 1,
|
255
259
|
max_depth: int = 1,
|
256
260
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
257
|
-
|
261
|
+
cooldown: int | float = 0,
|
262
|
+
base_url: None | str | Callable[[], str] = None,
|
263
|
+
extra_data: None | Mapping | Iterable[tuple[str, Any]] = None,
|
258
264
|
*,
|
259
265
|
async_: Literal[False, True] = False,
|
260
266
|
**request_kwargs,
|
@@ -273,7 +279,9 @@ def _iterdir(
|
|
273
279
|
- 如果返回值是 False,则跳过此节点(但依然会继续处理位于此节点之下的节点)
|
274
280
|
- 如果返回值是 True,则输出此节点
|
275
281
|
|
276
|
-
:param
|
282
|
+
:param cooldown: 两次调用之间,冷却的时间(用两次调用开始时的时间差,而不是一次完成到下一次开始的时间差)
|
283
|
+
:param base_url: 基地址,如果为空,则用默认
|
284
|
+
:param extra_data: 附加数据
|
277
285
|
:param async_: 是否异步
|
278
286
|
:param request_kwargs: 其它请求参数
|
279
287
|
|
@@ -281,6 +289,8 @@ def _iterdir(
|
|
281
289
|
"""
|
282
290
|
default_payload = payload
|
283
291
|
page_size = int(payload.setdefault("limit", 100))
|
292
|
+
if base_url:
|
293
|
+
request_kwargs["base_url"] = base_url
|
284
294
|
def gen_step():
|
285
295
|
nonlocal parent_id
|
286
296
|
dq: deque[tuple[int, int, str]] = deque()
|
@@ -293,13 +303,13 @@ def _iterdir(
|
|
293
303
|
payload = {**default_payload, "parentFileId": parent_id}
|
294
304
|
for i in count(1):
|
295
305
|
payload["Page"] = i
|
296
|
-
if last_ts and
|
306
|
+
if last_ts and cooldown > 0 and (remains := last_ts + cooldown - time()) > 0:
|
297
307
|
if async_:
|
298
308
|
yield async_sleep(remains)
|
299
309
|
else:
|
300
310
|
sleep(remains)
|
301
311
|
resp = yield fs_files(payload, async_=async_, **request_kwargs)
|
302
|
-
if
|
312
|
+
if cooldown > 0:
|
303
313
|
last_ts = time()
|
304
314
|
check_response(resp)
|
305
315
|
info_list = resp["data"]["InfoList"]
|
@@ -323,6 +333,8 @@ def _iterdir(
|
|
323
333
|
continue
|
324
334
|
elif pred:
|
325
335
|
if depth >= min_depth:
|
336
|
+
if extra_data:
|
337
|
+
info = dict(extra_data, **info)
|
326
338
|
yield Yield(info)
|
327
339
|
if pred is 1:
|
328
340
|
continue
|
@@ -336,7 +348,7 @@ def _iterdir(
|
|
336
348
|
break
|
337
349
|
if next_id := resp["data"]["Next"]:
|
338
350
|
payload["next"] = next_id
|
339
|
-
return run_gen_step_iter(gen_step, async_
|
351
|
+
return run_gen_step_iter(gen_step, async_)
|
340
352
|
|
341
353
|
|
342
354
|
@overload
|
@@ -346,7 +358,8 @@ def iterdir(
|
|
346
358
|
min_depth: int = 1,
|
347
359
|
max_depth: int = 1,
|
348
360
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
349
|
-
|
361
|
+
cooldown: int | float = 0,
|
362
|
+
base_url: None | str | Callable[[], str] = None,
|
350
363
|
use_list_new: bool = False,
|
351
364
|
*,
|
352
365
|
async_: Literal[False] = False,
|
@@ -360,7 +373,8 @@ def iterdir(
|
|
360
373
|
min_depth: int = 1,
|
361
374
|
max_depth: int = 1,
|
362
375
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
363
|
-
|
376
|
+
cooldown: int | float = 0,
|
377
|
+
base_url: None | str | Callable[[], str] = None,
|
364
378
|
use_list_new: bool = False,
|
365
379
|
*,
|
366
380
|
async_: Literal[True],
|
@@ -373,7 +387,8 @@ def iterdir(
|
|
373
387
|
min_depth: int = 1,
|
374
388
|
max_depth: int = 1,
|
375
389
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
376
|
-
|
390
|
+
cooldown: int | float = 0,
|
391
|
+
base_url: None | str | Callable[[], str] = None,
|
377
392
|
use_list_new: bool = False,
|
378
393
|
*,
|
379
394
|
async_: Literal[False, True] = False,
|
@@ -392,7 +407,8 @@ def iterdir(
|
|
392
407
|
- 如果返回值是 False,则跳过此节点(但依然会继续处理位于此节点之下的节点)
|
393
408
|
- 如果返回值是 True,则输出此节点
|
394
409
|
|
395
|
-
:param
|
410
|
+
:param cooldown: 两次调用之间,冷却的时间(用两次调用开始时的时间差,而不是一次完成到下一次开始的时间差)
|
411
|
+
:param base_url: 基地址,如果为空,则用默认
|
396
412
|
:param use_list_new: 使用 `P123Client.fs_list_new` 而不是 `P123Client.fs_list`
|
397
413
|
:param async_: 是否异步
|
398
414
|
:param request_kwargs: 其它请求参数
|
@@ -405,7 +421,8 @@ def iterdir(
|
|
405
421
|
min_depth=min_depth,
|
406
422
|
max_depth=max_depth,
|
407
423
|
predicate=predicate,
|
408
|
-
|
424
|
+
cooldown=cooldown,
|
425
|
+
base_url=base_url,
|
409
426
|
async_=async_,
|
410
427
|
**request_kwargs,
|
411
428
|
)
|
@@ -419,7 +436,8 @@ def share_iterdir(
|
|
419
436
|
min_depth: int = 1,
|
420
437
|
max_depth: int = 1,
|
421
438
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
422
|
-
|
439
|
+
cooldown: int | float = 0,
|
440
|
+
base_url: None | str | Callable[[], str] = None,
|
423
441
|
*,
|
424
442
|
async_: Literal[False] = False,
|
425
443
|
**request_kwargs,
|
@@ -433,7 +451,8 @@ def share_iterdir(
|
|
433
451
|
min_depth: int = 1,
|
434
452
|
max_depth: int = 1,
|
435
453
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
436
|
-
|
454
|
+
cooldown: int | float = 0,
|
455
|
+
base_url: None | str | Callable[[], str] = None,
|
437
456
|
*,
|
438
457
|
async_: Literal[True],
|
439
458
|
**request_kwargs,
|
@@ -446,15 +465,24 @@ def share_iterdir(
|
|
446
465
|
min_depth: int = 1,
|
447
466
|
max_depth: int = 1,
|
448
467
|
predicate: None | Callable[[dict], Literal[None, 0, 1, False, True]] = None,
|
449
|
-
|
468
|
+
cooldown: int | float = 0,
|
469
|
+
base_url: None | str | Callable[[], str] = None,
|
450
470
|
*,
|
451
471
|
async_: Literal[False, True] = False,
|
452
472
|
**request_kwargs,
|
453
473
|
) -> Iterator[dict] | AsyncIterator[dict]:
|
454
474
|
"""遍历分享的文件列表
|
455
475
|
|
456
|
-
:param share_key:
|
457
|
-
|
476
|
+
:param share_key: 分享码或者分享链接(可以携带提取码)
|
477
|
+
|
478
|
+
.. note::
|
479
|
+
在分享链接中的位置形如 f"https://www.123pan.com/s/{share_key}"
|
480
|
+
|
481
|
+
如果携带提取码,要写成 f"https://www.123pan.com/s/{share_key}?提取码:{share_pwd}"
|
482
|
+
|
483
|
+
上面的基地址不必是 "https://www.123pan.com"
|
484
|
+
|
485
|
+
:param share_pwd: 提取码(4个文字),可以为空
|
458
486
|
:param parent_id: 父目录 id,默认是根目录
|
459
487
|
:param min_depth: 最小深度,小于此深度的不会输出
|
460
488
|
:param max_depth: 最大深度,大于此深度的不会输出,如果小于 0 则无限
|
@@ -465,20 +493,33 @@ def share_iterdir(
|
|
465
493
|
- 如果返回值是 False,则跳过此节点(但依然会继续处理位于此节点之下的节点)
|
466
494
|
- 如果返回值是 True,则输出此节点
|
467
495
|
|
468
|
-
:param
|
496
|
+
:param cooldown: 两次调用之间,冷却的时间(用两次调用开始时的时间差,而不是一次完成到下一次开始的时间差)
|
497
|
+
:param base_url: 基地址,如果为空,则用默认(如果 `share_key` 是分享链接,则用它的 origin)
|
469
498
|
:param async_: 是否异步
|
470
499
|
:param request_kwargs: 其它请求参数
|
471
500
|
|
472
501
|
:return: 迭代器,产生文件或目录的信息
|
473
502
|
"""
|
503
|
+
if share_key.startswith(("http://", "https://")):
|
504
|
+
urlp = urlsplit(share_key)
|
505
|
+
if not base_url:
|
506
|
+
base_url = f"{urlp.scheme}://{urlp.netloc}"
|
507
|
+
share_key = urlp.path.rsplit("/", 1)[-1]
|
508
|
+
if not share_pwd:
|
509
|
+
share_pwd = urlp.query.rpartition(":")[-1]
|
510
|
+
if len(share_pwd) != 4:
|
511
|
+
share_pwd = ""
|
512
|
+
payload = {"ShareKey": share_key, "SharePwd": share_pwd}
|
474
513
|
return _iterdir(
|
475
514
|
P123Client.share_fs_list,
|
476
|
-
|
515
|
+
payload,
|
477
516
|
parent_id=parent_id,
|
478
517
|
min_depth=min_depth,
|
479
518
|
max_depth=max_depth,
|
480
519
|
predicate=predicate,
|
481
|
-
|
520
|
+
cooldown=cooldown,
|
521
|
+
base_url=base_url,
|
522
|
+
extra_data=payload,
|
482
523
|
async_=async_,
|
483
524
|
**request_kwargs,
|
484
525
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: p123client
|
3
|
-
Version: 0.0.6.
|
3
|
+
Version: 0.0.6.9
|
4
4
|
Summary: Python 123 webdisk client.
|
5
5
|
Home-page: https://github.com/ChenyangGao/p123client
|
6
6
|
License: MIT
|
@@ -31,7 +31,7 @@ Requires-Dist: python-filewrap (>=0.2.6.1)
|
|
31
31
|
Requires-Dist: python-hashtools (>=0.0.3.3)
|
32
32
|
Requires-Dist: python-http_request (>=0.0.7)
|
33
33
|
Requires-Dist: python-httpfile (>=0.0.5)
|
34
|
-
Requires-Dist: python-iterutils (>=0.2)
|
34
|
+
Requires-Dist: python-iterutils (>=0.2.4.1)
|
35
35
|
Requires-Dist: python-property (>=0.0.3)
|
36
36
|
Requires-Dist: yarl
|
37
37
|
Project-URL: Repository, https://github.com/ChenyangGao/p123client
|
@@ -1,12 +1,12 @@
|
|
1
1
|
LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
2
2
|
p123client/__init__.py,sha256=gfUum-q3f_XuXOk2HpArDAIxAlscZm8Fau1kiNkNFpg,214
|
3
|
-
p123client/client.py,sha256=
|
3
|
+
p123client/client.py,sha256=sjv9kzsiVl8hFMsaaAMGjCpsbewo3LaXqbYUpzhh5bI,258804
|
4
4
|
p123client/const.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
|
5
5
|
p123client/exception.py,sha256=020xGo8WQmGCJz1UzNg9oFzpEvToQcgTye0s6lkFASQ,1540
|
6
6
|
p123client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
p123client/tool/__init__.py,sha256=
|
7
|
+
p123client/tool/__init__.py,sha256=rZIgiXMNN21acq6OdT3ywQdPQRSmxDrifzHmhj-5E8E,18860
|
8
8
|
p123client/type.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
|
9
|
-
p123client-0.0.6.
|
10
|
-
p123client-0.0.6.
|
11
|
-
p123client-0.0.6.
|
12
|
-
p123client-0.0.6.
|
9
|
+
p123client-0.0.6.9.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
10
|
+
p123client-0.0.6.9.dist-info/METADATA,sha256=BGbHQeCskMwE3Lxh985P00v3W4BDi49-b-5-YRKJEHc,8859
|
11
|
+
p123client-0.0.6.9.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
12
|
+
p123client-0.0.6.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|