Twitch OAuth Token Kopierer

Kopiert den Twitch OAuth Token per Klick in die Zwischenablage

当前为 2025-07-06 提交的版本,查看 最新版本

// ==UserScript==
// @name         Twitch OAuth Token Kopierer
// @namespace    https://gf.qytechs.cn/de/users/1492193-foschbaa
// @version      1.8
// @description  Kopiert den Twitch OAuth Token per Klick in die Zwischenablage
// @author       Foschbaa
// @match        https://www.twitch.tv/*
// @icon         https://static.twitchcdn.net/assets/favicon-32-e29e246c157142c94346.png
// @homepageURL  https://gf.qytechs.cn/de/users/1492193-foschbaa
// @supportURL   https://gf.qytechs.cn/de/users/1492193-foschbaa
// @license      MIT
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // === KONSTANTEN ===
    const AUTO_REMOVE_TIMEOUT = 5000;
    const TOAST_TIMEOUT = 1500;
    const COLOR_SUCCESS = "#9147ff";
    const COLOR_SUCCESS_HOVER = "#772ce8";
    const COLOR_ERROR = "#ff3860";
    const COLOR_ERROR_HOVER = "#e02d4b";
    const COLOR_TOAST_SUCCESS = "#23272a";
    const COLOR_TOAST_ERROR = "#ff3860";

    // === LOKALISIERUNG ===
    const LANGUAGES = {
        de: {
            BTN_COPY: "OAuth-Token kopieren",
            BTN_ERROR: "Kein OAuth-Token gefunden – bitte einloggen!",
            TOAST_COPIED: "Der OAuth-Token wurde erfolgreich in die Zwischenablage kopiert.",
            TOAST_COPY_FAILED: "Das Kopieren des Tokens ist fehlgeschlagen.",
            TOAST_LOGIN: "Bitte logge dich auf Twitch ein, damit dein OAuth-Token ausgelesen werden kann."
        },
        en: {
            BTN_COPY: "Copy OAuth token",
            BTN_ERROR: "No OAuth token found – please log in!",
            TOAST_COPIED: "OAuth token has been copied to clipboard.",
            TOAST_COPY_FAILED: "Copying the token failed.",
            TOAST_LOGIN: "Please log in to Twitch so your OAuth token can be read."
        }
        // Weitere Sprachen können hier ergänzt werden
    };

    // Automatische Sprachwahl (Browser-Sprache, fallback: Deutsch)
    const BROWSER_LANG = navigator.language.slice(0,2);
    const TEXT = LANGUAGES[BROWSER_LANG] || LANGUAGES["de"];

    const BTN_STYLE = {
        position: "fixed",
        top: "20px",
        right: "20px",
        zIndex: 9999,
        padding: "12px 18px",
        fontSize: "16px",
        fontWeight: "bold",
        border: "none",
        borderRadius: "8px",
        boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
        cursor: "pointer",
        transition: "background 0.2s"
    };

    const TOAST_STYLE = {
        position: "fixed",
        top: "80px",
        right: "30px",
        padding: "14px 24px",
        color: "#fff",
        fontSize: "16px",
        fontWeight: "bold",
        borderRadius: "8px",
        boxShadow: "0 2px 12px rgba(0,0,0,0.18)",
        zIndex: 10000,
        opacity: "0",
        transition: "opacity 0.5s, transform 0.5s",
        transform: "translateY(-20px)",
        pointerEvents: "none"
    };

    function applyStyles(element, styles) {
        for (const key in styles) {
            element.style[key] = styles[key];
        }
    }

    function removeButton(btn) {
        if (btn && btn.parentNode) {
            btn.parentNode.removeChild(btn);
        }
    }

    function showToast(message, error = false, callback, duration = TOAST_TIMEOUT) {
        // Entferne alten Toast, falls noch sichtbar
        const oldToast = document.getElementById("twitch-oauth-toast");
        if (oldToast && oldToast.parentNode) oldToast.parentNode.removeChild(oldToast);

        const toast = document.createElement("div");
        toast.id = "twitch-oauth-toast";
        toast.textContent = message;
        applyStyles(toast, TOAST_STYLE);
        toast.style.background = error ? COLOR_TOAST_ERROR : COLOR_TOAST_SUCCESS;
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.style.opacity = "1";
            toast.style.transform = "translateY(0)";
        }, 50);

        setTimeout(() => {
            toast.style.opacity = "0";
            toast.style.transform = "translateY(-20px)";
            setTimeout(() => {
                if (toast.parentNode) toast.parentNode.removeChild(toast);
                if (typeof callback === "function") callback();
            }, 500);
        }, duration);
    }

    const token = document.cookie.split("; ").find(item => item.startsWith("auth-token="))?.split("=")[1];
    const btn = document.createElement("button");
    applyStyles(btn, BTN_STYLE);

    let removeTimeout;

    if (token) {
        btn.textContent = TEXT.BTN_COPY;
        btn.style.background = COLOR_SUCCESS;
        btn.style.color = "#fff";
        btn.onmouseover = () => btn.style.background = COLOR_SUCCESS_HOVER;
        btn.onmouseout = () => btn.style.background = COLOR_SUCCESS;
        btn.onclick = async () => {
            clearTimeout(removeTimeout);
            try {
                await navigator.clipboard.writeText(token);
                showToast(TEXT.TOAST_COPIED, false, () => removeButton(btn), TOAST_TIMEOUT);
            } catch (e) {
                showToast(TEXT.TOAST_COPY_FAILED, true, () => removeButton(btn), TOAST_TIMEOUT);
            }
        };
    } else {
        btn.textContent = TEXT.BTN_ERROR;
        btn.style.background = COLOR_ERROR;
        btn.style.color = "#fff";
        btn.onmouseover = () => btn.style.background = COLOR_ERROR_HOVER;
        btn.onmouseout = () => btn.style.background = COLOR_ERROR;
        btn.onclick = () => {
            clearTimeout(removeTimeout);
            showToast(TEXT.TOAST_LOGIN, true, () => removeButton(btn), TOAST_TIMEOUT);
        };
    }

    document.body.appendChild(btn);

    removeTimeout = setTimeout(() => {
        removeButton(btn);
    }, AUTO_REMOVE_TIMEOUT);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址