LOLZ Live Contest Counter

Добавляет значение лимита конкурсов в симпатии в профиль.

// ==UserScript==
// @name         LOLZ Live Contest Counter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Добавляет значение лимита конкурсов в симпатии в профиль.
// @author       QIYANA
// @match        https://lolz.live/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @connect      lolz.live
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    function createRPGModal({ title, message, input = false, onConfirm }) {
        const modal = document.createElement('div');
        modal.style.position = 'fixed';
        modal.style.top = '0';
        modal.style.left = '0';
        modal.style.width = '100%';
        modal.style.height = '100%';
        modal.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        modal.style.display = 'flex';
        modal.style.justifyContent = 'center';
        modal.style.alignItems = 'center';
        modal.style.zIndex = '9999';

        const modalContent = document.createElement('div');
        modalContent.style.background = 'linear-gradient(135deg, #f5e9f5 0%, #e0f7fa 100%)';
        modalContent.style.backgroundImage = 'url("https://www.transparenttextures.com/patterns/stardust.png")';
        modalContent.style.opacity = '0.98';
        modalContent.style.border = '4px solid #ff80ab';
        modalContent.style.padding = '25px';
        modalContent.style.borderRadius = '20px';
        modalContent.style.boxShadow = '0 0 20px rgba(255, 128, 171, 0.5), 0 0 40px rgba(179, 229, 252, 0.3)';
        modalContent.style.width = '450px';
        modalContent.style.fontFamily = '"M PLUS Rounded 1c", "Anime Ace", "Comic Sans MS", sans-serif';
        modalContent.style.color = '#ffffff';
        modalContent.style.textAlign = 'center';
        modalContent.style.position = 'relative';
        modalContent.style.animation = 'sparkle 4s infinite';

        const styleSheet = document.createElement('style');
        styleSheet.textContent = `
            @keyframes sparkle {
                0%, 100% { box-shadow: 0 0 20px rgba(255, 128, 171, 0.5), 0 0 40px rgba(179, 229, 252, 0.3); }
                50% { box-shadow: 0 0 30px rgba(255, 128, 171, 0.7), 0 0 50px rgba(179, 229, 252, 0.5); }
            }
        `;
        document.head.appendChild(styleSheet);

        const titleElement = document.createElement('h2');
        titleElement.textContent = title;
        titleElement.style.margin = '0 0 15px 0';
        titleElement.style.fontSize = '28px';
        titleElement.style.textShadow = '0 0 8px rgba(255, 128, 171, 1), 0 0 16px rgba(179, 229, 252, 1)';
        titleElement.style.color = '#ffffff';
        titleElement.style.fontWeight = 'bold';
        modalContent.appendChild(titleElement);

        const messageElement = document.createElement('p');
        messageElement.textContent = message;
        messageElement.style.margin = '0 0 20px 0';
        messageElement.style.fontSize = '18px';
        messageElement.style.lineHeight = '1.5';
        messageElement.style.color = '#ffffff';
        messageElement.style.textShadow = '0 0 3px rgba(255, 128, 171, 0.8), 0 0 6px rgba(179, 229, 252, 0.8)';
        modalContent.appendChild(messageElement);

        let inputElement;
        if (input) {
            inputElement = document.createElement('input');
            inputElement.type = 'text';
            inputElement.placeholder = 'Введите путь к данным...';
            inputElement.style.width = '100%';
            inputElement.style.padding = '10px';
            inputElement.style.marginBottom = '20px';
            inputElement.style.border = '3px solid #ff80ab';
            inputElement.style.borderRadius = '8px';
            inputElement.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
            inputElement.style.color = '#c2185b';
            inputElement.style.fontFamily = 'inherit';
            inputElement.style.fontSize = '16px';
            inputElement.style.boxShadow = '0 0 10px rgba(255, 128, 171, 0.4)';
            inputElement.style.zIndex = '10000';
            inputElement.style.pointerEvents = 'auto';
            modalContent.appendChild(inputElement);

            setTimeout(() => {
                inputElement.focus();
                console.log('Фокус установлен на поле ввода');
            }, 100);
        }

        const confirmButton = document.createElement('button');
        confirmButton.textContent = input ? 'Подтвердить' : 'Закрыть';
        confirmButton.style.padding = '12px 25px';
        confirmButton.style.background = 'linear-gradient(135deg, #ff80ab 0%, #b3e5fc 100%)';
        confirmButton.style.border = '3px solid #ff80ab';
        confirmButton.style.borderRadius = '10px';
        confirmButton.style.color = '#ffffff';
        confirmButton.style.fontFamily = 'inherit';
        confirmButton.style.fontSize = '18px';
        confirmButton.style.fontWeight = 'bold';
        confirmButton.style.cursor = 'pointer';
        confirmButton.style.boxShadow = '0 0 15px rgba(255, 128, 171, 0.7)';
        confirmButton.style.transition = 'all 0.3s';
        confirmButton.style.position = 'relative';
        confirmButton.style.overflow = 'hidden';
        confirmButton.addEventListener('mouseover', () => {
            confirmButton.style.boxShadow = '0 0 25px rgba(255, 128, 171, 0.9)';
            confirmButton.style.animation = 'sparkle 1.5s infinite';
        });
        confirmButton.addEventListener('mouseout', () => {
            confirmButton.style.boxShadow = '0 0 15px rgba(255, 128, 171, 0.7)';
            confirmButton.style.animation = 'none';
        });
        confirmButton.addEventListener('click', () => {
            const value = input ? inputElement.value : null;
            document.body.removeChild(modal);
            if (onConfirm) onConfirm(value);
        });
        modalContent.appendChild(confirmButton);

        modal.appendChild(modalContent);
        document.body.appendChild(modal);

        return new Promise((resolve) => {
            confirmButton.addEventListener('click', () => {
                const value = input ? inputElement.value : null;
                resolve(value);
            });
        });
    }

    let profileUrl = GM_getValue('profileUrl');
    if (!profileUrl) {
        createRPGModal({
            title: '✨ Запись в магическом нейро-свитке ✨',
            message: 'О, путник-чан! Назови путь к своему профилю в этой цифровой реальности! (Пример: https://lolz.live/kqlol/) 💖',
            input: true,
            onConfirm: (value) => {
                if (value) {
                    profileUrl = value.trim().replace(/\/$/, '');
                    GM_setValue('profileUrl', profileUrl);
                    location.reload();
                } else {
                    createRPGModal({
                        title: '🌸 Свиток данных пуст! 🌸',
                        message: 'Ты не указал путь к профилю. Моя нейромагия не сработает без этого! (ノД`)・゜・。',
                        onConfirm: () => {
                            location.reload();
                        }
                    });
                }
            }
        });
        return;
    }

    const currentUrl = window.location.href.replace(/\/$/, '');
    if (!currentUrl.startsWith(profileUrl)) {
        return;
    }

    document.addEventListener('keydown', (event) => {
        if (event.altKey && event.key.toLowerCase() === 'l') {
            GM_deleteValue('profileUrl');
            createRPGModal({
                title: '💿 Ссылка сброшена 💿',
                message: 'Ссылка на профиль сброшена. Перезагружаю магическую матрицу! ^_^. 💫',
                onConfirm: () => {
                    location.reload();
                }
            });
        }
    });

    function waitForElement(selector, callback, timeout = 10000) {
        const startTime = Date.now();
        const checkElement = () => {
            const element = document.querySelector(selector);
            if (element) {
                callback(element);
            } else if (Date.now() - startTime < timeout) {
                setTimeout(checkElement, 500);
            } else {
                console.error(`Элемент ${selector} не найден за ${timeout / 1000} секунд`);
            }
        };
        checkElement();
    }

    GM_xmlhttpRequest({
        method: "GET",
        url: "https://lolz.live/forums/contests/",
        withCredentials: true,
        onload: function(response) {
            const parser = new DOMParser();
            const doc = parser.parseFromString(response.responseText, "text/html");
            const counterElement = doc.querySelector('div.limitCounter .counterText');
            if (!counterElement) {
                console.error("Элемент div.limitCounter .counterText не найден на странице конкурсов");
                return;
            }

            const counterText = counterElement.textContent.trim();

            const computedStyles = getComputedStyle(counterElement);
            const counterStyles = {
                color: computedStyles.color,
                fontSize: computedStyles.fontSize,
                fontWeight: computedStyles.fontWeight,
                fontFamily: computedStyles.fontFamily
            };

            waitForElement('a.page_counter[href$="/likes"]', (pageCounter) => {
                const originalTitle = pageCounter.getAttribute('data-cachedtitle') || '';
                const newTitle = `${originalTitle}<br><div class="counterText">Лимит участий - ${counterText}</div>`;

                pageCounter.setAttribute('data-cachedtitle', newTitle);
                pageCounter.removeAttribute('title');

                pageCounter.addEventListener('mouseover', () => {
                    setTimeout(() => {
                        const tooltip = document.querySelector('div[id^="tippy-"] .tippy-content');
                        if (tooltip && tooltip.textContent.includes(originalTitle)) {
                            tooltip.innerHTML = `${originalTitle}<br><div class="counterText">Лимит участий - ${counterText}</div>`;
                            const counterDiv = tooltip.querySelector('.counterText');
                            if (counterDiv) {
                                counterDiv.style.color = counterStyles.color;
                                counterDiv.style.fontSize = counterStyles.fontSize;
                                counterDiv.style.fontWeight = counterStyles.fontWeight;
                                counterDiv.style.fontFamily = counterStyles.fontFamily;
                            }
                        }
                    }, 100);
                });
            });
        },
        onerror: function(err) {
            console.error("Ошибка при запросе страницы конкурсов:", err);
        }
    });
})();