Klok Automation

自动在Klok上循环创建新聊天并随机选择提示,仅在 klokapp.ai 运行

当前为 2025-03-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Klok Automation
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description 自动在Klok上循环创建新聊天并随机选择提示,仅在 klokapp.ai 运行
  6. // @author You
  7. // @match https://klokapp.ai/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // 验证当前域名是否为 klokapp.ai
  15. if (window.location.hostname !== 'klokapp.ai') {
  16. console.log('此脚本仅适用于 klokapp.ai 域名,当前域名:' + window.location.hostname);
  17. return;
  18. }
  19.  
  20. // 带超时的等待元素出现的函数
  21. function waitForElement(selector, timeout = 10000) { // 默认10秒超时
  22. return Promise.race([
  23. new Promise((resolve) => {
  24. const interval = setInterval(() => {
  25. const element = document.querySelector(selector);
  26. if (element) {
  27. clearInterval(interval);
  28. resolve(element);
  29. }
  30. }, 500);
  31. }),
  32. new Promise((_, reject) => {
  33. setTimeout(() => reject(new Error(`等待元素 ${selector} 超时`)), timeout);
  34. })
  35. ]);
  36. }
  37.  
  38. // 使用 XPath 等待元素出现的函数
  39. function waitForXPath(xpath, timeout = 10000) {
  40. return Promise.race([
  41. new Promise((resolve) => {
  42. const interval = setInterval(() => {
  43. const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  44. const element = result.singleNodeValue;
  45. if (element) {
  46. clearInterval(interval);
  47. resolve(element);
  48. }
  49. }, 500);
  50. }),
  51. new Promise((_, reject) => {
  52. setTimeout(() => reject(new Error(`等待 XPath ${xpath} 超时`)), timeout);
  53. })
  54. ]);
  55. }
  56.  
  57. // 带超时的等待四个按钮的容器出现的函数
  58. function waitForButtons(timeout = 10000) {
  59. return waitForElement('.flex.flex-col.lg\\:flex-row.justify-around.items-center.gap-1.w-full.xs\\:mb-40.md\\:mb-0', timeout);
  60. }
  61.  
  62. // 带超时的等待加载指示器消失的函数
  63. function waitForLoadingToFinish(timeout = 10000) {
  64. return new Promise((resolve, reject) => {
  65. const startTime = Date.now();
  66. const checkLoading = () => {
  67. const loadingDots = document.querySelector('.style_loadingDots__6shQU');
  68. console.log('检查加载状态:', loadingDots ? '存在' : '不存在');
  69. if (!loadingDots || loadingDots.offsetParent === null) {
  70. clearInterval(interval);
  71. resolve();
  72. } else if (Date.now() - startTime > timeout) {
  73. clearInterval(interval);
  74. reject(new Error('等待加载指示器消失超时'));
  75. }
  76. };
  77. const interval = setInterval(checkLoading, 500);
  78. checkLoading(); // 立即检查一次
  79. });
  80. }
  81.  
  82. // 模拟点击事件
  83. function simulateClick(element) {
  84. element.dispatchEvent(new MouseEvent('click', {
  85. bubbles: true,
  86. cancelable: true,
  87. view: window
  88. }));
  89. }
  90.  
  91. // 单独的跳转检查函数
  92. function checkAndRedirect() {
  93. return new Promise(async (resolve) => {
  94. try {
  95. const counterElement = await waitForXPath('/html/body/div[1]/div[2]/div[2]/div[1]/div/div[1]/div[1]/div[2]/div[1]', 5000);
  96. const counterText = counterElement ? counterElement.textContent.trim() : '';
  97. const counter = parseInt(counterText) || 0;
  98. console.log('当前计数器值:', counterText, '解析为:', counter);
  99.  
  100. if (counter === 10) {
  101. const nextPageUrl = 'https://earn.taker.xyz'; // 请替换为实际的下一页URL
  102. window.location.href = nextPageUrl;
  103. console.log('计数器为10,跳转到:', nextPageUrl);
  104. await new Promise(resolve => setTimeout(resolve, 2000)); // 等待2秒确认跳转
  105. resolve(); // 跳转后退出
  106. } else {
  107. console.log('计数器不为10,无需跳转');
  108. resolve();
  109. }
  110. } catch (error) {
  111. console.error('跳转检查出错:', error);
  112. resolve();
  113. }
  114. });
  115. }
  116.  
  117. // 一次完整流程的执行
  118. async function runChatCycle() {
  119. try {
  120. console.log('开始新聊天周期');
  121.  
  122. // 第一步:点击“New Chat”按钮
  123. const newChatButton = await waitForElement('a[href="/app"]', 5000);
  124. console.log('找到 New Chat 按钮,准备点击');
  125. simulateClick(newChatButton);
  126. await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒让页面响应
  127.  
  128. // 第二步:等待四个按钮出现并随机点击一个
  129. const buttonsContainer = await waitForButtons();
  130. console.log('找到按钮容器,准备随机点击');
  131. const buttons = buttonsContainer.querySelectorAll('button');
  132. if (buttons.length > 0) {
  133. const randomIndex = Math.floor(Math.random() * buttons.length);
  134. simulateClick(buttons[randomIndex]);
  135. console.log('随机点击第', randomIndex + 1, '个按钮');
  136. await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒让页面响应
  137. } else {
  138. console.log('未找到按钮');
  139. return false;
  140. }
  141.  
  142. // 等待加载指示器消失
  143. console.log('等待加载完成...');
  144. await waitForLoadingToFinish();
  145. console.log('加载完成');
  146.  
  147. // 检查跳转
  148. await checkAndRedirect();
  149. return true; // 表示周期成功完成
  150. } catch (error) {
  151. console.error('聊天周期出错:', error);
  152. return false; // 表示周期失败
  153. }
  154. }
  155.  
  156. // 主逻辑 - 循环执行
  157. (async () => {
  158. let maxCycles = 10; // 最大循环次数,可调整
  159. let cycleCount = 0;
  160.  
  161. while (cycleCount < maxCycles) {
  162. console.log(`开始第 ${cycleCount + 1} 次循环`);
  163. const success = await runChatCycle();
  164. if (!success) {
  165. console.log('本周期失败,暂停10秒后重试');
  166. await new Promise(resolve => setTimeout(resolve, 10000)); // 失败后暂停10秒
  167. } else {
  168. cycleCount++;
  169. console.log(`本周期成功,完成 ${cycleCount} 次循环`);
  170. await new Promise(resolve => setTimeout(resolve, 2000)); // 成功后暂停2秒
  171. }
  172.  
  173. // 单独检查计数器并跳转
  174. try {
  175. const counterElement = await waitForXPath('/html/body/div[1]/div[2]/div[2]/div[1]/div/div[1]/div[1]/div[2]/div[1]', 5000);
  176. const counterText = counterElement ? counterElement.textContent.trim() : '';
  177. const counter = parseInt(counterText) || 0;
  178. if (counter === 10) {
  179. console.log('检测到计数器为10,准备跳转');
  180. await checkAndRedirect(); // 调用跳转函数
  181. break; // 跳转后退出循环
  182. }
  183. } catch (error) {
  184. console.error('计数器检查超时:', error);
  185. }
  186. }
  187.  
  188. console.log('脚本执行结束,总计完成', cycleCount, '次循环');
  189. })();
  190.  
  191. // 提供手动触发跳转的接口
  192. window.checkAndRedirect = checkAndRedirect;
  193. })();