项目介绍
适用于 PT 玩家的追剧刷流一体化综合管理工具,通过规则自动rss向下载器添加种子和删除种子。
官方wiki: https://wiki.vertex-app.top
官方github: https://github.com/vertex-app/vertex
非常优秀的项目,有条件可以给栗大star、打赏
规则配置
项目主要配置四部分即可实现自动化刷流。
- 添加删种规则
- 添加rss规则
- 添加下载器
- 添加刷流任务
添加删种规则

删种规则的作用是vt连接下载器,将符合删种规则的种子自动删除或者通过勾选将符合删种规则的种子保留避免被错误删除。
普通类型的删种规则基本可以满足大部分人的需求,javascript类型删种规则则适合老玩家想实现更精细化的控制。
删种规则总体思路分为以下几种:
- 磁盘空间不足
- 出种后上传速度太慢导致无效占用空间
- 下载过程上传速度太慢导致无效占用空间(黑车)
- 分享率达标
- 种子状态错误
- 种子长时间停滞
- 需要保证种子hr要求
磁盘空间不足
普通类型
各类大小单位为 字节 / Byte, 可以使用 * 做乘法运算
5*1024*1024*1024代表5GiB5*1024*1024代表5MiB各类速度单位为 字节/s / Byte/s
30*1024*1024代表30MiB/s30*1024代表30KiB/s种子进度:以0-1表示完成情况
分享率三:上传/种子总大小 的结果
比较类型:比较类型中的 包含 / 包含于 或 不包含 / 不包含于值部分需以半角逗号 , 为分割符. 如种子分类不包含于 KEEP, KEEP2, KEEP3 三个分类, 则应填写: KEEP,KEEP2,KEEP3
该规则表示剩余空间小于10G时,删除上传速度小于30MiB/s且分类为common的种子,空间大小和速度可以自行调整。默认优先级可以不填 
可以设置多个该类型删种规则并配置优先级实现轮询删种,先删除上传速度小的,再删除上传速度大的种子保证空间(优先级数字越大,优先级越高)。

javascript类型
该规则作用是剩余空间小于30G时选择分类为common上传速度最小的种子删种,可自行修改分类和速度限制
// 仅针对白名单数组内的分类(区分大小写)
// 当全局可用空间 < 30 GiB:逐级阈值 5→10→…→90 MiB/s
// 只在“白名单分类”的种子上做全局判断;忽略其它分类
(maindata, torrent) => {
// 白名单分类(区分大小写)
const CATEGORY_WHITELIST = ["common"];
// 仅在全局剩余空间不足时触发
if (maindata.freeSpaceOnDisk >= util.calSize(30, "GiB")) return false;
// 当前种子必须在白名单中(区分大小写)
if (!CATEGORY_WHITELIST.includes(torrent.category || "")) return false;
// 仅保留白名单分类的种子用于“全局有无命中”的判断
const whiteListTorrents = (maindata.torrents || []).filter(
t => t && CATEGORY_WHITELIST.includes(t.category || "")
);
if (whiteListTorrents.length === 0) return false;
// 逐级门槛(MiB/s)
const thresholdsMiB = [3, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90];
// 逐级查找:以“白名单内的种子”为全集做判断
for (const mib of thresholdsMiB) {
const threshold = util.calSize(mib, "MiB"); // Byte/s
// 只看白名单分类里是否有人低于该门槛
const existsAnyUnder = whiteListTorrents.some(t => (t.uploadSpeed || 0) < threshold);
if (existsAnyUnder) {
// 本轮只删除低于该门槛的白名单分类种子
return (torrent.uploadSpeed || 0) < threshold;
}
}
// 到 90 MiB/s 都无人命中(白名单内),则不删
return false;
};出种后上传速度太慢导致无效占用空间

分享率达标
满足站点最大分享率的要求以及下载完成后立即删种。

种子状态错误
针对硬盘被撑爆,种子错误情况进行删种。

种子长时间停滞
主要针对发种人发种不做种或者未出种撤种情况,彩虹岛复活区经常长时间不发车,所以我添加了域名排除。当前规则为停滞十分钟,有需要可以修改持续时间。

需要保证种子hr要求
通过分类控制HR1分类种子满足一天hr要求后才能删种

添加下载器

下载过程上传速度太慢导致无效占用空间(黑车)
这类型种子基本上最后会被空间不足类型规则删除,所以没有仔细研究过,可以自行设计
添加rss规则
删种规则总体思路分为以下几种:
- 种子大小限制
- 不跳车选种
- 排除分集
如果在这里指定了下载器,那么后续rss任务中符合该条件的种子不会被负载均衡添加到其他下载器。
如果在这里指定了保存路径,那么后续rss任务中符合该条件的种子的保存路径不会生效。
如果在这里指定了分类,那么后续rss任务中符合该条件的种子的分类不会生效。
建议如果非必要,在rss任务中指定分类和保存路径。
普通选种限制种子大小

不跳车选种 如果刷猫站或者其他站点有不让频繁跳车的规则,此时需要javascript规则保证即将添加的种子小于qb剩余空间不会撑爆硬盘。
在规则开头,自行修改相关配置完成选种
(torrent) => {
// 配置部分:这些部分可以自定义
const config = {
downloaderId: 'd67a4881', // 下载器ID,指定适用的下载器ID
enableLogging: true, // 是否启用日志记录
enableSeedingVolumeLimit: true, // 是否启用保种体积限制
seedingVolumeLimit: 470 * 1024 * 1024 * 1024, // 保种体积限制(单位:字节),例如14GB
enableTaskCountLimit: true, // 是否启用下载器任务数量限制
taskCountLimit: 200, // 下载器任务数量限制,设置最大任务数
enableSizeLimit: true, // 是否启用种子大小限制
sizeLimitRange: [1 * 1024 * 1024 * 1024, 300 * 1024 * 1024 * 1024], // 种子大小范围(单位:字节)
enableFileNameMatchLimit: false, // 是否启用文件名匹配限制
fileNameRegex: /sample|test/i // 文件名正则匹配,支持正则表达式
};
const fs = require('fs');
const path = require('path');
// 获取本地时间字符串
function getLocalTimeString() {
return new Date().toLocaleString('zh-CN', { hour12: false });
}
// 辅助函数:向 /vertex/log22/log.txt 中追加日志信息
function logFailure(message) {
if (!config.enableLogging) return; // 如果未启用日志记录,直接返回
const logFilePath = '/vertex/log22/log.txt';
const logDir = path.dirname(logFilePath);
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
const now = getLocalTimeString();
fs.appendFileSync(logFilePath, `[${now}] ${message}\n`);
}
// 获取下载器ID和下载器对象
const downloaderId = config.downloaderId; // 当前下载器ID
const client = global.runningClient[downloaderId];
if (!client) {
logFailure(`未找到下载器 ${downloaderId}`);
return false;
}
// 2. 保种体积限制:先检查 /vertex/${downloaderId}/size.txt 中存储的时间和累计体积
if (config.enableSeedingVolumeLimit) {
const sizeFilePath = `/vertex/${downloaderId}/size.txt`;
const sizeDir = path.dirname(sizeFilePath);
if (!fs.existsSync(sizeDir)) {
fs.mkdirSync(sizeDir, { recursive: true });
}
let currentCumulative = 0; // 当前累计体积(字节)
let fileTimestamp = 0; // 文件中记录的时间(秒)
const now = Math.floor(Date.now() / 1000); // 当前时间,单位:秒
// 尝试读取文件,如果存在则解析内容(格式:timestamp,cumulativeSize)
if (fs.existsSync(sizeFilePath)) {
try {
const data = fs.readFileSync(sizeFilePath, 'utf8').trim();
if (data) {
const parts = data.split(',');
if (parts.length === 2) {
fileTimestamp = Number(parts[0]);
currentCumulative = Number(parts[1]);
}
}
} catch (err) {
logFailure(`读取 size.txt 失败: ${err}`);
}
} else {
// 如果文件不存在,则计算累计体积并创建文件
client.maindata.torrents.forEach(t => {
currentCumulative += Number(t.size || 0);
});
fileTimestamp = now;
try {
fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
} catch (err) {
logFailure(`写入 size.txt 失败: ${err}`);
}
}
// 如果下载器中没有任务,则重置累计体积为 0
if (!client.maindata.torrents || client.maindata.torrents.length === 0) {
currentCumulative = 0;
fileTimestamp = now;
try {
fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
} catch (err) {
logFailure(`重置 size.txt 失败: ${err}`);
}
}
// 如果文件中的时间超过2分钟,则重新计算累计体积
else if (now - fileTimestamp > 120) {
currentCumulative = 0;
client.maindata.torrents.forEach(t => {
currentCumulative += Number(t.size || 0);
});
fileTimestamp = now;
try {
fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
} catch (err) {
logFailure(`更新 size.txt 失败: ${err}`);
}
}
// 确保 torrent.size 为数值
const torrentSize = Number(torrent.size);
// 将累计体积加上当前种子的大小,与保种体积限制比较
if ((currentCumulative + torrentSize) >= config.seedingVolumeLimit) {
logFailure(`保种体积限制不通过:累计体积 ${currentCumulative} + 当前种子 ${torrentSize} 超过限制 ${config.seedingVolumeLimit}`);
return false;
}
}
// 3. 下载器任务数量限制:检查下载器当前任务数量
if (config.enableTaskCountLimit) {
if (client.maindata.torrents.length >= config.taskCountLimit) {
logFailure(`任务数量限制不通过:当前任务数量 ${client.maindata.torrents.length} 超过限制 ${config.taskCountLimit}`);
return false;
}
}
// 4. 种子大小限制:检查种子的大小是否在规定范围内
if (config.enableSizeLimit) {
const size = Number(torrent.size);
if (size < config.sizeLimitRange[0] || size > config.sizeLimitRange[1]) {
logFailure(`种子大小限制不通过:种子大小 ${size} 不在范围 ${config.sizeLimitRange[0]} - ${config.sizeLimitRange[1]}`);
return false;
}
}
// 5. 文件名匹配限制:检查文件名是否符合正则匹配
if (config.enableFileNameMatchLimit) {
const fileName = torrent.name;
if (!fileName.match(config.fileNameRegex)) {
logFailure(`文件名匹配限制不通过:种子名称 "${fileName}" 未匹配正则 ${config.fileNameRegex}`);
return false;
}
}
// 如果所有条件都满足,则表示添加该种子。
// 在返回 true 前,如果启用了保种体积限制,则更新 /vertex/${downloaderId}/size.txt
if (config.enableSeedingVolumeLimit) {
const sizeFilePath = `/vertex/${downloaderId}/size.txt`;
let cumulative = 0;
let fileTimestamp = 0;
if (fs.existsSync(sizeFilePath)) {
try {
const data = fs.readFileSync(sizeFilePath, 'utf8').trim();
if (data) {
const parts = data.split(',');
if (parts.length === 2) {
fileTimestamp = Number(parts[0]);
cumulative = Number(parts[1]);
}
}
} catch (err) {
logFailure(`读取 size.txt 更新部分失败: ${err}`);
}
}
cumulative += Number(torrent.size);
try {
fs.writeFileSync(sizeFilePath, `${fileTimestamp},${cumulative}`);
} catch (err) {
logFailure(`更新 size.txt 失败: ${err}`);
}
}
return true;
};下载器ID位置,同时qb勾选为所有文件预分配磁盘空间


排除分集
注意如果采用此规则,rss勾选时要勾选种子副标题,主要逻辑是通过正则表达式匹配分集标题进行排除
(torrent) => {
// 配置部分:自定义控制
const config = {
enableSizeLimit: true, // 是否启用种子大小限制
sizeLimitRange: [40 * 1024 * 1024 * 1024, 450 * 1024 * 1024 * 1024],
enableFileNameMatchLimit: true, // 是否启用文件名匹配限制
fileNameRegex: /第\s*[0-9一二三四五六七八九十百千零〇]+(?:\s*[-~—、,]\s*[0-9一二三四五六七八九十百千零〇]+)?\s*[集期]/i // 匹配“第01集”、“第23集”等,排除这些
};
// 1. 种子大小限制
if (config.enableSizeLimit) {
const size = Number(torrent.size);
if (size < config.sizeLimitRange[0] || size > config.sizeLimitRange[1]) {
return false;
}
}
// 2. 文件名正则匹配
if (config.enableFileNameMatchLimit) {
const fileName = torrent.name;
// 匹配到单集排除
if (config.fileNameRegex.test(fileName)) {
return false;
}
}
return true;
};添加下载器
直接填写账号密码没什么说的

删种规则:该下载器当中的种子满足任一删种规则自动被删除
拒绝删种规则:该下载器当中的种子满足任一拒绝删种规则不会被删除
如果同时满足拒绝删种规则和删种规则,拒绝删种优先级更高,种子不会被删除

如果配置正确,状态会显示正常

添加刷流任务
排序规则
如果一台下载器,排序规则任选其一即可没有区别。
如果勾选多台下载器,每一次rss,满足rss规则的种子会根据排序规则选择下载器进行添加种子,所谓负载均衡。
举例:如果有两台下载器nc1(剩余空间50G)、nc2(剩余空间70G)在此任务中同时勾选,此任务排序规则选择当前剩余空间,此时来了一个种子大小25G的种子,此种子会被添加进入nc2下载器,其他规则类似。

rss链接
站点提取rss链接,建议标题格式把类型 副标题 大小全部勾选。生成链接后选取含有”BT客户端字样”的链接
\ 
抓取免费和排除hr要看vt是否支持该站点,否则不要勾选。(详情参考vt支持站点)
rss周期基本上默认即可,部分站点可能会触发流控导致无法获取种子需要修改rss获取频率。
限制上传速度根据站点规则自行填写,注意单位 (部分可以参考:PT站点限速规则)

最长休眠时间
上一次成功获取rss链接是时间是10:00,本次成功获取rss链接时间是12:00,两次成功获取时间间隔大于最长休眠时间,那么就会抛弃本次获取的所有种子不添加进入下载器。本质是为了避免某几次rss获取失败导致本次成功获取的种子太多撑爆下载器。
如果想不休眠,获取到种子就马上添加,改为9999999999
选择规则直接勾选你想筛选的种子

特殊规则
天空前一小时限速上传
种子添加进入下载器后限制上传速度为10KiB/s,添加一小时后限制上传速度为450MiB/s
进入ssh执行脚本,在脚本后面按顺序填写 端口号 qb账号 qb密码 天空分类名称
bash <(curl -s https://raw.githubusercontent.com/guyuanwind/Seedbox/refs/heads/main/sky_limit.sh) qb端口号 qb账号 qb密码 "你的分类名称"三倍分享率限速
种子上传是种子体积三倍之后,将该种上传速度限制为10KiB/s。部分站点上传上限是下载量的三倍,所以上传最大化在保证出种同时避免流量浪费。
种子分类支持多个分类,留空默认下载器全部种子参与限速
bash <(curl -s https://raw.githubusercontent.com/guyuanwind/Seedbox/refs/heads/main/3ratio.sh) qb端口号 qb账号 qb密码 "分类1,分类2"常见问题
- 无法获取种子,rss历史持续显示“拒绝原因:最长休眠时间”:检查rss频率避免被流控,不要频繁编辑rss任务
部署
初始账号 admin
初始密码在/配置文件/data/password
compose部署
services:
vertex:
image: lswl/vertex:stable
container_name: vertex
network_mode: "host" # 使用 host 网络模式
environment:
- TZ=Asia/Shanghai
- PORT=3000 # 将 HTTP 服务端口修改为 4000
- HTTPS_ENABLE=false # 不启用 HTTPS (可以根据需要修改为 true,并指定 HTTPS_PORT)
- REDISPORT=6379 # 内部 Redis 服务端口
- PUID=0 # PUID(根据需要设置)
- PGID=0 # PGID(根据需要设置)
volumes:
- /vol1/1000/docker/vertex:/vertex
restart: alwaysdocker run 部署
docker run -d
\--name vertex
\--network host
\-e TZ=Asia/Shanghai
\-e PORT=4000
\-e HTTPS\_ENABLE=false
\-e REDISPORT=6379
\-e PUID=0
\-e PGID=0
\-v /root/vertex:/vertex
\--restart always
lswl/vertex:stable脚本部署
bash <(curl -s https://raw.githubusercontent.com/guyuanwind/docker/refs/heads/main/vertex_install.sh) -u 用户名 -p 密码 -o 端口号




























































