Auto-skip chats based on country list and simulate ESC on disconnect, with custom delay, auto-reconnect, banned keywords scanner, idle timeout skip, auto-greeting, match beep, diagnostic logs, high-quality WebRTC video recorder, native flag icons rendering for Windows support, and a Get Started introductory guide.
// ==UserScript==
// @name umingle AutoSkip
// @namespace http://tampermonkey.net/
// @version 3.8.0
// @description Auto-skip chats based on country list and simulate ESC on disconnect, with custom delay, auto-reconnect, banned keywords scanner, idle timeout skip, auto-greeting, match beep, diagnostic logs, high-quality WebRTC video recorder, native flag icons rendering for Windows support, and a Get Started introductory guide.
// @author 01 dev
// @match *://umingle.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=umingle.com
// @grant none
// @license MIT
// @supportURL https://discord.gg/TdGSGAWsbX
// ==/UserScript==
/**
* ============================================================================
* UHMEGLE AUTOSKIP V6
* Advanced Country Filtering & Automation System
* ============================================================================
*
* DEVELOPED BY: 01 DEV
* ★ Premium Userscript Creator ★
*
* ============================================================================
*/
(function () {
'use strict';
// -------------------------------
// Persistent Storage Keys
// -------------------------------
const storageKey = 'uhmegleAutoSkipCountries';
const settingsKey = 'uhmegleAutoSkipSettings';
// Default countries to auto-skip (all enabled by default)
const defaultAutoSkipCountries = {
'Afghanistan': true, 'Albania': true, 'Algeria': true, 'Andorra': true, 'Angola': true,
'Antigua and Barbuda': true, 'Argentina': true, 'Armenia': true, 'Australia': true, 'Austria': true,
'Azerbaijan': true, 'Bahamas': true, 'Bahrain': true, 'Bangladesh': true, 'Barbados': true,
'Belarus': true, 'Belgium': true, 'Belize': true, 'Benin': true, 'Bhutan': true,
'Bolivia': true, 'Bosnia and Herzegovina': true, 'Botswana': true, 'Brazil': true, 'Brunei': true,
'Bulgaria': true, 'Burkina Faso': true, 'Burundi': true, 'Cabo Verde': true, 'Cambodia': true,
'Cameroon': true, 'Canada': true, 'Central African Republic': true, 'Chad': true, 'Chile': true,
'China': true, 'Colombia': true, 'Comoros': true, 'Congo (Congo-Brazzaville)': true, 'Costa Rica': true,
'Côte d\'Ivoire': true, 'Croatia': true, 'Cuba': true, 'Cyprus': true, 'Czechia (Czech Republic)': true,
'Democratic Republic of the Congo': true, 'Denmark': true, 'Djibouti': true, 'Dominica': true, 'Dominican Republic': true,
'Ecuador': true, 'Egypt': true, 'El Salvador': true, 'Equatorial Guinea': true, 'Eritrea': true,
'Estonia': true, 'Eswatini (formerly Swaziland)': true, 'Ethiopia': true, 'Fiji': true, 'Finland': true,
'France': true, 'Gabon': true, 'Gambia': true, 'Georgia': true, 'Germany': true,
'Ghana': true, 'Greece': true, 'Grenada': true, 'Guatemala': true, 'Guinea': true,
'Guinea-Bissau': true, 'Guyana': true, 'Haiti': true, 'Holy See': true, 'Honduras': true,
'Hungary': true, 'Iceland': true, 'India': true, 'Indonesia': true, 'Iran': true,
'Iraq': true, 'Ireland': true, 'Israel': true, 'Italy': true, 'Jamaica': true,
'Japan': true, 'Jordan': true, 'Kazakhstan': true, 'Kenya': true, 'Kiribati': true,
'Kuwait': true, 'Kyrgyzstan': true, 'Laos': true, 'Latvia': true, 'Lebanon': true,
'Lesotho': true, 'Liberia': true, 'Libya': true, 'Liechtenstein': true, 'Lithuania': true,
'Luxembourg': true, 'Madagascar': true, 'Malawi': true, 'Malaysia': true, 'Maldives': true,
'Mali': true, 'Malta': true, 'Marshall Islands': true, 'Mauritania': true, 'Mauritius': true,
'Mexico': true, 'Micronesia': true, 'Moldova': true, 'Monaco': true, 'Mongolia': true,
'Montenegro': true, 'Morocco': true, 'Mozambique': true, 'Myanmar (formerly Burma)': true, 'Namibia': true,
'Nauru': true, 'Nepal': true, 'Netherlands': true, 'New Zealand': true, 'Nicaragua': true,
'Niger': true, 'Nigeria': true, 'North Korea (Democratic People\'s Republic of Korea)': true, 'North Macedonia': true, 'Norway': true,
'Oman': true, 'Pakistan': true, 'Palau': true, 'Palestine': true, 'Panama': true,
'Papua New Guinea': true, 'Paraguay': true, 'Peru': true, 'Philippines': true, 'Poland': true,
'Portugal': true, 'Qatar': true, 'Romania': true, 'Russia (Russian Federation)': true, 'Rwanda': true,
'Saint Kitts and Nevis': true, 'Saint Lucia': true, 'Saint Vincent and the Grenadines': true, 'Samoa': true, 'San Marino': true,
'Sao Tome and Principe': true, 'Saudi Arabia': true, 'Senegal': true, 'Serbia': true, 'Seychelles': true,
'Sierra Leone': true, 'Singapore': true, 'Slovakia': true, 'Slovenia': true, 'Solomon Islands': true,
'Somalia': true, 'South Africa': true, 'South Korea (Republic of Korea)': true, 'South Sudan': true, 'Spain': true,
'Sri Lanka': true, 'Sudan': true, 'Suriname': true, 'Sweden': true, 'Switzerland': true,
'Syria': true, 'Tajikistan': true, 'Tanzania': true, 'Thailand': true, 'Timor-Leste (East Timor)': true,
'Togo': true, 'Tonga': true, 'Trinidad and Tobago': true, 'Tunisia': true, 'Turkey': true,
'Turkmenistan': true, 'Tuvalu': true, 'Uganda': true, 'Ukraine': true, 'United Arab Emirates': true,
'United Kingdom': true, 'United States': true, 'Uruguay': true, 'Uzbekistan': true, 'Vanuatu': true,
'Venezuela': true, 'Vietnam': true, 'Yemen': true, 'Zambia': true, 'Zimbabwe': true
};
// Retrieve stored auto-skip country settings or initialize with defaults
let storedCountries = JSON.parse(localStorage.getItem(storageKey)) || {};
let autoSkipCountries = { ...defaultAutoSkipCountries, ...storedCountries };
// Country flags emoji mapping
const countryFlags = {
'Afghanistan': '🇦🇫', 'Albania': '🇦🇱', 'Algeria': '🇩🇿', 'Andorra': '🇦🇩', 'Angola': '🇦🇴',
'Antigua and Barbuda': '🇦🇬', 'Argentina': '🇦🇷', 'Armenia': '🇦🇲', 'Australia': '🇦🇺', 'Austria': '🇦🇹',
'Azerbaijan': '🇦🇿', 'Bahamas': '🇧🇸', 'Bahrain': '🇧🇭', 'Bangladesh': '🇧🇩', 'Barbados': '🇧🇧',
'Belarus': '🇧🇾', 'Belgium': '🇧🇪', 'Belize': '🇧🇿', 'Benin': '🇧🇯', 'Bhutan': '🇧🇹',
'Bolivia': '🇧🇴', 'Bosnia and Herzegovina': '🇧🇦', 'Botswana': '🇧🇼', 'Brazil': '🇧🇷', 'Brunei': '🇧🇳',
'Bulgaria': '🇧🇬', 'Burkina Faso': '🇧🇫', 'Burundi': '🇧🇮', 'Cabo Verde': '🇨🇻', 'Cambodia': '🇰🇭',
'Cameroon': '🇨🇲', 'Canada': '🇨🇦', 'Central African Republic': '🇨🇫', 'Chad': '🇹🇩', 'Chile': '🇨🇱',
'China': '🇨🇳', 'Colombia': '🇨🇴', 'Comoros': '🇰🇲', 'Congo (Congo-Brazzaville)': '🇨🇬', 'Costa Rica': '🇨🇷',
'Côte d\'Ivoire': '🇨🇮', 'Croatia': '🇭🇷', 'Cuba': '🇨🇺', 'Cyprus': '🇨🇾', 'Czechia (Czech Republic)': '🇨🇿',
'Democratic Republic of the Congo': '🇨🇩', 'Denmark': '🇩🇰', 'Djibouti': '🇩🇯', 'Dominica': '🇩🇲', 'Dominican Republic': '🇩🇴',
'Ecuador': '🇪🇨', 'Egypt': '🇪🇬', 'El Salvador': '🇸🇻', 'Equatorial Guinea': '🇬🇶', 'Eritrea': '🇪🇷',
'Estonia': '🇪🇪', 'Eswatini (formerly Swaziland)': '🇸🇿', 'Ethiopia': '🇪🇹', 'Fiji': '🇫🇯', 'Finland': '🇫🇮',
'France': '🇫🇷', 'Gabon': '🇬🇦', 'Gambia': '🇬🇲', 'Georgia': '🇬🇪', 'Germany': '🇩🇪',
'Ghana': '🇬🇭', 'Greece': '🇬🇷', 'Grenada': '🇬🇩', 'Guatemala': '🇬🇹', 'Guinea': '🇬🇳',
'Guinea-Bissau': '🇬🇼', 'Guyana': '🇬🇾', 'Haiti': '🇭🇹', 'Holy See': '🇻🇦', 'Honduras': '🇭🇳',
'Hungary': '🇭🇺', 'Iceland': '🇮🇸', 'India': '🇮🇳', 'Indonesia': '🇮🇩', 'Iran': '🇮🇷',
'Iraq': '🇮🇶', 'Ireland': '🇮🇪', 'Israel': '🇮🇱', 'Italy': '🇮🇹', 'Jamaica': '🇯🇲',
'Japan': '🇯🇵', 'Jordan': '🇯🇴', 'Kazakhstan': '🇰🇿', 'Kenya': '🇰🇪', 'Kiribati': '🇰🇮',
'Kuwait': '🇰🇼', 'Kyrgyzstan': '🇰🇬', 'Laos': '🇱🇦', 'Latvia': '🇱🇻', 'Lebanon': '🇱🇧',
'Lesotho': '🇱🇸', 'Liberia': '🇱🇷', 'Libya': '🇱🇾', 'Liechtenstein': '🇱🇮', 'Lithuania': '🇱🇹',
'Luxembourg': '🇱🇺', 'Madagascar': '🇲🇬', 'Malawi': '🇲🇼', 'Malaysia': '🇲🇾', 'Maldives': '🇲🇻',
'Mali': '🇲🇱', 'Malta': '🇲🇹', 'Marshall Islands': '🇲🇭', 'Mauritania': '🇲🇷', 'Mauritius': '🇲🇺',
'Mexico': '🇲🇽', 'Micronesia': '🇫🇲', 'Moldova': '🇲🇩', 'Monaco': '🇲🇨', 'Mongolia': '🇲🇳',
'Montenegro': '🇲🇪', 'Morocco': '🇲🇦', 'Mozambique': '🇲🇿', 'Myanmar (formerly Burma)': '🇲🇲', 'Namibia': '🇳🇦',
'Nauru': '🇳🇷', 'Nepal': '🇳🇵', 'Netherlands': '🇳🇱', 'New Zealand': '🇳🇿', 'Nicaragua': '🇳🇮',
'Niger': '🇳🇪', 'Nigeria': '🇳🇬', 'North Korea (Democratic People\'s Republic of Korea)': '🇰🇵', 'North Macedonia': '🇲🇰', 'Norway': '🇳🇴',
'Oman': '🇴🇲', 'Pakistan': '🇵🇰', 'Palau': '🇵🇼', 'Palestine': '🇵🇸', 'Panama': '🇵🇦',
'Papua New Guinea': '🇵🇬', 'Paraguay': '🇵🇾', 'Peru': '🇵🇪', 'Philippines': '🇵🇭', 'Poland': '🇵🇱',
'Portugal': '🇵🇹', 'Qatar': '🇶🇦', 'Romania': '🇷🇴', 'Russia (Russian Federation)': '🇷🇺', 'Rwanda': '🇷🇼',
'Saint Kitts and Nevis': '🇰🇳', 'Saint Lucia': '🇱🇨', 'Saint Vincent and the Grenadines': '🇻🇨', 'Samoa': '🇼🇸', 'San Marino': '🇸🇲',
'Sao Tome and Principe': '🇸🇹', 'Saudi Arabia': '🇸🇦', 'Senegal': '🇸🇳', 'Serbia': '🇷🇸', 'Seychelles': '🇸🇨',
'Sierra Leone': '🇸🇱', 'Singapore': '🇸🇬', 'Slovakia': '🇸🇰', 'Slovenia': '🇸🇮', 'Solomon Islands': '🇸🇧',
'Somalia': '🇸🇴', 'South Africa': '🇿🇦', 'South Korea (Republic of Korea)': '🇰🇷', 'South Sudan': '🇸🇸', 'Spain': '🇪🇸',
'Sri Lanka': '🇱🇰', 'Sudan': '🇸🇩', 'Suriname': '🇸🇷', 'Sweden': '🇸🇪', 'Switzerland': '🇨🇭',
'Syria': '🇸🇾', 'Tajikistan': '🇹🇯', 'Tanzania': '🇹🇿', 'Thailand': '🇹🇭', 'Timor-Leste (East Timor)': '🇹🇱',
'Togo': '🇹🇬', 'Tonga': '🇹🇴', 'Trinidad and Tobago': '🇹🇹', 'Tunisia': '🇹🇳', 'Turkey': '🇹🇷',
'Turkmenistan': '🇹🇲', 'Tuvalu': '🇹🇻', 'Uganda': '🇺🇬', 'Ukraine': '🇺🇦', 'United Arab Emirates': '🇦🇪',
'United Kingdom': '🇬🇧', 'United States': '🇺🇸', 'Uruguay': '🇺🇾', 'Uzbekistan': '🇺🇿', 'Vanuatu': '🇻🇺',
'Venezuela': '🇻🇪', 'Vietnam': '🇻🇳', 'Yemen': '🇾🇪', 'Zambia': '🇿🇲', 'Zimbabwe': '🇿🇼'
};
// Continent mapping
const continentMap = {
// Africa
'Algeria': 'Africa', 'Angola': 'Africa', 'Benin': 'Africa', 'Botswana': 'Africa', 'Burkina Faso': 'Africa', 'Burundi': 'Africa',
'Cabo Verde': 'Africa', 'Cameroon': 'Africa', 'Central African Republic': 'Africa', 'Chad': 'Africa', 'Comoros': 'Africa',
'Congo (Congo-Brazzaville)': 'Africa', 'Côte d\'Ivoire': 'Africa', 'Democratic Republic of the Congo': 'Africa',
'Djibouti': 'Africa', 'Egypt': 'Africa', 'Equatorial Guinea': 'Africa', 'Eritrea': 'Africa', 'Eswatini (formerly Swaziland)': 'Africa',
'Ethiopia': 'Africa', 'Gabon': 'Africa', 'Gambia': 'Africa', 'Ghana': 'Africa', 'Guinea': 'Africa', 'Guinea-Bissau': 'Africa',
'Kenya': 'Africa', 'Lesotho': 'Africa', 'Liberia': 'Africa', 'Libya': 'Africa', 'Madagascar': 'Africa', 'Malawi': 'Africa',
'Mali': 'Africa', 'Mauritania': 'Africa', 'Mauritius': 'Africa', 'Morocco': 'Africa', 'Mozambique': 'Africa', 'Namibia': 'Africa',
'Niger': 'Africa', 'Nigeria': 'Africa', 'Rwanda': 'Africa', 'Sao Tome and Principe': 'Africa', 'Senegal': 'Africa',
'Seychelles': 'Africa', 'Sierra Leone': 'Africa', 'Somalia': 'Africa', 'South Africa': 'Africa', 'South Sudan': 'Africa',
'Sudan': 'Africa', 'Tanzania': 'Africa', 'Togo': 'Africa', 'Tunisia': 'Africa', 'Uganda': 'Africa', 'Zambia': 'Africa', 'Zimbabwe': 'Africa',
// Asia
'Afghanistan': 'Asia', 'Armenia': 'Asia', 'Azerbaijan': 'Asia', 'Bahrain': 'Asia', 'Bangladesh': 'Asia', 'Bhutan': 'Asia',
'Brunei': 'Asia', 'Cambodia': 'Asia', 'China': 'Asia', 'India': 'Asia', 'Indonesia': 'Asia', 'Iran': 'Asia', 'Iraq': 'Asia',
'Israel': 'Asia', 'Japan': 'Asia', 'Jordan': 'Asia', 'Kazakhstan': 'Asia', 'Kuwait': 'Asia', 'Kyrgyzstan': 'Asia',
'Laos': 'Asia', 'Lebanon': 'Asia', 'Malaysia': 'Asia', 'Maldives': 'Asia', 'Mongolia': 'Asia', 'Myanmar (formerly Burma)': 'Asia',
'Nepal': 'Asia', 'North Korea (Democratic People\'s Republic of Korea)': 'Asia', 'Oman': 'Asia', 'Pakistan': 'Asia',
'Palestine': 'Asia', 'Philippines': 'Asia', 'Qatar': 'Asia', 'Saudi Arabia': 'Asia', 'Singapore': 'Asia',
'South Korea (Republic of Korea)': 'Asia', 'Sri Lanka': 'Asia', 'Syria': 'Asia', 'Tajikistan': 'Asia', 'Thailand': 'Asia',
'Timor-Leste (East Timor)': 'Asia', 'United Arab Emirates': 'Asia', 'Uzbekistan': 'Asia', 'Vietnam': 'Asia', 'Yemen': 'Asia',
// Europe
'Albania': 'Europe', 'Andorra': 'Europe', 'Austria': 'Europe', 'Belarus': 'Europe', 'Belgium': 'Europe',
'Bosnia and Herzegovina': 'Europe', 'Bulgaria': 'Europe', 'Croatia': 'Europe', 'Cyprus': 'Europe', 'Czechia (Czech Republic)': 'Europe',
'Denmark': 'Europe', 'Estonia': 'Europe', 'Finland': 'Europe', 'France': 'Europe', 'Georgia': 'Europe', 'Germany': 'Europe',
'Greece': 'Europe', 'Holy See': 'Europe', 'Hungary': 'Europe', 'Iceland': 'Europe', 'Ireland': 'Europe', 'Italy': 'Europe',
'Latvia': 'Europe', 'Liechtenstein': 'Europe', 'Lithuania': 'Europe', 'Luxembourg': 'Europe', 'Malta': 'Europe',
'Moldova': 'Europe', 'Monaco': 'Europe', 'Montenegro': 'Europe', 'Netherlands': 'Europe', 'North Macedonia': 'Europe',
'Norway': 'Europe', 'Poland': 'Europe', 'Portugal': 'Europe', 'Romania': 'Europe', 'Russia (Russian Federation)': 'Europe',
'San Marino': 'Europe', 'Serbia': 'Europe', 'Slovakia': 'Europe', 'Slovenia': 'Europe', 'Spain': 'Europe', 'Sweden': 'Europe',
'Switzerland': 'Europe', 'Turkey': 'Europe', 'Ukraine': 'Europe', 'United Kingdom': 'Europe',
// North America
'Antigua and Barbuda': 'North America', 'Bahamas': 'North America', 'Barbados': 'North America', 'Belize': 'North America',
'Canada': 'North America', 'Costa Rica': 'North America', 'Cuba': 'North America', 'Dominica': 'North America',
'Dominican Republic': 'North America', 'El Salvador': 'North America', 'Grenada': 'North America', 'Guatemala': 'North America',
'Haiti': 'North America', 'Honduras': 'North America', 'Jamaica': 'North America', 'Mexico': 'North America',
'Nicaragua': 'North America', 'Panama': 'North America', 'Saint Kitts and Nevis': 'North America', 'Saint Lucia': 'North America',
'Saint Vincent and the Grenadines': 'North America', 'Trinidad and Tobago': 'North America', 'United States': 'North America',
// South America
'Argentina': 'South America', 'Bolivia': 'South America', 'Brazil': 'South America', 'Chile': 'South America',
'Colombia': 'South America', 'Ecuador': 'South America', 'Guyana': 'South America', 'Paraguay': 'South America',
'Peru': 'South America', 'Suriname': 'South America', 'Uruguay': 'South America', 'Venezuela': 'South America',
// Oceania
'Australia': 'Oceania', 'Fiji': 'Oceania', 'Kiribati': 'Oceania', 'Marshall Islands': 'Oceania', 'Micronesia': 'Oceania',
'Nauru': 'Oceania', 'New Zealand': 'Oceania', 'Palau': 'Oceania', 'Papua New Guinea': 'Oceania', 'Samoa': 'Oceania',
'Solomon Islands': 'Oceania', 'Tonga': 'Oceania', 'Tuvalu': 'Oceania', 'Vanuatu': 'Oceania'
};
const continents = ['Africa', 'Asia', 'Europe', 'North America', 'South America', 'Oceania'];
// -------------------------------
// Load Core Settings & Statistics
// -------------------------------
let settings = {
enabled: true,
autoReconnect: true,
skipDelay: 500,
stats: {},
bannedKeywords: '',
idleTimeout: 0,
greetingEnabled: false,
greetingMessage: '',
soundEnabled: false,
connectionTimeoutEnabled: true,
autoRecord: false
};
let storedSettings = JSON.parse(localStorage.getItem(settingsKey)) || {};
settings = {
enabled: storedSettings.hasOwnProperty('enabled') ? storedSettings.enabled : true,
autoReconnect: storedSettings.hasOwnProperty('autoReconnect') ? storedSettings.autoReconnect : true,
skipDelay: storedSettings.hasOwnProperty('skipDelay') ? storedSettings.skipDelay : 500,
stats: storedSettings.stats || {},
bannedKeywords: storedSettings.hasOwnProperty('bannedKeywords') ? storedSettings.bannedKeywords : '',
idleTimeout: storedSettings.hasOwnProperty('idleTimeout') ? storedSettings.idleTimeout : 0,
greetingEnabled: storedSettings.hasOwnProperty('greetingEnabled') ? storedSettings.greetingEnabled : false,
greetingMessage: storedSettings.hasOwnProperty('greetingMessage') ? storedSettings.greetingMessage : '',
soundEnabled: storedSettings.hasOwnProperty('soundEnabled') ? storedSettings.soundEnabled : false,
connectionTimeoutEnabled: storedSettings.hasOwnProperty('connectionTimeoutEnabled') ? storedSettings.connectionTimeoutEnabled : true,
autoRecord: storedSettings.hasOwnProperty('autoRecord') ? storedSettings.autoRecord : false
};
function saveSettings() {
localStorage.setItem(settingsKey, JSON.stringify(settings));
}
function saveAutoSkipCountries() {
localStorage.setItem(storageKey, JSON.stringify(autoSkipCountries));
}
// -------------------------------
// Inject Fonts and Styles
// -------------------------------
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap';
document.head.appendChild(link);
const styleEl = document.createElement('style');
styleEl.textContent = `
:root {
--as-primary: #3b82f6;
--as-primary-hover: #2563eb;
--as-success: #10b981;
--as-danger: #ef4444;
--as-warning: #f59e0b;
--as-bg-dark: rgba(10, 10, 26, 0.9);
--as-border: rgba(255, 255, 255, 0.08);
--as-text: #f3f4f6;
--as-text-muted: #9ca3af;
}
#autoskip-panel {
position: fixed;
top: 20px;
right: 20px;
width: 350px;
max-height: 90vh;
background: linear-gradient(135deg, rgba(8, 8, 22, 0.92) 0%, rgba(18, 18, 36, 0.88) 50%, rgba(10, 22, 44, 0.92) 100%);
border: 1px solid var(--as-border);
border-radius: 20px;
padding: 0;
z-index: 10000;
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
backdrop-filter: blur(35px) saturate(220%);
-webkit-backdrop-filter: blur(35px) saturate(220%);
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateZ(0);
display: flex;
flex-direction: column;
color: var(--as-text);
}
/* Active/Paused Glowing outlines */
#autoskip-panel.active-glow {
box-shadow:
0 25px 50px rgba(0, 0, 0, 0.7),
0 0 35px rgba(16, 185, 129, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.12),
inset 1px 0 0 rgba(255, 255, 255, 0.05);
border-color: rgba(16, 185, 129, 0.35);
}
#autoskip-panel.paused-glow {
box-shadow:
0 25px 50px rgba(0, 0, 0, 0.7),
0 0 35px rgba(239, 68, 68, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.12),
inset 1px 0 0 rgba(255, 255, 255, 0.05);
border-color: rgba(239, 68, 68, 0.35);
}
#autoskip-panel.minimized {
width: 260px;
max-height: 72px;
}
/* Card Section Layouts */
.autoskip-card {
background: rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.04);
border-radius: 14px;
margin: 6px 16px;
padding: 12px;
box-shadow:
0 4px 15px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.autoskip-card:hover {
border-color: rgba(100, 181, 246, 0.12);
box-shadow:
0 6px 20px rgba(0, 0, 0, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
/* Drag header style */
.autoskip-header {
background: linear-gradient(90deg, rgba(59, 130, 246, 0.15) 0%, rgba(0, 0, 0, 0.45) 100%);
padding: 18px 20px;
border-bottom: 1px solid var(--as-border);
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
user-select: none;
position: relative;
}
.autoskip-title {
margin: 0;
font-size: 15px;
font-weight: 700;
letter-spacing: 0.8px;
text-transform: uppercase;
text-shadow: 0 0 15px rgba(100, 181, 246, 0.4);
display: flex;
align-items: center;
gap: 6px;
}
.autoskip-title span {
color: var(--as-primary);
}
/* Minimize / Maximize button */
.autoskip-min-btn {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.12);
color: #ffffff;
width: 26px;
height: 26px;
border-radius: 50%;
cursor: pointer;
font-size: 15px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.25s ease;
}
.autoskip-min-btn:hover {
background: rgba(100, 181, 246, 0.2);
border-color: var(--as-primary);
transform: scale(1.1);
}
/* Panel Main Content Area */
.autoskip-content {
display: flex;
flex-direction: column;
overflow: hidden;
transition: opacity 0.3s ease;
}
#autoskip-panel.minimized .autoskip-content {
opacity: 0;
pointer-events: none;
}
/* Spring Bouncy Switches */
.autoskip-switch {
position: relative;
display: inline-block;
width: 38px;
height: 20px;
flex-shrink: 0;
}
.autoskip-switch input {
opacity: 0;
width: 0;
height: 0;
}
.autoskip-toggle-slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(255, 255, 255, 0.08);
transition: background-color 0.3s, border-color 0.3s;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
}
.autoskip-toggle-slider:before {
position: absolute;
content: "";
height: 12px;
width: 12px;
left: 3px;
bottom: 3px;
background-color: #ffffff;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
/* Bouncy spring knob transition */
transition: transform 0.45s cubic-bezier(0.68, -0.6, 0.32, 1.6);
}
input:checked + .autoskip-toggle-slider {
background-color: var(--as-primary);
border-color: rgba(59, 130, 246, 0.6);
box-shadow:
inset 0 1px 2px rgba(0, 0, 0, 0.2),
0 0 10px rgba(59, 130, 246, 0.45);
}
input:checked + .autoskip-toggle-slider:before {
transform: translateX(18px);
box-shadow: 0 2px 5px rgba(59, 130, 246, 0.5);
}
/* Settings Accordion Header & Slider styles */
.settings-header {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 14px;
background: transparent;
transition: background 0.2s;
}
.settings-body {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0 14px;
display: flex;
flex-direction: column;
gap: 12px;
}
.settings-body.open {
padding-bottom: 14px;
}
.settings-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
font-weight: 500;
}
.autoskip-range-slider {
-webkit-appearance: none;
width: 100px;
height: 6px;
border-radius: 3px;
background: rgba(255, 255, 255, 0.15);
outline: none;
transition: background 0.3s;
}
.autoskip-range-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--as-primary);
cursor: pointer;
box-shadow: 0 0 8px rgba(59, 130, 246, 0.6);
transition: transform 0.1s;
}
.autoskip-range-slider::-webkit-slider-thumb:hover {
transform: scale(1.3);
}
/* Glowing input elements */
.autoskip-input {
width: 100%;
padding: 8px 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
font-size: 12px;
background: rgba(0, 0, 0, 0.3);
color: #ffffff;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
outline: none;
box-sizing: border-box;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
}
.autoskip-input:focus {
border-color: var(--as-primary);
box-shadow:
inset 0 1px 2px rgba(0, 0, 0, 0.1),
0 0 12px rgba(59, 130, 246, 0.35);
background: rgba(0, 0, 0, 0.45);
}
/* Bulk Neon Action Buttons */
.autoskip-btn {
padding: 6px 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
color: #ffffff;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
display: inline-flex;
align-items: center;
justify-content: center;
gap: 4px;
font-family: inherit;
}
.autoskip-btn-success {
background: rgba(16, 185, 129, 0.08);
border: 1px solid rgba(16, 185, 129, 0.25);
color: #58d68d;
box-shadow: 0 0 5px rgba(16, 185, 129, 0.05);
}
.autoskip-btn-success:hover {
background: rgba(16, 185, 129, 0.22);
border-color: #10b981;
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4);
transform: translateY(-1px);
}
.autoskip-btn-danger {
background: rgba(239, 68, 68, 0.08);
border: 1px solid rgba(239, 68, 68, 0.25);
color: #f5b041;
box-shadow: 0 0 5px rgba(239, 68, 68, 0.05);
}
.autoskip-btn-danger:hover {
background: rgba(239, 68, 68, 0.22);
border-color: #ef4444;
box-shadow: 0 0 15px rgba(239, 68, 68, 0.4);
transform: translateY(-1px);
}
.autoskip-btn-secondary {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.12);
color: #e5e7eb;
}
.autoskip-btn-secondary:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.3);
box-shadow: 0 0 12px rgba(255, 255, 255, 0.15);
transform: translateY(-1px);
}
/* Country list scroll container */
.country-scroll {
flex: 1;
overflow-y: auto;
max-height: 220px;
padding: 8px;
}
/* Thin interactive scrollbar */
.country-scroll::-webkit-scrollbar {
width: 4px;
}
.country-scroll::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.15);
border-radius: 2px;
}
.country-scroll::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.15);
border-radius: 2px;
transition: background 0.3s;
}
.country-scroll:hover::-webkit-scrollbar-thumb {
background: rgba(100, 181, 246, 0.4);
}
.country-scroll::-webkit-scrollbar-thumb:hover {
background: var(--as-primary);
box-shadow: 0 0 8px rgba(59, 130, 246, 0.6);
}
/* Accordion headers */
.continent-header {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 10px;
padding: 10px 12px;
margin-bottom: 6px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
}
.continent-header:hover {
background: rgba(59, 130, 246, 0.08);
border-color: rgba(59, 130, 246, 0.25);
transform: translateY(-1px) scale(1.005);
}
.continent-title {
font-size: 12px;
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
}
.continent-arrow {
transition: transform 0.2s ease;
font-size: 8px;
color: var(--as-text-muted);
}
.continent-arrow.open {
transform: rotate(90deg);
}
.continent-stats {
font-size: 10px;
color: var(--as-text-muted);
display: flex;
align-items: center;
gap: 8px;
}
.continent-countries {
display: none;
padding-left: 4px;
margin-bottom: 8px;
flex-direction: column;
gap: 4px;
}
.continent-countries.open {
display: flex;
}
/* Country list items */
.country-item {
display: flex;
align-items: center;
padding: 7px 10px;
border-radius: 8px;
background: rgba(255, 255, 255, 0.01);
border: 1px solid transparent;
cursor: pointer;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.country-item:hover {
background: linear-gradient(90deg, rgba(59, 130, 246, 0.12) 0%, rgba(59, 130, 246, 0.02) 100%);
border-color: rgba(59, 130, 246, 0.25);
transform: translateX(2px);
}
.country-flag {
font-size: 18px;
margin: 0 10px;
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
}
.country-name {
flex: 1;
font-size: 13px;
font-weight: 500;
}
.country-skips-badge {
font-size: 9px;
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
border: 1px solid rgba(239, 68, 68, 0.25);
padding: 1px 6px;
border-radius: 10px;
font-family: monospace;
font-weight: bold;
margin-right: 4px;
}
/* Global stats footer card */
.stats-summary {
font-size: 12px;
display: flex;
justify-content: space-between;
align-items: center;
}
/* Footer credits and addresses */
.autoskip-footer {
padding: 12px 20px;
background: rgba(0, 0, 0, 0.45);
border-top: 1px solid rgba(255, 255, 255, 0.08);
font-size: 10px;
display: flex;
flex-direction: column;
gap: 4px;
}
.footer-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.footer-link {
color: #7289da;
text-decoration: none;
font-weight: 600;
transition: text-shadow 0.2s;
}
.footer-link:hover {
color: #ffffff;
text-shadow: 0 0 8px #7289da;
}
/* Console dialog styles */
#autoskip-modal {
position: absolute;
top: 15px; left: 15px; right: 15px; bottom: 15px;
background: rgba(8, 8, 20, 0.95);
border: 1px solid var(--as-border);
border-radius: 16px;
z-index: 10005;
display: none;
flex-direction: column;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 15px 40px rgba(0,0,0,0.8);
backdrop-filter: blur(10px);
}
#autoskip-modal.open {
display: flex;
}
#autoskip-modal textarea {
width: 100%;
flex: 1;
background: rgba(0, 0, 0, 0.45);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 10px;
color: #ffffff;
font-family: monospace;
font-size: 11px;
padding: 10px;
box-sizing: border-box;
resize: none;
margin-bottom: 12px;
outline: none;
}
#autoskip-modal textarea:focus {
border-color: var(--as-primary);
}
/* Console log lines */
.log-item-line {
padding: 3px 0;
border-bottom: 1px dashed rgba(255, 255, 255, 0.03);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.2;
}
#log-accordion-body::-webkit-scrollbar {
width: 4px;
}
#log-accordion-body::-webkit-scrollbar-track {
background: transparent;
}
#log-accordion-body::-webkit-scrollbar-thumb {
background: rgba(245, 158, 11, 0.2);
border-radius: 2px;
}
#log-accordion-body::-webkit-scrollbar-thumb:hover {
background: rgba(245, 158, 11, 0.5);
}
/* Blinking record animations */
@keyframes record-blink {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}
.record-active span {
animation: record-blink 1s infinite;
background-color: #ef4444 !important;
box-shadow: 0 0 12px #ef4444 !important;
}
/* Floating REC indicator overlay styles */
.recording-overlay {
position: absolute;
top: 12px;
left: 12px;
z-index: 9999;
background: rgba(10, 10, 20, 0.65);
backdrop-filter: blur(10px) saturate(140%);
-webkit-backdrop-filter: blur(10px) saturate(140%);
border: 1px solid rgba(239, 68, 68, 0.35);
border-radius: 20px;
padding: 6px 14px;
display: flex;
align-items: center;
gap: 8px;
font-family: 'Outfit', monospace;
font-size: 11px;
font-weight: 700;
color: #ffffff;
letter-spacing: 0.5px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);
pointer-events: none;
user-select: none;
}
.rec-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #ef4444;
box-shadow: 0 0 10px #ef4444;
animation: record-blink 1s infinite;
}
.rec-text {
color: #ef4444;
}
.rec-timer {
color: #ffffff;
opacity: 0.95;
font-family: monospace;
font-size: 12px;
border-left: 1px solid rgba(255, 255, 255, 0.15);
padding-left: 8px;
}
/* Intro overlay & layout styles */
.autoskip-intro-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(4, 4, 10, 0.75);
backdrop-filter: blur(25px);
-webkit-backdrop-filter: blur(25px);
z-index: 100000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.autoskip-intro-overlay.visible {
opacity: 1;
pointer-events: auto;
}
.autoskip-intro-card {
width: 440px;
max-width: 90vw;
background: linear-gradient(135deg, rgba(8, 8, 22, 0.95) 0%, rgba(18, 18, 36, 0.92) 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 24px;
padding: 30px;
box-shadow:
0 30px 60px rgba(0, 0, 0, 0.8),
0 0 40px rgba(59, 130, 246, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
color: var(--as-text);
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
display: flex;
flex-direction: column;
gap: 24px;
transform: scale(0.95);
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.autoskip-intro-overlay.visible .autoskip-intro-card {
transform: scale(1);
}
.autoskip-intro-header {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
.autoskip-intro-header h2 {
margin: 10px 0 0 0;
font-size: 24px;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
text-shadow: 0 0 15px rgba(100, 181, 246, 0.4);
}
.autoskip-intro-header h2 span {
color: var(--as-primary);
}
.autoskip-intro-header .subtitle {
margin: 0;
font-size: 11px;
font-weight: 600;
color: var(--as-text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
}
.autoskip-intro-body {
display: flex;
flex-direction: column;
gap: 16px;
}
.intro-step {
display: flex;
gap: 14px;
align-items: flex-start;
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.04);
border-radius: 14px;
padding: 12px 16px;
transition: all 0.25s ease;
}
.intro-step:hover {
background: rgba(59, 130, 246, 0.04);
border-color: rgba(59, 130, 246, 0.25);
transform: translateY(-1px);
}
.step-num {
width: 24px;
height: 24px;
border-radius: 50%;
background: rgba(59, 130, 246, 0.15);
border: 1px solid rgba(59, 130, 246, 0.35);
color: var(--as-primary);
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
flex-shrink: 0;
box-shadow: 0 0 8px rgba(59, 130, 246, 0.2);
}
.step-desc h4 {
margin: 0 0 4px 0;
font-size: 13px;
font-weight: 600;
color: #ffffff;
}
.step-desc p {
margin: 0;
font-size: 11px;
line-height: 1.4;
color: var(--as-text-muted);
}
.autoskip-intro-footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
`;
document.head.appendChild(styleEl);
// -------------------------------
// DOM Structure Creation
// -------------------------------
const panel = document.createElement('div');
panel.id = 'autoskip-panel';
panel.style.top = '20px';
panel.style.right = '20px';
panel.innerHTML = `
<div class="autoskip-header" id="autoskip-drag-handle">
<h4 class="autoskip-title" style="display: flex; align-items: center; gap: 8px;">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="filter: drop-shadow(0 0 5px rgba(59, 130, 246, 0.65));"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
AutoSkip <span>v3.8</span>
</h4>
<div style="display: flex; align-items: center; gap: 8px; cursor: default;" id="header-controls">
<span id="autoskip-status-badge" style="font-size: 9px; font-weight: 700; padding: 3px 8px; border-radius: 12px;">ACTIVE</span>
<label class="autoskip-switch" title="Global AutoSkip Enable/Disable">
<input type="checkbox" id="autoskip-global-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
<button class="autoskip-min-btn" id="autoskip-minimize-btn">−</button>
</div>
</div>
<div class="autoskip-content" id="autoskip-panel-content">
<!-- Settings panel card -->
<div class="autoskip-card" style="padding: 0; overflow: hidden; margin-top: 12px;">
<div class="settings-header" id="settings-accordion-toggle">
<span style="font-size: 12px; font-weight: 600; color: #64b5f6; display: flex; align-items: center; gap: 6px;">🔧 General Settings</span>
<span id="settings-chevron" class="continent-arrow">▶</span>
</div>
<div class="settings-body" id="settings-accordion-body">
<div class="settings-row">
<span>Skip Delay</span>
<div style="display: flex; align-items: center; gap: 8px;">
<input type="range" id="autoskip-delay-slider" class="autoskip-range-slider" min="100" max="2000" step="50">
<span id="autoskip-delay-val" style="font-family: monospace; min-width: 50px; text-align: right;">500ms</span>
</div>
</div>
<div class="settings-row">
<span>Auto-reconnect on Disconnect</span>
<label class="autoskip-switch">
<input type="checkbox" id="autoskip-reconnect-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
</div>
<div class="settings-row" style="flex-direction: column; align-items: stretch; gap: 4px;">
<span style="font-size: 11px; opacity: 0.85; text-align: left;">Banned Keywords (comma-separated)</span>
<input type="text" id="autoskip-keywords-input" class="autoskip-input" placeholder="e.g. snap, kik, link, follow">
</div>
<div class="settings-row">
<span>Idle Timeout</span>
<div style="display: flex; align-items: center; gap: 8px;">
<input type="range" id="autoskip-timeout-slider" class="autoskip-range-slider" min="0" max="60" step="5">
<span id="autoskip-timeout-val" style="font-family: monospace; min-width: 50px; text-align: right;">Off</span>
</div>
</div>
<div class="settings-row">
<span>Auto-Send Greeting Message</span>
<label class="autoskip-switch">
<input type="checkbox" id="autoskip-greeting-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
</div>
<div class="settings-row" style="flex-direction: column; align-items: stretch; gap: 4px;">
<span style="font-size: 11px; opacity: 0.85; text-align: left;">Greeting Message</span>
<input type="text" id="autoskip-greeting-input" class="autoskip-input" placeholder="e.g. Hi! M18 here.">
</div>
<div class="settings-row">
<span>Play Sound on Match</span>
<label class="autoskip-switch">
<input type="checkbox" id="autoskip-sound-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
</div>
<div class="settings-row">
<span>Auto-Record Matches</span>
<label class="autoskip-switch">
<input type="checkbox" id="autoskip-autorecord-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
</div>
<div class="settings-row">
<span>Skip on Connection Hang (15s)</span>
<label class="autoskip-switch">
<input type="checkbox" id="autoskip-conntimeout-toggle">
<span class="autoskip-toggle-slider"></span>
</label>
</div>
</div>
</div>
<!-- Search container card -->
<div class="autoskip-card" style="padding: 0; overflow: hidden;">
<div class="search-container" style="border: none; padding: 10px;">
<input type="text" placeholder="🔍 Search countries..." class="autoskip-input" id="autoskip-search-input">
</div>
</div>
<!-- Bulk actions card -->
<div class="autoskip-card" style="padding: 8px; margin-bottom: 4px;">
<div class="bulk-actions" style="display: flex; gap: 6px; justify-content: space-between; margin-bottom: 6px;">
<button class="autoskip-btn autoskip-btn-success" id="autoskip-enable-all" style="flex: 1;">All</button>
<button class="autoskip-btn autoskip-btn-danger" id="autoskip-disable-all" style="flex: 1;">None</button>
<button class="autoskip-btn autoskip-btn-secondary" id="autoskip-reset">Reset</button>
<button class="autoskip-btn autoskip-btn-secondary" id="autoskip-backup">Backup</button>
</div>
<div style="display: flex; gap: 4px; justify-content: space-between;">
<button class="autoskip-btn" id="autoskip-record-btn" style="flex: 1; background: rgba(239, 68, 68, 0.08); border-color: rgba(239, 68, 68, 0.25); color: #ef4444; font-weight: bold; gap: 6px; display: flex; align-items: center; justify-content: center; width: 100%;">
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #ef4444; box-shadow: 0 0 6px #ef4444; transition: all 0.3s;"></span>
Record Partner
</button>
</div>
</div>
<!-- Country list scroll view card -->
<div class="autoskip-card" style="flex: 1; padding: 4px; display: flex; flex-direction: column; overflow: hidden; margin-top: 4px; min-height: 120px;">
<div class="country-scroll" id="autoskip-country-container"></div>
</div>
<!-- Statistics counter summary card -->
<div class="autoskip-card" style="padding: 8px 12px; margin-top: 4px;">
<div class="stats-summary">
<span style="font-weight: 600; opacity: 0.9;" id="autoskip-total-skips">Total Skips: 0</span>
<button class="autoskip-btn autoskip-btn-secondary" id="autoskip-clear-stats" style="padding: 2px 8px; font-size: 10px;">Clear Stats</button>
</div>
</div>
<!-- Live Diagnostic Activity Log Card -->
<div class="autoskip-card" style="padding: 0; overflow: hidden; margin-top: 4px; margin-bottom: 12px;">
<div class="settings-header" id="log-accordion-toggle" style="cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; background: rgba(255, 255, 255, 0.02);">
<span style="font-size: 12px; font-weight: 600; color: #f59e0b; display: flex; align-items: center; gap: 6px;">📋 Activity Log</span>
<span id="log-chevron" class="continent-arrow">▶</span>
</div>
<div class="settings-body" id="log-accordion-body" style="max-height: 0; overflow-y: auto; transition: max-height 0.3s ease; font-family: monospace; font-size: 10px; padding: 0 14px; color: #a7f3d0; background: rgba(0, 0, 0, 0.15); display: block;">
<div id="log-content" style="padding: 6px 0; display: flex; flex-direction: column; gap: 4px;">
<div style="color: rgba(255,255,255,0.4); font-style: italic; font-size: 10px;">Waiting for events...</div>
</div>
</div>
</div>
<!-- Footer links -->
<div class="autoskip-footer">
<div class="footer-row">
<a href="https://discord.gg/TdGSGAWsbX" target="_blank" class="footer-link">💬 Discord</a>
<span id="autoskip-open-intro" style="cursor: pointer; text-decoration: underline; font-weight: 600; color: var(--as-primary);" title="Show Get Started guide">❓ Guide</span>
<span style="font-size: 9px; opacity: 0.85;">₿ <span id="autoskip-btc" style="cursor: pointer; color: #f7931a; font-family: monospace;" title="Click to copy Bitcoin address">3EMEWx5b5wwfaf5NKAQzW1sWHDYwFGEqw2</span></span>
</div>
<div style="font-size: 9px; text-align: center; color: rgba(255,255,255,0.4); font-style: italic; margin-top: 2px;">by 01 dev & Antigravity</div>
</div>
</div>
<!-- Import / Export Dialog modal -->
<div id="autoskip-modal">
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64b5f6; font-weight: 700;">Backup / Restore Settings</h4>
<div style="font-size: 11px; opacity: 0.7; margin-bottom: 10px;">Copy/paste the configuration JSON data below to backup or restore settings.</div>
<textarea id="autoskip-modal-textarea" placeholder="Paste settings JSON here..."></textarea>
<div style="display: flex; gap: 8px;">
<button class="autoskip-btn autoskip-btn-success" id="autoskip-modal-import" style="flex: 1;">Import</button>
<button class="autoskip-btn autoskip-btn-secondary" id="autoskip-modal-copy" style="flex: 1;">Copy</button>
<button class="autoskip-btn autoskip-btn-danger" id="autoskip-modal-close" style="padding: 5px 15px;">Close</button>
</div>
</div>
`;
document.body.appendChild(panel);
// Create and append the Introduction modal element
const introModal = document.createElement('div');
introModal.id = 'autoskip-intro-modal';
introModal.className = 'autoskip-intro-overlay';
introModal.innerHTML = `
<div class="autoskip-intro-card">
<div class="autoskip-intro-header">
<svg width="42" height="42" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="filter: drop-shadow(0 0 10px rgba(59, 130, 246, 0.85));"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
<h2>AutoSkip <span>v3.8</span></h2>
<p class="subtitle">Ultimate uMingle Automation Suite</p>
</div>
<div class="autoskip-intro-body">
<div class="intro-step">
<span class="step-num">1</span>
<div class="step-desc">
<h4>Filter Countries</h4>
<p>Toggle and search over 195 countries organized by continent. Skip unwanted partners automatically.</p>
</div>
</div>
<div class="intro-step">
<span class="step-num">2</span>
<div class="step-desc">
<h4>High-Quality Recording</h4>
<p>Record partner streams directly. Supports raw WebRTC audio/video capture and automatic WebM saving.</p>
</div>
</div>
<div class="intro-step">
<span class="step-num">3</span>
<div class="step-desc">
<h4>Automation & Greetings</h4>
<p>Set custom delay timers, connection hang auto-skips, idle timeouts, and automatic text greetings.</p>
</div>
</div>
</div>
<div class="autoskip-intro-footer">
<a href="https://discord.gg/TdGSGAWsbX" target="_blank" class="autoskip-btn autoskip-btn-secondary" style="gap: 6px; padding: 12px 20px; text-decoration: none;">
💬 Join Discord
</a>
<button id="autoskip-intro-start" class="autoskip-btn autoskip-btn-success" style="padding: 12px 30px; font-size: 13px; font-weight: 700; box-shadow: 0 0 20px rgba(16, 185, 129, 0.4);">
Get Started
</button>
</div>
</div>
`;
document.body.appendChild(introModal);
// Show intro guide if not dismissed yet
const introDismissed = localStorage.getItem('uhmegleAutoSkipIntroDismissed') === 'true';
if (!introDismissed) {
setTimeout(() => {
introModal.classList.add('visible');
}, 800);
}
document.getElementById('autoskip-intro-start').addEventListener('click', () => {
introModal.classList.remove('visible');
localStorage.setItem('uhmegleAutoSkipIntroDismissed', 'true');
logActivity('Intro Guide Completed');
});
document.getElementById('autoskip-open-intro').addEventListener('click', () => {
introModal.classList.add('visible');
});
// Get UI elements reference
const minimizeBtn = document.getElementById('autoskip-minimize-btn');
const panelContent = document.getElementById('autoskip-panel-content');
const settingsAccordionToggle = document.getElementById('settings-accordion-toggle');
const settingsAccordionBody = document.getElementById('settings-accordion-body');
const settingsChevron = document.getElementById('settings-chevron');
const logAccordionToggle = document.getElementById('log-accordion-toggle');
const logAccordionBody = document.getElementById('log-accordion-body');
const logChevron = document.getElementById('log-chevron');
const logContent = document.getElementById('log-content');
const globalToggle = document.getElementById('autoskip-global-toggle');
const reconnectToggle = document.getElementById('autoskip-reconnect-toggle');
const delaySlider = document.getElementById('autoskip-delay-slider');
const delayVal = document.getElementById('autoskip-delay-val');
const keywordsInput = document.getElementById('autoskip-keywords-input');
const timeoutSlider = document.getElementById('autoskip-timeout-slider');
const timeoutVal = document.getElementById('autoskip-timeout-val');
const greetingToggle = document.getElementById('autoskip-greeting-toggle');
const greetingInput = document.getElementById('autoskip-greeting-input');
const soundToggle = document.getElementById('autoskip-sound-toggle');
const autoRecordToggle = document.getElementById('autoskip-autorecord-toggle');
const connTimeoutToggle = document.getElementById('autoskip-conntimeout-toggle');
const statusBadge = document.getElementById('autoskip-status-badge');
const searchInput = document.getElementById('autoskip-search-input');
const countryContainer = document.getElementById('autoskip-country-container');
const totalSkipsText = document.getElementById('autoskip-total-skips');
const btcText = document.getElementById('autoskip-btc');
const recordBtn = document.getElementById('autoskip-record-btn');
const modal = document.getElementById('autoskip-modal');
const modalTextarea = document.getElementById('autoskip-modal-textarea');
// -------------------------------
// Initialize UI Input Values
// -------------------------------
globalToggle.checked = settings.enabled;
reconnectToggle.checked = settings.autoReconnect;
delaySlider.value = settings.skipDelay;
delayVal.textContent = settings.skipDelay + 'ms';
keywordsInput.value = settings.bannedKeywords;
timeoutSlider.value = settings.idleTimeout;
timeoutVal.textContent = settings.idleTimeout > 0 ? settings.idleTimeout + 's' : 'Off';
greetingToggle.checked = settings.greetingEnabled;
greetingInput.value = settings.greetingMessage;
soundToggle.checked = settings.soundEnabled;
autoRecordToggle.checked = settings.autoRecord;
connTimeoutToggle.checked = settings.connectionTimeoutEnabled;
updateGlobalStatusUI();
// Continent expand state
const expandedContinents = {};
let currentSearchTerm = '';
// Video Recording Variables
let isRecording = false;
let mediaRecorder = null;
let recordedChunks = [];
let recInterval = null;
// -------------------------------
// Drag Panel Logic
// -------------------------------
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
const dragHandle = document.getElementById('autoskip-drag-handle');
dragHandle.addEventListener('mousedown', (e) => {
if (e.target.closest('#header-controls')) return;
isDragging = true;
dragOffset.x = e.clientX - panel.offsetLeft;
dragOffset.y = e.clientY - panel.offsetTop;
panel.style.transition = 'none';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const newX = e.clientX - dragOffset.x;
const newY = e.clientY - dragOffset.y;
panel.style.left = Math.max(0, Math.min(newX, window.innerWidth - panel.offsetWidth)) + 'px';
panel.style.top = Math.max(0, Math.min(newY, window.innerHeight - panel.offsetHeight)) + 'px';
panel.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
panel.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
}
});
// -------------------------------
// UI Expand / Collapse & Accordion Controls
// -------------------------------
let isMinimized = false;
minimizeBtn.addEventListener('click', () => {
isMinimized = !isMinimized;
if (isMinimized) {
panel.classList.add('minimized');
minimizeBtn.textContent = '+';
} else {
panel.classList.remove('minimized');
minimizeBtn.textContent = '−';
}
});
let settingsOpen = false;
settingsAccordionToggle.addEventListener('click', () => {
settingsOpen = !settingsOpen;
if (settingsOpen) {
settingsAccordionBody.classList.add('open');
settingsAccordionBody.style.maxHeight = '420px';
settingsChevron.classList.add('open');
} else {
settingsAccordionBody.classList.remove('open');
settingsAccordionBody.style.maxHeight = '0';
settingsChevron.classList.remove('open');
}
});
let logOpen = false;
logAccordionToggle.addEventListener('click', () => {
logOpen = !logOpen;
if (logOpen) {
logAccordionBody.style.maxHeight = '140px';
logChevron.classList.add('open');
} else {
logAccordionBody.style.maxHeight = '0';
logChevron.classList.remove('open');
}
});
// -------------------------------
// Settings event handlers
// -------------------------------
globalToggle.addEventListener('change', () => {
settings.enabled = globalToggle.checked;
saveSettings();
updateGlobalStatusUI();
logActivity(settings.enabled ? 'AutoSkip Enabled' : 'AutoSkip Paused');
});
reconnectToggle.addEventListener('change', () => {
settings.autoReconnect = reconnectToggle.checked;
saveSettings();
});
delaySlider.addEventListener('input', () => {
settings.skipDelay = parseInt(delaySlider.value);
delayVal.textContent = settings.skipDelay + 'ms';
saveSettings();
});
keywordsInput.addEventListener('input', () => {
settings.bannedKeywords = keywordsInput.value;
saveSettings();
});
timeoutSlider.addEventListener('input', () => {
settings.idleTimeout = parseInt(timeoutSlider.value);
timeoutVal.textContent = settings.idleTimeout > 0 ? settings.idleTimeout + 's' : 'Off';
saveSettings();
});
greetingToggle.addEventListener('change', () => {
settings.greetingEnabled = greetingToggle.checked;
saveSettings();
});
greetingInput.addEventListener('input', () => {
settings.greetingMessage = greetingInput.value;
saveSettings();
});
soundToggle.addEventListener('change', () => {
settings.soundEnabled = soundToggle.checked;
saveSettings();
});
autoRecordToggle.addEventListener('change', () => {
settings.autoRecord = autoRecordToggle.checked;
saveSettings();
logActivity(settings.autoRecord ? 'Auto-Record Matches Enabled' : 'Auto-Record Matches Disabled');
});
connTimeoutToggle.addEventListener('change', () => {
settings.connectionTimeoutEnabled = connTimeoutToggle.checked;
saveSettings();
});
// Update Status Badge UI
function updateGlobalStatusUI() {
if (settings.enabled) {
statusBadge.textContent = 'ACTIVE';
statusBadge.style.background = 'rgba(16, 185, 129, 0.15)';
statusBadge.style.color = '#10b981';
statusBadge.style.border = '1px solid rgba(16, 185, 129, 0.3)';
panel.classList.add('active-glow');
panel.classList.remove('paused-glow');
panelContent.style.opacity = '1';
} else {
statusBadge.textContent = 'PAUSED';
statusBadge.style.background = 'rgba(239, 68, 68, 0.15)';
statusBadge.style.color = '#ef4444';
statusBadge.style.border = '1px solid rgba(239, 68, 68, 0.3)';
panel.classList.add('paused-glow');
panel.classList.remove('active-glow');
panelContent.style.opacity = '0.75';
}
}
// BTC Copy to Clipboard
btcText.addEventListener('click', () => {
const address = '3EMEWx5b5wwfaf5NKAQzW1sWHDYwFGEqw2';
navigator.clipboard.writeText(address).then(() => {
const originalColor = btcText.style.color;
btcText.style.color = '#10b981';
btcText.textContent = 'Copied!';
setTimeout(() => {
btcText.style.color = originalColor;
btcText.textContent = address;
}, 1500);
}).catch(() => {
const textArea = document.createElement('textarea');
textArea.value = address;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
const originalColor = btcText.style.color;
btcText.style.color = '#10b981';
btcText.textContent = 'Copied!';
setTimeout(() => {
btcText.style.color = originalColor;
btcText.textContent = address;
}, 1500);
});
});
// Convert regional indicator flag emoji to lowercase ISO-2 code & fetch from CDN
function getFlagIcon(country) {
const emoji = countryFlags[country];
if (!emoji) return '🏳️';
try {
const cp1 = emoji.codePointAt(0);
const cp2 = emoji.codePointAt(2);
if (cp1 >= 0x1F1E6 && cp1 <= 0x1F1FF && cp2 >= 0x1F1E6 && cp2 <= 0x1F1FF) {
const code = (String.fromCharCode(cp1 - 0x1F1E6 + 65) + String.fromCharCode(cp2 - 0x1F1E6 + 65)).toLowerCase();
return `<img src="https://flagcdn.com/24x18/${code}.png" width="18" height="13" style="border-radius: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.3); vertical-align: middle; display: inline-block; filter: saturate(110%);" alt="${country} flag">`;
}
} catch (e) {
console.error('Error parsing flag emoji for: ' + country, e);
}
return emoji;
}
// -------------------------------
// Country Render & Continent Accordion Logic
// -------------------------------
function updateCountryListUI() {
countryContainer.innerHTML = '';
// Calculate global stats
let totalSkips = 0;
Object.keys(settings.stats).forEach(c => {
totalSkips += (settings.stats[c] || 0);
});
totalSkipsText.textContent = `Total Skips: ${totalSkips.toLocaleString()}`;
// Group countries by continent
const grouped = {};
continents.forEach(c => grouped[c] = []);
grouped['Other'] = [];
Object.keys(autoSkipCountries).forEach(country => {
const continent = continentMap[country] || 'Other';
grouped[continent].push(country);
});
// Loop and render continents
const continentsToRender = [...continents, 'Other'];
continentsToRender.forEach(continent => {
const countries = grouped[continent];
if (!countries || countries.length === 0) return;
// Filter countries based on search term
const filteredCountries = countries.filter(country =>
country.toLowerCase().includes(currentSearchTerm)
);
// Hide the continent group entirely if no countries match search
if (filteredCountries.length === 0 && currentSearchTerm) return;
// Count enabled countries and skips in group
const enabledInGroup = filteredCountries.filter(c => autoSkipCountries[c]).length;
const skipsInGroup = filteredCountries.reduce((sum, c) => sum + (settings.stats[c] || 0), 0);
// Create continent header container
const headerDiv = document.createElement('div');
headerDiv.className = 'continent-header';
headerDiv.dataset.continent = continent;
const isExpanded = expandedContinents[continent] || currentSearchTerm;
headerDiv.innerHTML = `
<div class="continent-title">
<span class="continent-arrow ${isExpanded ? 'open' : ''}">▶</span>
<span>${continent === 'Other' ? '🗺️' : '🌍'} ${continent}</span>
</div>
<div style="display: flex; align-items: center; gap: 8px; pointer-events: auto;">
<div style="display: flex; gap: 4px; margin-right: 6px;" class="group-toggle-btns">
<span class="autoskip-btn" data-action="enable-group" data-continent="${continent}" style="padding: 1px 5px; font-size: 9px; line-height: 1.1; background: rgba(16, 185, 129, 0.1); border-color: rgba(16, 185, 129, 0.25); color: #58d68d;">All</span>
<span class="autoskip-btn" data-action="disable-group" data-continent="${continent}" style="padding: 1px 5px; font-size: 9px; line-height: 1.1; background: rgba(239, 68, 68, 0.1); border-color: rgba(239, 68, 68, 0.25); color: #f5b041;">None</span>
</div>
<div class="continent-stats">
<span style="font-size: 9px; font-weight: bold; background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.25); color: #10b981; padding: 1px 5px; border-radius: 8px;">${enabledInGroup} active</span>
${skipsInGroup > 0 ? `<span style="font-size: 9px; font-weight: bold; background: rgba(59, 130, 246, 0.15); border: 1px solid rgba(59, 130, 246, 0.25); color: #3b82f6; padding: 1px 5px; border-radius: 8px;">${skipsInGroup} skips</span>` : ''}
</div>
</div>
`;
// Create countries container
const countriesDiv = document.createElement('div');
countriesDiv.className = `continent-countries ${isExpanded ? 'open' : ''}`;
countriesDiv.dataset.continent = continent;
// Alphabetical sorting of countries within continent
const sortedCountries = filteredCountries.sort();
sortedCountries.forEach(country => {
const countryItem = document.createElement('div');
countryItem.className = 'country-item';
const enabled = autoSkipCountries[country];
const skips = settings.stats[country] || 0;
// Search highlighting
let displayName = country;
if (currentSearchTerm) {
displayName = country.replace(new RegExp(currentSearchTerm, 'gi'),
match => `<mark style="background: #ffd700; color: #000; padding: 1px 2px; border-radius: 3px; font-weight: 700;">${match}</mark>`
);
}
countryItem.innerHTML = `
<label class="autoskip-switch">
<input type="checkbox" class="country-checkbox" data-country="${country}" ${enabled ? 'checked' : ''}>
<span class="autoskip-toggle-slider"></span>
</label>
<span class="country-flag" style="display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 18px; margin: 0 10px;">${getFlagIcon(country)}</span>
<span class="country-name">${displayName}</span>
${skips > 0 ? `<span class="country-skips-badge" title="Skipped ${skips} times">${skips}</span>` : ''}
`;
// Handle clicking country container to toggle
countryItem.addEventListener('click', (e) => {
if (e.target.closest('.autoskip-switch')) return;
const chk = countryItem.querySelector('.country-checkbox');
chk.checked = !chk.checked;
chk.dispatchEvent(new Event('change'));
});
// Checkbox toggle handler
const checkbox = countryItem.querySelector('.country-checkbox');
checkbox.addEventListener('change', () => {
autoSkipCountries[country] = checkbox.checked;
saveAutoSkipCountries();
updateCountryListUI();
});
countriesDiv.appendChild(countryItem);
});
// Handle accordion expand/collapse clicking
headerDiv.addEventListener('click', (e) => {
if (e.target.closest('.group-toggle-btns')) return;
const isNowExpanded = !countriesDiv.classList.contains('open');
if (isNowExpanded) {
countriesDiv.classList.add('open');
headerDiv.querySelector('.continent-arrow').classList.add('open');
expandedContinents[continent] = true;
} else {
countriesDiv.classList.remove('open');
headerDiv.querySelector('.continent-arrow').classList.remove('open');
expandedContinents[continent] = false;
}
});
// Group enable button handler
headerDiv.querySelector('[data-action="enable-group"]').addEventListener('click', (e) => {
e.stopPropagation();
countries.forEach(c => autoSkipCountries[c] = true);
saveAutoSkipCountries();
updateCountryListUI();
});
// Group disable button handler
headerDiv.querySelector('[data-action="disable-group"]').addEventListener('click', (e) => {
e.stopPropagation();
countries.forEach(c => autoSkipCountries[c] = false);
saveAutoSkipCountries();
updateCountryListUI();
});
countryContainer.appendChild(headerDiv);
countryContainer.appendChild(countriesDiv);
});
// Handle empty search result
if (countryContainer.children.length === 0 && currentSearchTerm) {
const noResults = document.createElement('div');
noResults.style.cssText = `
padding: 30px 20px;
text-align: center;
color: var(--as-text-muted);
font-style: italic;
font-size: 13px;
`;
noResults.textContent = `No countries found for "${currentSearchTerm}"`;
countryContainer.appendChild(noResults);
}
}
updateCountryListUI();
// -------------------------------
// General Actions Handlers
// -------------------------------
// Search input
searchInput.addEventListener('input', (e) => {
currentSearchTerm = e.target.value.toLowerCase();
updateCountryListUI();
});
// Global Action - Enable All
document.getElementById('autoskip-enable-all').addEventListener('click', () => {
Object.keys(autoSkipCountries).forEach(country => {
autoSkipCountries[country] = true;
});
saveAutoSkipCountries();
updateCountryListUI();
logActivity('All countries activated');
});
// Global Action - Disable All
document.getElementById('autoskip-disable-all').addEventListener('click', () => {
Object.keys(autoSkipCountries).forEach(country => {
autoSkipCountries[country] = false;
});
saveAutoSkipCountries();
updateCountryListUI();
logActivity('All countries deactivated');
});
// Global Action - Reset Settings
document.getElementById('autoskip-reset').addEventListener('click', () => {
if (confirm('Reset all country configurations, skip statistics, and settings to original defaults?')) {
if (isRecording) {
stopRecording();
}
autoSkipCountries = { ...defaultAutoSkipCountries };
settings = {
enabled: true,
autoReconnect: true,
skipDelay: 500,
stats: {},
bannedKeywords: '',
idleTimeout: 0,
greetingEnabled: false,
greetingMessage: '',
soundEnabled: false,
connectionTimeoutEnabled: true,
autoRecord: false
};
saveAutoSkipCountries();
saveSettings();
// Sync UI elements
globalToggle.checked = true;
reconnectToggle.checked = true;
delaySlider.value = 500;
delayVal.textContent = '500ms';
keywordsInput.value = '';
timeoutSlider.value = 0;
timeoutVal.textContent = 'Off';
greetingToggle.checked = false;
greetingInput.value = '';
soundToggle.checked = false;
autoRecordToggle.checked = false;
connTimeoutToggle.checked = true;
updateGlobalStatusUI();
updateCountryListUI();
// Clear log
activityLog = [];
updateActivityLogUI();
logActivity('Configuration Reset Completed');
}
});
// Global Action - Clear Statistics
document.getElementById('autoskip-clear-stats').addEventListener('click', () => {
if (confirm('Are you sure you want to clear all skip stats?')) {
settings.stats = {};
saveSettings();
updateCountryListUI();
logActivity('Statistics Cleared');
}
});
// -------------------------------
// Backup & Restore System Modal
// -------------------------------
const backupBtn = document.getElementById('autoskip-backup');
const modalImportBtn = document.getElementById('autoskip-modal-import');
const modalCopyBtn = document.getElementById('autoskip-modal-copy');
const modalCloseBtn = document.getElementById('autoskip-modal-close');
backupBtn.addEventListener('click', () => {
const configData = {
countries: autoSkipCountries,
settings: settings
};
modalTextarea.value = JSON.stringify(configData, null, 2);
modal.classList.add('open');
logActivity('Configuration Export Opened');
});
modalCloseBtn.addEventListener('click', () => {
modal.classList.remove('open');
});
modalCopyBtn.addEventListener('click', () => {
modalTextarea.select();
navigator.clipboard.writeText(modalTextarea.value).then(() => {
const originalText = modalCopyBtn.textContent;
modalCopyBtn.textContent = 'Copied!';
modalCopyBtn.classList.add('autoskip-btn-success');
setTimeout(() => {
modalCopyBtn.textContent = originalText;
modalCopyBtn.classList.remove('autoskip-btn-success');
}, 1500);
}).catch(() => {
modalTextarea.select();
document.execCommand('copy');
const originalText = modalCopyBtn.textContent;
modalCopyBtn.textContent = 'Copied!';
modalCopyBtn.classList.add('autoskip-btn-success');
setTimeout(() => {
modalCopyBtn.textContent = originalText;
modalCopyBtn.classList.remove('autoskip-btn-success');
}, 1500);
});
});
modalImportBtn.addEventListener('click', () => {
try {
const parsedData = JSON.parse(modalTextarea.value);
if (parsedData && typeof parsedData === 'object') {
// Validate parsed content
if (parsedData.countries && typeof parsedData.countries === 'object') {
autoSkipCountries = { ...autoSkipCountries, ...parsedData.countries };
saveAutoSkipCountries();
}
if (parsedData.settings && typeof parsedData.settings === 'object') {
settings = {
...settings,
...parsedData.settings,
stats: parsedData.settings.stats || settings.stats
};
saveSettings();
}
// Synchronize interface inputs
globalToggle.checked = settings.enabled;
reconnectToggle.checked = settings.autoReconnect;
delaySlider.value = settings.skipDelay;
delayVal.textContent = settings.skipDelay + 'ms';
keywordsInput.value = settings.bannedKeywords || '';
timeoutSlider.value = settings.idleTimeout || 0;
timeoutVal.textContent = settings.idleTimeout > 0 ? settings.idleTimeout + 's' : 'Off';
greetingToggle.checked = settings.greetingEnabled || false;
greetingInput.value = settings.greetingMessage || '';
soundToggle.checked = settings.soundEnabled || false;
autoRecordToggle.checked = settings.hasOwnProperty('autoRecord') ? settings.autoRecord : false;
connTimeoutToggle.checked = settings.hasOwnProperty('connectionTimeoutEnabled') ? settings.connectionTimeoutEnabled : true;
updateGlobalStatusUI();
updateCountryListUI();
modal.classList.remove('open');
alert('Settings and configuration imported successfully!');
logActivity('Settings Imported Successfully');
} else {
throw new Error('Invalid JSON schema');
}
} catch (err) {
alert('Failed to import config. Please check that you have pasted valid configuration JSON data.');
}
});
// -------------------------------
// ESC Key Simulation Functions
// -------------------------------
function simulateEsc() {
const escEvent = new KeyboardEvent('keydown', {
key: 'Escape',
code: 'Escape',
keyCode: 27,
which: 27,
bubbles: true,
cancelable: true
});
document.dispatchEvent(escEvent);
}
function simulateSkip() {
clearIdleTimer();
clearGreeting();
startConnectionTimer(); // start hang timer since we are searching now
if (!settings.enabled) return;
console.log('Simulating ESC key presses for auto-skip...');
simulateEsc();
// Slightly randomize delay around user setting
const baseDelay = settings.skipDelay;
const randomDelay = baseDelay - 50 + Math.random() * 100;
setTimeout(simulateEsc, Math.max(10, randomDelay));
}
// -------------------------------
// Diagnostic Activity Log System
// -------------------------------
let activityLog = [];
function logActivity(message) {
const time = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
activityLog.unshift(`[${time}] ${message}`);
if (activityLog.length > 15) {
activityLog.pop();
}
updateActivityLogUI();
}
function updateActivityLogUI() {
if (!logContent) return;
if (activityLog.length === 0) {
logContent.innerHTML = '<div style="color: rgba(255,255,255,0.4); font-style: italic; font-size: 10px;">Waiting for events...</div>';
return;
}
logContent.innerHTML = activityLog.map(line => {
let styledLine = line;
if (line.includes('Matched')) {
styledLine = line.replace('Matched', '<span style="color: #10b981; font-weight: bold;">Matched</span>');
} else if (line.includes('Skipped')) {
styledLine = line.replace('Skipped', '<span style="color: #ef4444;">Skipped</span>');
} else if (line.includes('Disconnected') || line.includes('disconnected')) {
styledLine = line.replace('disconnected', '<span style="color: #f59e0b;">disconnected</span>').replace('Disconnected', '<span style="color: #f59e0b;">Disconnected</span>');
} else if (line.includes('sent')) {
styledLine = line.replace('sent', '<span style="color: #3b82f6; font-weight: bold;">sent</span>');
} else if (line.includes('recording') || line.includes('Recording')) {
styledLine = line.replace('recording', '<span style="color: #ef4444; font-weight: bold;">recording</span>').replace('Recording', '<span style="color: #ef4444; font-weight: bold;">Recording</span>');
}
return `<div class="log-item-line">${styledLine}</div>`;
}).join('');
}
// -------------------------------
// Web Audio Synthesizer Beeps
// -------------------------------
function playBeep() {
if (!settings.soundEnabled) return;
try {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(587.33, audioCtx.currentTime); // D5 pitch
gainNode.gain.setValueAtTime(0.06, audioCtx.currentTime); // low volume
oscillator.start();
gainNode.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 0.15); // quick fade
oscillator.stop(audioCtx.currentTime + 0.16);
} catch (e) {
console.warn('AudioContext failed to trigger sound: ', e);
}
}
// -------------------------------
// Auto-Greeting Message Typer
// -------------------------------
let greetingTimeout = null;
function clearGreeting() {
if (greetingTimeout) {
clearTimeout(greetingTimeout);
greetingTimeout = null;
}
}
function scheduleGreeting() {
clearGreeting();
if (settings.enabled && settings.greetingEnabled && settings.greetingMessage && settings.greetingMessage.trim() !== '') {
const delay = 1000 + Math.random() * 500; // 1.0s to 1.5s delay
greetingTimeout = setTimeout(() => {
sendGreetingMessage();
}, delay);
}
}
function sendGreetingMessage() {
if (!settings.enabled || !settings.greetingEnabled) return;
const inputElement = document.querySelector('textarea, input[type="text"], .chatinput, .message-input, [contenteditable="true"]');
if (!inputElement) return;
console.log(`Sending auto-greeting: "${settings.greetingMessage}"`);
if (inputElement.tagName === 'DIV' || inputElement.contentEditable === 'true') {
inputElement.innerHTML = settings.greetingMessage;
} else {
inputElement.value = settings.greetingMessage;
}
// Fire listeners to inform UI framework (React/Vue/etc.)
inputElement.dispatchEvent(new Event('input', { bubbles: true }));
inputElement.dispatchEvent(new Event('change', { bubbles: true }));
setTimeout(() => {
const sendBtn = document.querySelector('button.sendbtn, button.send, button[type="submit"], .send-button, .btn-send');
if (sendBtn) {
sendBtn.click();
logActivity('Auto-greeting sent');
} else {
const enterDown = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true });
const enterUp = new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true });
inputElement.dispatchEvent(enterDown);
inputElement.dispatchEvent(enterUp);
logActivity('Auto-greeting sent (enter)');
}
}, 100);
}
// -------------------------------
// WebRTC Video Recorder Logic
// -------------------------------
function startRecording() {
if (isRecording) return;
const videos = document.querySelectorAll('video');
const targetVideo = Array.from(videos).find(v => v.videoWidth > 200) || videos[0];
if (!targetVideo) {
alert('No active video stream found to record.');
return;
}
let stream = null;
let isRawStream = false;
if (targetVideo.srcObject && targetVideo.srcObject instanceof MediaStream && targetVideo.srcObject.getVideoTracks().length > 0) {
stream = targetVideo.srcObject;
isRawStream = true;
} else {
try {
stream = targetVideo.captureStream ? targetVideo.captureStream() : (targetVideo.mozCaptureStream ? targetVideo.mozCaptureStream() : null);
} catch (e) {
console.warn('captureStream fallback failed: ', e);
}
}
if (!stream) {
alert('No recordable video stream found on this video node.');
return;
}
recordedChunks = [];
const options = { mimeType: 'video/webm;codecs=vp9' };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
options.mimeType = 'video/webm;codecs=vp8';
}
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
options.mimeType = 'video/webm';
}
try {
mediaRecorder = new MediaRecorder(stream, options);
} catch (e) {
mediaRecorder = new MediaRecorder(stream);
}
mediaRecorder.ondataavailable = (event) => {
if (event.data && event.data.size > 0) {
recordedChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
if (recordedChunks.length === 0) {
logActivity('Recording stopped (no frames captured)');
return;
}
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
const timeStr = new Date().toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '_');
a.download = `umingle_recording_${timeStr}.webm`;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 1500);
logActivity('Video recording saved');
};
try {
mediaRecorder.start(1000);
isRecording = true;
updateRecordBtnUI();
logActivity(isRawStream ? 'Recording WebRTC stream (with audio)' : 'Recording video canvas fallback');
// Build and inject floating overlay badge on parent container of targetVideo
const container = targetVideo.parentElement;
if (container) {
const origPos = window.getComputedStyle(container).position;
if (origPos !== 'relative' && origPos !== 'absolute' && origPos !== 'fixed') {
container.style.position = 'relative';
}
const existingOverlay = document.getElementById('autoskip-rec-overlay');
if (existingOverlay) existingOverlay.remove();
const overlay = document.createElement('div');
overlay.id = 'autoskip-rec-overlay';
overlay.className = 'recording-overlay';
overlay.innerHTML = `
<span class="rec-dot"></span>
<span class="rec-text">REC</span>
<span class="rec-timer">00:00</span>
`;
container.appendChild(overlay);
let recSeconds = 0;
const recTimerEl = overlay.querySelector('.rec-timer');
if (recInterval) clearInterval(recInterval);
recInterval = setInterval(() => {
recSeconds++;
const mins = String(Math.floor(recSeconds / 60)).padStart(2, '0');
const secs = String(recSeconds % 60).padStart(2, '0');
recTimerEl.textContent = `${mins}:${secs}`;
}, 1000);
}
} catch (err) {
alert('Failed to start MediaRecorder: ' + err.message);
isRecording = false;
updateRecordBtnUI();
}
}
function stopRecording() {
if (!isRecording) return;
if (recInterval) {
clearInterval(recInterval);
recInterval = null;
}
const overlay = document.getElementById('autoskip-rec-overlay');
if (overlay) {
overlay.remove();
}
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
isRecording = false;
updateRecordBtnUI();
logActivity('Stopped video recording');
}
function updateRecordBtnUI() {
if (!recordBtn) return;
if (isRecording) {
recordBtn.classList.add('record-active');
recordBtn.innerHTML = `
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #ef4444; box-shadow: 0 0 8px #ef4444;"></span>
Stop Recording
`;
recordBtn.style.background = 'rgba(239, 68, 68, 0.2)';
recordBtn.style.borderColor = '#ef4444';
} else {
recordBtn.classList.remove('record-active');
recordBtn.innerHTML = `
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #ef4444; box-shadow: 0 0 6px #ef4444;"></span>
Record Partner
`;
recordBtn.style.background = 'rgba(239, 68, 68, 0.08)';
recordBtn.style.borderColor = 'rgba(239, 68, 68, 0.25)';
}
}
recordBtn.addEventListener('click', () => {
if (isRecording) {
stopRecording();
} else {
startRecording();
}
});
// -------------------------------
// Connection Hang Timer Fail-Safe
// -------------------------------
let connectionTimer = null;
function startConnectionTimer() {
clearConnectionTimer();
if (settings.enabled && settings.connectionTimeoutEnabled) {
connectionTimer = setTimeout(() => {
console.log('Connection timeout reached. Recasting search...');
logActivity('Skipped (Connection Hang)');
simulateEsc();
startConnectionTimer();
}, 15000);
}
}
function clearConnectionTimer() {
if (connectionTimer) {
clearTimeout(connectionTimer);
connectionTimer = null;
}
}
// -------------------------------
// Idle Timeout Auto-Skipper Timer
// -------------------------------
let idleTimer = null;
function startIdleTimer() {
clearIdleTimer();
if (settings.enabled && settings.idleTimeout > 0) {
console.log(`Starting idle timer for ${settings.idleTimeout} seconds...`);
idleTimer = setTimeout(() => {
console.log(`Stranger was idle for ${settings.idleTimeout}s. Auto-skipping...`);
logActivity(`Skipped stranger (Idle Timeout)`);
simulateSkip();
}, settings.idleTimeout * 1000);
}
}
function clearIdleTimer() {
if (idleTimer) {
clearTimeout(idleTimer);
idleTimer = null;
}
}
// -------------------------------
// Chat Scan & Automation Checks
// -------------------------------
let lastCountry = '';
function checkCountry() {
if (!settings.enabled) return;
const countryElem = document.getElementById('countryName');
if (countryElem) {
const currentCountry = countryElem.textContent.trim();
if (currentCountry && currentCountry !== lastCountry) {
lastCountry = currentCountry;
// Auto-stop previous recording if active so it downloads before resetting tracks
if (isRecording) {
stopRecording();
}
clearConnectionTimer(); // Connected!
clearIdleTimer();
clearGreeting();
// Dynamic additions of new countries discovered in session
if (!(currentCountry in autoSkipCountries)) {
autoSkipCountries[currentCountry] = false;
saveAutoSkipCountries();
updateCountryListUI();
}
// If auto-skip is enabled for this country, count it and simulate skip
if (autoSkipCountries[currentCountry]) {
if (!settings.stats[currentCountry]) {
settings.stats[currentCountry] = 0;
}
settings.stats[currentCountry]++;
saveSettings();
logActivity(`Skipped ${currentCountry} (Country Filter)`);
updateCountryListUI();
simulateSkip();
} else {
// Chat is allowed (not skipped by country), start timers and beep!
logActivity(`Matched with ${currentCountry} (Active)`);
startIdleTimer();
scheduleGreeting();
playBeep();
if (settings.autoRecord) {
setTimeout(() => {
if (settings.enabled && !isRecording && lastCountry === currentCountry) {
startRecording();
}
}, 300);
}
}
}
}
}
let disconnectTriggered = false;
function checkForDisconnect() {
if (!settings.enabled) return;
// HIGH PERFORMANCE: textContent does not cause browser layout reflow (unlike innerText)
const pageText = document.body.textContent || "";
const found = pageText.includes("You have disconnected") ||
pageText.includes("Stranger has disconnected") ||
pageText.includes("Stranger disconnected");
if (found) {
if (!disconnectTriggered) {
disconnectTriggered = true;
// Stop recording when stranger leaves
if (isRecording) {
stopRecording();
}
clearIdleTimer();
clearGreeting();
startConnectionTimer(); // start hang timer since we are disconnected
console.log('"You have disconnected" detected.');
logActivity('Stranger disconnected');
if (settings.autoReconnect) {
console.log('Auto-reconnect is active. Simulating ESC to start new chat...');
const baseDelay = settings.skipDelay;
const randomDelay = baseDelay - 50 + Math.random() * 100;
setTimeout(simulateEsc, Math.max(10, randomDelay));
}
}
} else {
disconnectTriggered = false;
}
}
// Keyword & Stranger Messages Scanner
function scanStrangerMessages() {
if (!settings.enabled) return;
// Query DOM tags that might display text messages
const elements = document.querySelectorAll('.logitem, .message, .chat-message, div, span, p');
let strangerMessageFound = false;
for (let i = 0; i < elements.length; i++) {
const text = elements[i].textContent.trim();
const textLower = text.toLowerCase();
// Look for prefixes indicating a message from the stranger
if (textLower.startsWith('stranger:') || textLower.includes(' stranger:')) {
strangerMessageFound = true;
// If banned keywords are specified, check for them
if (settings.bannedKeywords && settings.bannedKeywords.trim() !== '') {
const keywords = settings.bannedKeywords.split(',')
.map(k => k.trim().toLowerCase())
.filter(k => k.length > 0);
for (let j = 0; j < keywords.length; j++) {
if (textLower.includes(keywords[j])) {
console.log(`Banned keyword "${keywords[j]}" detected. Auto-skipping stranger...`);
logActivity(`Skipped stranger (Keyword: ${keywords[j]})`);
simulateSkip();
return;
}
}
}
}
}
// Clear the idle timer if the stranger has sent at least one message
if (strangerMessageFound) {
clearIdleTimer();
}
}
// Throttled Observer to protect CPU cycles from micro-mutations during chats
let checkTimeout = null;
function queueAutomationChecks() {
if (checkTimeout) return;
checkTimeout = setTimeout(() => {
checkTimeout = null;
checkCountry();
checkForDisconnect();
scanStrangerMessages();
}, 120);
}
// Set up MutationObserver to target changes inside the body
const chatObserver = new MutationObserver(queueAutomationChecks);
chatObserver.observe(document.body, { childList: true, subtree: true });
// Fallback checks (slower interval) in case mutations miss updates
setInterval(queueAutomationChecks, 1200);
// Global Keyboard Shortcut (Alt+R to toggle recording)
document.addEventListener('keydown', (e) => {
if (e.altKey && (e.key === 'r' || e.key === 'R')) {
const activeEl = document.activeElement;
if (activeEl) {
const tagName = activeEl.tagName.toLowerCase();
const isContentEditable = activeEl.contentEditable === 'true';
if (tagName === 'input' || tagName === 'textarea' || isContentEditable) {
return;
}
}
e.preventDefault();
e.stopPropagation();
if (isRecording) {
stopRecording();
} else {
startRecording();
}
}
});
// Initial log message
logActivity('AutoSkip V6 Loaded');
startConnectionTimer(); // start connection timer initially as we start searching
})();