东航易学助手

检测超时弹窗,稳定多开加速,并处理所有弹出按钮

  1. // ==UserScript==
  2. // @name 东航易学助手
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.2.2
  5. // @description 检测超时弹窗,稳定多开加速,并处理所有弹出按钮
  6. // @author 买不起泡面的Hanley
  7. // @match *://dhyx.ceair.com/*
  8. // @require http://code.jquery.com/jquery-1.9.1.min.js
  9. // @grant unsafeWindow
  10. // @grant GM_addStyle
  11. // @grant GM_getResourceText
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. var Status = 0; // 初始化状态标识
  16. var lastClickTime = Date.now(); // 最后一次点击的时间
  17. var refreshInterval; // 用于存储定时器ID
  18. var isDragging = false; // 用于标识是否正在拖动
  19. var dragStartX, dragStartY; // 记录拖动开始时的鼠标位置
  20.  
  21. function getAutoNavigateEnabled() {
  22. return localStorage.getItem('autoNavigateEnabled') === 'true';
  23. }
  24.  
  25. function setAutoNavigateEnabled(value) {
  26. localStorage.setItem('autoNavigateEnabled', value);
  27. manageAutoRefresh();
  28. }
  29.  
  30. function manageAutoRefresh() {
  31. clearInterval(refreshInterval); // 清除之前的定时器
  32. if (Status == 0 && !getAutoNavigateEnabled()) {
  33. refreshInterval = setInterval(function() {
  34. window.top.location.reload(true);
  35. }, 300000); // 5分钟刷新一次
  36. }
  37. }
  38.  
  39. function updateToggleButton(toggleButton) {
  40. const autoNavigateEnabled = getAutoNavigateEnabled();
  41. toggleButton.innerText = autoNavigateEnabled ? "自动导航:开" : "自动导航:关";
  42. toggleButton.style.background = autoNavigateEnabled ? 'rgba(255, 255, 0, 0.5)' : 'rgba(128, 128, 128, 0.5)';
  43. }
  44.  
  45. function detectAndClickAlertButton() {
  46. // 查找弹窗的wrapper
  47. const alertWrapper = document.querySelector('.alert-shadow.new-alert-shadow');
  48. if (!alertWrapper) {
  49. return;
  50. }
  51.  
  52. // 查找确定按钮
  53. const alertButton = document.getElementById('D253btn-ok');
  54. if (alertButton) {
  55. alertButton.click(); // 自动点击确定按钮
  56. }
  57. }
  58.  
  59.  
  60. function detectString() {
  61. function checkString(node) {
  62. if (node.nodeType === Node.TEXT_NODE) {
  63. if (node.nodeValue.includes('可继续学习')) {
  64. var confirmBtns3 = document.getElementsByClassName("btn");
  65. if (confirmBtns3 != null && confirmBtns3.length > 0) {
  66. confirmBtns3[0].click();
  67. lastClickTime = Date.now();
  68. }
  69. } else if (node.nodeValue.includes('恭喜')) {
  70. var cancelBtns = document.querySelectorAll('button[data-bb-handler="cancel"]');
  71. if (cancelBtns.length > 0) {
  72. cancelBtns[0].click();
  73. }
  74. if (getAutoNavigateEnabled()) {
  75. setTimeout(function() {
  76. window.top.location.reload(true);
  77. }, 5000);
  78. }
  79. } else if (node.nodeValue.includes('进度已保存')) {
  80. if (getAutoNavigateEnabled()) {
  81. // 5秒后刷新页面
  82. setTimeout(function() {
  83. window.top.location.reload(true);
  84. }, 5000);
  85. }
  86. } else if (node.nodeValue.includes('小测试')) {
  87. // 执行一次遍历
  88. }
  89. } else if (node.nodeType === Node.ELEMENT_NODE) {
  90. // 检查元素节点中的文本内容
  91. if (node.textContent.includes('进度已保存')) {
  92. if (getAutoNavigateEnabled()) {
  93. // 5秒后刷新页面
  94. setTimeout(function() {
  95. window.top.location.reload(true);
  96. }, 5000);
  97. }
  98. }
  99. // 遍历子节点
  100. for (let child of node.childNodes) {
  101. checkString(child);
  102. }
  103. }
  104. }
  105.  
  106. const observer = new MutationObserver(function(mutations) {
  107. for (let mutation of mutations) {
  108. for (let addedNode of mutation.addedNodes) {
  109. checkString(addedNode);
  110. }
  111. }
  112. });
  113.  
  114. observer.observe(document.body, {
  115. childList: true,
  116. subtree: true
  117. });
  118. }
  119.  
  120. function updateFlagStatus() {
  121. const flag1 = document.getElementById('flag');
  122. if (Status == 1) {
  123. flag1.innerText = "检测到考试!代码停止运行!\nby:买不起泡面的Hanley";
  124. } else if (Status == 2) {
  125. flag1.innerText = "运行阅卷脚本\nby:买不起泡面的Hanley";
  126. } else {
  127. flag1.innerText = "脚本正在运行\nby:买不起泡面的Hanley";
  128. }
  129. }
  130.  
  131. function makeElementDraggable(element) {
  132. let offsetX, offsetY;
  133.  
  134. element.addEventListener('mousedown', function(event) {
  135. isDragging = false;
  136. dragStartX = event.clientX;
  137. dragStartY = event.clientY;
  138. offsetX = event.clientX - element.getBoundingClientRect().left;
  139. offsetY = event.clientY - element.getBoundingClientRect().top;
  140. element.style.cursor = 'move';
  141.  
  142. function onMouseMove(event) {
  143. const deltaX = event.clientX - dragStartX;
  144. const deltaY = event.clientY - dragStartY;
  145. if (!isDragging && (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5)) {
  146. isDragging = true;
  147. }
  148. if (isDragging) {
  149. element.style.left = event.clientX - offsetX + 'px';
  150. element.style.top = event.clientY - offsetY + 'px';
  151. event.preventDefault(); // 防止选择文本
  152. }
  153. }
  154.  
  155. function onMouseUp() {
  156. document.removeEventListener('mousemove', onMouseMove);
  157. document.removeEventListener('mouseup', onMouseUp);
  158. element.style.cursor = 'pointer';
  159. }
  160.  
  161. document.addEventListener('mousemove', onMouseMove);
  162. document.addEventListener('mouseup', onMouseUp);
  163. });
  164. }
  165.  
  166. if (window.self === window.top) { // 仅在顶层窗口显示悬浮窗
  167. setTimeout(function() {
  168. const flag = document.createElement("div");
  169. flag.id = 'flag';
  170. flag.style.cssText = 'left: 10px;bottom: 10px;background: rgba(26, 89, 183, 0.5);color:#ffffff;overflow: hidden;z-index: 9999;position: fixed;padding:3px;text-align:center;width: 175px;height: 45px;line-height: 20px;border-radius: 4px;cursor: pointer;';
  171. document.getElementById("content").appendChild(flag);
  172.  
  173. updateFlagStatus();
  174.  
  175. makeElementDraggable(flag);
  176.  
  177. flag.addEventListener('click', function() {
  178. if (!isDragging && flag.innerText.includes("脚本正在运行")) {
  179. flag.style.background = 'rgba(255, 0, 0, 0.5)';
  180. flag.innerText = "正在尝试爆破\nby:买不起泡面的Hanley";
  181. markVideoAsCompleted();
  182. setTimeout(function() {
  183. flag.style.background = 'rgba(26, 89, 183, 0.5)';
  184. updateFlagStatus();
  185. }, 2000);
  186. loadKnockoutJs(proceedWithModifications);
  187. }
  188. });
  189.  
  190. const toggleButton = document.createElement("div");
  191. toggleButton.id = 'toggleButton';
  192. toggleButton.style.cssText = 'right: 10px;bottom: 10px;color:#000000;overflow: hidden;z-index: 9999;position: fixed;padding:3px;text-align:center;width: 100px;height: 30px;line-height: 25px;border-radius: 4px;cursor: pointer;';
  193. document.body.appendChild(toggleButton);
  194.  
  195. updateToggleButton(toggleButton); // 确保页面加载时立即更新按钮背景颜色
  196.  
  197. makeElementDraggable(toggleButton);
  198.  
  199. toggleButton.addEventListener('click', function() {
  200. if (!isDragging) {
  201. const newState = !getAutoNavigateEnabled();
  202. setAutoNavigateEnabled(newState);
  203. updateToggleButton(toggleButton);
  204. setTimeout(function() {
  205. window.top.location.reload(true);
  206. }, 1000);//一秒刷新
  207. }
  208. });
  209.  
  210. // 初始化时检查并设置自动刷新
  211. manageAutoRefresh();
  212.  
  213. }, 4000); // 4秒后显示状态牌
  214. }
  215.  
  216. var AutoClick = setInterval(function() { Clicker() }, 1000); // 每秒运行一次
  217.  
  218. function Clicker() {
  219. console.error = function() {};
  220.  
  221. if (window.location.href.indexOf("exam") > -1) {
  222. if (window.location.href.indexOf("mark-paper") > -1) { // 检测到是在阅卷,停止运行但不跳弹窗
  223. clearInterval(AutoClick); // 阅卷了就不乱点了
  224. clearInterval(refreshInterval);
  225. Status = 2; // 阅卷了阅卷了
  226. } else {
  227. clearInterval(AutoClick); // 别是在考试,考试就直接摆烂
  228. clearInterval(refreshInterval);
  229. Status = 1; // 考试了还玩球,状态标异常
  230. alert('检测到考试!代码停止运行!');
  231. }
  232. }
  233. detectString(); // 叫外援
  234. checkLoginStatus();
  235. handleClicks();
  236. detectAndClickAlertButton();
  237.  
  238. if (getAutoNavigateEnabled()) {
  239. clickNextButtonInIframe();
  240. autoNavigateNextChapter();
  241. }
  242.  
  243. if (getAutoNavigateEnabled()) {
  244. const nextPage = document.querySelector(".navBtn.glyphicon.glyphicon-chevron-right");
  245. if (nextPage && !nextPage.disabled) {
  246. nextPage.click();
  247. lastClickTime = Date.now();
  248. }
  249. }
  250. }
  251.  
  252. function handleClicks() {
  253. if (!getAutoNavigateEnabled()) return;
  254.  
  255. const confirmBtns = document.querySelectorAll(".bootbox-close-button.close");
  256. if (confirmBtns.length > 0) {
  257. confirmBtns[0].click(); // 自动点击
  258. lastClickTime = Date.now();
  259. }
  260.  
  261. const confirmBtns2 = document.querySelectorAll(".alertify-button.alertify-button-ok");
  262. if (confirmBtns2.length > 0) {
  263. confirmBtns2[0].click();
  264. lastClickTime = Date.now();
  265. }
  266. }
  267.  
  268. // 自动导航到下一个章节
  269. function autoNavigateNextChapter() {
  270. if (!getAutoNavigateEnabled()) return;
  271.  
  272. const currentChapter = findCurrentChapter();
  273. if (currentChapter && isChapterCompleted(currentChapter)) {
  274. clickNextChapter(currentChapter);
  275. }
  276. }
  277.  
  278. // 查找当前正在学习的章节
  279. function findCurrentChapter() {
  280. return $(".chapter-list-box.focus");
  281. }
  282.  
  283. // 判断章节是否完成
  284. function isChapterCompleted(chapter) {
  285. return !chapter.find('.item.pointer.item22').length;
  286. }
  287.  
  288. function clickNextChapter(currentChapter) {
  289. if (!getAutoNavigateEnabled()) {
  290. return;
  291. }
  292. // 从当前章节开始,查找下一个未完成的章节
  293. let chapters = Array.from(document.querySelectorAll('.chapter-list-box'));
  294. let currentChapterIndex = chapters.indexOf(currentChapter[0]); // 获取当前章节的索引
  295.  
  296. for (let i = currentChapterIndex + 1; i < chapters.length; i++) {
  297. let nextChapterToStudy = chapters[i];
  298. if (nextChapterToStudy.querySelector('.item.pointer.item22')) {
  299. let clickableElement = nextChapterToStudy.querySelector('.chapter-item');
  300. if (clickableElement) {
  301. clickableElement.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
  302. lastClickTime = Date.now();
  303. break;
  304. }
  305. }
  306. }
  307. }
  308.  
  309. // 在 iframe 内部执行点击操作
  310. function clickNextButtonInIframe() {
  311. if (!getAutoNavigateEnabled()) return;
  312.  
  313. const iframe = document.getElementById('scormIframe');
  314. if (iframe) {
  315. const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
  316. const nextPageButton = iframeDocument.querySelector('.navBtn.glyphicon.glyphicon-chevron-right.nextCompleted');
  317. if (nextPageButton) {
  318. nextPageButton.click();
  319. lastClickTime = Date.now();
  320. }
  321. const popupBtns = iframeDocument.querySelectorAll('.btn[data-bb-handler="ok"], .btn[data-bb-handler="next"], .btn[data-bb-handler="confirm"]');
  322. popupBtns.forEach(function(btn) {
  323. simulateClick(btn, iframe.contentWindow);
  324. if (getAutoNavigateEnabled()) {
  325. btn.click();
  326. lastClickTime = Date.now();
  327. }
  328. });
  329.  
  330. const navigationLabel = iframeDocument.querySelector('.navigation-controls__label');
  331. if (navigationLabel && getAutoNavigateEnabled()) {
  332. const pageNumbers = navigationLabel.innerText.split('/');
  333. if (pageNumbers.length === 2 && pageNumbers[0].trim() === pageNumbers[1].trim()) {
  334. if (getAutoNavigateEnabled()) {
  335. setTimeout(function() {
  336. window.top.location.reload(true);
  337. }, 10000); // 等待 10 秒后强制导航到下一个章节
  338. }
  339. }
  340. }
  341.  
  342. const buttons = iframeDocument.querySelectorAll('.uikit-primary-button.uikit-primary-button_size_medium.play-controls-container__play-pause-button');
  343. buttons.forEach(function(button) {
  344. const svg = button.querySelector('svg');
  345. if (svg) {
  346. const path = svg.querySelector('path');
  347. if (path && getAutoNavigateEnabled() && path.getAttribute('d') === 'M5 16.3087V3.54659L5 3.54659L16.8484 8.87836C17.2245 9.04759 17.2455 9.57369 16.8842 9.77243L5 16.3087Z') {
  348. simulateClick(button, iframe.contentWindow);
  349. }
  350. }
  351. });
  352.  
  353. const popupBtns2 = iframeDocument.querySelectorAll('.message-box-buttons__window-button');
  354. popupBtns2.forEach(function(btn) {
  355. simulateClick(btn, iframe.contentWindow);
  356. });
  357. }
  358. }
  359.  
  360. function simulateClick(element, win) {
  361. if (!getAutoNavigateEnabled()) return;
  362.  
  363. const mouseDownEvent = new MouseEvent('mousedown', {
  364. bubbles: true,
  365. cancelable: true,
  366. view: win
  367. });
  368. const mouseUpEvent = new MouseEvent('mouseup', {
  369. bubbles: true,
  370. cancelable: true,
  371. view: win
  372. });
  373. const clickEvent = new MouseEvent('click', {
  374. bubbles: true,
  375. cancelable: true,
  376. view: win
  377. });
  378.  
  379. element.dispatchEvent(mouseDownEvent);
  380. element.dispatchEvent(mouseUpEvent);
  381. element.dispatchEvent(clickEvent);
  382. }
  383.  
  384. function loadKnockoutJs(callback) {
  385. var resources = performance.getEntriesByType('resource');
  386. var regex = /file-cloud\/01\/[0-9A-Za-z]+\/[0-9A-Za-z]+\/[0-9A-Za-z]+/;
  387. var knockoutJsUrl = '';
  388.  
  389. for (var i = 0; i < resources.length; i++) {
  390. var resource = resources[i];
  391. if (resource.name.includes('scorm_api.jsp?')) {
  392. var match = resource.name.match(regex);
  393. if (match) {
  394. var dynamicPath = match[0];
  395. if (dynamicPath.includes('/player')) {
  396. dynamicPath = dynamicPath.replace('/player', '');
  397. }
  398. knockoutJsUrl = 'https://dhyx.ceair.com/' + dynamicPath + '/lib/knockout/knockout.min.js';
  399. break;
  400. }
  401. }
  402. }
  403.  
  404. if (knockoutJsUrl) {
  405. var script = document.createElement('script');
  406. script.src = knockoutJsUrl;
  407. document.head.appendChild(script);
  408.  
  409. script.onload = function() {
  410. callback();
  411. };
  412. } else {
  413. callback();
  414. }
  415. }
  416.  
  417. function proceedWithModifications() {
  418. function findViewModel(root) {
  419. var queue = [{ obj: root, path: '' }];
  420. var visited = new Set();
  421.  
  422. while (queue.length > 0) {
  423. var current = queue.shift();
  424. var obj = current.obj;
  425. var path = current.path;
  426.  
  427. if (visited.has(obj)) {
  428. continue;
  429. }
  430. visited.add(obj);
  431.  
  432. for (var prop in obj) {
  433. if (obj.hasOwnProperty(prop) && typeof obj[prop] === 'object' && obj[prop] !== null) {
  434. try {
  435. if (obj[prop].constructor && obj[prop].constructor.name === 'CBTPlayer') {
  436. return obj[prop];
  437. }
  438. } catch (e) {
  439. continue;
  440. }
  441. queue.push({ obj: obj[prop], path: path + prop + '.' });
  442. }
  443. }
  444. }
  445. return null;
  446. }
  447.  
  448. var cbtPlayer = findViewModel(window);
  449.  
  450. if (cbtPlayer) {
  451. var currentOrg = cbtPlayer.currentOrg();
  452. if (currentOrg && currentOrg.items) {
  453. currentOrg.items().forEach(function(item) {
  454. item.completed(true);
  455. item.visited(true);
  456. item.playbackFinished(true);
  457. if (item.type === 'topic' || item.type === 'mergedpages') {
  458. item.items().forEach(function(subItem) {
  459. subItem.completed(true);
  460. subItem.visited(true);
  461. subItem.playbackFinished(true);
  462. });
  463. }
  464. });
  465.  
  466. currentOrg.items.valueHasMutated();
  467.  
  468. if (typeof cbtPlayer.SavePlayer === 'function') {
  469. cbtPlayer.SavePlayer();
  470. }
  471. }
  472. }
  473. }
  474.  
  475. //调用统一认证登录(不可用)
  476. function checkLoginStatus() {
  477. if (window.location.href.indexOf("oauth/#login") > -1) {
  478. setTimeout(function() {
  479. document.querySelector(".step-item.pointer:nth-child(3)").click();
  480. }, 5000);
  481. lastClickTime = Date.now();
  482. }
  483. }
  484.  
  485. // 添加视频爆破功能
  486. function markVideoAsCompleted() {
  487. var videoElements = document.querySelectorAll('video[id$="player_html5_api"]');
  488. if (videoElements.length > 0) {
  489. var videoElement = videoElements[0];
  490. videojs(videoElement).ready(function() {
  491. var player = this;
  492. player.currentTime(player.duration());
  493. player.trigger('ended');
  494. });
  495. }
  496. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址