p123client 0.0.6__py3-none-any.whl → 0.0.6.2__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 CHANGED
@@ -6,8 +6,8 @@ from __future__ import annotations
6
6
  __all__ = ["check_response", "P123OpenClient", "P123Client"]
7
7
 
8
8
  from collections.abc import (
9
- AsyncIterable, Awaitable, Buffer, Callable, Coroutine, ItemsView,
10
- Iterable, Iterator, Mapping, MutableMapping,
9
+ AsyncIterable, Awaitable, Buffer, Callable, Coroutine,
10
+ ItemsView, Iterable, Iterator, Mapping, MutableMapping,
11
11
  )
12
12
  from errno import EIO, EISDIR, ENOENT
13
13
  from functools import partial
@@ -17,7 +17,6 @@ from inspect import isawaitable
17
17
  from itertools import chain
18
18
  from os import fsdecode, fstat, PathLike
19
19
  from os.path import basename
20
- from platform import system
21
20
  from re import compile as re_compile
22
21
  from tempfile import TemporaryFile
23
22
  from typing import cast, overload, Any, Literal
@@ -40,18 +39,6 @@ from yarl import URL
40
39
  from .exception import P123OSError, P123BrokenUpload
41
40
 
42
41
 
43
- # 当前的系统平台
44
- SYS_PLATFORM = system()
45
- # 替换表,用于半角转全角,包括了 Windows 中不允许出现在文件名中的字符
46
- match SYS_PLATFORM:
47
- case "Windows":
48
- NAME_TANSTAB_FULLWIDH = {c: chr(c+65248) for c in b"\\/:*?|><"}
49
- case "Darwin":
50
- NAME_TANSTAB_FULLWIDH = {ord("/"): ":", ord(":"): ":"}
51
- case _:
52
- NAME_TANSTAB_FULLWIDH = {ord("/"): "/"}
53
- # 查找大写字母(除了左边第 1 个)
54
- CRE_UPPER_ALPHABET_sub = re_compile("(?<!^)[A-Z]").sub
55
42
  # 默认使用的域名
56
43
  DEFAULT_BASE_URL = "https://www.123pan.com/b"
57
44
  DEFAULT_LOGIN_BASE_URL = "https://login.123pan.com"
@@ -120,6 +107,14 @@ def dict_to_lower_merge[K, V](
120
107
  return m
121
108
 
122
109
 
110
+ def escape_filename(
111
+ s: str,
112
+ /,
113
+ table: dict[int, int | str] = {c: chr(c+65248) for c in b'"\\/:*?|><'}, # type: ignore
114
+ ) -> str:
115
+ return s.translate(table)
116
+
117
+
123
118
  def items[K, V](
124
119
  m: Mapping[K, V] | Iterable[tuple[K, V]],
125
120
  /,
@@ -710,6 +705,170 @@ class P123OpenClient:
710
705
  })
711
706
  return self.request(api, params=payload, async_=async_, **request_kwargs)
712
707
 
708
+ @overload
709
+ def dlink_m3u8(
710
+ self,
711
+ payload: dict | int | str,
712
+ /,
713
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
714
+ *,
715
+ async_: Literal[False] = False,
716
+ **request_kwargs,
717
+ ) -> dict:
718
+ ...
719
+ @overload
720
+ def dlink_m3u8(
721
+ self,
722
+ payload: dict | int | str,
723
+ /,
724
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
725
+ *,
726
+ async_: Literal[True],
727
+ **request_kwargs,
728
+ ) -> Coroutine[Any, Any, dict]:
729
+ ...
730
+ def dlink_m3u8(
731
+ self,
732
+ payload: dict | int | str,
733
+ /,
734
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
735
+ *,
736
+ async_: Literal[False, True] = False,
737
+ **request_kwargs,
738
+ ) -> dict | Coroutine[Any, Any, dict]:
739
+ """获取直链转码链接
740
+
741
+ GET https://open-api.123pan.com/api/v1/direct-link/get/m3u8
742
+
743
+ :payload:
744
+ - fileID: int 💡 文件 id
745
+
746
+ :return:
747
+ 响应数据的 data 字段是一个字典,键值如下:
748
+
749
+ +---------------------+--------+----------+--------------------------------------------------------------+
750
+ | 名称 | 类型 | 是否必填 | 说明 |
751
+ +=====================+========+==========+==============================================================+
752
+ | list | array | 必填 | 响应列表 |
753
+ +---------------------+--------+----------+--------------------------------------------------------------|
754
+ | list[*].resolutions | string | 必填 | 分辨率 |
755
+ +---------------------+--------+----------+--------------------------------------------------------------|
756
+ | list[*].address | string | 必填 | 播放地址。请将播放地址放入支持的 hls 协议的播放器中进行播放。|
757
+ | | | | 示例在线播放地址: https://m3u8-player.com/ |
758
+ | | | | 请注意:转码链接播放过程中将会消耗您的直链流量。 |
759
+ | | | | 如果您开启了直链鉴权,也需要将转码链接根据鉴权指引进行签名。 |
760
+ +---------------------+--------+----------+--------------------------------------------------------------+
761
+ """
762
+ api = complete_url("/api/v1/direct-link/get/m3u8", base_url)
763
+ if not isinstance(payload, dict):
764
+ payload = {"fileID": payload}
765
+ return self.request(api, params=payload, async_=async_, **request_kwargs)
766
+
767
+ @overload
768
+ def dlink_transcode(
769
+ self,
770
+ payload: dict | int | str | Iterable[int | str],
771
+ /,
772
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
773
+ *,
774
+ async_: Literal[False] = False,
775
+ **request_kwargs,
776
+ ) -> dict:
777
+ ...
778
+ @overload
779
+ def dlink_transcode(
780
+ self,
781
+ payload: dict | int | str | Iterable[int | str],
782
+ /,
783
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
784
+ *,
785
+ async_: Literal[True],
786
+ **request_kwargs,
787
+ ) -> Coroutine[Any, Any, dict]:
788
+ ...
789
+ def dlink_transcode(
790
+ self,
791
+ payload: dict | int | str | Iterable[int | str],
792
+ /,
793
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
794
+ *,
795
+ async_: Literal[False, True] = False,
796
+ **request_kwargs,
797
+ ) -> dict | Coroutine[Any, Any, dict]:
798
+ """发起直链转码
799
+
800
+ POST https://open-api.123pan.com/api/v1/direct-link/doTranscode
801
+
802
+ :payload:
803
+ - ids: list[int] 💡 视频文件 id 列表
804
+ """
805
+ api = complete_url("/api/v1/direct-link/doTranscode", base_url)
806
+ if not isinstance(payload, dict):
807
+ if isinstance(payload, (int, str)):
808
+ payload = [payload]
809
+ elif not isinstance(payload, (tuple, list)):
810
+ payload = list(payload)
811
+ payload = {"ids": payload}
812
+ return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
813
+
814
+ @overload
815
+ def dlink_transcode_query(
816
+ self,
817
+ payload: dict | int | str | Iterable[int | str],
818
+ /,
819
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
820
+ *,
821
+ async_: Literal[False] = False,
822
+ **request_kwargs,
823
+ ) -> dict:
824
+ ...
825
+ @overload
826
+ def dlink_transcode_query(
827
+ self,
828
+ payload: dict | int | str | Iterable[int | str],
829
+ /,
830
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
831
+ *,
832
+ async_: Literal[True],
833
+ **request_kwargs,
834
+ ) -> Coroutine[Any, Any, dict]:
835
+ ...
836
+ def dlink_transcode_query(
837
+ self,
838
+ payload: dict | int | str | Iterable[int | str],
839
+ /,
840
+ base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
841
+ *,
842
+ async_: Literal[False, True] = False,
843
+ **request_kwargs,
844
+ ) -> dict | Coroutine[Any, Any, dict]:
845
+ """查询直链转码进度
846
+
847
+ POST https://open-api.123pan.com/api/v1/direct-link/queryTranscode
848
+
849
+ :payload:
850
+ - ids: str 💡 视频文件 id 列表
851
+
852
+ :return:
853
+ 响应数据的 data 字段是一个字典,键值如下:
854
+
855
+ +-----------+-------+----------+-------------------------------------------+
856
+ | 名称 | 类型 | 是否必填 | 说明 |
857
+ +===========+=======+==========+===========================================+
858
+ | noneList | array | 必填 | 未发起过转码的 ID |
859
+ | errorList | array | 必填 | 错误文件ID列表,这些文件ID无法进行转码操作 |
860
+ | success | array | 必填 | 转码成功的文件ID列表 |
861
+ +-----------+-------+----------+-------------------------------------------+
862
+ """
863
+ api = complete_url("/api/v1/direct-link/queryTranscode", base_url)
864
+ if not isinstance(payload, dict):
865
+ if isinstance(payload, (int, str)):
866
+ payload = [payload]
867
+ elif not isinstance(payload, (tuple, list)):
868
+ payload = list(payload)
869
+ payload = {"ids": payload}
870
+ return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
871
+
713
872
  @overload
714
873
  def dlink_url(
715
874
  self,
@@ -751,7 +910,7 @@ class P123OpenClient:
751
910
  https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/tdxfsmtemp4gu4o2
752
911
 
753
912
  :payload:
754
- - fileID: int 💡 目录 id
913
+ - fileID: int 💡 文件 id
755
914
  """
756
915
  api = complete_url("/api/v1/direct-link/url", base_url)
757
916
  if not isinstance(payload, dict):
@@ -1596,7 +1755,7 @@ class P123OpenClient:
1596
1755
  https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/trahy3lmds4o0i3r
1597
1756
 
1598
1757
  :payload:
1599
- - fileIDs: list[int] 💡 文件 id 数组
1758
+ - fileIDs: list[int] 💡 文件 id 列表
1600
1759
  - toParentFileID: int = 0 💡 要移动到的目标目录 id,默认为根目录
1601
1760
  - sourceType: int = 1 💡 复制来源:1:云盘
1602
1761
  - type: int = 1 💡 业务类型,固定为 1
@@ -1770,7 +1929,7 @@ class P123OpenClient:
1770
1929
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
1771
1930
 
1772
1931
  @overload
1773
- def oss_info(
1932
+ def oss_detail(
1774
1933
  self,
1775
1934
  payload: dict | int | str,
1776
1935
  /,
@@ -1781,7 +1940,7 @@ class P123OpenClient:
1781
1940
  ) -> dict:
1782
1941
  ...
1783
1942
  @overload
1784
- def oss_info(
1943
+ def oss_detail(
1785
1944
  self,
1786
1945
  payload: dict | int | str,
1787
1946
  /,
@@ -1791,7 +1950,7 @@ class P123OpenClient:
1791
1950
  **request_kwargs,
1792
1951
  ) -> Coroutine[Any, Any, dict]:
1793
1952
  ...
1794
- def oss_info(
1953
+ def oss_detail(
1795
1954
  self,
1796
1955
  payload: dict | int | str,
1797
1956
  /,
@@ -2144,7 +2303,7 @@ class P123OpenClient:
2144
2303
 
2145
2304
  :payload:
2146
2305
  - filename: str 💡 文件名
2147
- - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 复用/跳过 1: 保留/后缀编号 2: 替换/覆盖
2306
+ - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 跳过/报错 1: 保留/后缀编号 2: 替换/覆盖
2148
2307
  - etag: str 💡 文件 md5
2149
2308
  - parentFileID: int = 0 💡 父目录 id,默认为根目录
2150
2309
  - size: int 💡 文件大小,单位:字节
@@ -2163,7 +2322,9 @@ class P123OpenClient:
2163
2322
  }
2164
2323
  """
2165
2324
  api = complete_url("/upload/v1/oss/file/create", base_url)
2166
- payload = dict_to_lower_merge(payload, duplicate=0, type=1)
2325
+ payload = dict_to_lower_merge(payload, type=1)
2326
+ if "duplicate" in payload and not payload["duplicate"]:
2327
+ del payload["duplicate"]
2167
2328
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
2168
2329
 
2169
2330
  @overload
@@ -2437,7 +2598,7 @@ class P123OpenClient:
2437
2598
  """上传文件
2438
2599
 
2439
2600
  .. note::
2440
- 如果文件名中包含 Windows 文件名非法字符,则转换为对应的全角字符
2601
+ 如果文件名中包含字符 "\\/:*?|><,则转换为对应的全角字符
2441
2602
 
2442
2603
  .. admonition:: Reference
2443
2604
  /API列表/图床/上传图片/💡上传流程说明
@@ -2571,7 +2732,7 @@ class P123OpenClient:
2571
2732
  file_name = getattr(file, "name", "")
2572
2733
  file_name = basename(file_name)
2573
2734
  if file_name:
2574
- file_name = file_name.translate(NAME_TANSTAB_FULLWIDH)
2735
+ file_name = escape_filename(file_name)
2575
2736
  else:
2576
2737
  file_name = str(uuid4())
2577
2738
  if file_size < 0:
@@ -2726,7 +2887,7 @@ class P123OpenClient:
2726
2887
  :payload:
2727
2888
  - fileIDList: str 💡 分享文件 id 列表,最多 100 个,用逗号,分隔连接
2728
2889
  - shareExpire: 0 | 1 | 7 | 30 = 0 💡 分享链接有效期天数,0 为永久
2729
- - shareName: str 💡 分享链接名称,须小于 35 个字符且不能包含特殊字符
2890
+ - shareName: str 💡 分享链接名称,须小于 35 个字符且不能包含特殊字符 "\\/:*?|><
2730
2891
  - sharePwd: str = "" 💡 设置分享链接提取码
2731
2892
  - trafficLimit: int = <default> 💡 免登陆限制流量,单位:字节
2732
2893
  - trafficLimitSwitch: 1 | 2 = <default> 💡 免登录流量限制开关:1:关闭 2:打开
@@ -2781,7 +2942,7 @@ class P123OpenClient:
2781
2942
  - isReward: 0 | 1 = 0 💡 是否开启打赏
2782
2943
  - payAmount: int = 1 💡 金额,从 1 到 99,单位:元
2783
2944
  - resourceDesc: str = "" 💡 资源描述
2784
- - shareName: str 💡 分享链接名称,须小于 35 个字符且不能包含特殊字符
2945
+ - shareName: str 💡 分享链接名称,须小于 35 个字符且不能包含特殊字符 "\\/:*?|><
2785
2946
  """
2786
2947
  api = complete_url("/api/v1/share/content-payment/create", base_url)
2787
2948
  payload = dict_to_lower_merge(payload, {"payAmount": 1, "isReward": 0, "resourceDesc": ""})
@@ -2991,9 +3152,9 @@ class P123OpenClient:
2991
3152
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
2992
3153
 
2993
3154
  @overload
2994
- def transcode_download_one(
3155
+ def transcode_download_all(
2995
3156
  self,
2996
- payload: dict,
3157
+ payload: dict | int | str,
2997
3158
  /,
2998
3159
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
2999
3160
  *,
@@ -3002,9 +3163,9 @@ class P123OpenClient:
3002
3163
  ) -> dict:
3003
3164
  ...
3004
3165
  @overload
3005
- def transcode_download_one(
3166
+ def transcode_download_all(
3006
3167
  self,
3007
- payload: dict,
3168
+ payload: dict | int | str,
3008
3169
  /,
3009
3170
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
3010
3171
  *,
@@ -3012,37 +3173,41 @@ class P123OpenClient:
3012
3173
  **request_kwargs,
3013
3174
  ) -> Coroutine[Any, Any, dict]:
3014
3175
  ...
3015
- def transcode_download_one(
3176
+ def transcode_download_all(
3016
3177
  self,
3017
- payload: dict,
3178
+ payload: dict | int | str,
3018
3179
  /,
3019
3180
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
3020
3181
  *,
3021
3182
  async_: Literal[False, True] = False,
3022
3183
  **request_kwargs,
3023
3184
  ) -> dict | Coroutine[Any, Any, dict]:
3024
- """单个转码文件下载(m3u8或ts)
3185
+ """某个视频全部转码文件下载
3025
3186
 
3026
- POST https://open-api.123pan.com/api/v1/transcode/m3u8_ts/download
3187
+ POST https://open-api.123pan.com/api/v1/transcode/file/download/all
3188
+
3189
+ .. attention::
3190
+ 该接口需要轮询去查询结果,建议 10s 一次
3027
3191
 
3028
3192
  .. admonition:: Reference
3029
- /API列表/视频转码/视频文件下载/单个转码文件下载(m3u8或ts)
3193
+ /API列表/视频转码/视频文件下载/某个视频全部转码文件下载
3030
3194
 
3031
- https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/yf97p60yyzb8mzbr
3195
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/yb7hrb0x2gym7xic
3032
3196
 
3033
3197
  :payload:
3034
- - fileId: int 💡 文件 id
3035
- - resolution: str 💡 分辨率
3036
- - type: int 💡 文件类型:1:m3u8 2:ts
3037
- - tsName: str 💡 下载 ts 文件时必须要指定名称,请参考查询某个视频的转码结果
3198
+ - fileId: int 💡 文件 id
3199
+ - zipName: str = f"转码{file_id}.zip" 💡 下载 zip 文件的名字
3038
3200
  """
3039
- api = complete_url("/api/v1/transcode/m3u8_ts/download", base_url)
3201
+ api = complete_url("/api/v1/transcode/file/download/all", base_url)
3202
+ if not isinstance(payload, dict):
3203
+ payload = {"fileId": payload}
3204
+ payload = dict_to_lower_merge(payload, zipName=f"转码{payload.get('fileid', '')}.zip")
3040
3205
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
3041
3206
 
3042
3207
  @overload
3043
- def transcode_download_all(
3208
+ def transcode_m3u8_ts_download(
3044
3209
  self,
3045
- payload: dict | int | str,
3210
+ payload: dict,
3046
3211
  /,
3047
3212
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
3048
3213
  *,
@@ -3051,9 +3216,9 @@ class P123OpenClient:
3051
3216
  ) -> dict:
3052
3217
  ...
3053
3218
  @overload
3054
- def transcode_download_all(
3219
+ def transcode_m3u8_ts_download(
3055
3220
  self,
3056
- payload: dict | int | str,
3221
+ payload: dict,
3057
3222
  /,
3058
3223
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
3059
3224
  *,
@@ -3061,35 +3226,31 @@ class P123OpenClient:
3061
3226
  **request_kwargs,
3062
3227
  ) -> Coroutine[Any, Any, dict]:
3063
3228
  ...
3064
- def transcode_download_all(
3229
+ def transcode_m3u8_ts_download(
3065
3230
  self,
3066
- payload: dict | int | str,
3231
+ payload: dict,
3067
3232
  /,
3068
3233
  base_url: str | Callable[[], str] = DEFAULT_OPEN_BASE_URL,
3069
3234
  *,
3070
3235
  async_: Literal[False, True] = False,
3071
3236
  **request_kwargs,
3072
3237
  ) -> dict | Coroutine[Any, Any, dict]:
3073
- """某个视频全部转码文件下载
3074
-
3075
- POST https://open-api.123pan.com/api/v1/transcode/file/download/all
3238
+ """单个转码文件下载(m3u8或ts)
3076
3239
 
3077
- .. attention::
3078
- 该接口需要轮询去查询结果,建议 10s 一次
3240
+ POST https://open-api.123pan.com/api/v1/transcode/m3u8_ts/download
3079
3241
 
3080
3242
  .. admonition:: Reference
3081
- /API列表/视频转码/视频文件下载/某个视频全部转码文件下载
3243
+ /API列表/视频转码/视频文件下载/单个转码文件下载(m3u8或ts)
3082
3244
 
3083
- https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/yb7hrb0x2gym7xic
3245
+ https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/yf97p60yyzb8mzbr
3084
3246
 
3085
3247
  :payload:
3086
- - fileId: int 💡 文件 id
3087
- - zipName: str = f"转码{file_id}.zip" 💡 下载 zip 文件的名字
3248
+ - fileId: int 💡 文件 id
3249
+ - resolution: str 💡 分辨率
3250
+ - type: int 💡 文件类型:1:m3u8 2:ts
3251
+ - tsName: str 💡 下载 ts 文件时必须要指定名称,请参考查询某个视频的转码结果
3088
3252
  """
3089
- api = complete_url("/api/v1/transcode/file/download/all", base_url)
3090
- if not isinstance(payload, dict):
3091
- payload = {"fileId": payload}
3092
- payload = dict_to_lower_merge(payload, zipName=f"转码{payload.get('fileid', '')}.zip")
3253
+ api = complete_url("/api/v1/transcode/m3u8_ts/download", base_url)
3093
3254
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
3094
3255
 
3095
3256
  @overload
@@ -3486,7 +3647,7 @@ class P123OpenClient:
3486
3647
  :payload:
3487
3648
  - containDir: "false" | "true" = "false" 💡 上传文件是否包含路径
3488
3649
  - filename: str 💡 文件名,但 `containDir` 为 "true" 时,视为路径
3489
- - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 复用/跳过 1: 保留/后缀编号 2: 替换/覆盖
3650
+ - duplicate: 0 | 1 | 2 = 0 💡 处理同名:0: 跳过/报错 1: 保留/后缀编号 2: 替换/覆盖
3490
3651
  - etag: str 💡 文件 md5
3491
3652
  - parentFileID: int = 0 💡 父目录 id,根目录是 0
3492
3653
  - size: int 💡 文件大小,单位:字节
@@ -3505,10 +3666,11 @@ class P123OpenClient:
3505
3666
  """
3506
3667
  api = complete_url("/upload/v1/file/create", base_url)
3507
3668
  payload = dict_to_lower_merge(payload, {
3508
- "duplicate": 0,
3509
3669
  "parentFileId": 0,
3510
3670
  "containDir": "false",
3511
3671
  })
3672
+ if "duplicate" in payload and not payload["duplicate"]:
3673
+ del payload["duplicate"]
3512
3674
  return self.request(api, "POST", json=payload, async_=async_, **request_kwargs)
3513
3675
 
3514
3676
  @overload
@@ -3788,7 +3950,7 @@ class P123OpenClient:
3788
3950
  """上传文件
3789
3951
 
3790
3952
  .. note::
3791
- 如果文件名中包含 Windows 文件名非法字符,则转换为对应的全角字符
3953
+ 如果文件名中包含字符 "\\/:*?|><,则转换为对应的全角字符
3792
3954
 
3793
3955
  .. admonition:: Reference
3794
3956
  /API列表/文件管理/上传/v1/💡上传流程说明
@@ -3926,7 +4088,7 @@ class P123OpenClient:
3926
4088
  file_name = getattr(file, "name", "")
3927
4089
  file_name = basename(file_name)
3928
4090
  if file_name:
3929
- file_name = file_name.translate(NAME_TANSTAB_FULLWIDH)
4091
+ file_name = escape_filename(file_name)
3930
4092
  else:
3931
4093
  file_name = str(uuid4())
3932
4094
  if file_size < 0:
@@ -4099,6 +4261,9 @@ class P123OpenClient:
4099
4261
  dlink_disable_open = dlink_disable
4100
4262
  dlink_enable_open = dlink_enable
4101
4263
  dlink_log_open = dlink_log
4264
+ dlink_m3u8_open = dlink_m3u8
4265
+ dlink_transcode_open = dlink_transcode
4266
+ dlink_transcode_query_open = dlink_transcode_query
4102
4267
  dlink_url_open = dlink_url
4103
4268
  download_info_open = download_info
4104
4269
  fs_delete_open = fs_delete
@@ -4118,7 +4283,7 @@ class P123OpenClient:
4118
4283
  oss_copy_fail_open = oss_copy_fail
4119
4284
  oss_copy_process_open = oss_copy_process
4120
4285
  oss_delete_open = oss_delete
4121
- oss_info_open = oss_info
4286
+ oss_detail_open = oss_detail
4122
4287
  oss_list_open = oss_list
4123
4288
  oss_mkdir_open = oss_mkdir
4124
4289
  oss_move_open = oss_move
@@ -4137,7 +4302,7 @@ class P123OpenClient:
4137
4302
  transcode_delete_open = transcode_delete
4138
4303
  transcode_download_open = transcode_download
4139
4304
  transcode_download_all_open = transcode_download_all
4140
- transcode_download_one_open = transcode_download_one
4305
+ transcode_m3u8_ts_download_open = transcode_m3u8_ts_download
4141
4306
  transcode_info_open = transcode_info
4142
4307
  transcode_list_open = transcode_list
4143
4308
  transcode_record_open = transcode_record
@@ -5894,7 +6059,8 @@ class P123Client(P123OpenClient):
5894
6059
  def to_snake_case(
5895
6060
  payload: dict[str, Any],
5896
6061
  /,
5897
- mapping={
6062
+ *,
6063
+ _map = {
5898
6064
  "sharekey": "share_key",
5899
6065
  "sharepwd": "share_pwd",
5900
6066
  "filelist": "file_list",
@@ -5903,15 +6069,16 @@ class P123Client(P123OpenClient):
5903
6069
  "parentfileid": "parent_file_id",
5904
6070
  "driveid": "drive_id",
5905
6071
  "currentlevel": "current_level",
5906
- },
6072
+ }.get,
6073
+ _sub = re_compile("(?<!^)[A-Z]").sub,
5907
6074
  ):
5908
6075
  d: dict[str, Any] = {}
5909
6076
  for k, v in payload.items():
5910
6077
  if "_" in k:
5911
6078
  d[k.lower()] = v
5912
- elif k2 := mapping.get(k.lower()):
6079
+ elif k2 := _map(k.lower()):
5913
6080
  d[k2] = v
5914
- elif (k2 := CRE_UPPER_ALPHABET_sub(r"_\g<0>", k)) != k:
6081
+ elif (k2 := _sub(r"_\g<0>", k)) != k:
5915
6082
  d[k2.lower()] = v
5916
6083
  else:
5917
6084
  d[k] = v
@@ -6610,7 +6777,7 @@ class P123Client(P123OpenClient):
6610
6777
  """上传文件
6611
6778
 
6612
6779
  .. note::
6613
- 如果文件名中包含 Windows 文件名非法字符,则转换为对应的全角字符
6780
+ 如果文件名中包含字符 "\\/:*?|><,则转换为对应的全角字符
6614
6781
 
6615
6782
  :param file: 待上传的文件
6616
6783
 
@@ -6737,7 +6904,7 @@ class P123Client(P123OpenClient):
6737
6904
  file_name = getattr(file, "name", "")
6738
6905
  file_name = basename(file_name)
6739
6906
  if file_name:
6740
- file_name = file_name.translate(NAME_TANSTAB_FULLWIDH)
6907
+ file_name = escape_filename(file_name)
6741
6908
  else:
6742
6909
  file_name = str(uuid4())
6743
6910
  if file_size < 0:
@@ -6967,7 +7134,7 @@ class P123Client(P123OpenClient):
6967
7134
  file_name = getattr(file, "name", "")
6968
7135
  file_name = basename(file_name)
6969
7136
  if file_name:
6970
- file_name = file_name.translate(NAME_TANSTAB_FULLWIDH)
7137
+ file_name = escape_filename(file_name)
6971
7138
  if not file_name:
6972
7139
  file_name = str(uuid4())
6973
7140
  if file_size < 0:
p123client/exception.py CHANGED
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env python3
2
2
  # encoding: utf-8
3
3
 
4
- __all__ = ["P123Warning", "P123OSError", "P123BrokenUpload"]
4
+ __all__ = [
5
+ "P123Warning", "P123OSError", "P123BrokenUpload",
6
+ "P123AccessTokenError", "P123AuthenticationError",
7
+ ]
5
8
 
6
9
  import warnings
7
10
 
@@ -47,3 +50,11 @@ class P123OSError(OSError):
47
50
  class P123BrokenUpload(P123OSError):
48
51
  pass
49
52
 
53
+
54
+ class P123AccessTokenError(P123OSError):
55
+ pass
56
+
57
+
58
+ class P123AuthenticationError(P123OSError):
59
+ pass
60
+
@@ -280,7 +280,7 @@ def _iterdir(
280
280
  :return: 迭代器,产生文件或目录的信息
281
281
  """
282
282
  default_payload = payload
283
- page_size = int(payload["limit"])
283
+ page_size = int(payload.setdefault("limit", 100))
284
284
  def gen_step():
285
285
  nonlocal parent_id
286
286
  dq: deque[tuple[int, int, str]] = deque()
@@ -302,7 +302,8 @@ def _iterdir(
302
302
  if interval > 0:
303
303
  last_ts = time()
304
304
  check_response(resp)
305
- for info in resp["data"]["InfoList"]:
305
+ info_list = resp["data"]["InfoList"]
306
+ for info in info_list:
306
307
  is_dir = info["is_dir"] = bool(info["Type"])
307
308
  fid = info["id"] = int(info["FileId"])
308
309
  info["parent_id"] = parent_id
@@ -328,8 +329,8 @@ def _iterdir(
328
329
  if is_dir and (max_depth < 0 or depth < max_depth):
329
330
  put((depth, fid, relpath + "/"))
330
331
  if (
331
- not resp["data"]["InfoList"] or
332
- len(resp["data"]["InfoList"]) < page_size or
332
+ not info_list or
333
+ len(info_list) < page_size or
333
334
  resp["data"]["Next"] == "-1"
334
335
  ):
335
336
  break
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: p123client
3
- Version: 0.0.6
3
+ Version: 0.0.6.2
4
4
  Summary: Python 123 webdisk client.
5
5
  Home-page: https://github.com/ChenyangGao/python-123-client
6
6
  License: MIT
@@ -0,0 +1,12 @@
1
+ LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
+ p123client/__init__.py,sha256=gfUum-q3f_XuXOk2HpArDAIxAlscZm8Fau1kiNkNFpg,214
3
+ p123client/client.py,sha256=AfMgAc5OY_5lTP4RXVlILImB3Cx_RSB5nMPdZZ6-YOE,246733
4
+ p123client/const.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
5
+ p123client/exception.py,sha256=020xGo8WQmGCJz1UzNg9oFzpEvToQcgTye0s6lkFASQ,1540
6
+ p123client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ p123client/tool/__init__.py,sha256=2k_tcc67O9QG4wzESIdnAwqNHybCGlrsnxo_uBqBhEI,16673
8
+ p123client/type.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
9
+ p123client-0.0.6.2.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
10
+ p123client-0.0.6.2.dist-info/METADATA,sha256=J1kKf76ITb6pxdXOW4GE7Rpxto3UncAUf1nVDO2VTbc,8869
11
+ p123client-0.0.6.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
+ p123client-0.0.6.2.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=Vo1QbNuDdNQBrrjXJki1n5IXFxoYd0QsK4R2eL5-Wxg,240077
4
- p123client/const.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
5
- p123client/exception.py,sha256=d2PN6mRJuw6SXNiTOBfjZQ6qfInAvkERkcbx4PQ-7vA,1369
6
- p123client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- p123client/tool/__init__.py,sha256=zlKMg_ETifq4pFsbmqAS_BqU-fuqrYWbCs_HD4Vra6o,16649
8
- p123client/type.py,sha256=T17OzPQrnIG6w_Hzjc8TF_fFMKa-hQMSn1gff8pVcBc,56
9
- p123client-0.0.6.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
10
- p123client-0.0.6.dist-info/METADATA,sha256=7JhGIxHwVQHzN9dc2fWzTFDkZCVBq6RXZWxfLmpeZo0,8867
11
- p123client-0.0.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
- p123client-0.0.6.dist-info/RECORD,,