logo NodeSeekbeta

分享几个有趣的vertex刷流工具的规则

vertex是挺好用的,但是规则不用js的话功能实在是有限。尤其是rss规则和删种规则,选种规则可设置的项目实在是太少了,严重不符合需求(分享的第三项是选种规则,目前已经基本符合我的轻度刷流需求了,得益于保种体积设置项,甚至可以用15G硬盘的小盘鸡刷而不爆硬盘。),下面分享几个有意思的规则。
1.删种规则(可配置,修改config部分),效果:根据种子的流行程度动态删除种子,只删除没什么人下载的种子,留着上传量大的种子。具体规则:超过七天才可能删除符合规则的种子,删种按分享率删除,每在3的基础上多0.1分享率就多留一天。

(maindata, torrent) => {
const config = {
  deleteHours: 7 * 24 *3600,    // 超时才删种的时间
  ratioThreshold: 3,          // 基础分享率一阈值(上传量 / 种子大小)
  enableLogging: false,        // 是否启用日志记录
};
    const moment = require('moment'); // 确保 moment 模块可用
    const now = moment().unix();

  // 辅助函数:向 /vertex/log22/log.txt 中追加日志信息
function logFailure(message) {
  if (!config.enableLogging) return; // 如果未启用日志记录,直接返回
  const fs = require('fs');
  const path = require('path');
  const logFilePath = '/vertex/log22/log.txt';
  const logDir = path.dirname(logFilePath);
  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir, { recursive: true });
  }
  const logMessage = `${new Date().toISOString()} - ${message}\n`;
  fs.appendFileSync(logFilePath, logMessage);
}
  
  // 计算下载时间和分享率
 const downloadTime = now - torrent.addedTime;
 const downloadTime2 = downloadTime - config.deleteHours;
 const extraDays = Math.max(0, Math.floor(downloadTime2 / 86400)); // 每天86400秒
  // 动态调整分享率上限
 const ratioLimit = config.ratioThreshold + extraDays * 0.1;
  
    // 检查种子是否完成下载
    if (now - torrent.completedTime < config.deleteHours ) {
		return false; // 不删除种子
		}
    if (torrent.completedTime > 0 && torrent.ratio < ratioLimit && torrent.uploadSpeed < 10* 1024) {
            return true; // 删除种子
    }
    return false; // 不删除种子
};


2.删种规则(可配置config部分),效果:适应馒头标盒机制,对于小流量的机器不当冤大头额外上传不计入上传流量的部分。同时又不暂停,可以获取魔力。规则:不实际删除种子,超过分享率后设置限速100k,两天后解除限速(适用于馒头盒子机制:新种标盒,两天盒子规则消失,盒子规则限制时间内只计算3倍种子大小上传量,标盒过期后取消限制)

// 参数:
//   maindata:qBittorrent 的全局数据
//   torrent:当前种子的信息
(maindata, torrent) => {
	// 统一配置对象(所有时间单位均为小时)
const config = {
  pauseThresholdHours: 72,    // 当种子添加时间小于72小时(3天)且分享率大于阈值时触发暂停
  resumeThresholdHours: 72,   // 当种子添加时间大于72小时时用于恢复(这里与暂停阈值相同)
  ratioThreshold: 3,          // 分享率一阈值(上传量 / 种子大小 > 3时触发操作)
  enableLogging: false,        // 是否启用日志记录
  downloaderId: 'e88e88dd',     // 下载器ID,指定适用的下载器ID
  speedLimit: 100 * 1024,            // 限速值(单位:KB/s)  
};

// 辅助函数:向 /vertex/log22/log.txt 中追加日志信息
function logFailure(message) {
  if (!config.enableLogging) return; // 如果未启用日志记录,直接返回
  const fs = require('fs');
  const path = require('path');
  const logFilePath = '/vertex/log22/log.txt';
  const logDir = path.dirname(logFilePath);
  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir, { recursive: true });
  }
  const logMessage = `${new Date().toISOString()} - ${message}\n`;
  fs.appendFileSync(logFilePath, logMessage);
}

// 获取下载器ID和下载器对象
  const downloaderId = config.downloaderId;
  const client = global.runningClient[downloaderId];
if (!client) {
  logFailure(`未找到下载器 ${downloaderId}`);
  return false;
}

  const moment = require('moment'); // 确保 moment 模块可用
  const now = moment().unix();
  // 计算种子添加后的持续时间(单位:秒)
  const ageSeconds = now - torrent.addedTime;
  // 根据配置中的小时数转换为秒数
  const thresholdSeconds = config.pauseThresholdHours * 3600;
  const thresholdSeconds2 = config.resumeThresholdHours * 3600;
  // 计算“分享率一”:上传量 / 种子大小
  const shareRatio1 = torrent.size > 0 ? torrent.uploaded / torrent.size : 0;
  
 // 如果种子添加时间小于阈值(72小时)且分享率大于阈值,则限速种子
  if (ageSeconds < thresholdSeconds && shareRatio1 > config.ratioThreshold) {
    client.setSpeedLimit(torrent.hash, 'upload', config.speedLimit)
      .then(() => {
        logFailure(`限速种子成功: ${torrent.name}`);
      })
      .catch(err => {
        logFailure(`限速种子 ${torrent.name} 失败: ${err}`);
      });
  }
  
  // 如果种子当前已限速且添加时间大于阈值,则取消限速
  if (ageSeconds > thresholdSeconds2) {
    client.setSpeedLimit(torrent.hash, 'upload', 0)  // 设置为0表示取消限速
      .then(() => {
        logFailure(`取消限速成功: ${torrent.name}`);
      })
      .catch(err => {
        logFailure(`取消限速 ${torrent.name} 失败: ${err}`);
      });
  }
  
  // 始终返回 false,不会执行删种操作

  return false;
};



3.rss规则(可以配置config),效果:可以根据更多规则选择要刷的种子,对于小盘鸡友好,完全不会超过设置的保种体积,同时计算体积带矫正,和性能缓解,2分钟前算过体积就不重新计算了,不会每个种子都算一遍全盘种子大小。可以限制下载数量,种子大小,文件名等,可以自定义开启关闭功能进行组合。15G小盘鸡也能刷了,添加种子前计算下载器中种子的大小,这个不是vertex自带的剩余空间大小,那个实际因为没下完种子可能会超过空间导致占满空间,当然可用提前分配缓解,但是还是不符合需求,这个可以直接实现完全不会超过设置空间。可以说是非常人性化了。注意要设置相应下载器的id。

(torrent) => {
  // 配置部分:这些部分可以自定义
  const config = {
    downloaderId: 'e88e88dd',             // 下载器ID,指定适用的下载器ID
    enableLogging: false,                  // 是否启用日志记录
    enableSeedingVolumeLimit: true,        // 是否启用保种体积限制
    seedingVolumeLimit: 50 * 1024 * 1024 * 1024, // 保种体积限制(单位:字节),例如14GB
    enableTaskCountLimit: true,            // 是否启用下载器任务数量限制
    taskCountLimit: 200,                    // 下载器任务数量限制,设置最大任务数
    enableSizeLimit: true,                 // 是否启用种子大小限制
    sizeLimitRange: [1 * 1024 * 1024 * 1024, 10 * 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;
};


1234
1234

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有72243位seeker

🎉欢迎新用户🎉