p123client 0.0.6.10.2__py3-none-any.whl → 0.0.7.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.
p123client/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 0, 6)
5
+ __version__ = (0, 0, 7)
6
6
 
7
7
  from .client import *
8
8
  from .const import *
p123client/client.py CHANGED
@@ -22,7 +22,7 @@ from os import fsdecode, fstat, isatty, PathLike
22
22
  from os.path import basename
23
23
  from pathlib import Path, PurePath
24
24
  from re import compile as re_compile, MULTILINE
25
- from string import digits, ascii_uppercase
25
+ from string import digits, hexdigits, ascii_uppercase
26
26
  from sys import _getframe
27
27
  from tempfile import TemporaryFile
28
28
  from typing import cast, overload, Any, Final, Literal, Self
@@ -1644,7 +1644,7 @@ class P123OpenClient:
1644
1644
 
1645
1645
  :payload:
1646
1646
  - businessType: int = <default> 💡 业务类型:2:转码空间
1647
- - category: int = <default> 💡 分类代码:0:未知 1:音频 2:视频 3:图片 4:音频 5:其它
1647
+ - category: int = <default> 💡 分类代码:0:未知 1:音频 2:视频 3:图片 4:音频 5:其它 6:保险箱 7:收藏夹
1648
1648
  - lastFileId: int = <default> 💡 上一页的最后一条记录的 FileID,翻页查询时需要填写
1649
1649
  - limit: int = 100 💡 分页大小,最多 100
1650
1650
  - parentFileId: int | str = 0 💡 父目录 id,根目录是 0
@@ -4424,6 +4424,125 @@ class P123OpenClient:
4424
4424
 
4425
4425
  ########## Upload API ##########
4426
4426
 
4427
+ @overload
4428
+ def upload_complete(
4429
+ self,
4430
+ payload: str | dict,
4431
+ /,
4432
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4433
+ *,
4434
+ async_: Literal[False] = False,
4435
+ **request_kwargs,
4436
+ ) -> dict:
4437
+ ...
4438
+ @overload
4439
+ def upload_complete(
4440
+ self,
4441
+ payload: str | dict,
4442
+ /,
4443
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4444
+ *,
4445
+ async_: Literal[True],
4446
+ **request_kwargs,
4447
+ ) -> Coroutine[Any, Any, dict]:
4448
+ ...
4449
+ def upload_complete(
4450
+ self,
4451
+ payload: str | dict,
4452
+ /,
4453
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4454
+ *,
4455
+ async_: Literal[False, True] = False,
4456
+ **request_kwargs,
4457
+ ) -> dict | Coroutine[Any, Any, dict]:
4458
+ """上传完毕
4459
+
4460
+ POST https://open-api.123pan.com/upload/v1/file/upload_complete
4461
+
4462
+ .. admonition:: Reference
4463
+
4464
+ /API列表/文件管理/上传/V1(旧)/上传完毕
4465
+
4466
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/hkdmcmvg437rfu6x
4467
+
4468
+ :payload:
4469
+ - preuploadID: str 💡 预上传 id
4470
+
4471
+ :return:
4472
+ 返回的数据说明如下:
4473
+
4474
+ .. code:: python
4475
+
4476
+ {
4477
+ "async": bool, # 是否需要异步查询上传结果
4478
+ "completed": bool, # 上传是否完成
4479
+ "fileID": int, # 上传的文件 id
4480
+ }
4481
+ """
4482
+ api = complete_url("/upload/v1/file/upload_complete", base_url)
4483
+ if not isinstance(payload, dict):
4484
+ payload = {"preuploadID": payload}
4485
+ return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4486
+
4487
+ @overload
4488
+ def upload_complete_v2(
4489
+ self,
4490
+ payload: str | dict,
4491
+ /,
4492
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4493
+ *,
4494
+ async_: Literal[False] = False,
4495
+ **request_kwargs,
4496
+ ) -> dict:
4497
+ ...
4498
+ @overload
4499
+ def upload_complete_v2(
4500
+ self,
4501
+ payload: str | dict,
4502
+ /,
4503
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4504
+ *,
4505
+ async_: Literal[True],
4506
+ **request_kwargs,
4507
+ ) -> Coroutine[Any, Any, dict]:
4508
+ ...
4509
+ def upload_complete_v2(
4510
+ self,
4511
+ payload: str | dict,
4512
+ /,
4513
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4514
+ *,
4515
+ async_: Literal[False, True] = False,
4516
+ **request_kwargs,
4517
+ ) -> dict | Coroutine[Any, Any, dict]:
4518
+ """上传完毕
4519
+
4520
+ POST https://open-api.123pan.com/upload/v2/file/upload_complete
4521
+
4522
+ .. admonition:: Reference
4523
+
4524
+ /API列表/文件管理/上传/V2(推荐)/上传完毕
4525
+
4526
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/fzzc5o8gok517720
4527
+
4528
+ :payload:
4529
+ - preuploadID: str 💡 预上传 id
4530
+
4531
+ :return:
4532
+ 返回的数据说明如下:
4533
+
4534
+ .. code:: python
4535
+
4536
+ {
4537
+ "completed": bool, # 上传是否完成
4538
+ "fileID": int, # 上传的文件 id
4539
+ }
4540
+ """
4541
+ api = complete_url("/upload/v2/file/upload_complete", base_url)
4542
+ if not isinstance(payload, dict):
4543
+ payload = {"preuploadID": payload}
4544
+ return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4545
+
4427
4546
  @overload
4428
4547
  def upload_create(
4429
4548
  self,
@@ -4465,9 +4584,17 @@ class P123OpenClient:
4465
4584
  - 开发者上传单文件大小限制 10 GB
4466
4585
  - 不会重名
4467
4586
 
4587
+ .. note::
4588
+ /API列表/文件管理/上传/V1(旧)/💡上传流程说明
4589
+
4590
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/il16qi0opiel4889
4591
+
4592
+ 1. 请求创建文件接口,接口返回的 "reuse" 为 "true" 时,表示秒传成功,上传结束。
4593
+ 2. 非秒传情况将会返回预上传ID ``preuploadID`` 与分片大小 ``sliceSize``,请将文件根据分片大小切分。
4594
+
4468
4595
  .. admonition:: Reference
4469
4596
 
4470
- /API列表/文件管理/上传/V1/创建文件
4597
+ /API列表/文件管理/上传/V1(旧)/创建文件
4471
4598
 
4472
4599
  https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/lrfuu3qe7q1ul8ig
4473
4600
 
@@ -4501,7 +4628,7 @@ class P123OpenClient:
4501
4628
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4502
4629
 
4503
4630
  @overload
4504
- def upload_url(
4631
+ def upload_create_v2(
4505
4632
  self,
4506
4633
  payload: dict,
4507
4634
  /,
@@ -4512,7 +4639,7 @@ class P123OpenClient:
4512
4639
  ) -> dict:
4513
4640
  ...
4514
4641
  @overload
4515
- def upload_url(
4642
+ def upload_create_v2(
4516
4643
  self,
4517
4644
  payload: dict,
4518
4645
  /,
@@ -4522,7 +4649,7 @@ class P123OpenClient:
4522
4649
  **request_kwargs,
4523
4650
  ) -> Coroutine[Any, Any, dict]:
4524
4651
  ...
4525
- def upload_url(
4652
+ def upload_create_v2(
4526
4653
  self,
4527
4654
  payload: dict,
4528
4655
  /,
@@ -4531,26 +4658,105 @@ class P123OpenClient:
4531
4658
  async_: Literal[False, True] = False,
4532
4659
  **request_kwargs,
4533
4660
  ) -> dict | Coroutine[Any, Any, dict]:
4534
- """获取上传地址&上传分片
4661
+ """创建文件
4535
4662
 
4536
- POST https://open-api.123pan.com/upload/v1/file/get_upload_url
4663
+ POST https://open-api.123pan.com/upload/v2/file/create
4537
4664
 
4538
4665
  .. note::
4539
- 有多个分片时,轮流分别根据序号获取下载链接,然后 PUT 方法上传分片。由于上传链接会过期,所以没必要提前获取一大批
4666
+ - 文件名要小于 256 个字符且不能包含以下字符:``"\\/:*?|><``
4667
+ - 文件名不能全部是空格
4668
+ - 开发者上传单文件大小限制 10 GB
4669
+ - 不会重名
4670
+
4671
+ .. note::
4672
+ /API列表/文件管理/上传/V2(推荐)/💡上传流程说明
4673
+
4674
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/xogi45g7okqk7svr#uqhyW
4675
+
4676
+ 1. 调用创建文件接口,接口返回的 "reuse" 为 "true" 时,表示秒传成功,上传结束。
4677
+ 2. 非秒传情况将会返回预上传ID ``preuploadID`` 与分片大小 ``sliceSize``,请将文件根据分片大小切分。
4678
+ 3. 非秒传情况下返回 "servers" 为后续上传文件的对应域名(重要),多个任选其一。
4540
4679
 
4541
4680
  .. admonition:: Reference
4542
4681
 
4543
- /API列表/文件管理/上传/V1/获取上传地址&上传分片
4682
+ /API列表/文件管理/上传/V2(推荐)/创建文件
4544
4683
 
4545
- https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/sonz9n085gnz0n3m
4684
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/txow0iqviqsgotfl
4546
4685
 
4547
4686
  :payload:
4548
- - preuploadID: str 💡 预上传 id
4549
- - sliceNo: int 💡 分片序号,从 1 开始自增
4687
+ - containDir: "false" | "true" = "false" 💡 上传文件是否包含路径
4688
+ - filename: str 💡 文件名,但 ``containDir`` 为 "true" 时,视为路径
4689
+ - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 跳过/报错 1: 保留/后缀编号 2: 替换/覆盖
4690
+ - etag: str 💡 文件 md5
4691
+ - parentFileID: int = 0 💡 父目录 id,根目录是 0
4692
+ - size: int 💡 文件大小,单位:字节
4693
+
4694
+ :return:
4695
+ 返回的数据说明如下:
4696
+
4697
+ .. code:: python
4698
+
4699
+ {
4700
+ "fileID": str, # 上传后的文件 id。当已有相同 ``size`` 和 ``etag`` 的文件时,会发生秒传
4701
+ "preuploadID": str, # 预上传 id。当 ``reuse`` 为 "true" 时,该字段不存在
4702
+ "reuse": bool, # 是否秒传,返回 "true" 时表示文件已上传成功
4703
+ "sliceSize": int, # 分片大小,必须按此大小生成文件分片再上传。当 ``reuse`` 为 "true" 时,该字段不存在
4704
+ "servers": list[str], # 上传地址,多个任选其一
4705
+ }
4550
4706
  """
4551
- api = complete_url("/upload/v1/file/get_upload_url", base_url)
4707
+ api = complete_url("/upload/v2/file/create", base_url)
4708
+ payload = dict_to_lower_merge(payload, {
4709
+ "parentFileId": 0,
4710
+ "containDir": "false",
4711
+ })
4712
+ if "duplicate" in payload and not payload["duplicate"]:
4713
+ del payload["duplicate"]
4552
4714
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4553
4715
 
4716
+ @overload
4717
+ def upload_domain(
4718
+ self,
4719
+ /,
4720
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4721
+ *,
4722
+ async_: Literal[False] = False,
4723
+ **request_kwargs,
4724
+ ) -> dict:
4725
+ ...
4726
+ @overload
4727
+ def upload_domain(
4728
+ self,
4729
+ /,
4730
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4731
+ *,
4732
+ async_: Literal[True],
4733
+ **request_kwargs,
4734
+ ) -> Coroutine[Any, Any, dict]:
4735
+ ...
4736
+ def upload_domain(
4737
+ self,
4738
+ /,
4739
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4740
+ *,
4741
+ async_: Literal[False, True] = False,
4742
+ **request_kwargs,
4743
+ ) -> dict | Coroutine[Any, Any, dict]:
4744
+ """获取上传域名
4745
+
4746
+ GET https://open-api.123pan.com/upload/v2/file/domain
4747
+
4748
+ .. admonition:: Reference
4749
+
4750
+ /API列表/文件管理/上传/V2(推荐)/获取上传域名
4751
+
4752
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/agn8lolktbqie7p9
4753
+
4754
+ :payload:
4755
+ - preuploadID: str 💡 预上传 id
4756
+ """
4757
+ api = complete_url("/upload/v2/file/domain", base_url)
4758
+ return self.request(api, async_=async_, **request_kwargs)
4759
+
4554
4760
  @overload
4555
4761
  def upload_list(
4556
4762
  self,
@@ -4591,7 +4797,7 @@ class P123OpenClient:
4591
4797
 
4592
4798
  .. admonition:: Reference
4593
4799
 
4594
- /API列表/文件管理/上传/V1/列举已上传分片(非必需)
4800
+ /API列表/文件管理/上传/V1(旧)/列举已上传分片(非必需)
4595
4801
 
4596
4802
  https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/dd28ws4bfn644cny
4597
4803
 
@@ -4604,69 +4810,229 @@ class P123OpenClient:
4604
4810
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4605
4811
 
4606
4812
  @overload
4607
- def upload_complete(
4813
+ def upload_result(
4814
+ self,
4815
+ payload: str | dict,
4816
+ /,
4817
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4818
+ *,
4819
+ async_: Literal[False] = False,
4820
+ **request_kwargs,
4821
+ ) -> dict:
4822
+ ...
4823
+ @overload
4824
+ def upload_result(
4825
+ self,
4826
+ payload: str | dict,
4827
+ /,
4828
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4829
+ *,
4830
+ async_: Literal[True],
4831
+ **request_kwargs,
4832
+ ) -> Coroutine[Any, Any, dict]:
4833
+ ...
4834
+ def upload_result(
4608
4835
  self,
4609
4836
  payload: str | dict,
4610
4837
  /,
4611
4838
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4612
4839
  *,
4840
+ async_: Literal[False, True] = False,
4841
+ **request_kwargs,
4842
+ ) -> dict | Coroutine[Any, Any, dict]:
4843
+ """异步轮询获取上传结果
4844
+
4845
+ POST https://open-api.123pan.com/upload/v1/file/upload_async_result
4846
+
4847
+ .. admonition:: Reference
4848
+
4849
+ /API列表/文件管理/上传/V1(旧)/异步轮询获取上传结果
4850
+
4851
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/qgcosr6adkmm51h7
4852
+
4853
+ :payload:
4854
+ - preuploadID: str 💡 预上传 id
4855
+
4856
+ :return:
4857
+ 返回的数据说明如下:
4858
+
4859
+ .. code:: python
4860
+
4861
+ {
4862
+ "completed": bool, # 上传合并是否完成,如果为 False,请至少 1 秒后再发起轮询
4863
+ "fileID": int, # 上传的文件 id
4864
+ }
4865
+ """
4866
+ api = complete_url("/upload/v1/file/upload_async_result", base_url)
4867
+ if not isinstance(payload, dict):
4868
+ payload = {"preuploadID": payload}
4869
+ return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4870
+
4871
+ @overload
4872
+ def upload_single(
4873
+ self,
4874
+ payload: dict,
4875
+ /,
4876
+ file: Buffer | SupportsRead[Buffer] | Iterable[Buffer],
4877
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4878
+ *,
4879
+ async_: Literal[False] = False,
4880
+ **request_kwargs,
4881
+ ) -> dict:
4882
+ ...
4883
+ @overload
4884
+ def upload_single(
4885
+ self,
4886
+ payload: dict,
4887
+ /,
4888
+ file: Buffer | SupportsRead[Buffer] | Iterable[Buffer] | AsyncIterable[Buffer],
4889
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4890
+ *,
4891
+ async_: Literal[True],
4892
+ **request_kwargs,
4893
+ ) -> Coroutine[Any, Any, dict]:
4894
+ ...
4895
+ def upload_single(
4896
+ self,
4897
+ payload: dict,
4898
+ /,
4899
+ file: Buffer | SupportsRead[Buffer] | Iterable[Buffer] | AsyncIterable[Buffer],
4900
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4901
+ *,
4902
+ async_: Literal[False, True] = False,
4903
+ **request_kwargs,
4904
+ ) -> dict | Coroutine[Any, Any, dict]:
4905
+ """单步上传
4906
+
4907
+ POST https://open-api.123pan.com/upload/v2/file/single/create
4908
+
4909
+ .. note::
4910
+ - 文件名要小于 256 个字符且不能包含以下任何字符:``"\\/:*?|><``
4911
+ - 文件名不能全部是空格
4912
+ - 请求头包含 ``Content-Type: multipart/form-data``
4913
+ - 此接口限制开发者上传单文件大小为 1 GB
4914
+ - 上传域名是 ``client.upload_domain_open`` 响应中的域名
4915
+ - 此接口用于实现小文件单步上传一次 HTTP 请求交互即可完成上传
4916
+
4917
+ .. admonition:: Reference
4918
+
4919
+ /API列表/文件管理/上传/V2(推荐)/单步上传
4920
+
4921
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/xhiht1uh3yp92pzc
4922
+
4923
+ :payload:
4924
+ - containDir: "false" | "true" = "false" 💡 上传文件是否包含路径
4925
+ - filename: str 💡 文件名,但 ``containDir`` 为 "true" 时,视为路径
4926
+ - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 跳过/报错 1: 保留/后缀编号 2: 替换/覆盖
4927
+ - etag: str 💡 文件 md5
4928
+ - parentFileID: int = 0 💡 父目录 id,根目录是 0
4929
+ - size: int 💡 文件大小,单位:字节
4930
+ - file: Any 💡 分片二进制流(请单独传递 ``file`` 参数)
4931
+
4932
+ :return:
4933
+ 返回的数据说明如下:
4934
+
4935
+ .. code:: python
4936
+
4937
+ {
4938
+ "completed": bool, # 是否上传完成(如果 "completed" 为 "true" 时,则说明上传完成)
4939
+ "fileID": int, # 文件 ID。当 123 云盘已有该文件,则会发生秒传。此时会将文件 ID 字段返回。唯一
4940
+ }
4941
+ """
4942
+ payload = dict_to_lower_merge(payload, {
4943
+ "parentFileId": "0",
4944
+ "containDir": "false",
4945
+ })
4946
+ if "duplicate" in payload and not payload["duplicate"]:
4947
+ del payload["duplicate"]
4948
+ for k, v in payload.items():
4949
+ if not isinstance(v, str):
4950
+ payload[k] = str(v)
4951
+ if async_:
4952
+ headers, request_kwargs["data"] = encode_multipart_data_async(payload, {"file": file})
4953
+ else:
4954
+ headers, request_kwargs["data"] = encode_multipart_data(payload, {"file": file}) # type: ignore
4955
+ request_kwargs["headers"] = {**(request_kwargs.get("headers") or {}), **headers}
4956
+ return self.request(
4957
+ "/upload/v2/file/single/create",
4958
+ "POST",
4959
+ base_url=base_url,
4960
+ async_=async_,
4961
+ **request_kwargs,
4962
+ )
4963
+
4964
+ @overload
4965
+ def upload_slice(
4966
+ self,
4967
+ payload: dict,
4968
+ /,
4969
+ slice: Buffer | SupportsRead[Buffer] | Iterable[Buffer],
4970
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4971
+ *,
4613
4972
  async_: Literal[False] = False,
4614
4973
  **request_kwargs,
4615
4974
  ) -> dict:
4616
4975
  ...
4617
4976
  @overload
4618
- def upload_complete(
4977
+ def upload_slice(
4619
4978
  self,
4620
- payload: str | dict,
4979
+ payload: dict,
4621
4980
  /,
4622
- base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4981
+ slice: Buffer | SupportsRead[Buffer] | Iterable[Buffer] | AsyncIterable[Buffer],
4982
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4623
4983
  *,
4624
4984
  async_: Literal[True],
4625
4985
  **request_kwargs,
4626
4986
  ) -> Coroutine[Any, Any, dict]:
4627
4987
  ...
4628
- def upload_complete(
4988
+ def upload_slice(
4629
4989
  self,
4630
- payload: str | dict,
4990
+ payload: dict,
4631
4991
  /,
4632
- base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4992
+ slice: Buffer | SupportsRead[Buffer] | Iterable[Buffer] | AsyncIterable[Buffer],
4993
+ base_url: str | Callable[[], str] = "https://openapi-upload.123242.com",
4633
4994
  *,
4634
4995
  async_: Literal[False, True] = False,
4635
4996
  **request_kwargs,
4636
4997
  ) -> dict | Coroutine[Any, Any, dict]:
4637
- """上传完毕
4998
+ """上传文件文件
4638
4999
 
4639
- POST https://open-api.123pan.com/upload/v1/file/upload_complete
5000
+ POST https://open-api.123pan.com/upload/v2/file/slice
5001
+
5002
+ .. note::
5003
+ - 上传域名是创建文件接口响应中的 "servers"
5004
+ - 请求头包含 ``Content-Type: multipart/form-data``
4640
5005
 
4641
5006
  .. admonition:: Reference
4642
5007
 
4643
- /API列表/文件管理/上传/V1/上传完毕
5008
+ /API列表/文件管理/上传/V2(推荐)/上传分片
4644
5009
 
4645
- https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/hkdmcmvg437rfu6x
5010
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/txow0iqviqsgotfl
4646
5011
 
4647
5012
  :payload:
4648
- - preuploadID: str 💡 预上传 id
4649
-
4650
- :return:
4651
- 返回的数据说明如下:
4652
-
4653
- .. code:: python
4654
-
4655
- {
4656
- "async": bool, # 是否需要异步查询上传结果
4657
- "completed": bool, # 上传是否完成
4658
- "fileID": int, # 上传的文件 id
4659
- }
5013
+ - preuploadID: str 💡 预上传ID
5014
+ - sliceNo: int 💡 分片序号,从 1 开始自增
5015
+ - sliceMD5: str 💡 当前分片 md5
5016
+ - slice: Any 💡 分片二进制流(请单独传递 ``slice`` 参数)
4660
5017
  """
4661
- api = complete_url("/upload/v1/file/upload_complete", base_url)
4662
- if not isinstance(payload, dict):
4663
- payload = {"preuploadID": payload}
4664
- return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
5018
+ payload["sliceNo"] = str(payload.get("sliceNo", 1))
5019
+ if async_:
5020
+ headers, request_kwargs["data"] = encode_multipart_data_async(payload, {"slice": slice})
5021
+ else:
5022
+ headers, request_kwargs["data"] = encode_multipart_data(payload, {"slice": slice}) # type: ignore
5023
+ request_kwargs["headers"] = {**(request_kwargs.get("headers") or {}), **headers}
5024
+ return self.request(
5025
+ "/upload/v2/file/slice",
5026
+ "POST",
5027
+ base_url=base_url,
5028
+ async_=async_,
5029
+ **request_kwargs,
5030
+ )
4665
5031
 
4666
5032
  @overload
4667
- def upload_result(
5033
+ def upload_url(
4668
5034
  self,
4669
- payload: str | dict,
5035
+ payload: dict,
4670
5036
  /,
4671
5037
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4672
5038
  *,
@@ -4675,9 +5041,9 @@ class P123OpenClient:
4675
5041
  ) -> dict:
4676
5042
  ...
4677
5043
  @overload
4678
- def upload_result(
5044
+ def upload_url(
4679
5045
  self,
4680
- payload: str | dict,
5046
+ payload: dict,
4681
5047
  /,
4682
5048
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4683
5049
  *,
@@ -4685,44 +5051,37 @@ class P123OpenClient:
4685
5051
  **request_kwargs,
4686
5052
  ) -> Coroutine[Any, Any, dict]:
4687
5053
  ...
4688
- def upload_result(
5054
+ def upload_url(
4689
5055
  self,
4690
- payload: str | dict,
5056
+ payload: dict,
4691
5057
  /,
4692
5058
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
4693
5059
  *,
4694
5060
  async_: Literal[False, True] = False,
4695
5061
  **request_kwargs,
4696
5062
  ) -> dict | Coroutine[Any, Any, dict]:
4697
- """异步轮询获取上传结果
5063
+ """获取上传地址&上传分片
4698
5064
 
4699
- POST https://open-api.123pan.com/upload/v1/file/upload_async_result
5065
+ POST https://open-api.123pan.com/upload/v1/file/get_upload_url
5066
+
5067
+ .. note::
5068
+ 有多个分片时,轮流分别根据序号获取下载链接,然后 PUT 方法上传分片。由于上传链接会过期,所以没必要提前获取一大批
4700
5069
 
4701
5070
  .. admonition:: Reference
4702
5071
 
4703
- /API列表/文件管理/上传/V1/异步轮询获取上传结果
5072
+ /API列表/文件管理/上传/V1(旧)/获取上传地址&上传分片
4704
5073
 
4705
- https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/qgcosr6adkmm51h7
5074
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/sonz9n085gnz0n3m
4706
5075
 
4707
5076
  :payload:
4708
5077
  - preuploadID: str 💡 预上传 id
4709
-
4710
- :return:
4711
- 返回的数据说明如下:
4712
-
4713
- .. code:: python
4714
-
4715
- {
4716
- "completed": bool, # 上传合并是否完成,如果为 False,请至少 1 秒后再发起轮询
4717
- "fileID": int, # 上传的文件 id
4718
- }
5078
+ - sliceNo: int 💡 分片序号,从 1 开始自增
4719
5079
  """
4720
- api = complete_url("/upload/v1/file/upload_async_result", base_url)
4721
- if not isinstance(payload, dict):
4722
- payload = {"preuploadID": payload}
5080
+ api = complete_url("/upload/v1/file/get_upload_url", base_url)
4723
5081
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
4724
5082
 
4725
- # TODO: 如果已经有 md5 和 大小,则先尝试直接上传,而不是打开文件
5083
+ # TODO: 如果已经有 md5 和 大小,则先尝试直接上传,而不是打开文件,等确定不能妙传,再打开文件
5084
+ # TODO: 支持 v2 接口,以及上传单个文件的接口(可以设定一个参数,是否优先用 upload_single,只要文件大小在 1 GB 内)
4726
5085
  @overload
4727
5086
  def upload_file(
4728
5087
  self,
@@ -4785,7 +5144,7 @@ class P123OpenClient:
4785
5144
 
4786
5145
  .. admonition:: Reference
4787
5146
 
4788
- /API列表/文件管理/上传/v1/💡上传流程说明
5147
+ /API列表/文件管理/上传/V1(旧)/💡上传流程说明
4789
5148
 
4790
5149
  https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/il16qi0opiel4889
4791
5150
 
@@ -5150,10 +5509,15 @@ class P123OpenClient:
5150
5509
  transcode_upload_open = transcode_upload
5151
5510
  transcode_video_open = transcode_video
5152
5511
  upload_complete_open = upload_complete
5512
+ upload_complete_v2_open = upload_complete_v2
5153
5513
  upload_create_open = upload_create
5514
+ upload_create_v2_open = upload_create_v2
5515
+ upload_domain_open = upload_domain
5154
5516
  upload_file_open = upload_file
5155
5517
  upload_list_open = upload_list
5156
5518
  upload_result_open = upload_result
5519
+ upload_single_open = upload_single
5520
+ upload_slice_open = upload_slice
5157
5521
  upload_url_open = upload_url
5158
5522
  user_info_open = user_info
5159
5523
 
@@ -5446,7 +5810,7 @@ class P123Client(P123OpenClient):
5446
5810
  """执行一次自动扫码,但并不因此更新 ``self.token``
5447
5811
 
5448
5812
  .. caution::
5449
- 非会员目前只支持同时在线 3 台登录设备
5813
+ 非会员目前只支持同时在线 3 台登录设备,VIP 则支持同时在线 10 台
5450
5814
 
5451
5815
  :param platform: 用哪个设备平台扫码
5452
5816
  :param base_url: 接口的基地址
@@ -6668,6 +7032,8 @@ class P123Client(P123OpenClient):
6668
7032
  - 3: 图片
6669
7033
  - 4: 音频
6670
7034
  - 5: 其它
7035
+ - 6: 保险箱
7036
+ - 7: 收藏夹
6671
7037
 
6672
7038
  - dateGranularity: int = <default> 💡 按时间分组展示
6673
7039
 
@@ -7062,6 +7428,98 @@ class P123Client(P123OpenClient):
7062
7428
  **request_kwargs,
7063
7429
  )
7064
7430
 
7431
+ @overload
7432
+ def fs_safe_box_lock(
7433
+ self,
7434
+ /,
7435
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7436
+ *,
7437
+ async_: Literal[False] = False,
7438
+ **request_kwargs,
7439
+ ) -> dict:
7440
+ ...
7441
+ @overload
7442
+ def fs_safe_box_lock(
7443
+ self,
7444
+ /,
7445
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7446
+ *,
7447
+ async_: Literal[True],
7448
+ **request_kwargs,
7449
+ ) -> Coroutine[Any, Any, dict]:
7450
+ ...
7451
+ def fs_safe_box_lock(
7452
+ self,
7453
+ /,
7454
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7455
+ *,
7456
+ async_: Literal[False, True] = False,
7457
+ **request_kwargs,
7458
+ ) -> dict | Coroutine[Any, Any, dict]:
7459
+ """锁定保险箱
7460
+
7461
+ POST https://www.123pan.com/api/restful/goapi/v1/file/safe_box/auth/lock
7462
+ """
7463
+ return self.request(
7464
+ "restful/goapi/v1/file/safe_box/auth/lock",
7465
+ "POST",
7466
+ base_url=base_url,
7467
+ async_=async_,
7468
+ **request_kwargs,
7469
+ )
7470
+
7471
+ @overload
7472
+ def fs_safe_box_unlock(
7473
+ self,
7474
+ payload: dict | int | str,
7475
+ /,
7476
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7477
+ *,
7478
+ async_: Literal[False] = False,
7479
+ **request_kwargs,
7480
+ ) -> dict:
7481
+ ...
7482
+ @overload
7483
+ def fs_safe_box_unlock(
7484
+ self,
7485
+ payload: dict | int | str,
7486
+ /,
7487
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7488
+ *,
7489
+ async_: Literal[True],
7490
+ **request_kwargs,
7491
+ ) -> Coroutine[Any, Any, dict]:
7492
+ ...
7493
+ def fs_safe_box_unlock(
7494
+ self,
7495
+ payload: dict | int | str,
7496
+ /,
7497
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
7498
+ *,
7499
+ async_: Literal[False, True] = False,
7500
+ **request_kwargs,
7501
+ ) -> dict | Coroutine[Any, Any, dict]:
7502
+ """解锁保险箱
7503
+
7504
+ .. note::
7505
+ 保险箱的 id,可以用 ``client.user_info()`` 接口获得,字段为 "SafeBoxFileId"
7506
+
7507
+ POST https://www.123pan.com/api/restful/goapi/v1/file/safe_box/auth/unlockbox
7508
+
7509
+ :payload:
7510
+ - password: int | str 💡 6 位密码
7511
+ """
7512
+ if not isinstance(payload, dict):
7513
+ payload = {"password": payload}
7514
+ return self.request(
7515
+ "restful/goapi/v1/file/safe_box/auth/unlockbox",
7516
+ "POST",
7517
+ json=payload,
7518
+ base_url=base_url,
7519
+ async_=async_,
7520
+ **request_kwargs,
7521
+ )
7522
+
7065
7523
  @overload
7066
7524
  def fs_star(
7067
7525
  self,
@@ -7903,6 +8361,64 @@ class P123Client(P123OpenClient):
7903
8361
 
7904
8362
  ########## Offline Download API ##########
7905
8363
 
8364
+ @overload
8365
+ def offline_task_abort(
8366
+ self,
8367
+ payload: int | Iterable[int] | dict,
8368
+ /,
8369
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8370
+ *,
8371
+ async_: Literal[False] = False,
8372
+ **request_kwargs,
8373
+ ) -> dict:
8374
+ ...
8375
+ @overload
8376
+ def offline_task_abort(
8377
+ self,
8378
+ payload: int | Iterable[int] | dict,
8379
+ /,
8380
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8381
+ *,
8382
+ async_: Literal[True],
8383
+ **request_kwargs,
8384
+ ) -> Coroutine[Any, Any, dict]:
8385
+ ...
8386
+ def offline_task_abort(
8387
+ self,
8388
+ payload: int | Iterable[int] | dict,
8389
+ /,
8390
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8391
+ *,
8392
+ async_: Literal[False, True] = False,
8393
+ **request_kwargs,
8394
+ ) -> dict | Coroutine[Any, Any, dict]:
8395
+ """取消离线下载任务
8396
+
8397
+ POST https://www.123pan.com/api/offline_download/task/abort
8398
+
8399
+ :payload:
8400
+ - task_ids: list[int] 💡 任务 id 列表
8401
+ - is_abort: bool = True 💡 是否取消
8402
+ - all: bool = False 💡 是否全部
8403
+ """
8404
+ if isinstance(payload, int):
8405
+ payload = {"task_ids": [payload]}
8406
+ elif not isinstance(payload, dict):
8407
+ if not isinstance(payload, (list, tuple)):
8408
+ payload = tuple(payload)
8409
+ payload = {"task_ids": payload}
8410
+ payload = cast(dict, payload)
8411
+ payload.setdefault("is_abort", True)
8412
+ payload.setdefault("all", False)
8413
+ return self.request(
8414
+ "offline_download/task/abort",
8415
+ "POST",
8416
+ json=payload,
8417
+ base_url=base_url,
8418
+ async_=async_,
8419
+ **request_kwargs,
8420
+ )
8421
+
7906
8422
  @overload
7907
8423
  def offline_task_delete(
7908
8424
  self,
@@ -8043,7 +8559,7 @@ class P123Client(P123OpenClient):
8043
8559
  ) -> dict | Coroutine[Any, Any, dict]:
8044
8560
  """解析下载链接
8045
8561
 
8046
- POST https://www.123pan.com/api/offline_download/task/resolve
8562
+ POST https://www.123pan.com/api/v2/offline_download/task/resolve
8047
8563
 
8048
8564
  :payload:
8049
8565
  - urls: str = <default> 💡 下载链接,多个用 "\\n" 隔开(用于新建链接下载任务)
@@ -8054,7 +8570,7 @@ class P123Client(P123OpenClient):
8054
8570
  elif not isinstance(payload, dict):
8055
8571
  payload = {"urls": "\n".join(payload)}
8056
8572
  return self.request(
8057
- "offline_download/task/resolve",
8573
+ "v2/offline_download/task/resolve",
8058
8574
  "POST",
8059
8575
  json=payload,
8060
8576
  base_url=base_url,
@@ -8062,11 +8578,10 @@ class P123Client(P123OpenClient):
8062
8578
  **request_kwargs,
8063
8579
  )
8064
8580
 
8065
- # TODO: 支持接受一个 Iterable[dict | int],int 视为 id (select_file 为 [0]),dict 视为 resolve 信息
8066
8581
  @overload
8067
8582
  def offline_task_submit(
8068
8583
  self,
8069
- payload: dict,
8584
+ payload: dict | Iterable[dict],
8070
8585
  /,
8071
8586
  base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8072
8587
  *,
@@ -8077,7 +8592,7 @@ class P123Client(P123OpenClient):
8077
8592
  @overload
8078
8593
  def offline_task_submit(
8079
8594
  self,
8080
- payload: dict,
8595
+ payload: dict | Iterable[dict],
8081
8596
  /,
8082
8597
  base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8083
8598
  *,
@@ -8087,7 +8602,7 @@ class P123Client(P123OpenClient):
8087
8602
  ...
8088
8603
  def offline_task_submit(
8089
8604
  self,
8090
- payload: dict,
8605
+ payload: dict | Iterable[dict],
8091
8606
  /,
8092
8607
  base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8093
8608
  *,
@@ -8096,7 +8611,19 @@ class P123Client(P123OpenClient):
8096
8611
  ) -> dict | Coroutine[Any, Any, dict]:
8097
8612
  """提交离线下载任务
8098
8613
 
8099
- POST https://www.123pan.com/api/offline_download/task/submit
8614
+ POST https://www.123pan.com/api/v2/offline_download/task/submit
8615
+
8616
+ .. note::
8617
+ 提交信息来自 ``client.offline_task_resolve()`` 接口的响应,假设响应为 ``resp``,那么
8618
+
8619
+ .. code:: python
8620
+
8621
+ payload = {
8622
+ "resource_list": [{
8623
+ "resource_id": resource["id"],
8624
+ "select_file_id": [info["id"] for info in resource["files"]],
8625
+ } for resource in resp["data"]["list"]]
8626
+ }
8100
8627
 
8101
8628
  :payload:
8102
8629
  - resource_list: list[Task] 💡 资源列表
@@ -8104,14 +8631,21 @@ class P123Client(P123OpenClient):
8104
8631
  .. code:: python
8105
8632
 
8106
8633
  File = {
8107
- "resource_id": int,
8108
- "select_file": list[int] # 如果是链接下载,则传 [0],如果BT下载,则传需要下载的文件在列表中的索引的列表
8634
+ "resource_id": int, # 资源 id
8635
+ "select_file_id": list[int], # 此资源内的文件 id
8109
8636
  }
8110
8637
 
8111
8638
  - upload_dir: int 💡 保存到目录的 id
8112
8639
  """
8640
+ if not isinstance(payload, dict):
8641
+ payload = {
8642
+ "resource_list": [{
8643
+ "resource_id": resource["id"],
8644
+ "select_file_id": [info["id"] for info in resource["files"]],
8645
+ } for resource in payload]
8646
+ }
8113
8647
  return self.request(
8114
- "offline_download/task/submit",
8648
+ "v2/offline_download/task/submit",
8115
8649
  "POST",
8116
8650
  json=payload,
8117
8651
  base_url=base_url,
@@ -8167,6 +8701,71 @@ class P123Client(P123OpenClient):
8167
8701
  **request_kwargs,
8168
8702
  )
8169
8703
 
8704
+ @overload
8705
+ def offline_add(
8706
+ self,
8707
+ /,
8708
+ url: str | Iterable[str],
8709
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8710
+ *,
8711
+ async_: Literal[False] = False,
8712
+ **request_kwargs,
8713
+ ) -> dict:
8714
+ ...
8715
+ @overload
8716
+ def offline_add(
8717
+ self,
8718
+ /,
8719
+ url: str | Iterable[str],
8720
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8721
+ *,
8722
+ async_: Literal[True],
8723
+ **request_kwargs,
8724
+ ) -> Coroutine[Any, Any, dict]:
8725
+ ...
8726
+ def offline_add(
8727
+ self,
8728
+ /,
8729
+ url: str | Iterable[str],
8730
+ base_url: str | Callable[[], str] = DEFAULT_BASE_URL,
8731
+ *,
8732
+ async_: Literal[False, True] = False,
8733
+ **request_kwargs,
8734
+ ) -> dict | Coroutine[Any, Any, dict]:
8735
+ """添加离线下载任务
8736
+
8737
+ POST https://www.123pan.com/api/offline_download/upload/seed
8738
+
8739
+ :param url: info_hash(只允许单个)、下载链接(多个用 "\n" 分隔)或者多个下载链接的迭代器
8740
+ :param base_url: API 链接的基地址
8741
+ :param async_: 是否异步
8742
+ :param request_kwargs: 其它请求参数
8743
+
8744
+ :return: 接口响应信息
8745
+ """
8746
+ def gen_step():
8747
+ if isinstance(url, str):
8748
+ if len(url) == 40 and not url.strip(hexdigits):
8749
+ payload: dict = {"info_hash": url}
8750
+ else:
8751
+ payload = {"urls": url}
8752
+ else:
8753
+ payload = {"urls": "\n".join(url)}
8754
+ resp = yield self.offline_task_resolve(
8755
+ payload,
8756
+ base_url=base_url,
8757
+ async_=async_,
8758
+ **request_kwargs,
8759
+ )
8760
+ check_response(resp)
8761
+ return self.offline_task_submit(
8762
+ resp["data"]["list"],
8763
+ base_url=base_url,
8764
+ async_=async_,
8765
+ **request_kwargs,
8766
+ )
8767
+ return run_gen_step(gen_step, async_)
8768
+
8170
8769
  ########## Share API ##########
8171
8770
 
8172
8771
  @overload
@@ -9903,16 +10502,4 @@ with temp_globals():
9903
10502
  except KeyError:
9904
10503
  CLIENT_API_METHODS_MAP[api] = [name]
9905
10504
 
9906
-
9907
- # TODO: 只有在使用密码登录和client_id登录的情况下,即使 token 失效,也可以重新登录(在有账号和密码的情况下,遇到 401 报错,会自动重新登录(需要加锁))
9908
- # TODO: 新的上传方法需要封装:https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/xogi45g7okqk7svr
9909
- # TODO: 对于某些工具的接口封装,例如 重复文件清理
9910
- # TODO: 同步空间
9911
- # TODO: 直链空间
9912
- # TODO: 图床
9913
- # TODO: 视频转码
9914
- # TODO: 移入保险箱
9915
- # TODO: 申诉和申诉列表
9916
- # TODO: 歌单(以及批量加入歌单)
9917
- # TODO: 最近查看
9918
- # TODO: 消息通知列表和操作
10505
+ # TODO: 实现 check_for_relogin 参数,当报错 401,则重新登录(如果用的是 client_id,账号密码 或 refresh_token),调用 client.login()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: p123client
3
- Version: 0.0.6.10.2
3
+ Version: 0.0.7.1
4
4
  Summary: Python 123 webdisk client.
5
5
  Home-page: https://github.com/ChenyangGao/p123client
6
6
  License: MIT
@@ -399,7 +399,7 @@ print(get_downurl(client, "123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512
399
399
 
400
400
  ### 4. 直链服务
401
401
 
402
- 需要先安装 [fastapi](https://pypi.org/project/blacksheep/)
402
+ 需要先安装 [blacksheep](https://www.neoteroi.dev/blacksheep/)
403
403
 
404
404
  ```console
405
405
  pip install 'blacksheep[uvicorn]'
@@ -0,0 +1,12 @@
1
+ LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
+ p123client/__init__.py,sha256=lcTiBpyNHH1HN4f1ueacumxkaahBNOUyvNA172UtSOU,214
3
+ p123client/client.py,sha256=RK74Lrxldx7d2dDbLZlexsq6gPKRisR6A08yqC_DY2E,349673
4
+ p123client/const.py,sha256=UYfBrgciCz7RJJPqCX6zwWlMoWiaTUwUU8bpFJyh0sM,348
5
+ p123client/exception.py,sha256=Vn2UlJulY63z3cF7bnTjMlZ6og7gCw1pAA-dswFwKpQ,3174
6
+ p123client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ p123client/tool/__init__.py,sha256=hnOwkk1CKk1CLGlhl6hlUl3BWNdqXdy8sWKXAGmOXHE,18812
8
+ p123client/type.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
9
+ p123client-0.0.7.1.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
10
+ p123client-0.0.7.1.dist-info/METADATA,sha256=FGry4TF8zhNXf_IiPewQY919FeymlN4vftG-D_R8vCE,14657
11
+ p123client-0.0.7.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
+ p123client-0.0.7.1.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
- p123client/__init__.py,sha256=gfUum-q3f_XuXOk2HpArDAIxAlscZm8Fau1kiNkNFpg,214
3
- p123client/client.py,sha256=KT2pQ7i1BItsATjhassthRX-6NJvm2FubfNE78sVy5g,329482
4
- p123client/const.py,sha256=UYfBrgciCz7RJJPqCX6zwWlMoWiaTUwUU8bpFJyh0sM,348
5
- p123client/exception.py,sha256=Vn2UlJulY63z3cF7bnTjMlZ6og7gCw1pAA-dswFwKpQ,3174
6
- p123client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- p123client/tool/__init__.py,sha256=hnOwkk1CKk1CLGlhl6hlUl3BWNdqXdy8sWKXAGmOXHE,18812
8
- p123client/type.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
9
- p123client-0.0.6.10.2.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
10
- p123client-0.0.6.10.2.dist-info/METADATA,sha256=REM9IKAXw4nj8x4ZCKcGY7ew7SIdiDWGUoPrcty-Qdo,14657
11
- p123client-0.0.6.10.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
- p123client-0.0.6.10.2.dist-info/RECORD,,