init
This commit is contained in:
commit
cc3e2c1b10
1 changed files with 345 additions and 0 deletions
345
script.js
Normal file
345
script.js
Normal file
|
|
@ -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();
|
||||
})();
|
||||
Loading…
Add table
Reference in a new issue