blob: a2aae5291e3261088177dbc04594c3d78a132641 [file] [log] [blame]
TRM-coding508b31f2025-06-09 02:07:14 +08001#!/usr/bin/env bash
2#
3# batch_test_torrents.sh — 批量检测 .torrent 文件是否能正确启动下载
4#
5# 依赖:curl, jq
6#
7# 用法:./batch_test_torrents.sh /path/to/torrent_dir
8
9set -euo pipefail
10
11QB_URL="http://127.0.0.1:8080"
12QB_USER="admin"
13QB_PASS="9H6k8VpcM"
14COOKIE_JAR="$(mktemp)"
15TORRENT_DIR="${1:-.}"
16TIMEOUT_SECS=60 # 最长等多久才判超时
17POLL_INTERVAL=2 # 每次轮询间隔
18FAILED_DIR="${TORRENT_DIR}/failed_torrents" # 失败种子存放目录
19
20
21# 登录
22_login() {
23 curl -s -c "$COOKIE_JAR" \
24 -d "username=$QB_USER&password=$QB_PASS" \
25 "$QB_URL/api/v2/auth/login" \
26 | grep -q "Ok." || {
27 echo "❌ 登录失败" >&2
28 exit 1
29 }
30}
31
32# 登出
33_logout() {
34 curl -s -b "$COOKIE_JAR" "$QB_URL/api/v2/auth/logout" >/dev/null
35 rm -f "$COOKIE_JAR"
36}
37
38# 添加 torrent,返回 infoHash
39# $1 = .torrent 文件路径
40_add_torrent() {
41 local file="$1"
42 # 丢弃 “Ok.”,只留下后续 info-hash
43 curl -s -b "$COOKIE_JAR" -X POST \
44 -F "torrents=@${file}" \
45 "$QB_URL/api/v2/torrents/add" >/dev/null
46
47 # 等待 qBittorrent 收到任务
48 sleep 3
49
50 # 取最新添加的那个 torrent(按 added_on 降序,limit=1)
51 local info
52 info=$(curl -s -b "$COOKIE_JAR" \
53 "$QB_URL/api/v2/torrents/info?limit=1&sort=added_on&reverse=true")
54
55 # 检查是否获取到有效的 JSON 响应
56 if ! echo "$info" | jq empty 2>/dev/null; then
57 echo "ERROR: Invalid JSON response from qBittorrent API" >&2
58 echo "Response: $info" >&2
59 return 1
60 fi
61
62 # 检查是否有 torrent 记录
63 local count
64 count=$(echo "$info" | jq 'length')
65 if [[ "$count" == "0" ]]; then
66 echo "ERROR: No torrents found after adding" >&2
67 return 1
68 fi
69
70 # 只输出 hash
71 echo "$info" | jq -r '.[0].hash'
72}
73
74# 删除 torrent,同时删除已下载的文件
75# $1 = infoHash
76_delete_torrent() {
77 local hash="$1"
78 curl -s -b "$COOKIE_JAR" \
79 -G --data-urlencode "hashes=${hash}" \
80 "$QB_URL/api/v2/torrents/delete?deleteFiles=true" >/dev/null
81}
82
83# 等待并检测状态
84# $1 = infoHash
85_wait_for_progress() {
86 local hash="$1"
87 local waited=0
88
89 while (( waited < TIMEOUT_SECS )); do
90 # 获取特定种子信息
91 local info
92 info=$(curl -s -b "$COOKIE_JAR" \
93 -G --data-urlencode "hashes=${hash}" \
94 "$QB_URL/api/v2/torrents/info")
95
96 # 检查 JSON 响应
97 if ! echo "$info" | jq empty 2>/dev/null; then
98 echo "⚠️ ${hash}: Invalid API response, retrying..."
99 sleep $POLL_INTERVAL
100 waited=$(( waited + POLL_INTERVAL ))
101 continue
102 fi
103
104 # 检查是否返回了数据
105 local count
106 count=$(echo "$info" | jq 'length')
107 if [[ "$count" == "0" ]]; then
108 echo "⚠️ ${hash}: Torrent not found, retrying..."
109 sleep $POLL_INTERVAL
110 waited=$(( waited + POLL_INTERVAL ))
111 continue
112 fi
113
114 local state progress
115 state=$(echo "$info" | jq -r '.[0].state // "unknown"')
116 progress=$(echo "$info" | jq -r '.[0].progress // 0')
117
118 # 成功开始下载(progress > 0)
119 if awk "BEGIN {exit !($progress > 0)}"; then
120 local progress_percent
121 progress_percent=$(awk "BEGIN {printf \"%.2f\", $progress * 100}")
122 echo "✅ ${hash}: started downloading (progress=${progress_percent}%)"
123 return 0
124 fi
125
126 # 出错状态
127 if [[ "$state" == "error" ]]; then
128 echo "❌ ${hash}: entered error state"
129 return 1
130 fi
131
132 sleep $POLL_INTERVAL
133 waited=$(( waited + POLL_INTERVAL ))
134 done
135
136 echo "⚠️ ${hash}: no progress after ${TIMEOUT_SECS}s timeout"
137 return 2
138}
139
140main() {
141 if [[ ! -d "$TORRENT_DIR" ]]; then
142 echo "Usage: $0 /path/to/torrent_dir" >&2
143 exit 1
144 fi
145
146 # 创建失败种子目录(如果不存在)
147 mkdir -p "$FAILED_DIR"
148
149 # 清空失败种子目录
150 if [[ -d "$FAILED_DIR" ]]; then
151 rm -f "$FAILED_DIR"/*.torrent 2>/dev/null || true
152 echo "已清空失败种子目录:$FAILED_DIR"
153 fi
154
155 _login
156 echo "开始批量测试目录:$TORRENT_DIR"
157 echo "失败的种子将被复制到:$FAILED_DIR"
158
159 for file in "$TORRENT_DIR"/*.torrent; do
160 [[ -e "$file" ]] || { echo "目录中没有 .torrent 文件"; break; }
161
162 echo "---- 测试 $file ----"
163 hash=$(_add_torrent "$file")
164 echo "添加成功,infoHash=$hash"
165
166 if _wait_for_progress "$hash"; then
167 echo ">>> $file 下载检测通过"
168 else
169 echo ">>> $file 下载检测失败"
170 cp "$file" "$FAILED_DIR/"
171 echo "已将失败种子复制到:$FAILED_DIR/$(basename "$file")"
172 fi
173
174 _delete_torrent "$hash"
175 echo
176 done
177
178 _logout
179 echo "全部完成。失败的种子文件已保存在:$FAILED_DIR"
180}
181
182main "$@"