├── .gitattributes
├── requirements.txt
├── README.md
├── LICENSE
├── main.py
├── api.py
├── const.py
├── .gitignore
└── utils.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzonefire/shareLink2bdLink/HEAD/requirements.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # shareLink2bdLink
2 | 从百度分享链接生成秒传链接的后端程序
3 |
4 | 代码写的比较简易, 仅供参考, 其他的平台自行实现
5 |
6 | # run
7 | ```
8 | pip install -r requirements.txt
9 | python main.py
10 | ```
11 |
12 | * 运行前先使用cookie插件: [Cookie Editor](https://cookie-editor.cgagnier.ca/#download) 导出百度网盘cookie并粘贴到 baidu_cookie.txt 内
13 |
14 | # protocol
15 | 后端默认监听 localhost:9001 (可自行在代码中修改)
16 |
17 | http协议发送json数据 { 'sharelink': 'https://pan.baidu.com/s/xxx, 'pw': 'xxxx' } 到后端
18 |
19 | 后端返回的json数据格式为: { 'errno':错误码, 'msg':错误信息, 'list':[ { 'path':文件路径, 'bdlink':秒传链接, 'errno':错误码, 'msg':错误信息 } ] }
20 |
21 | * errno=0为成功, 此时不会有'msg'字段
22 |
23 | # preview
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 mengzonefire
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | """
2 | Author: mengzonefire
3 | Date: 2023-01-08 01:13:00
4 | LastEditTime: 2023-04-25 21:33:41
5 | LastEditors: mengzonefire
6 | Description: 主函数入口, 创建http服务
7 | """
8 |
9 | import sys
10 | import const
11 | import traceback
12 | import argparse
13 | from utils import inital, readCookie, write_log
14 | from api import messageHandler
15 | from http.server import ThreadingHTTPServer
16 |
17 | parser = argparse.ArgumentParser()
18 | parser.add_argument("-w", "--www", action="store_true")
19 | parser.add_argument("-p", "--port", dest="port", type=int)
20 | args = parser.parse_args()
21 |
22 |
23 | def main():
24 | print(f"{const.title} by {const.author} {const.version} {const.date}")
25 | inital()
26 | if not readCookie():
27 | sys.exit()
28 | PORT = args.port or 9001
29 | HOST = "0.0.0.0" if args.www else "localhost"
30 | print("http服务运行在 {}:{}".format(HOST, PORT))
31 | server = ThreadingHTTPServer((HOST, PORT), messageHandler)
32 | server.serve_forever()
33 |
34 |
35 | if __name__ == "__main__":
36 | try:
37 | main()
38 | except Exception:
39 | traceback.print_exc() # 打印报错信息
40 | write_log(
41 | "msg: {}\nerror_log: {}".format(const.lastMsg, traceback.format_exc())
42 | ) # 报错信息写入log
43 | raise
44 |
--------------------------------------------------------------------------------
/api.py:
--------------------------------------------------------------------------------
1 | """
2 | Author: mengzonefire
3 | Date: 2023-04-25 19:55:50
4 | LastEditTime: 2023-04-25 21:33:34
5 | LastEditors: mengzonefire
6 | Description: 配置后端对应api的调用
7 | """
8 |
9 | from json import loads, dumps
10 | from http.server import BaseHTTPRequestHandler
11 | from utils import bdpanHelper
12 | import const
13 |
14 |
15 | class messageHandler(BaseHTTPRequestHandler):
16 | def do_POST(self):
17 | self.send_response(200)
18 | self.send_header("Content-type", "application/x-www-form-urlencoded")
19 | self.send_header("Access-Control-Allow-Origin", "*")
20 | self.send_header("Access-Control-Allow-Methods", "*")
21 | self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")
22 | self.end_headers()
23 | req_datas = self.rfile.read(int(self.headers["content-length"])) # 加上限制读取的报文长度
24 | message = req_datas.decode()
25 | const.lastMsg = message
26 | jsonData = loads(message)
27 | print(jsonData)
28 | if "sharelink" in jsonData and "pw" in jsonData:
29 | respon = bdpanHelper(
30 | jsonData["sharelink"], jsonData["pw"]
31 | ).getBdlink() # 单文件分享
32 | if respon["errno"]:
33 | msg = const.default_msg
34 | if respon["errno"] in const.errno_msg:
35 | msg = const.errno_msg[respon["errno"]]
36 | respon["msg"] = msg
37 | self.wfile.write(dumps(respon).encode("utf-8"))
38 | else:
39 | self.wfile.write(dumps({"errno": 114514, "msg": "接口参数错误!"}).encode("utf-8"))
40 |
--------------------------------------------------------------------------------
/const.py:
--------------------------------------------------------------------------------
1 | """
2 | Author: mengzonefire
3 | Date: 2023-01-05 14:50:05
4 | LastEditTime: 2023-04-25 21:33:25
5 | LastEditors: mengzonefire
6 | Description: 存放全局常量
7 | """
8 |
9 | import re
10 |
11 | author = "mengzonefire"
12 | title = "度盘分享链转秒传后端"
13 | version = "v1.0.3"
14 | date = "23.4.25"
15 |
16 | ua_web = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
17 | ua_dl = "netdisk;"
18 | tpl_url = "https://pan.baidu.com/share/tplconfig?fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0&surl={surl}&logid={logid}"
19 | sharedownload_url = "https://pan.baidu.com/api/sharedownload?channel=chunlei&clienttype=12&web=1&app_id=250528&sign={sign}×tamp={timestamp}"
20 | verify_url = "http://pan.baidu.com/share/verify?app_id=250528&channel=chunlei&clienttype=0&surl={surl}&web=1&bdstoken={bdstoken}"
21 | create_url = "https://pan.baidu.com/api/create"
22 | sharelist_url = "https://pan.baidu.com/share/list?showempty=0&num=10000&channel=chunlei&web=1&app_id=250528&clienttype=0&dir={dir}&logid={logid}&shareid={shareid}&uk={uk}&page={page}"
23 | p_surl = re.compile(r"(s\/1|surl=)([a-zA-Z0-9_-]+)")
24 | p_share_uk = re.compile(r'share_uk:"(\d+)"')
25 | p_shareid = re.compile(r'shareid:"(\d+)"')
26 | p_fileList = re.compile(r'"file_list":\[{(.+?)}\],')
27 | p_bdstoken = re.compile(r"bdstoken:'([a-z\d]{32})'")
28 | p_md5 = re.compile(r"'content-md5': '([\da-f]{32})'", flags=re.IGNORECASE) # 忽略大小写
29 | errno_msg = {
30 | -9: "提取码错误",
31 | 114: "链接格式错误",
32 | 514: "share_uk和shareid获取失败",
33 | 119: "文件已被和谐",
34 | 1919: "链接已失效",
35 | 810: "账号cookie已失效",
36 | 115: "fileList获取失败",
37 | 116: "dlink获取失败, 请尝试更换cookie",
38 | 996: "文件md5获取失败, 请下载后本地生成",
39 | }
40 | default_msg = "未知错误"
41 | cookie_file = "baidu_cookie.txt"
42 | issue_domain = "issuecdn.baidupcs.com" # 用于检测文件是否被和谐
43 | testPath = "/apps/生成秒传测试文件.mengzonefire"
44 | lastMsg = "" # 用于存储服务崩溃时接受的最后一条请求数据
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | venv
2 | .vscode
3 | .history
4 | baidu_cookie.txt
5 |
6 | # Byte-compiled / optimized / DLL files
7 | __pycache__/
8 | *.py[cod]
9 | *$py.class
10 |
11 | # C extensions
12 | *.so
13 |
14 | # Distribution / packaging
15 | .Python
16 | build/
17 | develop-eggs/
18 | dist/
19 | downloads/
20 | eggs/
21 | .eggs/
22 | lib/
23 | lib64/
24 | parts/
25 | sdist/
26 | var/
27 | wheels/
28 | share/python-wheels/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 | MANIFEST
33 |
34 | # PyInstaller
35 | # Usually these files are written by a python script from a template
36 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
37 | *.manifest
38 | *.spec
39 |
40 | # Installer logs
41 | pip-log.txt
42 | pip-delete-this-directory.txt
43 |
44 | # Unit test / coverage reports
45 | htmlcov/
46 | .tox/
47 | .nox/
48 | .coverage
49 | .coverage.*
50 | .cache
51 | nosetests.xml
52 | coverage.xml
53 | *.cover
54 | *.py,cover
55 | .hypothesis/
56 | .pytest_cache/
57 | cover/
58 |
59 | # Translations
60 | *.mo
61 | *.pot
62 |
63 | # Django stuff:
64 | *.log
65 | local_settings.py
66 | db.sqlite3
67 | db.sqlite3-journal
68 |
69 | # Flask stuff:
70 | instance/
71 | .webassets-cache
72 |
73 | # Scrapy stuff:
74 | .scrapy
75 |
76 | # Sphinx documentation
77 | docs/_build/
78 |
79 | # PyBuilder
80 | .pybuilder/
81 | target/
82 |
83 | # Jupyter Notebook
84 | .ipynb_checkpoints
85 |
86 | # IPython
87 | profile_default/
88 | ipython_config.py
89 |
90 | # pyenv
91 | # For a library or package, you might want to ignore these files since the code is
92 | # intended to run in multiple environments; otherwise, check them in:
93 | # .python-version
94 |
95 | # pipenv
96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
99 | # install all needed dependencies.
100 | #Pipfile.lock
101 |
102 | # poetry
103 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
104 | # This is especially recommended for binary packages to ensure reproducibility, and is more
105 | # commonly ignored for libraries.
106 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
107 | #poetry.lock
108 |
109 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
110 | __pypackages__/
111 |
112 | # Celery stuff
113 | celerybeat-schedule
114 | celerybeat.pid
115 |
116 | # SageMath parsed files
117 | *.sage.py
118 |
119 | # Environments
120 | .env
121 | .venv
122 | env/
123 | venv/
124 | ENV/
125 | env.bak/
126 | venv.bak/
127 |
128 | # Spyder project settings
129 | .spyderproject
130 | .spyproject
131 |
132 | # Rope project settings
133 | .ropeproject
134 |
135 | # mkdocs documentation
136 | /site
137 |
138 | # mypy
139 | .mypy_cache/
140 | .dmypy.json
141 | dmypy.json
142 |
143 | # Pyre type checker
144 | .pyre/
145 |
146 | # pytype static type analyzer
147 | .pytype/
148 |
149 | # Cython debug symbols
150 | cython_debug/
151 |
152 | # PyCharm
153 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
154 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
155 | # and can be added to the global gitignore or merged into this file. For a more nuclear
156 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
157 | #.idea/
158 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | """
2 | Author: mengzonefire
3 | Date: 2023-01-05 14:49:01
4 | LastEditTime: 2023-04-25 21:36:11
5 | LastEditors: mengzonefire
6 | Description: 存放工具函数
7 | """
8 |
9 | import os
10 | import re
11 | import sys
12 | import base64
13 | import json
14 | import copy
15 | import time
16 | import requests
17 | from urllib.parse import quote, unquote
18 | from const import *
19 |
20 | s = requests.Session()
21 | baidu_cookies_dict = dict()
22 |
23 | """
24 | description: 初始化步骤
25 | """
26 |
27 |
28 | def inital():
29 | exe_path, _ = os.path.split(sys.argv[0])
30 | if exe_path:
31 | os.chdir(exe_path) # 切换工作目录到可执行文件所在目录
32 |
33 |
34 | def write_log(err):
35 | now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
36 | with open("./{}.log".format(now_time), "a") as f:
37 | f.write(err)
38 | f.close()
39 |
40 |
41 | def readCookie():
42 | global logid
43 | if not os.path.isfile(cookie_file):
44 | print(
45 | f"cookie文件{cookie_file}不存在, 请使用浏览器Cookie Editor插件导出度盘cookie, 在程序所在目录创建{cookie_file}并复制进去"
46 | )
47 | return False
48 | with open(cookie_file, "r") as f:
49 | try:
50 | cookie_json = json.loads(f.read())
51 | except:
52 | print("cookie格式错误, 请使用浏览器cookie插件导出度盘cookie")
53 | return False
54 | for cookie in cookie_json:
55 | baidu_cookies_dict[cookie["name"]] = cookie["value"]
56 | logid = str(
57 | base64.b64encode(unquote(baidu_cookies_dict["BAIDUID"]).encode("utf-8")),
58 | "utf-8",
59 | )
60 | return True
61 |
62 |
63 | # def outputCookie():
64 | # cookie_text = ""
65 | # for key in baidu_cookies_dict:
66 | # cookie_text += f'{key}={baidu_cookies_dict[key]}; '
67 | # with open('baidu_cookie_output.txt', 'w') as f:
68 | # f.write(cookie_text)
69 |
70 |
71 | """
72 | description: 解密已加密的md5
73 | param {str} encryptMd5 (加密)
74 | return {str} (解密)
75 | """
76 |
77 |
78 | def decryptMd5(encryptMd5):
79 | if re.compile(r"[a-f\d]").match(encryptMd5[9]):
80 | return encryptMd5
81 | key = "{:x}".format(ord(encryptMd5[9]) - ord("g"))
82 | key2 = encryptMd5[0:9] + key + encryptMd5[10:]
83 | key3 = ""
84 | for i in range(len(key2)):
85 | key3 += "{:x}".format(int(key2[i], 16) ^ (15 & i))
86 | md5 = key3[8:16] + key3[0:8] + key3[24:32] + key3[16:24]
87 | return md5
88 |
89 |
90 | """
91 | description: 从接口元数据解析出正确文件路径
92 | param {*} fileInfo 接口获取的文件/目录数据
93 | return {str} path 文件路径
94 | """
95 |
96 |
97 | def parseFilePath(fileInfo):
98 | path = str
99 | if "app_id" in fileInfo:
100 | path = fileInfo["path"] if fileInfo["isdir"] else fileInfo["server_filename"]
101 | else:
102 | path = fileInfo["path"]
103 | if path[0] != "/":
104 | path = "/" + path
105 | return path.replace("\u200b", "")
106 |
107 |
108 | class bdpanHelper:
109 | cookie: dict
110 | bdstoken: str
111 | logid: str
112 | extra: str
113 | shareid: int
114 | share_uk: int
115 | url: str
116 | pwd: str
117 | surl: str
118 |
119 | def __init__(self, url: str, pwd: str):
120 | self.url = url
121 | self.pwd = pwd
122 | self.cookie = copy.deepcopy(baidu_cookies_dict)
123 |
124 | def getBdlink(self):
125 | fileInfoList = []
126 | outputInfoList = [] # [{path:, errno:, bdlink?:,}]
127 | respon = self.verify()
128 |
129 | if 0 == respon["errno"]:
130 | self.cookie["BDCLND"] = respon["randsk"]
131 | self.extra = f'{{"sekey":"{unquote(self.cookie["BDCLND"])}"}}'
132 | respon = self.getFileList()
133 | if 0 == respon["errno"]:
134 | fileInfoList = respon["data"]
135 | else:
136 | return respon
137 | else:
138 | return respon
139 |
140 | for fileInfo in fileInfoList:
141 | if fileInfo["md5"]:
142 | fileInfo["md5"] = decryptMd5(fileInfo["md5"])
143 | result = self.checkMd5(fileInfo)["errno"]
144 | if 0 == result:
145 | outputInfoList.append(
146 | {
147 | "path": fileInfo["path"],
148 | "bdlink": f"{fileInfo['md5']}#{fileInfo['size']}#{fileInfo['path'][1:]}",
149 | "errno": 0,
150 | }
151 | )
152 | elif 404 == result:
153 | outputInfoList.append(self.getMd5FromDlink(fileInfo))
154 | else:
155 | outputInfoList.append({"path": fileInfo["path"], "errno": result})
156 |
157 | for outputInfo in outputInfoList:
158 | if outputInfo["errno"]:
159 | msg = default_msg
160 | if outputInfo["errno"] in errno_msg:
161 | msg = errno_msg[respon["errno"]]
162 | outputInfo["msg"] = msg
163 |
164 | return {"errno": 0, "list": outputInfoList}
165 |
166 | """
167 | description: 递归扫描目录下的文件
168 | param {*} dirInfo 单条目录数据, 需包含path
169 | return {*} fileInfoList 文件数据列表
170 | """
171 |
172 | def scanFile(self, path, page):
173 | fileInfoList = []
174 | respon = s.get(
175 | sharelist_url.format(
176 | dir=quote(path),
177 | logid=logid,
178 | shareid=self.shareid,
179 | uk=self.share_uk,
180 | page=page,
181 | ),
182 | cookies=self.cookie,
183 | ).text
184 | respon = json.loads(respon)
185 | if 0 == respon["errno"]:
186 | if not len(respon["list"]):
187 | return fileInfoList
188 | else:
189 | for file in respon["list"]:
190 | if file["isdir"]:
191 | fileInfoList += self.scanFile(parseFilePath(file), 1)
192 | else:
193 | fileInfoList += [
194 | {
195 | "md5": file["md5"].lower(),
196 | "size": file["size"],
197 | "path": parseFilePath(file),
198 | "fs_id": file["fs_id"],
199 | }
200 | ]
201 | fileInfoList += self.scanFile(path, page + 1)
202 | else:
203 | fileInfoList.append({"path": path, "errno": respon["errno"]})
204 | return fileInfoList
205 |
206 | """
207 | description: 从分享链接递归读取文件列表数据
208 | param {*} info 接口参数数据dic
209 | return {List} 文件数据列表, 包含md5, size, path, fs_id
210 | """
211 |
212 | def getFileList(self):
213 | fileInfoList = []
214 | respon = s.get(self.url, cookies=self.cookie).text
215 | fileList = p_fileList.findall(respon)
216 | if len(fileList):
217 | fileList = json.loads(f"[{{{fileList[0]}}}]")
218 | else:
219 | return {"errno": 115}
220 | for file in fileList:
221 | if file["isdir"]:
222 | fileInfoList += self.scanFile(parseFilePath(file), 1)
223 | else:
224 | fileInfoList += [
225 | {
226 | "md5": file["md5"].lower(),
227 | "size": file["size"],
228 | "path": parseFilePath(file),
229 | "fs_id": file["fs_id"],
230 | }
231 | ]
232 | return {"errno": 0, "data": fileInfoList}
233 |
234 | """
235 | description: 验证链接, 获取randsk(密钥)和share_uk,shareid
236 | param {str} url 分享链接
237 | param {str} pwd 提取码
238 | return {*} info 接口参数数据dic
239 | """
240 |
241 | def verify(self):
242 | result = p_surl.findall(self.url)
243 | if len(result):
244 | self.surl = result[0][1]
245 | else:
246 | return {"errno": 114}
247 | respon = s.get(self.url, cookies=self.cookie).text
248 | if "百度网盘-链接不存在" in respon:
249 | return {"errno": 1919}
250 | _share_uk = p_share_uk.findall(respon)
251 | _shareid = p_shareid.findall(respon)
252 | _bdstoken = p_bdstoken.findall(respon)
253 | if len(_share_uk) and len(_shareid):
254 | self.share_uk = int(_share_uk[0])
255 | self.shareid = int(_shareid[0])
256 | else:
257 | return {"errno": 514}
258 | if len(_bdstoken):
259 | self.bdstoken = _bdstoken[0]
260 | else:
261 | return {"errno": 810}
262 | respon = s.post(
263 | verify_url.format(surl=self.surl, bdstoken=self.bdstoken),
264 | headers={
265 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
266 | "User-Agent": ua_web,
267 | "Referer": self.url,
268 | },
269 | data={"pwd": self.pwd, "vcode": "", "vcode_str": ""},
270 | ).text
271 | respon = json.loads(respon)
272 | if 0 == respon["errno"]:
273 | return {"errno": 0, "randsk": respon["randsk"]}
274 | else:
275 | return {"errno": respon["errno"]}
276 |
277 | """
278 | description: 从dlink(文件下载直链)获取文件md5
279 | param {*} fileInfo 单条文件数据, 需包含md5, size, path, file_id
280 | return {*} 修正md5后的输出文件数据
281 | """
282 |
283 | def getMd5FromDlink(self, fileInfo):
284 | dlink: str
285 | sign: str
286 | timestamp: int
287 | respon = s.get(
288 | tpl_url.format(surl="1" + self.surl, logid=logid), cookies=self.cookie
289 | ).text
290 | respon = json.loads(respon)
291 | if 0 == respon["errno"]:
292 | sign = respon["data"]["sign"]
293 | timestamp = respon["data"]["timestamp"]
294 | else:
295 | return {"path": fileInfo["path"], "errno": respon["errno"]}
296 | data = {
297 | "extra": self.extra,
298 | "logid": logid,
299 | "fid_list": json.dumps([fileInfo["fs_id"]]),
300 | "primaryid": self.shareid,
301 | "uk": self.share_uk,
302 | "product": "share",
303 | "encrypt": 0,
304 | }
305 | respon = s.post(
306 | sharedownload_url.format(sign=sign, timestamp=timestamp),
307 | cookies=self.cookie,
308 | data=data,
309 | ).text
310 | respon = json.loads(respon)
311 | if 0 == respon["errno"]:
312 | if "list" in respon and len(respon["list"]):
313 | dlink = respon["list"][0]["dlink"]
314 | else:
315 | return {"path": fileInfo["path"], "errno": 116}
316 | else:
317 | return {"path": fileInfo["path"], "errno": respon["errno"]}
318 | respon = s.get(dlink, headers={"Range": "bytes=0-1", "User-Agent": ua_dl})
319 | if issue_domain in respon.url:
320 | return {"path": fileInfo["path"], "errno": 119}
321 | responHeader = str(respon.headers)
322 | md5 = p_md5.findall(responHeader)
323 | if len(md5):
324 | fileInfo["md5"] = md5[0].lower()
325 | else:
326 | return {"path": fileInfo["path"], "errno": 996}
327 | return {
328 | "path": fileInfo["path"],
329 | "bdlink": f"{fileInfo['md5']}#{fileInfo['size']}#{fileInfo['path']}",
330 | "errno": 0,
331 | }
332 |
333 | """
334 | description: 验证秒传信息的有效性
335 | param {*} fileInfo 单条文件数据, 需包含md5, size
336 | return {'errno': int} 验证结果 errno=0为验证通过
337 | """
338 |
339 | def checkMd5(self, fileInfo):
340 | if not fileInfo["md5"]:
341 | return {"errno": 404}
342 | data = {
343 | "block_list": json.dumps([fileInfo["md5"]]),
344 | "size": fileInfo["size"],
345 | "path": testPath,
346 | "isdir": 0,
347 | "rtype": 3,
348 | "is_revision": 1,
349 | }
350 | respon = s.post(
351 | create_url + f"?bdstoken={self.bdstoken}",
352 | cookies=baidu_cookies_dict,
353 | data=data,
354 | ).text
355 | respon = json.loads(respon)
356 | if 0 == respon["errno"]:
357 | return {"errno": 0}
358 | elif 31190 == respon["errno"]:
359 | return {"errno": 404}
360 | else:
361 | return {"errno": respon["errno"]}
362 |
363 |
364 | if __name__ == "__main__":
365 | readCookie()
366 | respon = bdpanHelper(
367 | "https://pan.baidu.com/s/1eShrmBBtKqQCP3zHjIOxkw?pwd=ais4", "ais4"
368 | ).getBdlink() # 模块测试
369 | if 0 == respon["errno"]:
370 | print(respon)
371 | else:
372 | msg = default_msg
373 | if respon["errno"] in errno_msg:
374 | msg = errno_msg[respon["errno"]]
375 | print(f"错误码: {respon['errno']}, 提示: {msg}")
376 |
--------------------------------------------------------------------------------