commit cc3e2c1b109158594067feef05041d31cd6c4cdb Author: MasterAkulon Date: Sat Dec 6 11:58:24 2025 +0300 init diff --git a/script.js b/script.js new file mode 100644 index 0000000..28b0a43 --- /dev/null +++ b/script.js @@ -0,0 +1,345 @@ +(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 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); + } + + async function handleFeedbackForm(form) { + console.log('📝 Форма обратной связи...'); + + // Проверяем, есть ли текстовое поле + const textarea = form.querySelector(FEEDBACK_TEXTAREA_SELECTOR); + if (textarea) { + // Симулируем ввод текста + simulateTyping(textarea, 'СПАСИБО!'); + console.log('✓ Введён текст "СПАСИБО!"'); + await sleep(500); + + // Пробуем ещё раз если кнопка всё ещё disabled + let nextBtn = form.querySelector(FEEDBACK_NEXT_SELECTOR); + if (nextBtn && nextBtn.disabled) { + // Ещё один способ - через React fiber + 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 { + // Обрабатываем radio-кнопки + 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) { + nextBtn.click(); + console.log('✓ Нажата кнопка "Далее"'); + handledFeedbacks.add(form); + await sleep(CLICK_DELAY); + return true; + } + + // Если кнопка всё ещё disabled, пробуем кликнуть принудительно + if (nextBtn) { + console.log('⚠️ Кнопка disabled, пробуем принудительный клик...'); + nextBtn.disabled = false; + nextBtn.classList.remove('button2_disabled'); + nextBtn.click(); + handledFeedbacks.add(form); + await sleep(CLICK_DELAY); + return true; + } + + handledFeedbacks.add(form); + return false; + } + + async function handleQuizForm(form) { + console.log('❓ Квиз...'); + + 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 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 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 === '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); + clickedButtons = new WeakSet(); + handledQuizzes = new WeakSet(); + handledFeedbacks = new WeakSet(); + } + + console.log(`\n✅ Готово!`); + console.log(`📊 Уроков пройдено: ${lessonCount}`); + console.log(`🖱️ Кнопок нажато: ${clickCount}`); + } + + window.stopAutoClick = function() { + isRunning = false; + console.log('⏹ Остановлено'); + }; + + console.log('💡 Для остановки: stopAutoClick()'); + run(); +})(); \ No newline at end of file