您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Scrape Albert.io questions and answer choices, very basic
// ==UserScript== // @name Albert.io Question Scraper // @namespace http://tampermonkey.net/ // @version 1.4 // @description Scrape Albert.io questions and answer choices, very basic // @author You // @match https://*.albert.io/* // @grant GM_addStyle // @license GPL-3.0-or-later // @run-at document-idle // ==/UserScript== (function() { 'use strict'; GM_addStyle(` .albert-dl-btn { background-color: #4080BD; color: white; border: none; border-radius: 4px; padding: 5px 10px; margin: 5px; cursor: pointer; font-size: 12px; transition: background-color 0.3s; z-index: 9999; } .albert-dl-btn:hover { background-color: #336699; } .albert-primary-btn { background-color: #4080BD; color: white; border: none; border-radius: 4px; padding: 8px 15px; margin: 5px; cursor: pointer; font-size: 14px; font-weight: bold; transition: background-color 0.3s; } .albert-primary-btn:hover { background-color: #336699; } .albert-danger-btn { background-color: #dc3545; color: white; } .albert-danger-btn:hover { background-color: #bd2130; } .albert-success-btn { background-color: #28a745; color: white; } .albert-success-btn:hover { background-color: #218838; } .albert-dl-all-btn { position: fixed; top: 10px; right: 10px; background-color: #4080BD; color: white; border: none; border-radius: 4px; padding: 8px 12px; font-size: 14px; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .albert-scraper-panel { position: fixed; top: 50px; right: 10px; background-color: white; border: 1px solid #ccc; border-radius: 4px; padding: 15px; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.2); display: none; max-width: 400px; font-family: Arial, sans-serif; } .albert-question-count { margin-bottom: 10px; font-weight: bold; } .albert-option-row { margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; } .albert-option-label { flex-grow: 1; margin-right: 10px; font-size: 14px; } .albert-checkbox-container { display: flex; align-items: center; margin-bottom: 10px; } .albert-checkbox { margin-right: 8px; } .albert-progress { margin-top: 10px; background-color: #f0f0f0; border-radius: 4px; height: 20px; overflow: hidden; display: none; } .albert-progress-bar { background-color: #4080BD; height: 100%; width: 0%; transition: width 0.3s; } .albert-progress-text { text-align: center; margin-top: 5px; font-size: 12px; } .albert-question-checkbox { position: absolute; top: 5px; right: 5px; z-index: 9999; } .albert-checkbox-label { font-size: 12px; cursor: pointer; } .albert-tab-container { margin-bottom: 15px; } .albert-tab { display: inline-block; padding: 8px 15px; background-color: #f0f0f0; border: 1px solid #ccc; border-bottom: none; border-radius: 4px 4px 0 0; cursor: pointer; } .albert-tab.active { background-color: #4080BD; color: white; } .albert-tab-content { border: 1px solid #ccc; padding: 15px; border-radius: 0 4px 4px 4px; } .albert-input-group { margin-bottom: 10px; display: flex; align-items: center; } .albert-input-label { flex-grow: 1; margin-right: 10px; } .albert-input { width: 70px; padding: 5px; border: 1px solid #ccc; border-radius: 4px; } .albert-switch { position: relative; display: inline-block; width: 45px; height: 24px; } .albert-switch input { opacity: 0; width: 0; height: 0; } .albert-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 24px; } .albert-slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .albert-slider { background-color: #4080BD; } input:checked + .albert-slider:before { transform: translateX(21px); } .albert-status-badge { display: inline-block; padding: 3px 8px; border-radius: 10px; font-size: 12px; font-weight: bold; margin-left: 5px; } .albert-status-badge.active { background-color: #28a745; color: white; } .albert-status-badge.inactive { background-color: #dc3545; color: white; } .albert-status-badge.pending { background-color: #ffc107; color: black; } .albert-divider { margin: 15px 0; border-top: 1px solid #eee; } .albert-section-title { font-weight: bold; margin-bottom: 10px; font-size: 16px; } .albert-counter { font-weight: bold; color: #4080BD; } .albert-textarea { width: 100%; height: 150px; margin-top: 10px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-family: monospace; font-size: 12px; resize: vertical; } .albert-button-container { display: flex; justify-content: center; margin-top: 10px; } .albert-debug { position: fixed; bottom: 10px; left: 10px; padding: 8px; background-color: rgba(0,0,0,0.7); color: white; font-size: 10px; border-radius: 4px; z-index: 9999; } `); let foundQuestions = []; let selectedQuestions = []; let autoNavigationActive = false; let autoNavigationDelay = 2000; let questionsProcessed = 0; let totalQuestionsToProcess = 0; let collectedContent = ''; let currentQuestionNumber = 1; let debugMode = false; window.addEventListener('load', function() { setTimeout(initScraper, 2000); }); function initScraper() { console.log('Albert.io Question Scraper is running...'); findAndProcessQuestions(); addScanButton(); observeDOMChanges(); } function findAndProcessQuestions() { foundQuestions = []; const questions = document.querySelectorAll('.question-wrapper, .question-container, .question'); if (questions && questions.length > 0) { console.log(`Found ${questions.length} question(s) with standard selectors`); processQuestions(Array.from(questions)); } else { console.log('No questions found with standard selectors. Trying alternative approach...'); scanForQuestions(); } } function processQuestions(questions) { foundQuestions = questions; if (questions.length > 0) { addScraperPanel(questions); } questions.forEach((question, index) => { addSelectionToQuestion(question, index); addDownloadButton(question, index); }); } function addSelectionToQuestion(questionElement, index) { if (questionElement.querySelector('.albert-question-checkbox')) { return; } const checkboxContainer = document.createElement('div'); checkboxContainer.className = 'albert-question-checkbox'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `albert-question-${index}`; checkbox.className = 'albert-checkbox'; checkbox.dataset.index = index; checkbox.addEventListener('change', function() { if (this.checked) { if (!selectedQuestions.includes(index)) { selectedQuestions.push(index); } } else { const selectedIndex = selectedQuestions.indexOf(index); if (selectedIndex > -1) { selectedQuestions.splice(selectedIndex, 1); } } updateSelectedCount(); }); const label = document.createElement('label'); label.className = 'albert-checkbox-label'; label.htmlFor = `albert-question-${index}`; label.textContent = 'Select'; checkboxContainer.appendChild(checkbox); checkboxContainer.appendChild(label); const insertTarget = questionElement.querySelector('.question-wrapper__heading') || questionElement.querySelector('.mcq-option') || questionElement; insertTarget.style.position = 'relative'; insertTarget.appendChild(checkboxContainer); } function downloadTextAsFile(filename, text) { const blob = new Blob([text], {type: 'text/plain'}); const url = URL.createObjectURL(blob); const element = document.createElement('a'); element.href = url; element.download = filename; element.style.display = 'none'; document.body.appendChild(element); element.click(); setTimeout(function() { document.body.removeChild(element); URL.revokeObjectURL(url); }, 100); } function extractQuestionContent(questionElement = null) { let questionText = ''; let questionTitle = ''; let questionNumber = currentQuestionNumber; let optionsFound = false; if (!questionElement) { questionElement = document.querySelector('.practice-view__question-area') || document.querySelector('.question-wrapper') || document.querySelector('.question-container') || document.querySelector('.question') || document.body; } if (debugMode) { logDebug(`Extracting from ${questionElement.className}`); } const titleElem = document.querySelector('.student-practice-view-toolbar__title'); if (titleElem) { questionTitle = titleElem.textContent.trim(); questionText += "Title: " + questionTitle + "\n\n"; } const questionNumElem = document.querySelector('[data-testid="question-dropdown-navigator__toggle-button"]'); if (questionNumElem) { const questionNumText = questionNumElem.textContent.trim(); const match = questionNumText.match(/Question\s+(\d+)/i); if (match && match[1]) { questionNumber = parseInt(match[1]); questionText += "Question " + questionNumber + "\n\n"; } else { questionText += "Question " + questionNumber + "\n\n"; } } else { questionText += "Question " + questionNumber + "\n\n"; } const instructions = document.querySelector('.question-wrapper__body, .instructions-pane'); if (instructions) { const markdownContent = instructions.querySelector('.markdown-renderer-v2'); if (markdownContent) { questionText += markdownContent.textContent.trim() + "\n\n"; } else { questionText += instructions.textContent.trim() + "\n\n"; } } let options = document.querySelectorAll('.mcq-option-eliminator'); if (options && options.length > 0) { questionText += "Options:\n"; optionsFound = true; options.forEach((option) => { const letterElement = option.querySelector('.mcq-option__letter'); const contentElement = option.querySelector('.mcq-option__content'); if (letterElement && contentElement) { const letter = letterElement.textContent.trim(); const content = contentElement.textContent.trim(); questionText += letter + ") " + content + "\n"; } }); questionText += "\n"; if (debugMode) { logDebug(`Found ${options.length} options with method 1`); } } if (!optionsFound) { options = document.querySelectorAll('.mcq-option-accessible-wrapper'); if (options && options.length > 0) { questionText += "Options:\n"; optionsFound = true; options.forEach((option) => { const letterElement = option.querySelector('.mcq-option__letter'); const contentElement = option.querySelector('.mcq-option__content'); if (letterElement && contentElement) { const letter = letterElement.textContent.trim(); const content = contentElement.textContent.trim(); questionText += letter + ") " + content + "\n"; } }); questionText += "\n"; if (debugMode) { logDebug(`Found ${options.length} options with method 2`); } } } if (!optionsFound) { options = document.querySelectorAll('label[for^="input-"]'); if (options && options.length > 0) { questionText += "Options:\n"; optionsFound = true; options.forEach((option, index) => { const letterElement = option.querySelector('.mcq-option__letter'); const contentElement = option.querySelector('.mcq-option__content'); const letter = letterElement ? letterElement.textContent.trim() : String.fromCharCode(65 + index); const content = contentElement ? contentElement.textContent.trim() : option.textContent.replace(letter, '').trim(); questionText += letter + ") " + content + "\n"; }); questionText += "\n"; if (debugMode) { logDebug(`Found ${options.length} options with method 3`); } } } if (!optionsFound) { const selector = '[class*="option" i]:not(.albert-option-row):not(.albert-option-label)'; options = document.querySelectorAll(selector); if (options && options.length > 0) { questionText += "Options:\n"; optionsFound = true; options.forEach((option, index) => { const letter = String.fromCharCode(65 + index); let content = option.textContent.trim(); content = content.replace(/^[A-E][)\]]?\s*/, ''); questionText += letter + ") " + content + "\n"; }); questionText += "\n"; if (debugMode) { logDebug(`Found ${options.length} options with method 4`); } } } if (debugMode) { logDebug(`Options found: ${optionsFound}`); } const explanation = document.querySelector('.explanation-content, .explanation'); if (explanation) { questionText += "Explanation:\n" + explanation.textContent.trim() + "\n"; } const tables = document.querySelectorAll('table'); if (tables && tables.length > 0) { tables.forEach((table, idx) => { questionText += `\nTable ${idx + 1}:\n`; const headers = table.querySelectorAll('th'); if (headers.length > 0) { const headerRow = Array.from(headers).map(th => th.textContent.trim()); questionText += headerRow.join(' | ') + '\n'; questionText += '-'.repeat(headerRow.join(' | ').length) + '\n'; } const rows = table.querySelectorAll('tr'); rows.forEach(row => { if (row.querySelector('th')) return; const cells = row.querySelectorAll('td'); if (cells.length > 0) { questionText += Array.from(cells).map(td => td.textContent.trim()).join(' | ') + '\n'; } }); questionText += '\n'; }); } return { text: questionText, number: questionNumber, optionsFound: optionsFound }; } function addDownloadButton(questionElement, index) { if (questionElement.querySelector('.albert-dl-btn')) { return; } const downloadBtn = document.createElement('button'); downloadBtn.className = 'albert-dl-btn'; downloadBtn.innerText = 'Save as TXT'; downloadBtn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); downloadCurrentQuestion(questionElement); }); const insertTarget = questionElement.querySelector('.question-wrapper__heading') || questionElement.querySelector('.mcq-option') || questionElement; insertTarget.style.position = 'relative'; insertTarget.appendChild(downloadBtn); } function downloadCurrentQuestion(questionElement) { const extract = extractQuestionContent(questionElement); const content = extract.text; let filename = `albert_question_${extract.number}.txt`; const contentLines = content.split('\n'); if (contentLines.length > 0 && contentLines[0].startsWith('Title:')) { const title = contentLines[0].replace('Title:', '').trim(); filename = `albert_${title.substring(0, 30).replace(/[^a-z0-9]/gi, '_')}_q${extract.number}.txt`; } if (content.trim() !== '') { downloadTextAsFile(filename, content); if (autoNavigationActive) { questionsProcessed++; updateAutoNavigationStatus(); } } else { alert('Could not extract question content. Please try using the "Scan for Questions" button.'); } } function addScraperPanel(questions) { if (document.querySelector('.albert-scraper-panel')) { updateScraperPanel(questions); return; } const panel = document.createElement('div'); panel.className = 'albert-scraper-panel'; const tabContainer = document.createElement('div'); tabContainer.className = 'albert-tab-container'; const autoNavTab = document.createElement('div'); autoNavTab.className = 'albert-tab active'; autoNavTab.textContent = 'Auto Collector'; autoNavTab.dataset.tab = 'autonav'; const manualTab = document.createElement('div'); manualTab.className = 'albert-tab'; manualTab.textContent = 'Manual Selection'; manualTab.dataset.tab = 'manual'; tabContainer.appendChild(autoNavTab); tabContainer.appendChild(manualTab); panel.appendChild(tabContainer); const tabContent = document.createElement('div'); tabContent.className = 'albert-tab-content'; panel.appendChild(tabContent); const autoNavContent = document.createElement('div'); autoNavContent.id = 'albert-autonav-tab'; const autoNavDescription = document.createElement('p'); autoNavDescription.innerText = 'Automatically navigate through all questions, collecting them into a single file.'; autoNavContent.appendChild(autoNavDescription); const delayGroup = document.createElement('div'); delayGroup.className = 'albert-input-group'; const delayLabel = document.createElement('label'); delayLabel.className = 'albert-input-label'; delayLabel.innerText = 'Delay between questions (ms)'; const delayInput = document.createElement('input'); delayInput.type = 'number'; delayInput.min = '1000'; delayInput.max = '10000'; delayInput.step = '500'; delayInput.value = autoNavigationDelay; delayInput.className = 'albert-input'; delayInput.addEventListener('change', function() { const value = parseInt(this.value); if (value >= 1000 && value <= 10000) { autoNavigationDelay = value; } else { this.value = autoNavigationDelay; alert('Please enter a value between 1000 and 10000 milliseconds'); } }); delayGroup.appendChild(delayLabel); delayGroup.appendChild(delayInput); autoNavContent.appendChild(delayGroup); const debugGroup = document.createElement('div'); debugGroup.className = 'albert-input-group'; const debugLabel = document.createElement('label'); debugLabel.className = 'albert-input-label'; debugLabel.innerText = 'Debug Mode'; const debugSwitch = document.createElement('label'); debugSwitch.className = 'albert-switch'; const debugCheckbox = document.createElement('input'); debugCheckbox.type = 'checkbox'; debugCheckbox.checked = debugMode; debugCheckbox.addEventListener('change', function() { debugMode = this.checked; if (debugMode) { addDebugPanel(); } else { removeDebugPanel(); } }); const debugSlider = document.createElement('span'); debugSlider.className = 'albert-slider'; debugSwitch.appendChild(debugCheckbox); debugSwitch.appendChild(debugSlider); debugGroup.appendChild(debugLabel); debugGroup.appendChild(debugSwitch); autoNavContent.appendChild(debugGroup); const statusGroup = document.createElement('div'); statusGroup.className = 'albert-input-group'; const statusLabel = document.createElement('label'); statusLabel.className = 'albert-input-label'; statusLabel.innerText = 'Auto-Collection Status'; const statusBadge = document.createElement('span'); statusBadge.className = 'albert-status-badge inactive'; statusBadge.id = 'albert-autonav-status'; statusBadge.innerText = 'Inactive'; statusGroup.appendChild(statusLabel); statusGroup.appendChild(statusBadge); autoNavContent.appendChild(statusGroup); const counterGroup = document.createElement('div'); counterGroup.className = 'albert-input-group'; const counterLabel = document.createElement('label'); counterLabel.className = 'albert-input-label'; counterLabel.innerText = 'Questions Collected'; const counterValue = document.createElement('span'); counterValue.className = 'albert-counter'; counterValue.id = 'albert-questions-processed'; counterValue.innerText = '0'; counterGroup.appendChild(counterLabel); counterGroup.appendChild(counterValue); autoNavContent.appendChild(counterGroup); const divider = document.createElement('div'); divider.className = 'albert-divider'; autoNavContent.appendChild(divider); const textareaLabel = document.createElement('div'); textareaLabel.className = 'albert-section-title'; textareaLabel.innerText = 'Collected Content'; autoNavContent.appendChild(textareaLabel); const contentTextarea = document.createElement('textarea'); contentTextarea.className = 'albert-textarea'; contentTextarea.id = 'albert-collected-content'; contentTextarea.readOnly = true; contentTextarea.placeholder = 'Collected question content will appear here...'; contentTextarea.value = collectedContent; autoNavContent.appendChild(contentTextarea); const downloadCollectedBtn = document.createElement('button'); downloadCollectedBtn.className = 'albert-primary-btn'; downloadCollectedBtn.innerText = 'Download Collected Content'; downloadCollectedBtn.id = 'albert-download-collected'; downloadCollectedBtn.addEventListener('click', function() { downloadCollectedContent(); }); downloadCollectedBtn.style.width = '100%'; downloadCollectedBtn.style.marginTop = '10px'; autoNavContent.appendChild(downloadCollectedBtn); const navBtnGroup = document.createElement('div'); navBtnGroup.className = 'albert-button-container'; const startNavBtn = document.createElement('button'); startNavBtn.className = 'albert-primary-btn albert-success-btn'; startNavBtn.innerText = 'Start Auto-Collection'; startNavBtn.id = 'albert-start-autonav'; startNavBtn.addEventListener('click', function() { startAutoNavigation(); }); const stopNavBtn = document.createElement('button'); stopNavBtn.className = 'albert-primary-btn albert-danger-btn'; stopNavBtn.innerText = 'Stop'; stopNavBtn.id = 'albert-stop-autonav'; stopNavBtn.style.display = 'none'; stopNavBtn.addEventListener('click', function() { stopAutoNavigation(); }); navBtnGroup.appendChild(startNavBtn); navBtnGroup.appendChild(stopNavBtn); autoNavContent.appendChild(navBtnGroup); tabContent.appendChild(autoNavContent); const manualContent = document.createElement('div'); manualContent.id = 'albert-manual-tab'; manualContent.style.display = 'none'; const countDisplay = document.createElement('div'); countDisplay.className = 'albert-question-count'; countDisplay.innerText = `Found ${questions.length} question(s)`; countDisplay.id = 'albert-question-count'; manualContent.appendChild(countDisplay); const selectedDisplay = document.createElement('div'); selectedDisplay.className = 'albert-question-count'; selectedDisplay.style.fontSize = '12px'; selectedDisplay.innerText = `Selected: 0 question(s)`; selectedDisplay.id = 'albert-selected-count'; manualContent.appendChild(selectedDisplay); const selectionOptions = document.createElement('div'); selectionOptions.className = 'albert-option-row'; const selectAllBtn = document.createElement('button'); selectAllBtn.className = 'albert-dl-btn'; selectAllBtn.innerText = 'Select All'; selectAllBtn.addEventListener('click', function() { selectedQuestions = []; for (let i = 0; i < questions.length; i++) { selectedQuestions.push(i); const checkbox = document.getElementById(`albert-question-${i}`); if (checkbox) { checkbox.checked = true; } } updateSelectedCount(); }); const deselectAllBtn = document.createElement('button'); deselectAllBtn.className = 'albert-dl-btn'; deselectAllBtn.innerText = 'Deselect All'; deselectAllBtn.addEventListener('click', function() { selectedQuestions = []; for (let i = 0; i < questions.length; i++) { const checkbox = document.getElementById(`albert-question-${i}`); if (checkbox) { checkbox.checked = false; } } updateSelectedCount(); }); selectionOptions.appendChild(selectAllBtn); selectionOptions.appendChild(deselectAllBtn); manualContent.appendChild(selectionOptions); const downloadAllBtn = document.createElement('button'); downloadAllBtn.className = 'albert-dl-btn'; downloadAllBtn.style.width = '100%'; downloadAllBtn.style.marginTop = '10px'; downloadAllBtn.innerText = 'Download All as One File'; downloadAllBtn.addEventListener('click', function() { downloadAllQuestionsAsOne(questions); }); manualContent.appendChild(downloadAllBtn); const downloadSelectedBtn = document.createElement('button'); downloadSelectedBtn.className = 'albert-dl-btn'; downloadSelectedBtn.style.width = '100%'; downloadSelectedBtn.style.marginTop = '10px'; downloadSelectedBtn.innerText = 'Download Selected as One File'; downloadSelectedBtn.addEventListener('click', function() { if (selectedQuestions.length === 0) { alert('Please select at least one question to download.'); return; } downloadSelectedQuestionsAsOne(questions); }); manualContent.appendChild(downloadSelectedBtn); tabContent.appendChild(manualContent); const closeBtn = document.createElement('button'); closeBtn.className = 'albert-dl-btn'; closeBtn.innerText = 'Close'; closeBtn.style.marginTop = '15px'; closeBtn.addEventListener('click', function() { panel.style.display = 'none'; toggleButton.style.display = 'block'; }); tabContent.appendChild(closeBtn); document.body.appendChild(panel); const toggleButton = document.createElement('button'); toggleButton.className = 'albert-dl-all-btn'; toggleButton.innerText = 'Albert.io Scraper'; toggleButton.addEventListener('click', function() { panel.style.display = 'block'; toggleButton.style.display = 'none'; }); document.body.appendChild(toggleButton); autoNavTab.addEventListener('click', function() { setActiveTab('autonav'); }); manualTab.addEventListener('click', function() { setActiveTab('manual'); }); } function addDebugPanel() { if (document.getElementById('albert-debug-panel')) { return; } const debugPanel = document.createElement('div'); debugPanel.id = 'albert-debug-panel'; debugPanel.className = 'albert-debug'; debugPanel.textContent = 'Debug mode active'; document.body.appendChild(debugPanel); } function removeDebugPanel() { const debugPanel = document.getElementById('albert-debug-panel'); if (debugPanel) { debugPanel.remove(); } } function logDebug(message) { console.log('[Albert.io Scraper] ' + message); const debugPanel = document.getElementById('albert-debug-panel'); if (debugPanel) { debugPanel.textContent = message; } } function startAutoNavigation() { if (autoNavigationActive) { return; } questionsProcessed = 0; collectedContent = ''; const contentTextarea = document.getElementById('albert-collected-content'); if (contentTextarea) { contentTextarea.value = ''; } const questionNavbar = document.querySelector('[data-testid="question-dropdown-navigator__toggle-button"]'); if (questionNavbar) { const navbarText = questionNavbar.textContent.trim(); const match = navbarText.match(/Question\s+\d+\s+\/\s+(\d+)/i); if (match && match[1]) { totalQuestionsToProcess = parseInt(match[1]); } } if (!totalQuestionsToProcess) { totalQuestionsToProcess = 100; } document.getElementById('albert-autonav-status').innerText = 'Active'; document.getElementById('albert-autonav-status').className = 'albert-status-badge active'; document.getElementById('albert-start-autonav').style.display = 'none'; document.getElementById('albert-stop-autonav').style.display = 'block'; autoNavigationActive = true; processCurrentQuestion(); } function stopAutoNavigation() { autoNavigationActive = false; document.getElementById('albert-autonav-status').innerText = 'Stopped'; document.getElementById('albert-autonav-status').className = 'albert-status-badge inactive'; document.getElementById('albert-start-autonav').style.display = 'block'; document.getElementById('albert-stop-autonav').style.display = 'none'; } function processCurrentQuestion() { if (!autoNavigationActive) { return; } setTimeout(() => { const extract = extractQuestionContent(); if (extract.text.trim() !== '') { collectedContent += `==================== QUESTION ${extract.number} ====================\n\n`; collectedContent += extract.text; collectedContent += '\n\n'; const contentTextarea = document.getElementById('albert-collected-content'); if (contentTextarea) { contentTextarea.value = collectedContent; contentTextarea.scrollTop = contentTextarea.scrollHeight; } questionsProcessed++; updateAutoNavigationStatus(); if (debugMode) { logDebug(`Question ${extract.number}: Options found = ${extract.optionsFound}`); } } else { if (debugMode) { logDebug('No content extracted for current question'); } } setTimeout(navigateToNextQuestion, autoNavigationDelay); }, 1000); } function navigateToNextQuestion() { if (!autoNavigationActive) { return; } const nextButton = document.querySelector('[data-testid="question-dropdown-navigator__next-button"]'); if (nextButton && !nextButton.disabled) { nextButton.click(); setTimeout(processCurrentQuestion, 1000); } else { console.log('Reached the end of the questions'); stopAutoNavigation(); alert(`Auto-collection complete! Collected ${questionsProcessed} questions. You can now download the content.`); } } function downloadCollectedContent() { if (collectedContent.trim() === '') { alert('No content has been collected yet. Please start auto-collection first.'); return; } let assignmentName = document.querySelector('.student-practice-view-toolbar__title')?.textContent.trim() || 'questions'; assignmentName = assignmentName.substring(0, 30).replace(/[^a-z0-9]/gi, '_'); const timeStamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 16); downloadTextAsFile(`albert_${assignmentName}_all_${questionsProcessed}_questions_${timeStamp}.txt`, collectedContent); } function updateAutoNavigationStatus() { const counterElement = document.getElementById('albert-questions-processed'); if (counterElement) { counterElement.innerText = `${questionsProcessed} / ${totalQuestionsToProcess}`; } } function updateScraperPanel(questions) { const countDisplay = document.getElementById('albert-question-count'); if (countDisplay) { countDisplay.innerText = `Found ${questions.length} question(s)`; } const contentTextarea = document.getElementById('albert-collected-content'); if (contentTextarea) { contentTextarea.value = collectedContent; } updateSelectedCount(); } function setActiveTab(tabName) { const tabs = document.querySelectorAll('.albert-tab'); tabs.forEach(tab => { if (tab.dataset.tab === tabName) { tab.classList.add('active'); } else { tab.classList.remove('active'); } }); const autoNavContent = document.getElementById('albert-autonav-tab'); const manualContent = document.getElementById('albert-manual-tab'); autoNavContent.style.display = tabName === 'autonav' ? 'block' : 'none'; manualContent.style.display = tabName === 'manual' ? 'block' : 'none'; } function updateSelectedCount() { const selectedDisplay = document.getElementById('albert-selected-count'); if (selectedDisplay) { selectedDisplay.innerText = `Selected: ${selectedQuestions.length} question(s)`; } } function downloadAllQuestionsAsOne(questions) { let allContent = ''; let validQuestions = 0; for (let i = 0; i < questions.length; i++) { const question = questions[i]; const extract = extractQuestionContent(question); if (extract.text.trim() !== '') { validQuestions++; allContent += `==================== QUESTION ${extract.number} ====================\n\n`; allContent += extract.text; allContent += '\n\n'; } } if (allContent.trim() !== '') { let assignmentName = document.querySelector('.student-practice-view-toolbar__title')?.textContent.trim() || 'questions'; assignmentName = assignmentName.substring(0, 30).replace(/[^a-z0-9]/gi, '_'); const timeStamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 16); downloadTextAsFile(`albert_${assignmentName}_all_${validQuestions}_questions_${timeStamp}.txt`, allContent); } else { alert('Could not extract any question content.'); } } function downloadSelectedQuestionsAsOne(questions) { if (selectedQuestions.length === 0) { alert('Please select at least one question to download.'); return; } let allContent = ''; let validQuestions = 0; for (const index of selectedQuestions) { if (index >= 0 && index < questions.length) { const question = questions[index]; const extract = extractQuestionContent(question); if (extract.text.trim() !== '') { validQuestions++; allContent += `==================== QUESTION ${extract.number} ====================\n\n`; allContent += extract.text; allContent += '\n\n'; } } } if (allContent.trim() !== '') { let assignmentName = document.querySelector('.student-practice-view-toolbar__title')?.textContent.trim() || 'questions'; assignmentName = assignmentName.substring(0, 30).replace(/[^a-z0-9]/gi, '_'); const timeStamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 16); downloadTextAsFile(`albert_${assignmentName}_selected_${validQuestions}_questions_${timeStamp}.txt`, allContent); } else { alert('Could not extract any question content from selected questions.'); } } function scanForQuestions() { const potentialQuestions = []; const albertElements = document.querySelectorAll('.markdown-renderer-v2, .question-statement, .mcq-option'); if (albertElements.length > 0) { let commonParents = []; albertElements.forEach(el => { let parent = el; for (let i = 0; i < 3; i++) { if (parent.parentElement) parent = parent.parentElement; } if (parent && !commonParents.includes(parent)) { commonParents.push(parent); } }); commonParents.forEach(parent => { if (!potentialQuestions.includes(parent)) { potentialQuestions.push(parent); } }); } const allElements = document.querySelectorAll('div:not([class*="albert-"]), section, article'); allElements.forEach(element => { const text = element.innerText; if ( (text.includes('Question') && text.length > 100) || /[A-E]\)\s/.test(text) || (element.querySelector('table') && text.includes('Instructions')) || (text.match(/p-value|t-test|confidence interval/i) && text.length > 200) ) { let isContained = false; for (const potentialQuestion of potentialQuestions) { if (potentialQuestion.contains(element) && potentialQuestion !== element) { isContained = true; break; } } if (!isContained && element.offsetHeight > 100) { potentialQuestions.push(element); } } }); if (potentialQuestions.length > 0) { console.log(`Found ${potentialQuestions.length} potential question elements`); processQuestions(potentialQuestions); } else { console.log('No potential questions found'); const message = document.createElement('div'); message.style.position = 'fixed'; message.style.top = '10px'; message.style.left = '10px'; message.style.padding = '10px'; message.style.backgroundColor = '#f8d7da'; message.style.color = '#721c24'; message.style.borderRadius = '4px'; message.style.zIndex = '9999'; message.innerHTML = 'No questions detected. Try using the "Scan for Questions" button manually.'; document.body.appendChild(message); setTimeout(() => { message.remove(); }, 5000); } } function addScanButton() { const scanBtn = document.createElement('button'); scanBtn.className = 'albert-dl-btn'; scanBtn.innerText = 'Scan for Questions'; scanBtn.style.position = 'fixed'; scanBtn.style.bottom = '10px'; scanBtn.style.left = '10px'; scanBtn.style.zIndex = '9999'; scanBtn.addEventListener('click', function(e) { e.preventDefault(); scanForQuestions(); }); document.body.appendChild(scanBtn); } function observeDOMChanges() { const observer = new MutationObserver(function(mutations) { let shouldRescan = false; mutations.forEach(function(mutation) { if (mutation.addedNodes && mutation.addedNodes.length > 0) { for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; if (node.nodeType === 1) { if ( (node.classList && ( node.classList.contains('question-wrapper') || node.classList.contains('question-container') || node.classList.contains('question') )) || node.querySelector('.question-wrapper, .question-container, .question, .mcq-option') ) { shouldRescan = true; break; } } } } }); if (shouldRescan) { console.log('New question content detected, rescanning...'); setTimeout(findAndProcessQuestions, 1000); } }); observer.observe(document.body, { childList: true, subtree: true }); } })();