您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Auto-navigate slides & auto-answer assessments in GCN Training with single-line debug overlay and random answer selection
// ==UserScript== // @name GCN Training Auto-Navigation + Auto-Answer (Random Answers) // @namespace http://tampermonkey.net/ // @version 5.1 // @description Auto-navigate slides & auto-answer assessments in GCN Training with single-line debug overlay and random answer selection // @author Cole Mistretta // @match https://site.gcntraining.com/user-admin/dashboard.html // @match https://site.gcntraining.com/t*/* // @license GNU // @grant none // ==/UserScript== (function() { 'use strict'; /////////////////////// // Debug Panel Setup // /////////////////////// const panel = document.createElement('div'); panel.id = "gcn-debug-panel"; panel.innerHTML = `<div id="gcn-debug-text">GCN Auto-Navigation started.</div>`; document.body.appendChild(panel); const styles = document.createElement('style'); styles.textContent = ` #gcn-debug-panel { position: fixed; bottom: 10px; right: 10px; width: 300px; background: rgba(0,0,0,0.85); color: #00ffcc; font-family: monospace; font-size: 12px; border-radius: 8px; padding: 8px; z-index: 99999; text-align: center; box-shadow: 0 0 10px rgba(0,255,200,0.5); } `; document.head.appendChild(styles); function setDebug(text) { document.getElementById("gcn-debug-text").textContent = text; console.log(text); } ////////////////////////// // Helper Functions // ////////////////////////// function clickNextStartButton() { // Check if we're on the dashboard if (!window.location.href.includes('dashboard.html')) { return false; } // FIRST PRIORITY: Look for Continue buttons (partially completed tutorials) const continueButtons = document.querySelectorAll('form.ud-continue button.ud-button'); if (continueButtons.length > 0) { const firstContinueButton = continueButtons[0]; const form = firstContinueButton.closest('form'); const tutorialTitle = form ? form.querySelector('.tut-title')?.textContent : 'Unknown'; setDebug(`Found ${continueButtons.length} tutorials to continue. Prioritizing: ${tutorialTitle}`); // Click the continue button firstContinueButton.click(); return true; } // SECOND PRIORITY: Look for Start buttons (new tutorials) only if no Continue buttons const startButtons = document.querySelectorAll('form.ud-start button.ud-button'); if (startButtons.length > 0) { const firstStartButton = startButtons[0]; const form = firstStartButton.closest('form'); const tutorialTitle = form ? form.querySelector('.tut-title')?.textContent : 'Unknown'; setDebug(`No Continue buttons found. Found ${startButtons.length} tutorials to start. Starting: ${tutorialTitle}`); // Click the start button firstStartButton.click(); return true; } setDebug("No Continue or Start buttons found on dashboard"); return false; } function clickStartTutorialButton() { // Check if we're on a start page (pattern: /*/start) if (!window.location.pathname.endsWith('/start')) { return false; } // Look for the start tutorial button with multiple selector patterns const startTutorialSelectors = [ 'a.start-button img[alt="Start Tutorial"]', 'a.start-button', 'a[href*="/t"] img[alt="Start Tutorial"]', 'a[href*="/t"]', '.start-button', 'img[alt="Start Tutorial"]' ]; let startButton = null; let usedSelector = ""; for (const selector of startTutorialSelectors) { const element = document.querySelector(selector); if (element && element.offsetParent !== null) { // Check if element is visible startButton = element; usedSelector = selector; break; } } if (startButton) { setDebug(`Start Tutorial button found with selector: ${usedSelector}, clicking...`); // If we found an img, click its parent link if (startButton.tagName === 'IMG') { const parentLink = startButton.closest('a'); if (parentLink) { parentLink.click(); } else { startButton.click(); } } else { startButton.click(); } setDebug("Start Tutorial button clicked, waiting for tutorial to load..."); return true; } setDebug("Start Tutorial button not found on start page"); return false; } function selectRandomAnswer() { // Try multiple selector patterns for radio buttons const selectorPatterns = [ ".tut-slides-selectors input[type=radio][name='ans']", "input[type=radio][name='ans']", ".tut-slides-selectors input[type=radio]", "input[type=radio]" ]; let answers = []; for (const pattern of selectorPatterns) { answers = document.querySelectorAll(pattern); if (answers.length > 0) { setDebug(`Found ${answers.length} answers using pattern: ${pattern}`); break; } } if (answers.length === 0) { setDebug("No radio button answers found"); return false; } // Check if an answer is already selected const alreadySelected = Array.from(answers).find(answer => answer.checked); if (alreadySelected) { const answerLabel = alreadySelected.nextElementSibling?.textContent || alreadySelected.value; setDebug(`Answer already selected: ${answerLabel} (${alreadySelected.value})`); return true; } // Randomly select an answer - FORCE CLICK IT! const randomIndex = Math.floor(Math.random() * answers.length); const chosen = answers[randomIndex]; // Get the answer label for better debugging const answerLabel = chosen.nextElementSibling?.textContent || chosen.value; setDebug(`Attempting to select answer: ${answerLabel} (${chosen.value})`); // FORCE the radio button selection using multiple aggressive methods try { // Method 1: Direct property setting chosen.checked = true; // Method 2: Focus and click chosen.focus(); chosen.click(); // Method 3: Simulate mouse events chosen.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); chosen.dispatchEvent(new MouseEvent('mouseup', { bubbles: true })); chosen.dispatchEvent(new MouseEvent('click', { bubbles: true })); // Method 4: Form events chosen.dispatchEvent(new Event("change", { bubbles: true })); chosen.dispatchEvent(new Event("input", { bubbles: true })); // Method 5: Try clicking the label too const label = chosen.nextElementSibling; if (label && label.tagName === 'LABEL') { label.click(); } // Verify the selection worked setTimeout(() => { if (chosen.checked) { setDebug(`SUCCESS: Answer ${answerLabel} is now selected!`); } else { setDebug(`FAILED: Answer ${answerLabel} was not selected - trying alternative method`); // Try one more aggressive approach const labelElement = document.querySelector(`label[for="${chosen.id}"]`); if (labelElement) { labelElement.click(); setDebug(`Tried clicking label for ${chosen.id}`); } } }, 100); return true; } catch (error) { setDebug(`Error selecting answer: ${error.message}`); return false; } } ////////////////////////// // Auto Navigation Core // ////////////////////////// function tryAdvance() { // FIRST: Check if we're on dashboard and need to start a tutorial if (window.location.href.includes('dashboard.html')) { const startedTutorial = clickNextStartButton(); if (startedTutorial) { setDebug("Started tutorial from dashboard, waiting for page load..."); return; } } // SECOND: Check if we're on a start page and need to click Start Tutorial if (window.location.pathname.endsWith('/start')) { const clickedStartTutorial = clickStartTutorialButton(); if (clickedStartTutorial) { setDebug("Clicked Start Tutorial button, waiting for tutorial to load..."); return; } } // THIRD: Look for next button (highest priority for tutorial navigation) const nextBtnSelectors = [ "span.tut-slides-next img.complete-tutorial", // Submit button at end "span.tut-slides-next img.next-active", "button.tut-slides-next img.next-active", "span.tut-slides-next", "button.tut-slides-next", ".tut-slides-next", "span[class*='next'] img.next-active", "button[class*='next'] img.next-active", "img.complete-tutorial", // Direct submit button "img.next-active", ".next-active", ".complete-tutorial" ]; let nextBtn = null; let usedSelector = ""; for (const selector of nextBtnSelectors) { const element = document.querySelector(selector); if (element && element.offsetParent !== null) { // Check if element is visible nextBtn = element; usedSelector = selector; break; } } if (nextBtn) { // Special handling for submit/complete tutorial buttons const isSubmitButton = nextBtn.classList?.contains('complete-tutorial') || nextBtn.alt === 'Submit' || usedSelector.includes('complete-tutorial'); if (isSubmitButton) { setDebug(`Submit/Complete button found with selector: ${usedSelector}, clicking with enhanced method...`); // Enhanced clicking for submit buttons try { // Method 1: Direct click nextBtn.click(); // Method 2: Parent click const parent = nextBtn.closest('span, button'); if (parent) { parent.click(); } // Method 3: Mouse events nextBtn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); nextBtn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true })); nextBtn.dispatchEvent(new MouseEvent('click', { bubbles: true })); // Method 4: Focus and click if (parent) { parent.focus(); parent.dispatchEvent(new MouseEvent('click', { bubbles: true })); } setDebug("Submit button clicked with multiple methods - tutorial should complete"); } catch (error) { setDebug(`Error clicking submit button: ${error.message}`); } } else { setDebug(`Next button found with selector: ${usedSelector}, clicking...`); // Regular next button handling if (nextBtn.tagName === 'IMG') { const parent = nextBtn.closest('span, button'); if (parent) { parent.click(); } else { nextBtn.click(); } } else { nextBtn.click(); } } setTimeout(() => setDebug("Button clicked, waiting..."), 1000); return; // Exit early if we clicked next button } // FOURTH: Only check for questions if no next button was found const question = document.querySelector(".question-title"); if (question) { setDebug("Question detected, no next button available yet"); // IMMEDIATELY try to select an answer when we find a question const answerSelected = selectRandomAnswer(); if (answerSelected) { // Now look for submit button after selecting answer const submitBtn = document.querySelector("button.submit-answer"); if (!submitBtn) { setDebug("Answer selected, but submit button not found, waiting..."); return; } if (submitBtn.disabled) { setDebug("Answer selected, but submit button disabled, waiting..."); return; } setDebug("Answer selected, submitting in 1.5 seconds..."); // Wait longer to ensure the selection is fully registered setTimeout(() => { const currentSubmitBtn = document.querySelector("button.submit-answer"); if (currentSubmitBtn && !currentSubmitBtn.disabled) { currentSubmitBtn.click(); setDebug("Answer submitted – waiting for next button to appear..."); } else { setDebug("Submit button not available after selection, will retry..."); } }, 1500); } else { setDebug("Could not select answer, checking for other question types..."); } } else { setDebug("No dashboard start buttons, no start tutorial button, no next button, no questions found - waiting..."); } } ////////////////////////// // Main Loop // ////////////////////////// setDebug("GCN Auto-Navigation started."); setInterval(tryAdvance, 2000); })();