YouTube DeBlock

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

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();
    }
})();