logo NodeSeekbeta

【一键脚本/PT盒子/刷流神器】Auto-Seedbox-PT (ASP):全自动部署 + 内核级极限调优,榨干服务器每一滴性能!

  • @iota #70 HDSky (空)刷流脚本。使用VT的定时任务功能,进种子时候选择暂停。 分类保持sky,刷空时候尽量不要添加其他站点,只刷空:

    /**
     * =======================================================================================
     * 脚本名称:HDSky (空) 极速周转引擎 
     * * [功能概述]
     * 建议设置(重要):Cron 设置 * * * * * (每分钟),RSS 任务限速 250KB/s,qB 取消预分配。
     * 1. 智能流控:配合 RSS任务初始 限速250KB/s ,1小时后自动解封 + 强制汇报抢 Peer。
     * 2. 精准止盈:扣除首小时无效流量,计算真实有效分享率,达标(3.1)即删。
     * 3. 深度防御:
     * - 黑车防御 (只下不上)
     * - 死车清理 (3h无进度)
     * - 超时熔断 (24h未完成)
     * - 空间阶梯 (剩余空间越少,清理阈值越高)
     * =======================================================================================
     */
    
    async () => {
      const moment = require('moment');
      const util = require('../libs/util');
      const clients = global.runningClient;
    
      // ==============================================================================
      // 详细策略配置 (参数均已校对)
      // ==============================================================================
      const CONFIG = {
        // 目标分类 (脚本忽略大小写,填 'sky' 可匹配 'SKY', 'Sky')
        category: 'sky',
    
        // --- A. 进攻策略 (刷流核心) ---
        protectTime: 3600,               // 保护期: 1小时 (秒)
        protectSpeed: 250 * 1024,        // 保护期限速: 250 KB/s
        targetRatio: 3.1,                // 目标有效分享率: 3.1倍
        reannounceWindow: 300,           // 解封后抢 Peer 窗口: 5分钟
    
        // --- B. 防御策略  ---
    
        // 1. 黑车防御 (下载中且无上传)
        blackCar: {
          minAge: 600,                   // 最小观察时间: 10分钟 (防止误判刚添加的种子)
          minDownSpeed: 1024,            // 下载速度 > 1 KB/s
          maxUpSpeed: 10 * 1024          // 上传速度 < 10 KB/s
        },
    
        // 2. 死车清理 (3小时不开车)
        deadTorrent: {
          age: 3 * 3600,                 // 添加时间 > 3小时
          maxUpSpeed: 50 * 1024          // 上传速度 < 50 KB/s (且进度为0)
        },
    
        // 3. 超时熔断 (24小时未下载完)
        timeout: {
          age: 24 * 3600,                // 添加时间 > 24小时
          maxUpSpeed: 1024 * 1024        // 上传速度 < 1 MB/s (且未完成)
        },
    
        // 4. 绝对生命周期 (兜底策略)
        maxLife: 48 * 3600,              // 超过 48小时 强制删除
    
        // 5. 空间保护:低于该值时不再自动恢复/解封,避免和清理打架
        panicSpaceGB: 5,
    
        // --- C. 空间阶梯清理  ---
        // 逻辑:剩余空间越少,清理条件越苛刻 (从上到下匹配)
        spaceLadder: [
          { free: 100, type: 'speed',  val: 50 },     // <100G, 速度 < 50 KB/s
          { free: 50,  type: 'upload', val: 1 },      // <50G,  总上传 < 1 MB
          { free: 40,  type: 'upload', val: 5 },      // <40G,  总上传 < 5 MB
          { free: 30,  type: 'upload', val: 8 },      // <30G,  总上传 < 8 MB
          { free: 20,  type: 'upload', val: 50 },     // <20G,  总上传 < 50 MB
          { free: 10,  type: 'upload', val: 130 },    // <10G,  总上传 < 130 MB
          { free: 5,   type: 'upload', val: 230 }     // <5G,   总上传 < 230 MB
        ]
      };
      // ==============================================================================
    
      // 辅助函数:批量高效查询历史记录
      const fetchHistoryRecords = async (hashList, minTime) => {
        if (!hashList || hashList.length === 0) return new Map();
        try {
          const sql = `SELECT hash, upload, time FROM torrent_flow WHERE time >= ?`;
          const records = await util.getRecords(sql, [minTime]);
          const map = new Map();
          for (const r of records) {
            if (hashList.includes(r.hash)) {
              if (!map.has(r.hash)) map.set(r.hash, []);
              map.get(r.hash).push(r);
            }
          }
          return map;
        } catch (e) { return new Map(); }
      };
    
      for (const clientId of Object.keys(clients)) {
        const client = clients[clientId];
        const maindata = client.maindata;
        const torrents = maindata?.torrents;
        const serverState = maindata?.serverState || maindata?.server_state;
    
        // 基础数据校验,防止报错
        if (!torrents || !serverState) continue;
    
        const now = moment().unix();
        const currentFreeSpace = serverState.free_space_on_disk || 0;
        const freeSpaceGB = currentFreeSpace / (1024 ** 3);
        const isPanicSpace = freeSpaceGB < CONFIG.panicSpaceGB;
    
        // =========================================================
        // 1. 筛选目标种子 (双向忽略大小写)
        // =========================================================
        const targetTorrents = torrents.filter(t =>
          (t.category || '').toLowerCase().includes(CONFIG.category.toLowerCase())
        );
    
        if (targetTorrents.length === 0) continue;
    
        // 筛选过保护期的 Hash,用于查库 (减少数据库压力)
        const activeHashes = targetTorrents
          .filter(t => (now - t.addedTime) > CONFIG.protectTime)
          .map(t => t.hash);
    
        // 批量查库 (只查过去48小时的记录)
        const historyMap = await fetchHistoryRecords(activeHashes, now - CONFIG.maxLife);
    
        for (const t of targetTorrents) {
          const age = now - t.addedTime;
          const state = t.state || '';
          const stateLower = String(state).toLowerCase();
          const isFinished = t.progress === 1;
          const uploadSpeed = typeof t.uploadSpeed === 'number' ? t.uploadSpeed : (typeof t.upspeed === 'number' ? t.upspeed : 0);
          const downloadSpeed = typeof t.dlspeed === 'number' ? t.dlspeed : (typeof t.downloadSpeed === 'number' ? t.downloadSpeed : 0);
          const currentUploadLimit = t.originProp && typeof t.originProp.up_limit === 'number'
            ? t.originProp.up_limit
            : (typeof t.uploadLimit === 'number' ? t.uploadLimit : 0);
    
          // 仅忽略明确的过渡状态;不再忽略 error / missingFiles,交给后续清理逻辑处理
          if (['checkingup', 'checkingdl', 'moving', 'unknown', 'metadl'].includes(stateLower)) continue;
    
          // ================= 模块 A: 计算有效产出 =================
          let effectiveRatio = 0;
          if (age > CONFIG.protectTime) {
            const boundaryTime = t.addedTime + CONFIG.protectTime;
            const records = historyMap.get(t.hash) || [];
            // 找到 1小时节点之后的第一条记录作为基准
            const startRecord = records.filter(r => r.time >= boundaryTime).sort((a, b) => a.time - b.time)[0];
            const baseUpload = startRecord ? startRecord.upload : 0;
            const effectiveUpload = Math.max(0, t.uploaded - baseUpload);
            effectiveRatio = t.size > 0 ? (effectiveUpload / t.size) : 0;
          }
    
          // ================= 模块 B: 自动化流控 =================
          let targetLimit = -1;
          let needReannounce = false;
          let needResume = false;
          const resumableStates = ['pauseddl', 'pausedup', 'stopped'];
    
          // 空间过低时,不自动恢复/不自动解封,避免和空间清理打架
          if (!isPanicSpace) {
            if (age < CONFIG.protectTime) {
              targetLimit = CONFIG.protectSpeed; // 潜伏期 250K
              if (resumableStates.includes(stateLower)) {
                needResume = true; // 保护期内自动拉起
              }
            } else {
              targetLimit = 0; // 爆发期 无限
              if (resumableStates.includes(stateLower)) {
                needResume = true; // 过保护期后自动拉起并解封
              }
              // 刚过 1小时 的窗口期强制汇报
              if (age < (CONFIG.protectTime + CONFIG.reannounceWindow)) {
                if (['uploading', 'stalledup', 'forcedup', 'downloading', 'stalleddl'].includes(stateLower) || needResume) {
                  if (client.reannounceTorrent && typeof client.reannounceTorrent === 'function') {
                    needReannounce = true;
                  }
                }
              }
            }
    
            // 执行流控 (仅当数值变动时调用)
            if (targetLimit !== -1 && currentUploadLimit !== targetLimit) {
              await client.setSpeedLimit(t.hash, 'upload', targetLimit);
            }
    
            // 拉起暂停种子
            if (needResume) {
              if (client.resumeTorrent && typeof client.resumeTorrent === 'function') {
                await client.resumeTorrent(t.hash);
              } else if (client.startTorrent && typeof client.startTorrent === 'function') {
                await client.startTorrent(t.hash);
              }
            }
    
            // 1小时后自动解封后的抢 Peer 汇报
            if (needReannounce) {
              await client.reannounceTorrent(t.hash);
            }
          }
    
          // ================= 模块 C: 防御与清理 (逻辑判定) =================
          let deleteReason = null;
    
          // 0. [异常] 报错/丢失文件优先清理
          if (stateLower.includes('error')) {
            deleteReason = '异常清理(error)';
          } else if (stateLower.includes('missingfiles')) {
            deleteReason = '异常清理(missingFiles)';
          }
          // 1. [止盈] 达标删除
          else if (effectiveRatio >= CONFIG.targetRatio) {
            deleteReason = `产出达标(Eff:${effectiveRatio.toFixed(2)})`;
          }
          // 2. [兜底] 绝对生命周期结束
          else if (age > CONFIG.maxLife) {
            deleteReason = `周期结束(${CONFIG.maxLife / 3600}h)`;
          }
          // 3. [防御] 超时熔断 (24h未下载完)
          else if (!isFinished && age > CONFIG.timeout.age && uploadSpeed < CONFIG.timeout.maxUpSpeed) {
            deleteReason = "超时熔断(24h未完)";
          }
          // 4. [防御] 死车清理 (3h零进度)
          else if (t.progress === 0 && age > CONFIG.deadTorrent.age && uploadSpeed < CONFIG.deadTorrent.maxUpSpeed) {
            deleteReason = "死车清理(3h零进度)";
          }
          // 5. [防御] 黑车检测 (下载中, 进度>1%, 下>1K, 上<10K)
          else if (stateLower === 'downloading' && t.progress > 0.01 && age > CONFIG.blackCar.minAge) {
            if (downloadSpeed > CONFIG.blackCar.minDownSpeed && uploadSpeed < CONFIG.blackCar.maxUpSpeed) {
              deleteReason = "黑车清理(只下不上)";
            }
          }
          // 6. [防爆] 空间阶梯清理 (Oracle)
          else {
            for (const ladder of CONFIG.spaceLadder) {
              if (freeSpaceGB < ladder.free) {
                // 类型 1: 速度检测 (KB/s)
                if (ladder.type === 'speed') {
                  // 给 1.5h 内的新种豁免权 (除非是黑车,黑车上面已处理)
                  if (age > 1.5 * 3600 && uploadSpeed < ladder.val * 1024) {
                    deleteReason = `空间紧缩(<${ladder.free}G): 低速(${ladder.val}K)`;
                    break;
                  }
                }
                // 类型 2: 总上传检测 (MB)
                else if (ladder.type === 'upload') {
                  // 给 1h 内的新种豁免权
                  if (age > 3600 && t.uploaded < ladder.val * 1024 * 1024) {
                    deleteReason = `空间紧缩(<${ladder.free}G): 贡献低(<${ladder.val}M)`;
                    break;
                  }
                }
              }
            }
          }
    
          // 执行删除
          if (deleteReason) {
            // true 代表同时删除文件
            await client.deleteTorrent(t.hash, true);
          }
        }
      }
    };
    
  • @Supcutie #69 已切换V4+M1,我的猫站达成PB就指望你了

  • @prinze #72 我现在测试的就是两台NC 刷的V4+M1模式 在跑猫, VT规则设置好就行

  • @Supcutie #73 ↑ 3.04 TB ↓ 4.74 TB这几天我刷的不太好,看看未来几天上传能不能超过下载量

  • @prinze #74
    目前脚本最不好搞的点就是动态判断(极限刷流/平稳保种的同时,又要根据硬件情况动态设置参数,又不能完全暴力导致卡顿封号断流),完全暴力是最简单的,毕竟只需要把各个参数调到最高就好了.

    欢迎兄弟测试和反馈,脚本肯定会不断改进的。

  • 更新3.5版本动态控制器完成。折腾一整天,目前在服务器上测试中。

  • 强强强!支持大佬的干货分享!

  • 先滚去收藏夹吃灰

  • 牛啊

你好啊,陌生人!

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

📈用户数目📈

目前论坛共有72033位seeker

🎉欢迎新用户🎉