YYPOST群发软件 发表于 2026-8-24 07:03:22

七猫阅读赚钱自动刷框架

七猫阅读赚钱自动刷框架







// =============================================================================
//通用阅读赚钱自动刷框架(七猫/番茄/快音等通用版)
//平台: AIWROK Android (ES5 严格语法)
//原理: 翻页阅读 + 看广告领奖励 + 防检测随机化
//特点: 每个App只需配置包名和翻页方向,框架自动处理其余逻辑
//
//支持App:
//    1. 七猫小说   com.kmxs.reader          翻页方向: horizontal(左右)
//    2. 番茄免费小说com.dragon.read         翻页方向: horizontal(左右)
//    3. 快音         com.kuaiyin.x             翻页方向: vertical(上下)
//    4. 抖音极速版   com.ss.android.ugc.aweme.lite   翻页方向: vertical(上下)
//    5. 自定义App    (在APP表里添加即可)
//
//防检测策略:
//    - 随机翻页间隔 (8~18秒,每个页面不同)
//    - 随机停留时长 (在页面上多停一会再翻)
//    - 随机滑动轨迹 (起点/终点都有微小偏移)
//    - 随机滑动速度 (300~700ms之间)
//    - 偶尔做"回翻"动作 (模拟真人回头看一下)
//    - 偶尔做"点赞"动作 (模拟真人互动)
//    - 每30分钟休息一次 (模拟真人离开)
// =============================================================================

print.log("╔══════════════════════════════════════════════╗");
print.log("║通用阅读赚钱自动刷框架 v1.0                  ║");
print.log("║七猫/番茄/快音等通用 | 防检测随机化            ║");
print.log("╚══════════════════════════════════════════════╝");
print.time();

// =============================================================================
//第一部分:配置(只需改这里就能适配新App)
// =============================================================================

var CONFIG = {
    // ====== 选择目标App (1~4) ======
    目标App编号: 1,

    // ====== 运行时长 ======
    总运行分钟: 60,               // 总共跑多久(分钟)
    每隔N分钟休息: 30,            // 每跑N分钟休息一次
    休息秒数: 30,                   // 每次休息多少秒

    // ====== 翻页参数(随机范围) ======
    最小停留秒: 8,                  // 每页最少停留秒数
    最大停留秒: 18,               // 每页最多停留秒数
    滑动时长最小毫秒: 300,         // 滑动速度下限
    滑动时长最大毫秒: 700,         // 滑动速度上限

    // ====== 防检测概率 ======
    回翻概率: 0.08,               // 8%概率做一次回翻动作
    点赞概率: 0.05,               // 5%概率做一次双击点赞
    休息概率: 0.03,               // 3%概率额外多停一会

    // ====== 看广告领奖励 ======
    看广告间隔分钟: 5,               // 每N分钟去看一次广告领奖励
    广告等待秒: 30,                  // 看广告等待秒数

    // ====== 弹窗关键词 ======
    弹窗关键词: [
      "我知道了", "知道了", "暂不开启", "以后再说", "取消",
      "暂不更新", "下次再说", "拒绝", "不允许", "跳过", "关闭",
      "暂不领取", "稍后再说", "不再提示", "暂不签到", "继续阅读",
      "暂不参加", "不了谢谢", "以后再领", "下次再领"
    ],

    // ====== 阅读页特征文字(多个满足一个即认为在阅读页) ======
    阅读页特征: ["目录", "上一章", "下一章", "书签", "设置", "夜间", "亮度", "字体"],

    // ====== 模式 ======
    优先使用Agent模式: true,
    调试模式: true,

    // ====== App表(添加新App只需在这里加一行) ======
    App表: [
      {
            编号: 1,
            名称: "七猫小说",
            包名: "com.kmxs.reader",
            翻页方向: "horizontal",      // horizontal=左右翻页(小说), vertical=上下滑动(视频)
            翻页起点X: 0.80,            // 水平翻页: 从右侧往左滑 (起点X) 七猫阅读区0~1.0
            翻页起点Y: 0.45,            // 翻页起点Y 避开顶部菜单和底部进度条
            翻页终点X: 0.20,            // 水平翻页: 终点X
            翻页终点Y: 0.45,            // 翻页终点Y
            福利页坐标: ,      // 底部"福利"Tab (实测XML: centerPercent=)
            广告按钮文字: "看视频领金币",    // 看广告按钮上的文字
            启动后等待秒: 8,
            阅读页检测文字: "目录",          // 在阅读页能看到的文字(判断是否在阅读界面)
            需要找书: true,               // 七猫书架可能为空,需要去书城找书
            书城Tab坐标: ,    // 底部"书城"Tab (实测XML: centerPercent=)
            书架Tab坐标: ,    // 底部"书架"Tab (实测XML: centerPercent=)
            点击中央呼出菜单: false         // 七猫阅读页菜单是常驻的,不需要点中央呼出/隐藏
      },
      {
            编号: 2,
            名称: "番茄免费小说",
            包名: "com.dragon.read",
            翻页方向: "horizontal",
            翻页起点X: 0.75,
            翻页起点Y: 0.50,
            翻页终点X: 0.25,
            翻页终点Y: 0.50,
            福利页坐标: ,
            广告按钮文字: "看视频领金币",
            启动后等待秒: 8,
            阅读页检测文字: "目录",
            需要找书: true,
            书城Tab坐标: ,
            书架Tab坐标: ,
            点击中央呼出菜单: false
      },
      {
            编号: 3,
            名称: "快音",
            包名: "com.kuaiyin.x",
            翻页方向: "vertical",          // 上下滑动(短视频类)
            翻页起点X: 0.35,                // 左侧滑动避开全屏按钮
            翻页起点Y: 0.78,
            翻页终点X: 0.35,
            翻页终点Y: 0.22,
            福利页坐标: ,
            广告按钮文字: "看视频领金币",
            启动后等待秒: 8,
            阅读页检测文字: null,             // 短视频类不需要检测阅读页
            需要找书: false,
            书城Tab坐标: null,
            书架Tab坐标: null,
            点击中央呼出菜单: false
      },
      {
            编号: 4,
            名称: "抖音极速版",
            包名: "com.ss.android.ugc.aweme.lite",
            翻页方向: "vertical",
            翻页起点X: 0.35,
            翻页起点Y: 0.78,
            翻页终点X: 0.35,
            翻页终点Y: 0.22,
            福利页坐标: ,          // 右侧红包挂件
            广告按钮文字: "看视频赚金币",
            启动后等待秒: 8,
            阅读页检测文字: null,
            需要找书: false,
            书城Tab坐标: null,
            书架Tab坐标: null,
            点击中央呼出菜单: false
      }
    ]
};

// =============================================================================
//第二部分:引擎(Agent / 无碍 双模式自动切换)
// =============================================================================

var Engine = {
    mode: "",
    屏幕宽: 1080,
    屏幕高: 2400,

    init: function() {
      print.log("\n【引擎初始化】检测模式...");
      if (CONFIG.优先使用Agent模式) {
            try { if (agent.isOpen()) { this.mode = "agent"; print.log("✓ Agent代理模式"); } } catch(e) {}
      }
      if (this.mode === "") {
            try { if (typeof auto !== 'undefined') { this.mode = "auto"; print.log("✓ 无碍(Accessibility)模式"); } } catch(e) {}
      }
      if (this.mode === "") {
            print.log("✗ 两个模式都不可用!请开启 Agent 或无障碍后再跑");
            return false;
      }

      try {
            if (this.mode === "agent") {
                var raw = "" + agent.shell("wm size");
                var m = raw.match(/(\d+)x(\d+)/);
                this.屏幕宽 = m ? parseInt(m) : 1080;
                this.屏幕高 = m ? parseInt(m) : 2400;
            } else {
                this.屏幕宽 = screen.getScreenWidth();
                this.屏幕高 = screen.getScreenHeight();
            }
      } catch(e) {
            this.屏幕宽 = 1080;
            this.屏幕高 = 2400;
      }
      print.log("✓ 屏幕尺寸:" + this.屏幕宽 + " × " + this.屏幕高);
      return true;
    },

    // 随机整数 [min, max)
    randInt: function(min, max) {
      return Math.floor(min + Math.random() * (max - min));
    },

    // 随机浮点 [0, 1)
    randFloat: function() {
      return Math.random();
    },

    // 随机偏移(在基准值上加微小随机量)
    jitter: function(base, range) {
      return base + (Math.random() - 0.5) * range;
    },

    // 翻页滑动(核心防检测:随机轨迹 + 随机速度 + 随机偏移)
    nextPage: function(app) {
      var x1, y1, x2, y2;
      var dur = this.randInt(CONFIG.滑动时长最小毫秒, CONFIG.滑动时长最大毫秒);

      if (app.翻页方向 === "horizontal") {
            // 水平翻页:从右往左滑(下一页)
            x1 = this.jitter(app.翻页起点X, 0.04);
            y1 = this.jitter(app.翻页起点Y, 0.08);
            x2 = this.jitter(app.翻页终点X, 0.04);
            y2 = this.jitter(app.翻页终点Y, 0.08);
      } else {
            // 垂直翻页:从下往上滑(下一个视频)
            x1 = this.jitter(app.翻页起点X, 0.06);
            y1 = this.jitter(app.翻页起点Y, 0.04);
            x2 = this.jitter(app.翻页终点X, 0.06);
            y2 = this.jitter(app.翻页终点Y, 0.04);
      }

      // 确保坐标在合法范围
      x1 = Math.max(0.02, Math.min(0.98, x1));
      y1 = Math.max(0.02, Math.min(0.98, y1));
      x2 = Math.max(0.02, Math.min(0.98, x2));
      y2 = Math.max(0.02, Math.min(0.98, y2));

      if (CONFIG.调试模式) {
            print.log("→ 翻页 [" + app.翻页方向 + "] (" +
                x1.toFixed(2) + "," + y1.toFixed(2) + ") → (" +
                x2.toFixed(2) + "," + y2.toFixed(2) + ") " + dur + "ms");
      }

      try {
            auto.swipPercent_v2(x1, y1, x2, y2, dur, 0);
      } catch(e) {
            // 兜底:用 agent.shell input swipe
            try {
                var px1 = Math.floor(this.屏幕宽 * x1);
                var py1 = Math.floor(this.屏幕高 * y1);
                var px2 = Math.floor(this.屏幕宽 * x2);
                var py2 = Math.floor(this.屏幕高 * y2);
                agent.shell("input swipe " + px1 + " " + py1 + " " + px2 + " " + py2 + " " + dur);
            } catch(e2) {
                print.log("⚠ 翻页失败: " + e2.message);
            }
      }
      sleep.millisecond(this.randInt(300, 600));

      // 小说类App翻页后可能弹出广告/弹窗,关闭它
      if (app.点击中央呼出菜单) {
            // 不再点中央隐藏菜单——七猫阅读页菜单是常驻的(上一章/下一章/目录在底部)
            // 只关闭可能弹出的广告弹窗
            this.closePopup();
      }
    },

    // 回翻(模拟真人回头看一下上一页)
    backPage: function(app) {
      print.log("↩ 回翻一页(模拟真人回头)");
      var x1, y1, x2, y2;

      if (app.翻页方向 === "horizontal") {
            // 水平回翻:从左往右滑(上一页)
            x1 = this.jitter(app.翻页终点X, 0.04);
            y1 = this.jitter(app.翻页起点Y, 0.08);
            x2 = this.jitter(app.翻页起点X, 0.04);
            y2 = this.jitter(app.翻页终点Y, 0.08);
      } else {
            // 垂直回翻:从上往下滑(上一个视频)
            x1 = this.jitter(app.翻页终点X, 0.06);
            y1 = this.jitter(app.翻页终点Y, 0.04);
            x2 = this.jitter(app.翻页起点X, 0.06);
            y2 = this.jitter(app.翻页起点Y, 0.04);
      }

      try {
            auto.swipPercent_v2(x1, y1, x2, y2, this.randInt(400, 800), 0);
      } catch(e) {
            try {
                var px1 = Math.floor(this.屏幕宽 * x1);
                var py1 = Math.floor(this.屏幕高 * y1);
                var px2 = Math.floor(this.屏幕宽 * x2);
                var py2 = Math.floor(this.屏幕高 * y2);
                agent.shell("input swipe " + px1 + " " + py1 + " " + px2 + " " + py2 + " 600");
            } catch(e2) {}
      }
      sleep.millisecond(this.randInt(500, 1000));
    },

    // 双击点赞(模拟真人双击屏幕点赞)
    doubleTap: function() {
      print.log("❤ 双击点赞");
      var x = this.jitter(0.5, 0.1);
      var y = this.jitter(0.4, 0.1);
      try {
            auto.clickPercent(x, y);
            sleep.millisecond(80);
            auto.clickPercent(x, y);
      } catch(e) {
            try {
                var px = Math.floor(this.屏幕宽 * x);
                var py = Math.floor(this.屏幕高 * y);
                agent.shell("input tap " + px + " " + py);
                sleep.millisecond(80);
                agent.shell("input tap " + px + " " + py);
            } catch(e2) {}
      }
      sleep.millisecond(this.randInt(300, 600));
    },

    // 点击百分比坐标
    clickPercent: function(px, py) {
      try {
            auto.clickPercent(px, py);
      } catch(e) {
            try {
                agent.shell("input tap " + Math.floor(this.屏幕宽 * px) + " " + Math.floor(this.屏幕高 * py));
            } catch(e2) {}
      }
      sleep.millisecond(this.randInt(600, 1000));
    },

    // 返回键
    back: function() {
      try {
            if (this.mode === "agent") agent.shell("input keyevent 4");
            else auto.back();
      } catch(e) {}
      sleep.second(1);
    },

    // Home键
    home: function() {
      try {
            if (this.mode === "agent") agent.shell("input keyevent 3");
            else auto.home();
      } catch(e) {}
      sleep.second(2);
    },

    // 启动 App
    openApp: function(pkg, name) {
      print.log("→ 启动:" + name + "(" + pkg + ")");
      try {
            app.resetApp(pkg);
            print.log("✓ 启动APP:" + pkg);
            return true;
      } catch(e) {
            print.log("⚠ app.resetApp 失败:" + e.message + ",尝试 monkey 兜底");
            try {
                agent.shell("monkey -p " + pkg + " -c android.intent.category.LAUNCHER 1");
                return true;
            } catch(e2) {
                print.log("✗ 启动完全失败:" + e2.message);
                return false;
            }
      }
    },

    // 关闭弹窗(全用 nodeSearch,不依赖 findText)
    closePopup: function() {
      var words = CONFIG.弹窗关键词;
      try {
            var nodes = auto.nodeSearch(1000);
            if (!nodes) return false;

            // 第一轮:精确匹配关键词
            for (var i = 0; i < words.length; i++) {
                try {
                  var filtered = nodes.text(words);
                  if (filtered && filtered.count() > 0) {
                        var node = filtered.getNode(0);
                        if (node && this.clickNode(node, words, "弹窗")) {
                            return true;
                        }
                  }
                } catch(e2) {}
            }

            // 第二轮:模糊匹配关键词
            for (var j = 0; j < words.length; j++) {
                try {
                  var inc = nodes.textIncludes(words);
                  if (inc && inc.count() > 0) {
                        var node2 = inc.getNode(0);
                        if (node2 && this.clickNode(node2, words, "模糊弹窗")) {
                            return true;
                        }
                  }
                } catch(e3) {}
            }

            // 第三轮:关闭悬浮广告/红包(通过节点ID,带包名前缀)
            var pkg = "";
            try { pkg = app.getTopPackName() || ""; } catch(e5) {}
            var closeIds = [
                (pkg ? pkg + ":id/" : "") + "close_red_packet",
                (pkg ? pkg + ":id/" : "") + "close",
                (pkg ? pkg + ":id/" : "") + "iv_close",
                (pkg ? pkg + ":id/" : "") + "btn_close",
                (pkg ? pkg + ":id/" : "") + "img_close",
                "close_red_packet", "close", "iv_close", "btn_close", "img_close"
            ];
            for (var k = 0; k < closeIds.length; k++) {
                try {
                  var idNode = nodes.id(closeIds);
                  if (idNode && idNode.count() > 0) {
                        var node3 = idNode.getNode(0);
                        if (node3 && this.clickNode(node3, closeIds, "浮窗ID")) {
                            return true;
                        }
                  }
                } catch(e4) {}
            }

      } catch(e) {
            if (CONFIG.调试模式) print.log("- 弹窗检测异常: " + e.message);
      }
      return false;
    },

    // 查找并点击文字(精确→模糊→desc匹配,每个都先node.click再坐标fallback)
    findAndClickText: function(keyword) {
      try {
            var nodes = auto.nodeSearch(2000);
            if (!nodes) return false;

            // 1. 精确匹配 text
            try {
                var filtered = nodes.text(keyword);
                if (filtered && filtered.count() > 0) {
                  var node = filtered.getNode(0);
                  if (node && this.clickNode(node, keyword)) return true;
                }
            } catch(e1) {}

            // 2. 模糊匹配 textIncludes
            try {
                var inc = nodes.textIncludes(keyword);
                if (inc && inc.count() > 0) {
                  var node2 = inc.getNode(0);
                  if (node2 && this.clickNode(node2, keyword)) return true;
                }
            } catch(e2) {}

            // 3. desc 精确匹配
            try {
                var descNode = nodes.desc(keyword);
                if (descNode && descNode.count() > 0) {
                  var node3 = descNode.getNode(0);
                  if (node3 && this.clickNode(node3, keyword, "desc")) return true;
                }
            } catch(e3) {}

            // 4. descIncludes 模糊匹配
            try {
                var descInc = nodes.descIncludes(keyword);
                if (descInc && descInc.count() > 0) {
                  var node4 = descInc.getNode(0);
                  if (node4 && this.clickNode(node4, keyword, "desc模糊")) return true;
                }
            } catch(e4) {}
      } catch(e) {
            if (CONFIG.调试模式) print.log("- findAndClickText 异常: " + e.message);
      }
      return false;
    },

    // 点击节点(先尝试node.click(),失败则用坐标点击)
    // AIWROK节点对象的 text/centerPercent/center 都是属性不是方法,用node.xxx不是node.xxx()
    clickNode: function(node, label, matchType) {
      matchType = matchType || "text";
      try {
            // 先尝试 node.click()
            node.click();
            print.log("✓ 点击" + matchType + "【" + label + "】(node.click)");
            sleep.second(1);
            return true;
      } catch(e) {
            // node.click() 失败,用坐标点击
            try {
                // 获取节点的 centerPercent 属性(注意:是属性不是方法)
                var cp = null;
                try { cp = node.centerPercent; } catch(e3) {}
                if (cp) {
                  // centerPercent 格式 ""
                  var m = ("" + cp).match(/([\d.]+),([\d.]+)/);
                  if (m) {
                        var px = parseFloat(m);
                        var py = parseFloat(m);
                        this.clickPercent(px, py);
                        print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px + "," + py + ")");
                        return true;
                  }
                }
                // 兜底:用 center 属性
                var ct = null;
                try { ct = node.center; } catch(e4) {}
                if (ct) {
                  var m2 = ("" + ct).match(/([\d.]+),([\d.]+)/);
                  if (m2) {
                        var cx = parseInt(m2);
                        var cy = parseInt(m2);
                        var px2 = cx / this.屏幕宽;
                        var py2 = cy / this.屏幕高;
                        this.clickPercent(px2, py2);
                        print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px2 + "," + py2 + ")");
                        return true;
                  }
                }
                // 兜底2:用 boundsPercent 属性
                var bp = null;
                try { bp = node.boundsPercent; } catch(e5) {}
                if (bp) {
                  // boundsPercent 格式 "" 取中心
                  var m3 = ("" + bp).match(/\[([\d.]+),([\d.]+)\]\[([\d.]+),([\d.]+)\]/);
                  if (m3) {
                        var px3 = (parseFloat(m3) + parseFloat(m3)) / 2;
                        var py3 = (parseFloat(m3) + parseFloat(m3)) / 2;
                        this.clickPercent(px3, py3);
                        print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px3 + "," + py3 + ")");
                        return true;
                  }
                }
            } catch(e2) {
                if (CONFIG.调试模式) print.log("- clickNode坐标fallback也失败: " + e2.message);
            }
      }
      return false;
    },

    // 判断当前是否在阅读页/视频页
    // 优先用阅读页特有的ID检测(最准确),文字特征只作为辅助
    isOnReadingPage: function(app) {
      if (!app.阅读页检测文字) return true; // 不需要检测的直接返回true
      try {
            var nodes = auto.nodeSearch(1500);
            if (!nodes) return true; // nodeSearch失败时不阻断流程

            // 1. 优先检测阅读页特有的ID(最准确,不会误判)
            try {
                var pkg = app.包名;
                var ids = [
                  pkg + ":id/read_progress_layout",
                  pkg + ":id/book_directory",
                  pkg + ":id/btn_progress_left",
                  pkg + ":id/btn_progress_right",
                  pkg + ":id/read_blank_area",
                  pkg + ":id/read_page_container",
                  pkg + ":id/read_view",
                  pkg + ":id/tv_read_progress"
                ];
                for (var j = 0; j < ids.length; j++) {
                  var idNode = nodes.id(ids);
                  if (idNode && idNode.count() > 0) return true;
                }
            } catch(e3) {}

            // 2. 再用文字特征辅助判断(注意:要同时满足多个特征才算,避免误判)
            var matchCount = 0;
            var features = CONFIG.阅读页特征;
            for (var i = 0; i < features.length; i++) {
                try {
                  var matched = nodes.text(features);
                  if (matched && matched.count() > 0) {
                        matchCount++;
                        // 至少匹配2个阅读页特征文字才认定(减少误判)
                        if (matchCount >= 2) return true;
                  }
                } catch(e) {}
            }

            // 3. 检测主检测文字 + 至少1个其他特征
            try {
                var main = nodes.text(app.阅读页检测文字);
                if (main && main.count() > 0 && matchCount >= 1) return true;
            } catch(e2) {}

            return false;
      } catch(e) {
            return true; // 检测失败时假设在阅读页(不中断流程)
      }
    },

    // 等待一段时间,期间周期性关闭弹窗
    smartSleep: function(totalSec, intervalSec) {
      var remain = totalSec;
      while (remain > 0) {
            var step = Math.min(intervalSec, remain);
            sleep.second(step);
            remain -= step;
            this.closePopup();
      }
    }
};

// =============================================================================
//第三部分:阅读赚钱核心模块
// =============================================================================

var ReadingBot = {
    app: null,
    totalReads: 0,         // 总翻页次数
    totalAds: 0,             // 看广告次数
    totalPopups: 0,          // 关弹窗次数
    totalBackReads: 0,       // 回翻次数
    totalLikes: 0,         // 点赞次数
    totalRests: 0,         // 休息次数
    startTime: 0,
    lastAdTime: 0,         // 上次看广告的时间戳

    run: function(app) {
      this.app = app;
      this.startTime = Date.now();
      this.lastAdTime = this.startTime;

      var maxMs = CONFIG.总运行分钟 * 60 * 1000;

      print.log("\n╔══════════ 开始阅读赚钱 ══════════╗");
      print.log("· App:" + app.名称 + "(" + app.包名 + ")");
      print.log("· 翻页方向:" + app.翻页方向);
      print.log("· 总时长:" + CONFIG.总运行分钟 + " 分钟");
      print.log("· 停留:" + CONFIG.最小停留秒 + "~" + CONFIG.最大停留秒 + " 秒");
      print.log("· 看广告间隔:" + CONFIG.看广告间隔分钟 + " 分钟");
      print.log("╚══════════════════════════════════╝");

      // 1. 启动App
      print.log("\n[步骤1] 启动App...");
      if (!Engine.openApp(app.包名, app.名称)) {
            print.log("✗ 启动失败,退出");
            return;
      }
      sleep.second(app.启动后等待秒 || 8);
      Engine.closePopup();

      // 2. 确保在阅读页/视频页
      print.log("[步骤2] 确认阅读页面...");

      if (app.需要找书 && !Engine.isOnReadingPage(app)) {
            // 书架可能为空或不在阅读页,需要找一本书
            print.log("→ 不在阅读页,需要找一本书进入阅读...");
            this.findBookAndRead(app);
      } else if (!Engine.isOnReadingPage(app)) {
            // 不需要找书的App(如短视频),点中央进入
            print.log("⚠ 不在阅读页,尝试点击屏幕中央进入...");
            Engine.clickPercent(0.5, 0.5);
            sleep.second(2);
            Engine.closePopup();
      }

      if (Engine.isOnReadingPage(app)) {
            print.log("✓ 已进入阅读页面");
      } else {
            print.log("⚠ 未确认在阅读页,但仍继续尝试翻页...");
      }

      // 3. 主循环
      print.log("\n[步骤3] 开始自动翻页阅读...\n");

      while ((Date.now() - this.startTime) < maxMs) {
            var elapsedMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
            var remainMin = (CONFIG.总运行分钟 - elapsedMin).toFixed(1);

            // === A. 检查是否该休息了 ===
            if (CONFIG.每隔N分钟休息 > 0 &&
                (Date.now() - this.startTime) > CONFIG.每隔N分钟 * 60 * 1000 * (this.totalRests + 1)) {
                this.totalRests++;
                var restSec = Engine.randInt(CONFIG.休息秒数, CONFIG.休息秒数 + 20);
                print.log("\n[" + elapsedMin + "m] ☕ 第" + this.totalRests + "次休息 " + restSec + "秒");
                Engine.smartSleep(restSec, 10);
                print.log("✓ 休息完毕,继续阅读");
                continue;
            }

            // === B. 检查是否该看广告了 ===
            var sinceAd = Date.now() - this.lastAdTime;
            if (sinceAd >= CONFIG.看广告间隔分钟 * 60 * 1000) {
                this.watchAd();
                this.lastAdTime = Date.now();
                // 看完广告后确保回到阅读页
                this.ensureReadingPage();
                continue;
            }

            // === C. 随机停留看当前页 ===
            var staySec = Engine.randInt(CONFIG.最小停留秒, CONFIG.最大停留秒);

            // 小概率额外多停一会(模拟真人被内容吸引)
            if (Engine.randFloat() < CONFIG.休息概率) {
                staySec += Engine.randInt(10, 30);
                if (CONFIG.调试模式) print.log("&#128214; 这段内容不错,多看 " + (staySec - CONFIG.最小停留秒) + " 秒");
            }

            if (CONFIG.调试模式) {
                print.log("[" + elapsedMin + "m] 第" + (this.totalReads + 1) + "页 停留" + staySec + "s (剩" + remainMin + "m)");
            } else if ((this.totalReads % 10) === 0) {
                print.log("[" + elapsedMin + "m] 已翻" + this.totalReads + "页 广告" + this.totalAds + "次 弹窗" + this.totalPopups + "次");
            }

            // 停留期间每5秒关一次弹窗
            Engine.smartSleep(staySec, 5);

            // === D. 随机防检测动作 ===
            var dice = Engine.randFloat();

            if (dice < CONFIG.回翻概率) {
                // 小概率回翻一页
                this.totalBackReads++;
                Engine.backPage(this.app);
                sleep.second(Engine.randInt(3, 6));
                // 再翻回来
                Engine.nextPage(this.app);
                this.totalReads++;
            } else if (dice < CONFIG.回翻概率 + CONFIG.点赞概率) {
                // 小概率双击点赞
                this.totalLikes++;
                Engine.doubleTap();
            } else {
                // 正常翻页
                Engine.nextPage(this.app);
                this.totalReads++;
            }

            // 每20页关一次弹窗
            if ((this.totalReads % 20) === 0) {
                if (Engine.closePopup()) this.totalPopups++;
            }

            // 每50页确保在阅读页
            if ((this.totalReads % 50) === 0) {
                if (!Engine.isOnReadingPage(this.app)) {
                  print.log("⚠ 偏离阅读页,尝试恢复...");
                  Engine.back();
                  sleep.second(2);
                  if (!Engine.isOnReadingPage(this.app)) {
                        Engine.clickPercent(0.5, 0.5);
                        sleep.second(2);
                  }
                  Engine.closePopup();
                }
            }
      }

      // 4. 结束统计
      var totalMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
      print.log("\n╔══════════ 阅读结束 ══════════╗");
      print.log("║总翻页:" + this.totalReads + " 次");
      print.log("║回翻次数:" + this.totalBackReads + " 次");
      print.log("║点赞次数:" + this.totalLikes + " 次");
      print.log("║看广告:" + this.totalAds + " 次");
      print.log("║关弹窗:" + this.totalPopups + " 次");
      print.log("║休息次数:" + this.totalRests + " 次");
      print.log("║总时长:" + totalMin + " 分钟");
      print.log("╚══════════════════════════════════╝");

      Engine.home();
    },

    // 找一本书进入阅读页面(七猫/番茄等小说类App用)
    // 基于实测XML节点结构编写,支持重试和多策略fallback
    findBookAndRead: function(app) {
      var maxRetry = 4; // 最多尝试4本书
      var readBtns = ["开始阅读", "免费阅读", "立即阅读", "继续阅读", "免费读", "开始免费读"];
      var addBtns = ["加入书架", "添加到书架", "收藏"];

      for (var retry = 0; retry < maxRetry; retry++) {
            print.log("\n[找书] === 第" + (retry + 1) + "/" + maxRetry + "轮 ===");
            try {
                // 0. 已在阅读页则直接返回
                if (Engine.isOnReadingPage(app)) {
                  print.log("[找书] ✓ 已在阅读页,无需找书");
                  return true;
                }

                // 1. 确保在书城页(点书城Tab)
                if (retry === 0 && app.书城Tab坐标) {
                  print.log("[找书] 1. 点击书城Tab...");
                  Engine.clickPercent(app.书城Tab坐标, app.书城Tab坐标);
                  sleep.second(3);
                  Engine.closePopup();
                }

                // 2. 点击一本书:优先用节点ID,兜底用坐标
                var bookClicked = false;
                var bookTitle = "";

                // 策略A: 用 tv_book_title 节点点击(通过坐标fallback确保点击成功)
                try {
                  var nodes = auto.nodeSearch(2000);
                  if (nodes) {
                        var titleNodes = nodes.id(app.包名 + ":id/tv_book_title");
                        if (titleNodes && titleNodes.count() > 0) {
                            var idx = Math.min(retry, titleNodes.count() - 1);
                            var titleNode = titleNodes.getNode(idx);
                            if (titleNode) {
                              // AIWROK节点text是属性不是方法
                              bookTitle = titleNode.text || ("书" + idx);
                              // tv_book_title 本身 clickable=false,用 clickNode 坐标fallback
                              if (Engine.clickNode(titleNode, bookTitle, "书名")) {
                                    print.log("[找书] 2A. 点击书名[" + bookTitle + "] idx=" + idx);
                                    bookClicked = true;
                              }
                            }
                        }
                  }
                } catch(e2a) {
                  if (CONFIG.调试模式) print.log("[找书] 2A异常: " + e2a.message);
                }

                // 策略B: 用 rank_book_cover 节点点击
                if (!bookClicked) {
                  try {
                        var nodes2 = auto.nodeSearch(2000);
                        if (nodes2) {
                            var coverIds = [
                              app.包名 + ":id/rank_book_cover",
                              "rank_book_cover",
                              "book_cover", "iv_cover", "item_book"
                            ];
                            for (var ci = 0; ci < coverIds.length; ci++) {
                              try {
                                    var coverNodes = nodes2.id(coverIds);
                                    if (coverNodes && coverNodes.count() > 0) {
                                        var cIdx = Math.min(retry, coverNodes.count() - 1);
                                        var coverNode = coverNodes.getNode(cIdx);
                                        if (coverNode && Engine.clickNode(coverNode, "封面" + cIdx, "书籍")) {
                                          print.log("[找书] 2B. 点击封面 id=" + coverIds + " idx=" + cIdx);
                                          bookClicked = true;
                                          break;
                                        }
                                    }
                              } catch(e2b2) {}
                            }
                        }
                  } catch(e2b) {
                        if (CONFIG.调试模式) print.log("[找书] 2B异常: " + e2b.message);
                  }
                }

                // 策略C: 用坐标点击不同的书
                // XML实测: 第1本书 center=, 第5本书 center=
                // 垂直方向间隔约0.1187 (0.3932→0.512→0.6307→0.7495)
                if (!bookClicked) {
                  var bookPositions = [
                        , , , ,
                        , , ,
                  ];
                  var posIdx = retry % bookPositions.length;
                  print.log("[找书] 2C. 坐标点击推荐书 (" + bookPositions + "," + bookPositions + ")");
                  Engine.clickPercent(bookPositions, bookPositions);
                  bookClicked = true;
                }

                if (!bookClicked) {
                  print.log("[找书] ⚠ 无法找到可点击的书籍,重试...");
                  sleep.second(2);
                  continue;
                }

                // 3. 等待页面跳转,然后关闭弹窗
                sleep.second(3);
                Engine.closePopup();

                // 4. 检查是否直接进入了阅读页(有些App会直接打开)
                if (Engine.isOnReadingPage(app)) {
                  print.log("[找书] ✓ 直接进入阅读页");
                  return true;
                }

                // 5. 在书籍详情页找"开始阅读"按钮或"左滑开始阅读"提示
                print.log("[找书] 3. 查找阅读入口...");
                var found = false;

                // 5a. 先检测是否有"左滑开始阅读"提示(七猫特有)
                try {
                  var nodesTip = auto.nodeSearch(2000);
                  if (nodesTip) {
                        // 七猫详情页左滑进入阅读
                        var tipNode = nodesTip.id(app.包名 + ":id/tv_tip1");
                        if (tipNode && tipNode.count() > 0) {
                            print.log("[找书] 检测到【左滑开始阅读】提示,执行左滑手势...");
                            // 左滑:从右(0.8)到左(0.2),在屏幕中部
                            auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
                            sleep.second(3);
                            Engine.closePopup();

                            if (Engine.isOnReadingPage(app)) {
                              print.log("[找书] ✓ 左滑后进入阅读页");
                              return true;
                            }
                            found = true; // 假设左滑成功了
                        }
                  }
                } catch(e5a) {
                  if (CONFIG.调试模式) print.log("[找书] 5a左滑检测异常: " + e5a.message);
                }

                // 5b. 精确匹配阅读按钮文字
                if (!found) {
                  for (var i = 0; i < readBtns.length; i++) {
                        if (Engine.findAndClickText(readBtns)) {
                            print.log("[找书] ✓ 点击了【" + readBtns + "】");
                            found = true;
                            break;
                        }
                  }
                }

                // 5c. 模糊匹配(七猫按钮可能含图标符号)
                if (!found) {
                  var readKeywords = ["免费读", "开始读", "立即读", "阅读", "左滑"];
                  try {
                        var nodes3 = auto.nodeSearch(2000);
                        if (nodes3) {
                            for (var ri = 0; ri < readKeywords.length; ri++) {
                              try {
                                    var inc = nodes3.textIncludes(readKeywords);
                                    if (inc && inc.count() > 0) {
                                        var rn = inc.getNode(0);
                                        if (rn && Engine.clickNode(rn, readKeywords, "模糊阅读")) {
                                          print.log("[找书] ✓ 模糊点击【" + readKeywords + "】");
                                          found = true;
                                          break;
                                        }
                                    }
                              } catch(e3) {}
                            }
                        }
                  } catch(e3b) {}
                }

                // 5d. 如果找到"左滑"文字但之前没处理,做左滑手势
                if (!found) {
                  try {
                        var nodes4 = auto.nodeSearch(2000);
                        if (nodes4) {
                            var swipeTip = nodes4.textIncludes("左滑");
                            if (swipeTip && swipeTip.count() > 0) {
                              print.log("[找书] 检测到【左滑】文字,执行左滑手势...");
                              auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
                              sleep.second(3);
                              Engine.closePopup();
                              found = true;
                            }
                        }
                  } catch(e5d) {}
                }

                // 5e. 兜底:如果以上都没找到,先尝试左滑(七猫最常见的入口),再尝试点底部
                if (!found) {
                  print.log("[找书] 3b. 尝试左滑手势进入阅读...");
                  auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
                  sleep.second(3);
                  Engine.closePopup();

                  if (Engine.isOnReadingPage(app)) {
                        print.log("[找书] ✓ 左滑后进入阅读页");
                        return true;
                  }

                  // 左滑不行,再试点底部常见按钮位置
                  print.log("[找书] 3c. 左滑未成功,点底部按钮位置...");
                  Engine.clickPercent(0.5, 0.88);
                  sleep.second(2);
                  if (!Engine.isOnReadingPage(app)) {
                        Engine.clickPercent(0.5, 0.80);
                        sleep.second(2);
                  }
                }

                // 6. 等待进入阅读页
                sleep.second(3);
                Engine.closePopup();

                if (Engine.isOnReadingPage(app)) {
                  print.log("[找书] ✓ 已进入阅读页");
                  return true;
                }

                // 7. 可能需要先加入书架才能阅读
                print.log("[找书] 4. 尝试加入书架...");
                for (var j = 0; j < addBtns.length; j++) {
                  if (Engine.findAndClickText(addBtns)) {
                        print.log("[找书] ✓ 点击了【" + addBtns + "】");
                        sleep.second(2);
                        break;
                  }
                }

                // 8. 加入书架后再找阅读按钮
                for (var k = 0; k < readBtns.length; k++) {
                  if (Engine.findAndClickText(readBtns)) {
                        print.log("[找书] ✓ 加入书架后点击了【" + readBtns + "】");
                        found = true;
                        break;
                  }
                }

                sleep.second(3);
                Engine.closePopup();

                if (Engine.isOnReadingPage(app)) {
                  print.log("[找书] ✓ 通过加入书架进入阅读页");
                  return true;
                }

                // 9. 本轮失败,返回书城重试
                print.log("[找书] ⚠ 第" + (retry + 1) + "轮失败,返回书城重试...");
                Engine.back();
                sleep.second(2);
                if (app.书城Tab坐标) {
                  Engine.clickPercent(app.书城Tab坐标, app.书城Tab坐标);
                  sleep.second(2);
                }

            } catch(e) {
                print.log("[找书] 第" + (retry + 1) + "轮异常: " + e.message);
                try { Engine.back(); sleep.second(2); } catch(e2) {}
            }
      }

      print.log("[找书] ⚠ " + maxRetry + "轮尝试后仍未进入阅读页");
      return false;
    },

    // 看广告领奖励
    watchAd: function() {
      this.totalAds++;
      var elapsedMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
      print.log("\n[" + elapsedMin + "m] &#128250; 第" + this.totalAds + "次看广告领奖励");

      try {
            // 0. 先关闭可能挡住的浮窗
            Engine.closePopup();

            // 1. 点底部福利/任务Tab
            print.log("[广告] 1. 点击福利Tab (" + this.app.福利页坐标 + "," + this.app.福利页坐标 + ")");
            Engine.clickPercent(this.app.福利页坐标, this.app.福利页坐标);
            sleep.second(3);
            Engine.closePopup();

            // 2. 找"看视频领金币"按钮并点击
            print.log("[广告] 2. 查找【" + this.app.广告按钮文字 + "】");
            var clicked = Engine.findAndClickText(this.app.广告按钮文字);

            if (!clicked) {
                // 尝试其他常见的看广告按钮文字
                var adBtns = ["看视频", "看广告", "领金币", "领取", "看视频奖励", "立即领取"];
                for (var i = 0; i < adBtns.length; i++) {
                  if (Engine.findAndClickText(adBtns)) {
                        clicked = true;
                        break;
                  }
                }
            }

            if (!clicked) {
                // 兜底:点屏幕中下方常见位置
                print.log("[广告] 2b. 文字未找到,点常见位置 (0.5, 0.65)");
                Engine.clickPercent(0.5, 0.65);
                sleep.second(2);
            }

            // 3. 等待广告播放
            print.log("[广告] 3. 等待广告播放 " + CONFIG.广告等待秒 + " 秒...");
            Engine.smartSleep(CONFIG.广告等待秒, 5);

            // 4. 关闭广告结束后的弹窗
            print.log("[广告] 4. 关闭广告弹窗");
            Engine.closePopup();
            sleep.second(2);

            // 5. 返回阅读页
            print.log("[广告] 5. 返回阅读页");
            Engine.back();
            sleep.second(2);
            Engine.closePopup();

      } catch(e) {
            print.log("⚠ 看广告异常: " + e.message);
            // 尽力恢复
            try { Engine.back(); sleep.second(2); } catch(e2) {}
            try { Engine.closePopup(); } catch(e3) {}
      }
    },

    // 确保回到阅读页
    ensureReadingPage: function() {
      if (Engine.isOnReadingPage(this.app)) return;

      print.log("[恢复] 不在阅读页,尝试恢复...");
      var tryCount = 0;
      while (tryCount < 3) {
            tryCount++;
            Engine.back();
            sleep.second(2);
            Engine.closePopup();
            if (Engine.isOnReadingPage(this.app)) {
                print.log("[恢复] ✓ 已回到阅读页");
                return;
            }
            // 点击屏幕中央尝试进入阅读
            Engine.clickPercent(0.5, 0.5);
            sleep.second(2);
            if (Engine.isOnReadingPage(this.app)) {
                print.log("[恢复] ✓ 已回到阅读页");
                return;
            }
      }

      // 多次返回都不在阅读页,可能回退到了书架/书城
      // 尝试重新找书进入阅读
      if (this.app.需要找书) {
            print.log("[恢复] 返回到非阅读页,尝试重新找书...");
            this.findBookAndRead(this.app);
            if (Engine.isOnReadingPage(this.app)) {
                print.log("[恢复] ✓ 重新进入阅读页");
                return;
            }
      }

      print.log("[恢复] ⚠ 多次尝试后仍未回到阅读页,继续翻页");
    }
};

// =============================================================================
//第四部分:主入口
// =============================================================================

function main() {
    if (!Engine.init()) {
      print.log("✗ 引擎初始化失败,退出");
      return;
    }

    // 获取目标App配置
    var app = null;
    for (var i = 0; i < CONFIG.App表.length; i++) {
      if (CONFIG.App表.编号 === CONFIG.目标App编号) {
            app = CONFIG.App表;
            break;
      }
    }

    if (!app) {
      print.log("✗ 目标App编号 " + CONFIG.目标App编号 + " 不存在!");
      print.log("可用编号:");
      for (var j = 0; j < CONFIG.App表.length; j++) {
            print.log("    " + CONFIG.App表.编号 + " = " + CONFIG.App表.名称 + "(" + CONFIG.App表.包名 + ")");
      }
      return;
    }

    // 先回桌面
    Engine.home();
    sleep.second(2);

    // 运行
    try {
      ReadingBot.run(app);
    } catch(e) {
      print.log("⚠ 主流程异常: " + e.message);
      print.log("尝试恢复...");
      try { Engine.home(); } catch(e2) {}
    }

    print.log("\n✓ 脚本完成!");
    print.timeEnd();
}

// 启动
main();


页: [1]
查看完整版本: 七猫阅读赚钱自动刷框架