(async function autoClickSequential() { // Настройки const CLICK_DELAY = 800; const CHECK_INTERVAL = 500; const MAX_WAIT_TIME = 5000; const PAGE_LOAD_DELAY = 2000; // Селекторы const BUTTON_SELECTOR = 'button.content-expander__button'; const NEXT_LESSON_SELECTOR = 'button[data-test-id="next-lesson-control-button"]'; const FEEDBACK_FORM_SELECTOR = 'section.quiz_type_feedback'; const FEEDBACK_NEXT_SELECTOR = 'button.quiz__move-on'; const FEEDBACK_TEXTAREA_SELECTOR = 'textarea.input__control'; const QUIZ_FORM_SELECTOR = 'form.quiz_type_select'; const QUIZ_SUBMIT_SELECTOR = 'button.quiz__submit'; let clickCount = 0; let lessonCount = 0; let isRunning = true; let clickedButtons = new WeakSet(); let handledQuizzes = new WeakSet(); let handledFeedbacks = new WeakSet(); function findNewButton() { const buttons = document.querySelectorAll(BUTTON_SELECTOR); for (const button of buttons) { if (clickedButtons.has(button)) continue; if (button.offsetParent !== null) { return button; } } return null; } function findNextLessonButton() { const button = document.querySelector(NEXT_LESSON_SELECTOR); if (button && button.offsetParent !== null) { return button; } return null; } function findFeedbackForm() { const forms = document.querySelectorAll(FEEDBACK_FORM_SELECTOR); for (const form of forms) { if (handledFeedbacks.has(form)) continue; if (form.offsetParent !== null) { return form; } } return null; } function isQuizAnswered(form) { const checkedRadio = form.querySelector('input[type="radio"][aria-checked="true"]'); if (checkedRadio) return true; if (form.classList.contains('quiz_answered')) return true; const submitBtn = form.querySelector(QUIZ_SUBMIT_SELECTOR); if (!submitBtn) return true; return false; } function findTextQuiz() { const quizzes = document.querySelectorAll('section.quiz_type_text'); for (const quiz of quizzes) { if (handledQuizzes.has(quiz)) continue; if (quiz.classList.contains('quiz_answered')) { handledQuizzes.add(quiz); continue; } const submitBtn = quiz.querySelector('button.quiz__submit'); if (!submitBtn) { handledQuizzes.add(quiz); continue; } if (quiz.offsetParent !== null) return quiz; } return null; } async function handleTextQuiz(quiz) { console.log('✏️ Текстовый квиз...'); const textarea = quiz.querySelector('textarea.quiz__input-control'); if (textarea) { simulateTyping(textarea, 'не знаю'); console.log('✓ Введён ответ'); await sleep(400); } const submitBtn = quiz.querySelector('button.quiz__submit'); if (submitBtn && !submitBtn.disabled) { submitBtn.click(); console.log('✓ Нажата кнопка "Узнать ответ"'); } else if (submitBtn) { submitBtn.disabled = false; submitBtn.click(); console.log('✓ Принудительный клик "Узнать ответ"'); } handledQuizzes.add(quiz); await sleep(CLICK_DELAY); return true; } function findCodingQuiz() { const quizzes = document.querySelectorAll('section.quiz_type_coding'); for (const quiz of quizzes) { if (handledQuizzes.has(quiz)) continue; if (quiz.classList.contains('quiz_answered')) { handledQuizzes.add(quiz); continue; } const runBtn = quiz.querySelector('button.quiz__coding-footer-action-button'); if (!runBtn) { handledQuizzes.add(quiz); continue; } if (quiz.offsetParent !== null) return quiz; } return null; } async function handleCodingQuiz(quiz) { console.log('💻 Квиз с кодом — запускаем...'); const runBtn = quiz.querySelector('button.quiz__coding-footer-action-button'); runBtn.click(); // Ждём пока квиз пометится как решённый const startTime = Date.now(); while (Date.now() - startTime < 60000) { await sleep(CHECK_INTERVAL); if (quiz.classList.contains('quiz_answered') || !quiz.querySelector('button.quiz__coding-footer-action-button')) { console.log('✓ Код выполнен'); break; } } handledQuizzes.add(quiz); await sleep(CLICK_DELAY); return true; } function findQuizForm() { const forms = document.querySelectorAll(QUIZ_FORM_SELECTOR); for (const form of forms) { if (handledQuizzes.has(form)) continue; if (isQuizAnswered(form)) { handledQuizzes.add(form); continue; } if (form.offsetParent !== null) { return form; } } return null; } // Симуляция нативного ввода текста function simulateTyping(textarea, text) { textarea.focus(); // Устанавливаем значение через нативный setter const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLTextAreaElement.prototype, 'value' ).set; nativeInputValueSetter.call(textarea, text); // Триггерим все возможные события textarea.dispatchEvent(new Event('input', { bubbles: true, cancelable: true })); textarea.dispatchEvent(new Event('change', { bubbles: true, cancelable: true })); textarea.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true })); textarea.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true })); textarea.dispatchEvent(new KeyboardEvent('keypress', { bubbles: true })); // React-specific события const reactEvent = new Event('input', { bubbles: true }); reactEvent.simulated = true; textarea.dispatchEvent(reactEvent); } function isLastFeedbackPage(form) { const counter = form.querySelector('.quiz__counter'); if (!counter) return true; const parts = counter.textContent.split('—').map(s => s.trim()); return parts.length === 2 && parts[0] === parts[1]; } async function handleFeedbackPage(form) { const textarea = form.querySelector(FEEDBACK_TEXTAREA_SELECTOR); if (textarea) { simulateTyping(textarea, 'СПАСИБО!'); console.log('✓ Введён текст "СПАСИБО!"'); await sleep(500); let nextBtn = form.querySelector(FEEDBACK_NEXT_SELECTOR); if (nextBtn && nextBtn.disabled) { const reactKey = Object.keys(textarea).find(key => key.startsWith('__reactFiber') || key.startsWith('__reactProps')); if (reactKey) { const reactProps = textarea[reactKey]; if (reactProps && reactProps.onChange) { reactProps.onChange({ target: textarea }); } } await sleep(300); } } else { const radioGroups = form.querySelectorAll('.likert-scale__statement-row'); for (const row of radioGroups) { const firstRadio = row.querySelector('input[type="radio"]'); if (firstRadio && !firstRadio.checked) { firstRadio.click(); await sleep(100); } } console.log('✓ Выбраны ответы "да"'); } await sleep(300); let nextBtn = form.querySelector(FEEDBACK_NEXT_SELECTOR); let attempts = 0; while (nextBtn && nextBtn.disabled && attempts < 15) { await sleep(200); nextBtn = form.querySelector(FEEDBACK_NEXT_SELECTOR); attempts++; } if (nextBtn && nextBtn.disabled) { console.log('⚠️ Кнопка disabled, пробуем принудительный клик...'); nextBtn.disabled = false; nextBtn.classList.remove('button2_disabled'); } if (nextBtn) { nextBtn.click(); console.log('✓ Нажата кнопка "Далее"'); await sleep(CLICK_DELAY); return true; } return false; } async function handleFeedbackForm(form) { console.log('📝 Форма обратной связи...'); while (true) { const last = isLastFeedbackPage(form); const counter = form.querySelector('.quiz__counter'); console.log(`📄 Страница: ${counter ? counter.textContent.trim() : '?'}`); await handleFeedbackPage(form); if (last) break; // Ждём загрузки следующей страницы формы await sleep(CLICK_DELAY); } handledFeedbacks.add(form); return true; } async function handleQuizForm(form) { console.log('❓ Квиз...'); const checkboxes = form.querySelectorAll('input[type="checkbox"]'); if (checkboxes.length > 0) { for (const cb of checkboxes) { if (!cb.checked) cb.click(); await sleep(100); } console.log(`✓ Выбраны все чекбоксы (${checkboxes.length})`); } else { const firstRadio = form.querySelector('input[type="radio"]'); if (firstRadio) { firstRadio.click(); console.log('✓ Выбран первый вариант'); await sleep(300); } } const submitBtn = form.querySelector(QUIZ_SUBMIT_SELECTOR); if (submitBtn && !submitBtn.disabled) { submitBtn.click(); console.log('✓ Нажата кнопка "Узнать ответ"'); handledQuizzes.add(form); await sleep(CLICK_DELAY); return true; } await sleep(200); const submitBtnRetry = form.querySelector(QUIZ_SUBMIT_SELECTOR); if (submitBtnRetry && !submitBtnRetry.disabled) { submitBtnRetry.click(); console.log('✓ Нажата кнопка "Узнать ответ"'); handledQuizzes.add(form); await sleep(CLICK_DELAY); return true; } handledQuizzes.add(form); return false; } function scrollToElement(element) { element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function waitForElement(timeout = MAX_WAIT_TIME) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (!isRunning) return null; const codingQuiz = findCodingQuiz(); if (codingQuiz) return { type: 'coding', element: codingQuiz }; const textQuiz = findTextQuiz(); if (textQuiz) return { type: 'text', element: textQuiz }; const quiz = findQuizForm(); if (quiz) return { type: 'quiz', element: quiz }; const feedback = findFeedbackForm(); if (feedback) return { type: 'feedback', element: feedback }; const nextLesson = findNextLessonButton(); if (nextLesson) return { type: 'next', button: nextLesson }; const button = findNewButton(); if (button) return { type: 'expander', button: button }; await sleep(CHECK_INTERVAL); } return null; } async function processLesson() { while (isRunning) { let codingQuiz = findCodingQuiz(); if (codingQuiz) { scrollToElement(codingQuiz); await sleep(300); await handleCodingQuiz(codingQuiz); continue; } let textQuiz = findTextQuiz(); if (textQuiz) { scrollToElement(textQuiz); await sleep(300); await handleTextQuiz(textQuiz); continue; } let quiz = findQuizForm(); if (quiz) { scrollToElement(quiz); await sleep(300); await handleQuizForm(quiz); continue; } let feedback = findFeedbackForm(); if (feedback) { scrollToElement(feedback); await sleep(300); await handleFeedbackForm(feedback); continue; } let nextLesson = findNextLessonButton(); if (nextLesson) { return nextLesson; } let button = findNewButton(); if (!button) { console.log('⏳ Ожидание...'); const result = await waitForElement(); if (!result) { console.log('🏁 Элементов больше нет'); return null; } if (result.type === 'coding') { scrollToElement(result.element); await sleep(300); await handleCodingQuiz(result.element); continue; } if (result.type === 'text') { scrollToElement(result.element); await sleep(300); await handleTextQuiz(result.element); continue; } if (result.type === 'quiz') { scrollToElement(result.element); await sleep(300); await handleQuizForm(result.element); continue; } if (result.type === 'feedback') { scrollToElement(result.element); await sleep(300); await handleFeedbackForm(result.element); continue; } if (result.type === 'next') { return result.button; } button = result.button; } scrollToElement(button); await sleep(300); clickedButtons.add(button); const buttonText = button.textContent.trim(); button.click(); clickCount++; console.log(`✓ [${clickCount}] Нажата: "${buttonText}"`); await sleep(CLICK_DELAY); } return null; } async function run() { console.log('🚀 Запуск...'); while (isRunning) { lessonCount++; console.log(`📖 Урок ${lessonCount}`); const nextLessonBtn = await processLesson(); if (!nextLessonBtn) { console.log('🏁 Уроки закончились'); break; } scrollToElement(nextLessonBtn); await sleep(300); nextLessonBtn.click(); console.log('➡️ Переход к следующему уроку...'); await sleep(PAGE_LOAD_DELAY); // Проверяем не завис ли загрузчик const loadingStart = Date.now(); while (document.querySelector('.page__loading')) { await sleep(1000); const elapsed = Date.now() - loadingStart; if (elapsed > 60000) { isRunning = false; alert('⚠️ Страница грузится больше минуты. Обновите страницу и запустите скрипт снова.'); return; } } clickedButtons = new WeakSet(); handledQuizzes = new WeakSet(); handledFeedbacks = new WeakSet(); } console.log(`\n✅ Готово!`); console.log(`📊 Уроков пройдено: ${lessonCount}`); console.log(`🖱️ Кнопок нажато: ${clickCount}`); } function handleAssociatedProgramsPage() { const cards = document.querySelectorAll('button.card.course-card'); for (const card of cards) { const isCompleted = card.querySelector('.course-card__info-item_active'); if (!isCompleted) { const title = card.querySelector('.course-card__title')?.textContent?.trim() || '(без названия)'; console.log(`🎯 Найдена непройденная программа: "${title}"`); card.click(); return true; } } console.log('✅ Все программы пройдены'); return false; } async function waitForModal() { return new Promise(resolve => { const startTime = Date.now(); const interval = setInterval(() => { const el = document.querySelector('#portals .skills-modal_visible'); if (el) { clearInterval(interval); resolve(el); } else if (Date.now() - startTime > MAX_WAIT_TIME) { clearInterval(interval); resolve(null); } }, CHECK_INTERVAL); }); } async function handleCourseModal() { console.log('🔍 Ищем непройденную тему в модалке...'); const modal = await waitForModal(); if (!modal) { console.log('⚠️ Модальное окно не появилось'); return false; } // Шаг 1.js: найти и кликнуть первую тему без course-navigation-topic_solved const topics = modal.querySelectorAll('a.course-navigation-topic'); let clickedTopic = false; for (const topic of topics) { if (!topic.classList.contains('course-navigation-topic_solved')) { const title = topic.querySelector('.course-navigation-item__title')?.textContent?.trim() || '(без названия)'; console.log(`📂 Тема: "${title}"`); topic.click(); clickedTopic = true; break; } } if (!clickedTopic) { console.log('✅ Все темы пройдены'); return false; } // Шаг 2: ждём пока появятся уроки внутри темы await sleep(CLICK_DELAY); const startTime = Date.now(); let lesson = null; while (Date.now() - startTime < MAX_WAIT_TIME) { const lessons = modal.querySelectorAll('a.course-navigation-lesson'); for (const l of lessons) { if (!l.classList.contains('course-navigation-lesson_status_solved')) { lesson = l; break; } } if (lesson) break; await sleep(CHECK_INTERVAL); } if (!lesson) { console.log('⚠️ Непройденный урок не найден'); return false; } const lessonTitle = lesson.querySelector('.course-navigation-item__title')?.textContent?.trim() || '(без названия)'; console.log(`📚 Урок: "${lessonTitle}"`); lesson.click(); return true; } function insertSolutionIntoMonaco(code) { const editors = window.monaco.editor.getEditors(); if (!editors || editors.length === 0) { console.log('⚠️ Monaco редактор не найден'); return false; } const editor = editors[0]; const model = editor.getModel(); if (!model) { console.log('⚠️ Monaco модель не найдена'); return false; } const fullRange = model.getFullModelRange(); editor.executeEdits('auto-solution', [{ range: fullRange, text: code, forceMoveMarkers: true, }]); editor.focus(); console.log('✅ Решение вставлено в редактор'); return true; } async function fetchAnswerPanes() { const html = await fetch(window.location.href).then(r => r.text()); const match = html.match(/"answer_panes":(\[.*?\]),"has_author_solution"/); if (!match) return null; try { return JSON.parse(match[1]); } catch (e) { return null; } } async function handleTrainerPage() { if (!document.querySelector('button.trainer-footer__solution-button')) { console.log('💡 Загружаем исходник страницы для поиска решения...'); const answerPanes = await fetchAnswerPanes(); if (!answerPanes || answerPanes.length === 0) { console.log('ℹ️ Авторского решения нет для этой задачи'); return false; } const solution = answerPanes[0].content; if (!solution) { console.log('ℹ️ Контент решения пустой'); return false; } console.log(`💡 Найдено решение (${answerPanes[0].name}), вставляем...`); insertSolutionIntoMonaco(solution); await sleep(CLICK_DELAY); const checkBtn = document.querySelector('button.trainer-footer__check-button'); if (checkBtn) { checkBtn.click(); console.log('✅ Нажата кнопка "Проверить", ждём результата...'); } else { console.log('⚠️ Кнопка "Проверить" не найдена'); return true; } } else { console.log('ℹ️ Задача уже решена'); } // Ждём кнопку "Далее" без ограничения по времени let nextBtn = null; let elapsed = 0; while (!nextBtn) { await sleep(CHECK_INTERVAL); elapsed += CHECK_INTERVAL; nextBtn = document.querySelector('button.trainer-footer__solution-button'); if (elapsed % 10000 === 0) { console.log(`⏳ Ожидаем результат проверки... (${elapsed / 1000}с)`); } } nextBtn.click(); console.log('➡️ Нажата кнопка "Далее"'); return true; } async function dispatch() { // Сброс состояния при каждом вызове isRunning = true; clickedButtons = new WeakSet(); handledQuizzes = new WeakSet(); handledFeedbacks = new WeakSet(); const path = window.location.pathname; console.log(`🔄 Страница: ${path}`); if (path.includes('/profile/associated-programs-android-st-v2')) { const found = handleAssociatedProgramsPage(); if (found) await handleCourseModal(); } else if (path.includes('/trainer/') && window.monaco?.editor.getEditors().length > 0) { await handleTrainerPage(); } else if (path.includes('/trainer/') || path.includes('/topics/')) { await run(); } } // Перехват SPA-навигации const _pushState = history.pushState.bind(history); history.pushState = function(...args) { _pushState(...args); setTimeout(() => dispatch(), PAGE_LOAD_DELAY); }; window.addEventListener('popstate', () => { setTimeout(() => dispatch(), PAGE_LOAD_DELAY); }); window.stopAutoClick = function() { isRunning = false; console.log('⏹ Остановлено'); }; console.log('💡 Для остановки: stopAutoClick()'); await dispatch(); })();