您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name Nedo Auto Contest Participation Script with adblock
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Автоматом участвует в розыгрышах после ручного входа в первый розыгрыш + удаляет содержимое розыгрыша.
// @author eretly
// @match https://lolz.live/*
// @match https://lolz.guru/*
// @match https://zelenka.guru/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// Конфиг
const CHECK_INTERVAL = 20; // 200 ms
const PARTICIPATION_WAIT = 3000; // ms, ждем 3 секунды, прежде чем проверять скрытое состояние кнопки (если вы проходите капчу за 1 секунду после захода в тему, то уменьшите)
const SCROLL_ATTEMPTS = 2; // Количество попыток прокрутки (ненужная хуйня)
const SCROLL_INTERVAL = 2000; // ms, интервал между попытками прокрутки (ненужная хуйня)
const SCROLL_OFFSET = 10; // px, Выше (0+) / Ниже (-0) прокручивать страницу
const DOUBLE_CHECK_DELAY = 400; // 400 ms, задержка перед повторной проверкой скролла (типо если не долистал до конца, чет прогрузилось на странице, через 0.5 сек чекнет и долистает как надо - поставил оптимальное для себя)
const BEFORE_CLICK_DELAY = 10; // 100 ms, задержка перед нажатием на кнопку
const AFTER_CLICK_DELAY = 30; // 300 ms, задержка после нажатия на кнопку
const STORAGE_KEY = 'nedoAutoContestListURL';
const AUTO_MODE_KEY = 'nedoAutoContestMode';
const FIRST_ENTRY_KEY = 'nedoFirstContestEntry';
const SUCCESSFUL_PARTICIPATION_KEY = 'nedoSuccessfulParticipation';
function saveContestListURL(url) {
sessionStorage.setItem(STORAGE_KEY, url);
console.log('Сохранен URL списка розыгрышей с фильтрами:', url);
}
function getSavedContestListURL() {
return sessionStorage.getItem(STORAGE_KEY);
}
function getContestListURL() {
const hostname = window.location.hostname;
switch (hostname) {
case 'lolz.live':
return 'https://lolz.live/forums/contests/';
case 'lolz.guru':
return 'https://lolz.guru/forums/contests/';
case 'zelenka.guru':
return 'https://zelenka.guru/forums/contests/';
default:
console.warn('Неизвестный домен:', hostname);
return null;
}
}
function setAutoMode(value) {
sessionStorage.setItem(AUTO_MODE_KEY, value.toString());
console.log(value ? 'Авто-режим активирован' : 'Авто-режим деактивирован');
}
function getAutoMode() {
return sessionStorage.getItem(AUTO_MODE_KEY) === 'true';
}
function setFirstEntry(value) {
sessionStorage.setItem(FIRST_ENTRY_KEY, value.toString());
}
function getFirstEntry() {
return sessionStorage.getItem(FIRST_ENTRY_KEY) === 'true';
}
function setSuccessfulParticipation(value) {
sessionStorage.setItem(SUCCESSFUL_PARTICIPATION_KEY, value.toString());
}
function getSuccessfulParticipation() {
return sessionStorage.getItem(SUCCESSFUL_PARTICIPATION_KEY) === 'true';
}
function updateContestListURL() {
const contestListURL = getContestListURL();
if (window.location.href.includes(contestListURL)) {
saveContestListURL(window.location.href);
if (isDirectAccess()) {
resetAllStates();
console.log('Обнаружен прямой вход на страницу розыгрышей. Все состояния сброшены.');
}
}
}
function isDirectAccess() {
return document.referrer === '' || !document.referrer.includes(window.location.hostname);
}
function resetAllStates() {
setFirstEntry(false);
setAutoMode(false);
setSuccessfulParticipation(false);
}
function cleanUpContestPage() {
let contestBlock = document.querySelector(".contestThreadBlock");
if (contestBlock) {
let contentBlock = document.querySelector(".messageText.SelectQuoteContainer.baseHtml.ugc");
let pollBlock = document.querySelector(".PollContainer");
if (contentBlock) contentBlock.remove();
if (pollBlock) pollBlock.remove();
}
}
function scrollToElement() {
const xpath = "/html/body/div[4]/div/div/div/form/ol/li/div[2]/div[3]/article/div";
let scrollAttempts = 0;
let elementFound = false;
return new Promise((resolve) => {
function attemptScroll() {
const element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (element) {
elementFound = true;
const elementRect = element.getBoundingClientRect();
const absoluteElementTop = elementRect.top + window.pageYOffset;
const middleOfElement = absoluteElementTop + elementRect.height / 2;
const scrollTo = middleOfElement - (window.innerHeight / 2) - SCROLL_OFFSET;
window.scrollTo({
top: scrollTo,
behavior: 'smooth'
});
console.log('Прокручено к элементу');
setTimeout(() => {
const newElementRect = element.getBoundingClientRect();
if (newElementRect.top > SCROLL_OFFSET) {
console.log('Элемент не на нужной позиции, корректировка...');
window.scrollTo({
top: window.pageYOffset + newElementRect.top - SCROLL_OFFSET,
behavior: 'smooth'
});
}
resolve(elementFound);
}, DOUBLE_CHECK_DELAY);
} else {
console.log('Элемент не найден, повторная попытка...');
if (scrollAttempts < SCROLL_ATTEMPTS) {
scrollAttempts++;
setTimeout(attemptScroll, SCROLL_INTERVAL);
} else {
console.log('Не удалось найти элемент после нескольких попыток');
resolve(elementFound);
}
}
}
attemptScroll();
});
}
function clickNextContestLink() {
const selector = ".discussionListItem a.listBlock.main.PreviewTooltip";
const links = document.querySelectorAll(selector);
for (let link of links) {
if (!link.closest('.discussionListItem').classList.contains('participated')) {
console.log('Кликаем по следующему розыгрышу:', link.href);
link.click();
return true;
}
}
console.log('Не найдено больше розыгрышей для участия.');
return false;
}
function waitForParticipateButton() {
return new Promise((resolve) => {
const interval = setInterval(() => {
const participateButton = document.querySelector('a.LztContest--Participate.button:not(.disabled)');
if (participateButton && participateButton.getAttribute('href').includes('token')) {
clearInterval(interval);
resolve(participateButton);
}
}, CHECK_INTERVAL);
});
}
async function participateInContest() {
console.log('Ожидание доступности кнопки участия...');
const participateButton = await waitForParticipateButton();
console.log('Кнопка участия доступна, ожидаем перед кликом...');
await new Promise(resolve => setTimeout(resolve, BEFORE_CLICK_DELAY));
participateButton.click();
console.log('Кликнули по кнопке участия');
await new Promise(resolve => setTimeout(resolve, AFTER_CLICK_DELAY));
console.log('Участие завершено, возвращаемся к списку розыгрышей');
setSuccessfulParticipation(true);
const contestListURL = getSavedContestListURL();
if (contestListURL) {
window.location.href = contestListURL;
} else {
console.warn('Не удалось определить URL списка розыгрышей для возврата.');
}
}
async function init() {
const currentURL = window.location.href;
const contestListURL = getContestListURL();
if (currentURL.includes('/threads/')) {
console.log('На странице розыгрыша, начинаем процесс участия...');
cleanUpContestPage();
const elementFound = await scrollToElement();
if (elementFound) {
if (!getFirstEntry()) {
setFirstEntry(true);
setAutoMode(true);
console.log('Первый вход в розыгрыш, активируем авто-режим');
}
if (getAutoMode()) {
setTimeout(participateInContest, PARTICIPATION_WAIT);
}
} else {
console.log('Элемент для прокрутки не найден, участие не будет выполнено.');
}
} else if (currentURL.includes(contestListURL)) {
console.log('На странице списка розыгрышей, обновляем URL...');
updateContestListURL();
if (getAutoMode() && getSuccessfulParticipation()) {
setSuccessfulParticipation(false);
setTimeout(() => {
if (!clickNextContestLink()) {
setAutoMode(false);
setFirstEntry(false);
console.log('Авто-режим выключен, так как не осталось розыгрышей для участия.');
}
}, 1000);
}
} else {
console.log('На другой странице, скрипт не активирован.');
}
}
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
init();
}
}).observe(document, { subtree: true, childList: true });
init();
})();