YouTube DeBlock

Fully Working 2023 UnBlocker for YouTube. Get rid of that pesky blocker, and return my vids!

// ==UserScript==
// @name            YouTube DeBlock
// @description     Fully Working 2023 UnBlocker for YouTube. Get rid of that pesky blocker, and return my vids!
// @author          YelloNox
// @version         1.1.8
// @created         2023-10-10
// @namespace       https://yello.zip
// @homepage        https://github.com/YelloNox/YouTube-UnBlock
// @match           *://www.youtube.com/*
// @grant           none
// ==/UserScript==

(function () {
    "use strict";

    /* User Customization */
    const disableTheaterToggle = false;
    const disableReloadToggle = false;
    const disableOptionsMenu = false;
    var forceEnableEmbed = false;
    /* Language INFO: https://github.com/YelloNox/YouTube-UnBlock/blob/main/language.md */
    const language = "en";
    /* End User Customization */

    // Any class the blocker uses
    const blockerClass = "ytd-enforcement-message-view-model";
    // Any class on the broken video (e.x. yt-playability-error-supported-renderers)
    var ogVideoClass = "yt-playability-error-supported-renderers";
    if (forceEnableEmbed) {
        // Any class of the official video for force replacing
        ogVideoClass = "html5-video-player";
    }
    // Class of the parent for the custom content locaiton
    const customContentParentID = "end";
    // Original Youtube URL
    const youtubeURL = "youtube.com";
    // Change to theater mode on load
    const changeTheaterOnStart = false;

    // Domains to redirect to.
    var domainList = [
        "youtube.com/embed",
        "yout-ube.com",
        "piped.kavin.rocks",
        "subscriptions.gir.st",
        "nsfwyoutube.com", // Disabled (for now)
    ];
    // Does domain include www. (if not, need to remove later)
    var domainListUrlStat = [
        true, //"youtube.com/embed",
        true, //"yout-ube.com",
        false, //"piped.kavin.rocks",
        false, //"subscriptions.gir.st",
        false, //"nsfwyoutube.com",
    ];

    // --- Do Not Touch --- //
    var newDomain = domainList[0];
    var newDomainListUrlStat = domainListUrlStat[0];
    // Temp Functions //
    const tempReplaceClass = "replaceme";
    let isBlocked = false;
    let isSubChange = false;
    let isChangingFrame = false;
    var updatedURL = window.location.href;
    var previousDropdownValue;
    // --- Do Not Touch --- //

    // -------------- Main Loop Funcitons -------------- //

    // Function that checks if the page is even blocked
    var theaterStartRunOnce = false;
    function checkClass() {
        const blockerElement = document.querySelectorAll("." + blockerClass);
        const videoElement = document.querySelectorAll("." + ogVideoClass);

        if (blockerElement.length > 0) {
            isBlocked = true;
            console.log("blocked [checkClass]: yes");
        }

        if (forceEnableEmbed && videoElement.length > 0) {
            isBlocked = true;
            forceEnableEmbed = false;
            console.log("Forcing Unblock");
        }

        if (isBlocked) {
            console.log("Replacing Original [checkClass]");
            replaceVideo();
            addDomainToURLs();
            isBlocked = false;
        } else {
            // console.log("[checkClass] #2") - Cogs Log
            urlTracker();
            dropdownTracker();
        }

        if (changeTheaterOnStart && !theaterStartRunOnce) {
            changeTheaterMode(true);
            theaterStartRunOnce = true;
        }
    }

    // -------------- Event Listeners -------------- //

    // Checks if the url has changed, if so, reload the iframe (thus reloading the video)
    function urlTracker() {
        var currentURL = window.location.href;
        // console.log("Test URL [urlTracker]"); - Cogs Log
        if (currentURL != updatedURL) {
            console.log("Found New URL");
            updatedURL = window.location.href;
            if (isSubChange) {
                isBlocked = true;
            }
        }
    }

    // Checks if the dropdown has changed
    function dropdownTracker() {
        var dropdown = document.getElementById("dropdown");
        if (dropdown) {
            changeSelection(dropdown);
        }
    }

    function changeSelection(dropdown) {
        try {
            dropdown.addEventListener("change", function () {
                checkDropdownChange(dropdown);
            });
        } catch (error) {
            console.error("Error [changeSelection]: " + error);
        }
    }

    function checkDropdownChange(dropdown) {
        var newValue = dropdown.value;

        // Check if the value has actually changed
        if (newValue !== previousDropdownValue) {
            newDomain = domainList[newValue];
            newDomainListUrlStat = domainListUrlStat[newValue];
            console.log("Selection Changed [newDomain]: " + newDomain);
            console.log(
                "Selection Changed [newDomainListUrlStat]: " +
                    newDomainListUrlStat
            );
            reloadFrame();

            // Update the previousValue variable
            previousDropdownValue = newValue;
        }
    }

    // Reload Frame when "Reload Frame" button is clicked
    function reloadFrame() {
        replaceVideo();
        addDomainToURLs();

        console.log("clicked [reloadFrame]");
    }

    // -------------- Checks -------------- //

    function appendingFrame(isSet) {
        if (isSet == true) {
            isChangingFrame = true;
        } else {
            isChangingFrame = false;
        }
        console.log("ChangingFrames: " + changingFrame);
    }

    // -------------- Actions -------------- //

    // Remove the *blocker* from the page by locating the class name.
    function removeElementsByClassName(removeClass) {
        console.log("Removing [removeElementsByClassName]: " + removeClass);
        const elements = document.querySelectorAll("." + removeClass);
        try {
            elements.forEach((element) => {
                element.remove();
            });
        } catch (error) {
            console.error(
                "Error removing elements [removeElementsByClassName]: " + error
            );
        }
    }

    // Checks string and returns if contains matching text
    function checkText(string, text) {
        console.log("Checking string [checkText]");
        return string.includes(text);
    }

    // Function to replace "youtube.com" with selected domain
    function getNewURL(newDomain) {
        console.log("New URL [newDomain]: " + newDomain);
        const currentURL = window.location.href;
        try {
            if (currentURL.includes(youtubeURL)) {
                var newURL = currentURL.replace(youtubeURL, newDomain);
                if (newDomainListUrlStat == false) {
                    newURL = newURL.replace(/www./g, "");
                }
                return newURL;
            }
        } catch (error) {
            console.error("Error [newURL]: " + error);
        }
    }

    // Adds "youtube.com" to all nameless urls on webpage
    function addDomainToURLs() {
        console.log("Adding [addDomainToURLs]");
        const links = document.querySelectorAll("a");

        try {
            links.forEach((link) => {
                let href = link.getAttribute("href");
                if (
                    href &&
                    !href.startsWith("http") &&
                    !href.startsWith("www")
                ) {
                    href = "https://www." + youtubeURL + href;

                    link.setAttribute("href", href);
                }
            });
        } catch (error) {
            console.error("[addDomainToURLs] #1", error);
        }
    }

    // Is it the first video change, or recurring?
    function replaceVideo() {
        if (!isSubChange) {
            console.log("replacing [replaceVideo]");
            removeElementsByClassName(blockerClass);
            createJFrame(ogVideoClass);
            isSubChange = true;

            return;
        }
        if (isSubChange) {
            console.log("replacing subclick [replaceVideo]");
            removeOgIframe();
            createJFrame(tempReplaceClass);
            console.log("In with the new [replaceVideo]");
        }

        isBlocked = false;
    }

    // Fixes unusable URL(s)
    function fixURL(URL) {
        const playlistCheck = "&list=";
        const watchStamp = "watch?v=";
        const timestamp = "&t=";
        const isURL = checkText(URL, youtubeURL);
        const isPlaylist = checkText(URL, playlistCheck);
        const isTimestamp = checkText(URL, timestamp);

        console.log(
            "isURL:" +
                isURL +
                " isPlaylist:" +
                isPlaylist +
                " isTimestamp:" +
                isTimestamp
        );
        console.log("URL [fixURL]:" + URL);

        if (isURL) {
            URL = URL.replace(watchStamp, "");
            console.log("Is Not Playlist [fixURL]: " + URL);
        }
        if (isURL && isTimestamp) {
            URL = URL.split(timestamp)[0];
            console.log("\nURL Split Timestamp Fix [fixURL]: " + URL);
        }
        if (isPlaylist) {
            URL = URL.split(playlistCheck)[0];
            console.log("\nURL Split Playlist Fix [fixURL]: " + URL);
        }

        return URL;
    }

    // Fixes webpage address
    function fixPage() {
        var tmpURL = window.location.href;
        const playlistCheck = "&list=";
        const isBrokePlaylist = checkText(tmpURL, playlistCheck);

        if (isBrokePlaylist) {
            printAlert(0);
            var regex = /(&list)\D+\d+/g;
            console.log("URL Fix Original: [fixPage]: " + tmpURL);
            tmpURL = tmpURL.replace(regex, "");
            console.log("URL Fix New: [fixPage]: " + tmpURL);
            window.location.href = tmpURL;
        }
    }

    var theaterModeToggle = true;
    function toggleTheater() {
        if (theaterModeToggle) {
            console.log("Changing Mode [toggleTheater]: Off");
            theaterModeToggle = false;
        } else {
            console.log("Changing Mode [toggleTheater]: On");
            theaterModeToggle = true;
        }
        changeTheaterMode(theaterModeToggle);
    }

    // Thanx https://stackoverflow.com/questions/53584026/toggle-the-cinema-mode-on-youtube-with-javascript :>
    function changeTheaterMode(state) {
        try {
            const collection = document.getElementsByTagName("ytd-watch-flexy");
            const ytd_watch_flexy = collection.item(0);
            if (!ytd_watch_flexy) {
                console.error("No ytd-watch-flexy Found[changeTheaterMode]");
                return;
            }

            if (state) {
                ytd_watch_flexy.theater = true;
                console.log("Theater On [changeTheaterMode]");
            } else {
                ytd_watch_flexy.theater = false;
                console.log("Theater Off [changeTheaterMode]");
            }
        } catch (error) {
            console.error("Theater-Mode Error [changeTheaterMode]: " + error);
        }
    }

    // -------------- JFrame Control -------------- //
    // Create video embedding frame
    function createJFrame(classToOverturn) {
        var newURL = getNewURL(newDomain);
        const elements = document.querySelectorAll("." + classToOverturn);
        console.log("newURL Beginning [createJFrame]: " + newURL);

        fixPage();
        newURL = fixURL(newURL);

        try {
            const firstElement = elements[0]; // Get the first element in the array -> trying to prevent duplicate videos
            if (firstElement) {
                const iframe = document.createElement("iframe");
                iframe.width = "100%";
                iframe.height = "100%";
                iframe.src = newURL;
                iframe.allow =
                    "accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
                // autoplay:       ^ (autoplay removed after bug; also never worked anyhow)
                iframe.allowFullscreen = true;
                iframe.zIndex = "9999";

                firstElement.parentNode.replaceChild(iframe, firstElement);
                console.log("Modified URL:", newURL);
            }
        } catch (error) {
            console.error("Error creating iframe [createJFrame]: " + error);
        }
    }

    // Removes the original video frame.
    function removeOgIframe() {
        const iframes = document.querySelectorAll("iframe");

        console.log("removing jFrame [removeOgIframe]");
        try {
            iframes.forEach((iframe) => {
                const paragraph = document.createElement("p");
                paragraph.className = tempReplaceClass;
                iframe.parentNode.insertBefore(paragraph, iframe);
                iframe.remove();
                console.log("Out with the old [removeOgIframe]");
            });
        } catch (error) {
            console.error("Error [removeOgIframe]: " + error);
        }
    }

    // -------------- Experimental Features (unused) -------------- //

    // Save dropdown selection to local storage
    function dropdownStore() {
        try {
            rememberButton.addEventListener("click", function () {
                localStorage.setItem("selectedOption", dropdown.value);
                console.log("Selection Stored");
            });
        } catch (error) {
            console.error("Error [dropdownStore]: " + error);
        }
    }

    // -------------- Language Information -------------- //

    // xtxt is for the type of text needed (i.e. dropdown / theater mode button / ect...) for the main category of text.
    // vers is the item in the container (i.e. dropdown: youtube, yout-ube) for multiple subtexts.
    // top tier explination!
    function getText(xtxt, vers) {
        const translations = {
            en: {
                theaterMode: ["Theater"],
                reloadFrame: ["Reload Frame"],
                dropdown: [
                    "YouTube™ [Embed]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            de: {
                theaterMode: ["Theater"],
                reloadFrame: ["Rahmen neu laden"],
                dropdown: [
                    "YouTube™ [Einbetten]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            es: {
                theaterMode: ["Teatro"],
                reloadFrame: ["Recargar Marco"],
                dropdown: [
                    "YouTube™ [Incrustar]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            fr: {
                theaterMode: ["Théâtre"],
                reloadFrame: ["Recharger le Cadre"],
                dropdown: [
                    "YouTube™ [Intégrer]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            it: {
                theaterMode: ["Teatro"],
                reloadFrame: ["Ricarica Cornice"],
                dropdown: [
                    "YouTube™ [Incorpora]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            jp: {
                theaterMode: ["劇場"],
                reloadFrame: ["フレームを再読み込み"],
                dropdown: [
                    "YouTube™ [埋め込み]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            ko: {
                theaterMode: ["극장"],
                reloadFrame: ["프레임 다시 로드"],
                dropdown: [
                    "YouTube™ [임베드]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            nl: {
                theaterMode: ["Theater"],
                reloadFrame: ["Frame Herladen"],
                dropdown: [
                    "YouTube™ [Insluiten]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            pl: {
                theaterMode: ["Teatr"],
                reloadFrame: ["Przeładuj Ramkę"],
                dropdown: [
                    "YouTube™ [Osadź]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            pt: {
                theaterMode: ["Teatro"],
                reloadFrame: ["Recarregar Quadro"],
                dropdown: [
                    "YouTube™ [Embutir]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            ru: {
                theaterMode: ["Театр"],
                reloadFrame: ["Перезагрузить Рамку"],
                dropdown: [
                    "YouTube™ [Вставить]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            ar: {
                theaterMode: ["مسرح"],
                reloadFrame: ["إعادة تحميل الإطار"],
                dropdown: [
                    "YouTube™ [تضمين]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            zh: {
                theaterMode: ["剧院"],
                reloadFrame: ["重新加载框架"],
                dropdown: [
                    "YouTube™ [嵌入]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            hi: {
                theaterMode: ["रंगमंच"],
                reloadFrame: ["फ्रेम पुनः लोड करें"],
                dropdown: [
                    "YouTube™ [एम्बेड करें]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            sv: {
                theaterMode: ["Teater"],
                reloadFrame: ["Ladda om Ramen"],
                dropdown: [
                    "YouTube™ [Bädda in]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            no: {
                theaterMode: ["Teater"],
                reloadFrame: ["Last Inn Rammen på Nytt"],
                dropdown: [
                    "YouTube™ [Bygg inn]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            da: {
                theaterMode: ["Teater"],
                reloadFrame: ["Genindlæs Rammen"],
                dropdown: [
                    "YouTube™ [Vložit]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            cs: {
                theaterMode: ["Divadlo"],
                reloadFrame: ["Rámeček znovu načíst"],
                dropdown: [
                    "YouTube™ [Vložit]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            hu: {
                theaterMode: ["Színház"],
                reloadFrame: ["Keret Újratöltése"],
                dropdown: [
                    "YouTube™ [Beágyazás]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },

            tr: {
                theaterMode: ["Tiyatro"],
                reloadFrame: ["Çerçeveyi Yeniden Yükle"],
                dropdown: [
                    "YouTube™ [Gömme]",
                    "yout-ube",
                    "kavin.rocks",
                    "gir.st",
                ],
            },
        };

        const languageTranslations = translations[language];
        return languageTranslations && languageTranslations[xtxt]
            ? languageTranslations[xtxt][vers]
            : undefined;
    }

    // alertT is the alert type (i.e. invalid page...)
    function printAlert(alertT) {
        const translations = {
            en: {
                0: [
                    "Oops! Something went wrong.\n\n- Issue: The playlist feature is currently not working.\n- Action: You will be redirected to a static page shortly.\n\nI am looking for a fix.",
                ],
            },

            de: {
                0: [
                    "Hoppla! Etwas ist schief gelaufen.\n\n- Problem: Die Playlist-Funktion funktioniert derzeit nicht.\n- Aktion: Sie werden in Kürze auf eine Standardseite umgeleitet.\n\nIch suche nach einer Lösung.",
                ],
            },

            es: {
                0: [
                    "¡Vaya! Algo salió mal.\n\n- Problema: La función de lista de reproducción no está funcionando actualmente.\n- Acción: Serás redirigido a una página estándar en breve.\n\nEstoy buscando una solución.",
                ],
            },

            fr: {
                0: [
                    "Oups ! Un problème est survenu.\n\n- Problème : La fonction de playlist ne fonctionne pas actuellement.\n- Action : Vous serez redirigé vers une page standard sous peu.\n\nJe cherche une solution.",
                ],
            },

            it: {
                0: [
                    "Ops! Qualcosa è andato storto.\n\n- Problema: La funzione playlist non sta funzionando al momento.\n- Azione: Sarai reindirizzato a una pagina standard a breve.\n\nSto cercando una soluzione.",
                ],
            },

            jp: {
                0: [
                    "おっと!何かが間違っていました。\n\n- 問題:プレイリスト機能は現在動作していません。\n- 処置:間もなく標準ページにリダイレクトされます。\n\n修正を探しています。",
                ],
            },

            ko: {
                0: [
                    "이런! 문제가 발생했습니다.\n\n- 문제: 플레이리스트 기능이 현재 작동하지 않습니다.\n- 조치: 곧 표준 페이지로 리디렉션됩니다.\n\n해결책을 찾고 있습니다.",
                ],
            },

            nl: {
                0: [
                    "Oeps! Er is iets misgegaan.\n\n- Probleem: De afspeellijstfunctie werkt momenteel niet.\n- Actie: Je wordt binnenkort omgeleid naar een standaardpagina.\n\nIk ben op zoek naar een oplossing.",
                ],
            },

            pl: {
                0: [
                    "Ups! Coś poszło nie tak.\n\n- Problem: Funkcja listy odtwarzania obecnie nie działa.\n- Działanie: Wkrótce zostaniesz przekierowany na standardową stronę.\n\nSzukam rozwiązania.",
                ],
            },

            pt: {
                0: [
                    "Ops! Algo deu errado.\n\n- Problema: A função de playlist atualmente não está funcionando.\n- Ação: Você será redirecionado para uma página padrão em breve.\n\nEstou procurando uma solução.",
                ],
            },

            ru: {
                0: [
                    "Ой! Что-то пошло не так.\n\n- Проблема: В настоящее время функция плейлиста не работает.\n- Действие: Скоро вы будете перенаправлены на стандартную страницу.\n\nЯ ищу решение.",
                ],
            },

            ar: {
                0: [
                    "عفوًا! هناك خطأ ما.\n\n- المشكلة: ميزة قائمة التشغيل لا تعمل حاليًا.\n- الإجراء: ستتم إعادتك إلى صفحة قياسية قريبًا.\n\nأبحث عن حل.",
                ],
            },

            zh: {
                0: [
                    "哎呀!出了点问题。\n\n- 问题:播放列表功能目前无法使用。\n- 操作:您将很快被重定向到标准页面。\n\n我正在寻找解决方案。",
                ],
            },

            hi: {
                0: [
                    "उफ! कुछ गलत हो गया।\n\n- समस्या: प्लेलिस्ट सुविधा वर्तमान में काम नहीं कर रही है।\n- कार्रवाई: आपको जल्द ही एक मानक पृष्ठ पर अनुप्रेषित किया जाएगा।\n\nमैं एक समाधान ढूँढ रहा हूँ।",
                ],
            },

            sv: {
                0: [
                    "Oops! Något gick fel.\n\n- Problem: Spellistefunktionen fungerar inte för närvarande.\n- Åtgärd: Du kommer att omdirigeras till en standard sida inom kort.\n\nJag letar efter en lösning.",
                ],
            },

            no: {
                0: [
                    "Oisann! Noe gikk galt.\n\n- Problem: Spillelistefunksjonen virker ikke for øyeblikket.\n- Handling: Du vil bli omdirigert til en standardside snart.\n\nJeg ser etter en løsning.",
                ],
            },

            da: {
                0: [
                    "Ups! Noget gik galt.\n\n- Problem: Afspilningsliste funktionen virker ikke i øjeblikket.\n- Handling: Du vil snart blive omdirigeret til en standard side.\n\nJeg leder efter en løsning.",
                ],
            },

            cs: {
                0: [
                    "Jejda! Něco se pokazilo.\n\n- Problém: Funkce playlistu momentálně nefunguje.\n- Akce: Brzy budete přesměrováni na standardní stránku.\n\nHledám řešení.",
                ],
            },

            hu: {
                0: [
                    "Hoppá! Valami hiba történt.\n\n- Probléma: A lejátszási lista funkció jelenleg nem működik.\n- Teendő: Hamarosan egy szabványos oldalra lesz átirányítva.\n\nMegoldást keresek.",
                ],
            },

            tr: {
                0: [
                    "Oops! Bir şeyler yanlış gitti.\n\n- Sorun: Oynatma listesi özelliği şu anda çalışmıyor.\n- Eylem: Yakında standart bir say",
                ],
            },
        };

        const languageTranslations = translations[language];
        alert(languageTranslations[alertT]);
    }

    // -------------- Custom HTML Start -------------- //

    // Custom CSS
    var css = `
    .btn-style {
        position: relative;
        display: inline-block;
        padding: 9px;
        height: 40px;
        color: white;
        background-color: transparent;
        box-shadow: none;
        text-shadow: none;
        border: 1px solid white;
        border-radius: 0px;
        z-index: 9999;
        opacity: 100%;
        transition: transform 0.3s ease;
        user-select: none;
    }
    .btn-style:hover {
        opacity: 80%;
    }
    .main-btn {
        margin-right: 16px;
        transition: transform 0.1s ease;
    }
    .main-btn:active {
        border: 1px solid transparent !important;
        transform: scale(0.9);
    }
    .dropdown-content {
        position: relative;
        background-color: black;
    }
    .custom-container {
        border: none;
        display: inline-block;
        margin-right: 16px;
        margin-left: 16px;
        transition: transform 0.3s ease;

    }
    `;

    var ranCustomContentOnce = false;
    function customContent() {
        // Create Container
        var customContainer = document.createElement("div");
        customContainer.classList.add("custom-container");
        /* Not Complete */
        // Create Button Theater Mode
        var theaterButton = document.createElement("button");
        theaterButton.textContent = getText("theaterMode", 0);
        theaterButton.classList.add("btn-style", "main-btn");
        /**/
        // Create Button Reload
        var reloadButton = document.createElement("button");
        reloadButton.textContent = getText("reloadFrame", 0);
        reloadButton.classList.add("btn-style", "main-btn");

        // Create Dropdown Menu
        var dropdownButton = document.createElement("select");
        dropdownButton.id = "dropdown";
        dropdownButton.classList.add("btn-style");
        const options = [
            { value: "0", text: getText("dropdown", 0) },
            { value: "1", text: getText("dropdown", 1) },
            { value: "2", text: getText("dropdown", 2) },
            { value: "3", text: getText("dropdown", 3) },
            //{ value: "4", text: "NSFW YouTube [Broken!]" } Fix later?
        ];
        var htmlContent = options
            .map(
                (option) =>
                    `<option class="dropdown-content" value="${option.value}">${option.text}</option>`
            )
            .join("");
        dropdownButton.innerHTML = htmlContent;

        // -------------- Custom HTML End -------------- //

        // ----- Appending custom content to page ----- //

        // Add items to Container

        if (!disableTheaterToggle) {
            customContainer.appendChild(theaterButton);
        }
        if (!disableReloadToggle) {
            customContainer.appendChild(reloadButton);
        }
        if (!disableOptionsMenu) {
            customContainer.appendChild(dropdownButton);
        }

        // Append CSS to page
        var style = document.createElement("style");
        style.appendChild(document.createTextNode(css));
        document.head.appendChild(style);

        // Find ID Location
        var exsistingParent = document.getElementById(customContentParentID);
        console.log("Found exsistingParent: " + exsistingParent);

        // Add Container to Page
        if (exsistingParent != null) {
            exsistingParent.insertBefore(
                customContainer,
                exsistingParent.firstChild
            );
            console.log("Added customContainer to page");
        } else {
            console.error("Error [customContent]: No exsistingParent found");
        }

        theaterButton.addEventListener("click", toggleTheaterStingyWorkaround);
        reloadButton.addEventListener("click", reloadFrame);

        ranCustomContentOnce = true;
    }

    try {
        if (!ranCustomContentOnce) {
            customContent();
            console.log("Loaded [customContent]");
        } else {
            console.log(
                "Tried to load, but was allready loaded [customContent]"
            );
        }
    } catch (error) {
        console.error("Error [customContent]: " + error);
    }

    // -------------- Active Listeners -------------- //

    // Run every second to check for updates on page (Will not ping any server till a new page is clicked)
    try {
        window.setInterval(checkClass, 1000);
    } catch (error) {
        console.error("Error Running [window.setInterval]: " + error);
    }
    try {
        document.addEventListener("click", checkClass, 1000);
    } catch (error) {
        console.error("Error Running [document.addEventListener]: " + error);
    }

    // ------------- Passive Listeners ------------- //

    // Fullscreen Toggle
    function toggleTheaterStingyWorkaround() {
        const event = new KeyboardEvent("keydown", {
            key: "t",
            keyCode: 84,
        });
        document.dispatchEvent(event);
        location.reload();
    }
})();