02.302后台服务¶
我已经写了几个可开箱即用的 302 模块
1. 一个最简 302 后台服务¶
首先需要安装依赖模块
pip install -U blacksheep p115client uvicorn
下面的代码分享了一个最简单的 302 服务,实现了 id 和 pickcode 查询,并对取得的下载链接进行 302 重定向
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 1)
from pathlib import Path
from p115client import P115Client
client = P115Client(Path("~/115-cookies.txt").expanduser())
from blacksheep import json, redirect, Application, Request
app = Application(show_error_details=__debug__)
@app.router.route("/", methods=["GET", "HEAD"])
async def index(
request: Request,
id: int = 0,
pickcode: str = "",
):
if id > 0 and not pickcode:
pickcode = client.to_pickcode(id)
if not pickcode:
return json({"error": "请指定查询参数 id 或 pickcode,并确保有效"}, 500)
user_agent = request.get_first_header(b"user-agent") or b""
try:
url = await client.download_url(
pickcode,
headers={"user-agent": user_agent.decode("latin-1")},
app="android",
async_=True,
)
except (FileNotFoundError, IsADirectoryError):
return json({"pickcode": pickcode, "error": "not found"}, 404)
return redirect(url)
if __name__ == "__main__":
from uvicorn import run
run(app, host="0.0.0.0", port=8115)
2. 扩展:支持查询 sha1 和 name¶
首先需要安装依赖模块
pip install -U blacksheep p115client uvicorn
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 2)
from pathlib import Path
from p115client import P115Client
client = P115Client(Path("~/115-cookies.txt").expanduser())
from blacksheep import json, redirect, Application, Request
app = Application(show_error_details=__debug__)
@app.router.route("/", methods=["GET", "HEAD"])
async def index(
request: Request,
id: int = 0,
pickcode: str = "",
sha1: str = "",
name: str = "",
):
if not pickcode:
if id > 0:
pickcode = client.to_pickcode(id)
elif sha1:
resp = await client.fs_shasearch(sha1, async_=True)
if not resp["state"]:
return json({"sha1": sha1, "resp": resp}, 404)
pickcode = resp["data"]["pick_code"]
elif name:
payload = {"fc": 2, "limit": 16, "search_value": name, "type": 99}
suffix = name.rpartition(".")[-1]
if len(suffix) < 5 and suffix.isalnum() and suffix[0].isalpha():
payload["suffix"] = suffix
resp = await client.fs_search(payload, async_=True)
if not resp["state"]:
return json({"name": name, "resp": resp}, 404)
for info in resp["data"]:
if info["n"] == name and info.get("sha"):
pickcode = info["pc"]
break
if not pickcode:
return json({"name": name, "error": "not found"}, 500)
user_agent = request.get_first_header(b"user-agent") or b""
try:
url = await client.download_url(
pickcode,
headers={"user-agent": user_agent.decode("latin-1")},
app="android",
async_=True,
)
except (FileNotFoundError, IsADirectoryError):
return json({"pickcode": pickcode, "error": "not found"}, 404)
return redirect(url)
if __name__ == "__main__":
from uvicorn import run
run(app, host="0.0.0.0", port=8115)
3. 扩展:支持对下载链接缓存一定时间¶
首先需要安装依赖模块
pip install -U blacksheep cachedict p115client uvicorn
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 3)
from pathlib import Path
from p115client import P115Client
client = P115Client(Path("~/115-cookies.txt").expanduser())
from binascii import crc32
from urllib.parse import parse_qsl, urlsplit
from blacksheep import json, redirect, Application, Request
from cachedict import TLRUDict
app = Application(show_error_details=__debug__)
cached_urls = TLRUDict(1024)
@app.router.route("/", methods=["GET", "HEAD"])
async def index(
request: Request,
id: int = 0,
pickcode: str = "",
refresh: bool = False,
):
user_agent = request.get_first_header(b"user-agent") or b""
if id <= 0:
id = client.to_id(pickcode)
if id <= 0:
return json({"error": "请指定查询参数 id 或 pickcode,并确保有效"}, 500)
#key = (id, user_agent)
key = (len(user_agent) << id.bit_length()) + id << 32 | crc32(user_agent, id)
if not refresh and (pair := cached_urls.get(key)):
return redirect(pair[1])
if not pickcode:
pickcode = client.to_pickcode(id)
try:
url = await client.download_url(
pickcode,
headers={"user-agent": user_agent.decode("latin-1")},
app="android",
async_=True,
)
except (FileNotFoundError, IsADirectoryError):
return json({"pickcode": pickcode, "error": "not found"}, 404)
# NOTE: 缓存的过期时间为链接过期时间提前 5 分钟
expire_ts = int(next(v for k, v in parse_qsl(urlsplit(url).query) if k == "t")) - 60 * 5
cached_urls[key] = (expire_ts, url)
return redirect(url)
if __name__ == "__main__":
from uvicorn import run
run(app, host="0.0.0.0", port=8115)