Skip to content

下载器的自动化链路:搜、下、搬、清 ​

我的下载流程早就不打开界面了。整套是五个环节串起来的:

搜索资源 → 加任务 → 监控完成 → 归档到媒体库 → 删种子

每一环单独看都很简单,但它们之间有四个"手动的坑",如果不管,你就会每天花时间在搬文件上。这篇讲这五环怎么用 HTTP API 串起来。

一、搜索:拿到磁力链接 ​

自己找资源站的搜索接口,比用浏览器自动化稳定一百倍。核心是看它的搜索页有没有一个可以直接拼的 URL:

https://<资源站>/search?q=<关键词>&p=<页码>

很多站返回的是 HTML,用正则抓就行,不需要无头浏览器:

python
results = []
for page in range(1, 4):
    html = get(f"{BASE}/search?q={quote(keyword)}&p={page}")
    for m in re.finditer(r'magnet:\?xt=urn:btih:[a-zA-Z0-9]{32,40}[^"<\s]*', html):
        results.append(m.group(0))

页数给 3 页就够了。 同一个片子,前十来条结果基本覆盖了所有还活着的源。

⚠️ 注意资源站的域名经常换、国内访问可能需要代理。搜索失败时先判断是内容没有还是网络不通(curl -o /dev/null -w '%{http_code}' 看一眼),别混为一谈。

二、加任务:qBittorrent 的 WebAPI ​

qBittorrent 有个挺完整的 HTTP API。整套流程只需要三个调用:

bash
# 1) 登录,拿 cookie
curl -s -c /tmp/qbt.txt \
  --data "username=admin&password=<密码>" \
  http://127.0.0.1:8080/api/v2/auth/login
# 返回 "Ok." 就是成功。注意:它用 cookie,不是 token

# 2) 加任务(磁力记得带 tracker,见后面)
curl -s -b /tmp/qbt.txt \
  http://127.0.0.1:8080/api/v2/torrents/add \
  --data-urlencode "urls=$MAGNET" \
  --data-urlencode "savepath=/data/downloads"

# 3) 查进度(按 hash 或看全量列表)
curl -s -b /tmp/qbt.txt http://127.0.0.1:8080/api/v2/torrents/info | jq '.[] | {name, progress, state}'

state 的取值很关键:

  • metaDL —— 还在要元数据(卡住就是死种,见磁力那篇)
  • downloading / stalledDL —— 在下 / 卡住了
  • uploading / stalledUP —— 下完了(BT 客户端下完即做种,所以"完成"的标记是 uploading)

"完成"的判断不要用 progress == 1 一个条件,stalledDL 时进度可能是 0.999。用 state in (uploading, stalledUP, pausedUP) 更稳。

三、监控:怎么知道下完了 ​

两种做法,各有适用场景:

A. 轮询 API(推荐)

python
while True:
    info = qbt_torrents()
    if all(t["state"].startswith(("uploading", "pausedUP", "stalledUP")) for t in info):
        break
    time.sleep(300)   # 5 分钟一次就够

B. 看文件系统(下载器的"临时文件"特征)

很多下载器边下边写临时文件,下完了才改成正式扩展名:

movie.mkv.!qB     ← 下载中(qBittorrent 的临时后缀)
movie.mkv         ← 完成
video.xltd        ← 迅雷的临时文件

所以一个"每 5 分钟检查有没有新 .mkv 出现"的脚本,也能判断完成。但这是启发式的,BT 分片下载可能很早就创建了目标文件。能查 API 就别猜文件系统。

四、归档:搬进媒体库 ​

这一步是大多数人手工做的部分。搬到媒体库有两个必须注意的点:

1. 先看目录结构。 下载下来的通常是 [站名] 片名 (年份) [分辨率][编码]/ 这种目录,里面才是视频文件。搬的时候整个目录搬,别只搬文件,否则字幕、nfo、样片全丢。

2. 顺序:先移文件,再删任务。

反过来做(先删任务、勾选删除文件)就把片子一起删了。这个错我犯过一次,不用再犯。

3. 目录名带中文/全角括号/emoji 是常态。 脚本里所有路径都要加引号,用 --data-urlencode 或等价方式传参,别自己拼 shell 字符串。

五、清理:删种子,防 PCDN ​

这一步被严重低估。BT 客户端下完之后默认继续做种,持续上传。家用宽带下这可能触发两个后果:

  • 运营商把"持续大流量上行"当成 PCDN 特征,限速甚至断网
  • 上传占满,别的服务(远程访问、同步)全卡

所以下完就该清:

bash
# 删任务但保留文件(文件已经搬到媒体库了)
curl -s -b /tmp/qbt.txt http://127.0.0.1:8080/api/v2/torrents/delete \
  --data-urlencode "hashes=$HASH" --data "deleteFiles=false"

⚠️ deleteFiles=false 还是 true 取决于你的流程:

  • 文件已经移动到媒体库 → false(下载目录里那份已经不在了,删了也无所谓,但 false 更安全)
  • 文件还在下载目录、你要保留它 → false,然后自己搬
  • 确定不要了 → true

另外顺手看一眼种子备份目录,清完之后应该是空的或只有活着的任务:

bash
ls /path/to/qbt/config/BT_backup/ | wc -l

整条链路的骨架 ​

python
def grab(keyword, target_dir):
    magnets = search(keyword)                 # 搜索,拿候选
    if not magnets:
        return "没找到资源"
    magnet = pick(magnets[0])                 # 选一个(带 tracker)
    h = add_torrent(magnet, SAVE_PATH)        # 加任务
    wait_until_done(h)                        # 轮询到完成
    move_to_library(h, target_dir)            # 归档(先搬)
    delete_torrent(h, delete_files=False)     # 清种子(后删)
    return "好了"

四个"手动的坑"总结 ​

  1. 磁力链接不带 tracker → 卡 metaDL(单独的坑)
  2. 完成判断只看进度 → stalledDL 的 0.999 让你白等
  3. 先删任务再搬文件 → 片子没了
  4. 下完不清种子 → 持续上传,可能被限速

一句话版本:搜索抓 HTML 就够,别上浏览器;完成判断看 state 不看 progress;归档永远"先搬后删";下完就删种子。