Facesploit

FaceTime automation spawner with dark theme

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

})();