AIO - Auto-Liker & Auto-Subscriber

Vytvoří tlačítko které po aktivaci automaticky lajkuje komentáře na YouTube

// ==UserScript==
// @name         AIO - Auto-Liker & Auto-Subscriber
// @namespace    AIO - YouTube Tool LeSubs
// @version      2.0
// @description  Vytvoří tlačítko které po aktivaci automaticky lajkuje komentáře na YouTube
// @author       Projekt Darkside - DevIT Brno - EU
// @license      Darkside; MIT;
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// ==/UserScript==

/* eslint-disable */

(function () {
    'use strict';

    let isAutoLiking = false; // Indikátor běžícího auto-lajkování
    let likeStats = { liked: 0, total: 0 }; // Statistika lajků
    let activeTimeouts = []; // Seznam aktivních timeoutů pro zrušení
    let lastUrl = location.href; // Sledování aktuální URL

    let lastLikedCount = 0; // počet aktuálně likovaných
    let lastTotalCount = 0; // počet nalezených k olajkování
    let idleTimer = null; // resetujeme funkce

    // Volby pro aktivaci funkcí
    let NOTIF_GIF = false;  // Pokud je true, bude se spouštět GIF notifikace
    let NOTIF_SVG = true; // Pokud je true, bude se spouštět SVG zvoneček
    let DEBUG_MODE = false; // Pokud je true, bude se simulovat stisk každých 10 vteřin

    // Konstanty pro GIF URL a text notifikace
    const GIF_URL = 'https://cdn3.emoji.gg/emojis/4381-anouncements-animated.gif'; // URL pro GIF
    const NOTIF_TEXT = 'Toto je notifikace s GIF!'; // Text pro notifikaci u GIFu

    // Jazykové varianty tlačítka "Líbí se mi"
    const Wlang = [
        // líbí se komentář
        "Mark this comment as liked",
        "Označit tento komentář jako Líbí se mi",         // Angličtina
        "Označiť tento komentár ako Páči sa mi",          // Čeština
        "Marquer ce commentaire comme aimé",              // Slovenština
        "Marcar este comentario como Me gusta",           // Francouzština
        "Diesen Kommentar als Gefällt mir markieren",     // Španělština
        "Contrassegna questo commento come Mi piace",     // Němčina
        "Marcar este comentário como Gostei",             // Portugalština
        "Отметить этот комментарий как понравившийся",    // Ruština
        "このコメントを高評価としてマーク",                    // Japonština

        // Líbí se odpověď na komentář
        "Mark this answer as liked",                      // Angličtina
        "Označit tuto odpověď jako Líbí se mi",           // Čeština
        "Označiť túto odpoveď ako Páči sa mi",            // Slovenština
        "Marquer cette réponse comme aimée",              // Francouzština
        "Marcar esta respuesta como Me gusta",            // Španělština
        "Diese Antwort als Gefällt mir markieren",        // Němčina
        "Contrassegna questa risposta come Mi piace",     // Italština
        "Marcar esta resposta como Gostei",               // Portugalština
        "Отметить этот ответ как понравившийся",          // Ruština
        "この回答を高評価としてマーク",                       // Japonština
    ];

    // Překlady pro statistiky "Olajkováno"
    const likedTranslations = {
        'en': 'Liked',
        'cs': 'Olajkováno',
        'sk': 'Olajkované',
        'fr': 'Aimé',
        'es': 'Gustado',
        'de': 'Gemocht',
        'it': 'Apprezzato',
        'pt': 'Curtido',
        'ru': 'Понравилось',
        'ja': '高評価済み'
    };

    // Detekce jazyka (kompatibilní se všemi hlavními prohlížeči)
    function getLikedTranslation() {
        const lang = (navigator.languages && navigator.languages[0]) || navigator.language || 'en';
        const shortLang = lang.slice(0, 2);

        console.log(`Detected language: ${lang} (short: ${shortLang})`);

        return likedTranslations[shortLang] || likedTranslations['en'];
    }

    // Resetuje statistiky a zastaví všechny timeouty */
    function resetStats() {
        activeTimeouts.forEach(clearTimeout);
        activeTimeouts = [];
        likeStats = { liked: 0, total: 0 };
        //updateLikeStatus();
        console.log('🔄 Statistika byla resetována a všechny timeouty zastaveny.');
    }

    // Sleduje změnu URL a resetuje stav */
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            isAutoLiking = false;
            console.log('⏹️ Auto-liking byl zastaven kvůli změně URL.');
            resetStats();
        }
    }).observe(document, { subtree: true, childList: true });

    // Vytváří tlačítko pro spuštění auto-lajkování a zobrazení statistik */
    // Vytváří tlačítko pro spuštění auto-lajkování a zobrazení statistik */
    function createButton() {
        const container = document.querySelector('#info #top-row') || document.querySelector('.item.style-scope.ytd-watch-metadata');
        if (container && !document.querySelector('#auto-like-btn')) {
            const button = document.createElement('button');
            button.id = 'auto-like-btn';
            button.classList.add('auto-like-btn');
            button.title = 'Spustit olajkování načtených komentářů.';
            button.innerText = 'Auto-Like 👍';
            button.onclick = () => {
                startAutoLike();
            };
            container.appendChild(button);

            const status = document.createElement('div');
            status.id = 'like-status';
            status.classList.add('like-status', 'loading'); // Přidáme třídu 'loading' pro gif
            // status.innerHTML = `<strong>0/0</strong> &nbsp; ${getLikedTranslation()}`;
            status.innerHTML = ``;
            status.title = 'Odebírat !všechna! videa tohoto kanálu.';
            status.onclick = () => {
                startNotificationSystem();
                autoSubscribe()
            };
            container.appendChild(status);

            console.log('✅ Tlačítko Auto-Like a statistika byly přidány.');
        }
    }

    // Přidává vlastní styly pro tlačítko a stavové pole */
    function addCustomStyles() {
        const style = document.createElement('style');
        style.innerHTML = `
    .auto-like-btn {
        margin-left: 10px !important;
        background-image: url('https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExMnloN3Q5Mjh1b2Z0MmlrMTltZGo4MWJ0aGh3cHZ1YTdiMmJoMTJiciZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/26xBRt3iLuAesGzQI/giphy.gif') !important;
        background-size: cover;
        background-position: center;
        color: #fff !important;
        border: none !important;
        border-radius: 18px !important;
        cursor: pointer !important;
        font-size: 14px !important;
        transition: background-color 0.3s ease !important;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2) !important;
        text-align: center !important;
        display: inline-flex !important;
        justify-content: center !important;
        align-items: center !important;
        font-weight: bold !important;
        box-sizing: border-box !important;
        min-width: 130px !important;
        min-height: 36px !important;
    }
    .auto-like-btn:hover {
        background-color: #cc0000 !important;
        border: solid white 2px !important;
    }

    .like-status {
        background-size: cover;
        background-position: center;
        display: inline-flex !important;
        justify-content: center !important;
        align-items: center !important;
        margin-left: 10px !important;
        background: #f1f1f1;
        border-radius: 18px !important;
        font-size: 14px !important;
        color: #333 !important;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1) !important;
        font-weight: bold !important;
        text-align: center !important;
        box-sizing: border-box !important;
        user-select: none !important;
        /*cursor: not-allowed !important;*/
        cursor: pointer !important;
        min-width: 130px !important;
        min-height: 36px !important;
        position: relative !important;
        overflow: hidden !important;
    }
    .like-status:hover {
        border: solid white 2px !important;
    }

    /* GIF pozadí při načtení */
    .like-status.loading {
        background-image: url('https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExZzhxZmtmdTNzbWh5Z3NjejRqemdpZXJyMzZrdXJjZGluNWpjbXIzYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/byMmCtRgmb6XpQ6sod/giphy.gif') !important;
        background-size: cover !important;
        background-position: center !important;
    }
    `;
        document.head.appendChild(style);
    }

    ////////////////////////////////////

    // Funkce pro vytvoření notifikace s GIF a textem */
    function generateRandomGifAlert(gifUrl, message) {
        const notificationBox = document.createElement('div');
        notificationBox.style.position = 'fixed';
        notificationBox.style.left = '20px';
        notificationBox.style.bottom = '20px';
        notificationBox.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        notificationBox.style.color = 'white';
        notificationBox.style.borderRadius = '10px';
        notificationBox.style.padding = '10px';
        notificationBox.style.display = 'flex';
        notificationBox.style.alignItems = 'center';
        notificationBox.style.zIndex = '9999';
        notificationBox.style.transition = 'all 0.3s ease-in-out';

        // Vloží GIF
        const gifImage = document.createElement('img');
        gifImage.src = gifUrl;
        gifImage.style.width = '50px';
        gifImage.style.height = '50px';
        gifImage.style.marginRight = '10px';

        // Vloží text
        const alertText = document.createElement('span');
        alertText.innerText = message;

        // Přidá GIF a text do notifikace
        notificationBox.appendChild(gifImage);
        notificationBox.appendChild(alertText);

        // Přidá notifikaci na stránku
        document.body.appendChild(notificationBox);

        // Po 3 sekundách notifikaci skryje
        setTimeout(() => {
            notificationBox.style.opacity = '0';
            setTimeout(() => {
                document.body.removeChild(notificationBox);
            }, 300); // Počkáme, až animace skončí
        }, 3000);
    }

    // Funkce pro vytvoření zvonečku s textem "SUBSCRIBED" */
    function generateRandomBellSubscription() {
        const bellSVG = `
    <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24">
        <path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6V9c0-3.31-2.69-6-6-6S6 5.69 6 9v7l-1 1v1h14v-1l-1-1zm-2-1H8v-7c0-2.21 1.79-4 4-4s4 1.79 4 4v7z"/>
    </svg>
`;

        const bellNotification = document.createElement('div');
        bellNotification.style.position = 'fixed';
        bellNotification.style.left = '20px';
        bellNotification.style.bottom = '20px';
        bellNotification.style.backgroundColor = '#e63946'; // Červená barva pro menu
        bellNotification.style.color = 'white';
        bellNotification.style.borderRadius = '10px';
        bellNotification.style.padding = '10px 20px';
        bellNotification.style.display = 'flex';
        bellNotification.style.alignItems = 'center';
        bellNotification.style.justifyContent = 'space-between';
        bellNotification.style.zIndex = '9999';
        bellNotification.style.transition = 'all 0.3s ease-in-out';

        // Vloží SVG zvoneček
        const bellContainer = document.createElement('div');
        bellContainer.innerHTML = bellSVG;
        bellContainer.style.display = 'flex';
        bellContainer.style.alignItems = 'center';

        // Vloží text "SUBSCRIBED"
        const subscriptionText = document.createElement('span');
        subscriptionText.innerText = 'SUBSCRIBED';
        subscriptionText.style.fontWeight = 'bold';
        subscriptionText.style.fontSize = '20px';

        // Přidá SVG zvoneček a text do notifikace
        bellNotification.appendChild(bellContainer);
        bellNotification.appendChild(subscriptionText);

        // Přidá notifikaci na stránku
        document.body.appendChild(bellNotification);

        // Po 3 sekundách notifikaci skryje
        setTimeout(() => {
            bellNotification.style.opacity = '0';
            setTimeout(() => {
                document.body.removeChild(bellNotification);
            }, 300); // Počkáme, až animace skončí
        }, 3000);
    }

    // Funkce pro spuštění notifikace podle volby true/false */
    function startNotificationSystem() {
        if (NOTIF_GIF) {
            generateRandomGifAlert(GIF_URL, NOTIF_TEXT); // Použije hodnoty z konstant
        }

        if (NOTIF_SVG) {
            generateRandomBellSubscription();
        }
    }

    // Funkce čeká na prvek v DOM s daným selektorem (max. timeout sekund)
    function waitForElement(selector, timeout = 5000) {
        return new Promise((resolve, reject) => {
            const startTime = Date.now();

            function check() {
                const element = document.querySelector(selector);
                if (element) {
                    resolve(element);
                } else if (Date.now() - startTime > timeout) {
                    reject(new Error(`Prvek '${selector}' nebyl nalezen v časovém limitu.`));
                } else {
                    requestAnimationFrame(check);
                }
            }

            check();
        });
    }


    // .yt-spec-button-shape-next.yt-spec-button-shape-next--tonal.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--size-m.yt-spec-button-shape-next--icon-leading-trailing
    // Funkce pro automatické přihlášení odběru kanálu
    function autoSubscribe() {
        waitForElement('ytd-subscribe-button-renderer button')
            .then(subButton => {
                console.log("✅ Tlačítko pro odběr nalezeno:", subButton.innerText);
                subButton.click(); // Klikne na tlačítko "Odebírat" nebo "Odebíráno"

                setTimeout(() => {
                    // Otevře menu kliknutím na tlačítko s danou třídou
                    waitForElement('.yt-spec-button-shape-next.yt-spec-button-shape-next--tonal.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--size-m.yt-spec-button-shape-next--icon-leading-trailing')
                        .then(menuButton => {
                            console.log("✅ Tlačítko pro otevření menu nalezeno, klikám...");
                            menuButton.click();

                            setTimeout(() => {
                                // Jazykové varianty pro "Vše"
                                const allLabels = [
                                    "All",        // Angličtina
                                    "Vše",        // Čeština
                                    "Všetko",     // Slovenština
                                    "Tout",       // Francouzština
                                    "Todo",       // Španělština
                                    "Alle",       // Němčina
                                    "Tutto",      // Italština
                                    "Tudo",       // Portugalština
                                    "Все",        // Ruština
                                    "すべて"        // Japonština
                                ];

                                // Čeká na zobrazení menu s možnostmi odběru
                                waitForElement('yt-formatted-string.style-scope.ytd-menu-service-item-renderer')
                                    .then(() => {
                                        // Najde první položku v menu odpovídající jakékoli jazykové variantě "Vše"
                                        let menuOption = Array.from(document.querySelectorAll('yt-formatted-string.style-scope.ytd-menu-service-item-renderer'))
                                            .find(el => allLabels.some(label => el.innerText.trim() === label));

                                        if (menuOption) {
                                            console.log("✅ Položka 'Odebírat Vše' nalezena, klikám...");
                                            menuOption.click();
                                        } else {
                                            console.log("⚠️ Položka 'Odebírat Vše' nebyla nalezena.");
                                        }
                                    })
                                    .catch(() => console.log("❌ Nepodařilo se najít položku menu."));
                            }, 500); // Počkám na otevření menu
                        })
                        .catch(() => console.log("❌ Tlačítko pro otevření menu nenalezeno."));
                }, 500); // Počkám na otevření menu tlačítka
            })
            .catch(() => console.log("❌ Tlačítko pro odběr nenalezeno."));
    }

    // MutationObserver sleduje změny v DOM a spustí funkci autoSubscribe, když se objeví tlačítko
    const observer = new MutationObserver(() => {
        if (document.querySelector('ytd-subscribe-button-renderer button')) {
            observer.disconnect(); // Odpojíme, aby se funkce nespouštěla vícekrát
            // autoSubscribe();
        }
    });

    // Spustíme sledování změn v celém dokumentu
    observer.observe(document.body, { childList: true, subtree: true });



    // Pokud je DEBUG_MODE aktivní, simuluj stisknutí každých 10 vteřin
    if (DEBUG_MODE) {
        setInterval(() => {
            console.log('⚠️ DEBUG: Simulace stisknutí notifikace...');
            startNotificationSystem(); // Spustí notifikace podle aktuálního nastavení
        }, 10000); // Každých 10 vteřin
    }

    ////////////////////////////////////

    // Funkce, která spustí auto-like a změní styl statusu */
    function startAutoLike() {
        const statusElement = document.getElementById('like-status');
        if (statusElement) {
            statusElement.classList.remove('loading'); // Odebere GIF pozadí
        }

        // Spuštění hlavní funkce lajkování
        autoLikeThumbsUp();
    }

    // Aktualizuje vizuální zobrazení počtu lajků */
    function updateLikeStatus() {
        const statusElement = document.getElementById('like-status');
        if (statusElement) {
            statusElement.innerHTML = `<strong>${likeStats.liked}/${likeStats.total}</strong>&nbsp; ${getLikedTranslation()}`;

            //  Změní border na červený páč to jinak moc nejde :)
            document.querySelectorAll(".like-status").forEach(el => {
                el.addEventListener("mouseenter", () => {
                    el.style.setProperty("border", "solid red 2px", "important");
                });

                el.addEventListener("mouseleave", () => {
                    el.style.removeProperty("border"); // Vrátí border do původního stavu
                });
            });

            // Pokud se čísla změnila, restartuj časovač
            if (likeStats.liked !== lastLikedCount || likeStats.total !== lastTotalCount) {
                lastLikedCount = likeStats.liked;
                lastTotalCount = likeStats.total;
                resetIdleTimer();
            }
        }
    }

    // Restartuje časovač, který po 3 sekundách obnoví animaci a resetuje text */
    function resetIdleTimer() {
        clearTimeout(idleTimer); // Zastaví předchozí časovač
        idleTimer = setTimeout(() => {
            const statusElement = document.getElementById('like-status');
            if (statusElement) {
                statusElement.classList.add('loading'); // Po nečinnosti přidá GIF zpět
                // statusElement.innerHTML = `<strong>0/0</strong> &nbsp; ${getLikedTranslation()}`; // Resetuje text
                statusElement.innerHTML = ``;

                //  Změní border na červený páč to jinak moc nejde :)
                document.querySelectorAll(".like-status").forEach(el => {
                    el.addEventListener("mouseenter", () => {
                        el.style.setProperty("border", "solid white 2px", "important");
                    });

                    el.addEventListener("mouseleave", () => {
                        el.style.removeProperty("border"); // Vrátí border do původního stavu
                    });
                });
            }
            console.log('✅ Restartuji časovač');
        }, 3000); // 3 sekundy
    }

    // Hlavní funkce pro automatické lajkování komentářů */
    function autoLikeThumbsUp() {
        if (isAutoLiking) return;
        isAutoLiking = true;
        likeStats = { liked: 0, total: 0 };
        updateLikeStatus();

        const selector = Wlang.map(phrase => `button[aria-label^="${phrase}"]`).join(', ');
        const buttons = document.querySelectorAll(selector);
        likeStats.total = buttons.length;
        updateLikeStatus();

        // pokud tlačítko neexistuje
        if (buttons.length === 0) {
            console.warn('⚠️ Žádná tlačítka "Líbí se mi" nebyla nalezena.');
            isAutoLiking = false;
            return;
        }

        console.log(`🔹 Nalezeno ${buttons.length} komentářů k lajknutí.`);
        buttons.forEach((button, index) => {
            const timeoutId = setTimeout(() => {
                if (!button.classList.contains('style-default-active')) {
                    button.click();
                    likeStats.liked++;
                    updateLikeStatus();
                    console.log(`👍 Lajknut komentář #${index + 1}`);
                }
                if (index === buttons.length - 1) isAutoLiking = false;
            }, getRandomDelay(index));
            activeTimeouts.push(timeoutId);
        });
    }

    // Generuje náhodné zpoždění mezi lajky (v milisekundách) */
    function getRandomDelay(index) {
        const minDelay = 300;
        const maxDelay = 500;
        return minDelay + (Math.random() * (maxDelay - minDelay)) + (index * 500);
    }

    // Sleduje změny v DOM pro vykreslení tlačítka */
    function observeDOM() {
        const observer = new MutationObserver(() => {
            createButton();
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // Spuštění skriptu
    observeDOM();
    addCustomStyles();
    getLikedTranslation();
    updateLikeStatus();
})();