(function () {
'use strict';
const ACCENT = '#00f0c8';
const ACCENT2 = '#58a6ff';
const MUTED = '#8b9aad';
const DANGER = '#ff4757';
const OK = '#3fb950';
const $ = (id) => document.getElementById(id);
function isPrivateIP(ip) {
if (!ip) return true;
if (ip.startsWith('0.') || ip.startsWith('127.') || ip === '::1') return true;
if (ip.startsWith('10.') || ip.startsWith('192.168.')) return true;
if (ip.startsWith('172.')) { const s = parseInt(ip.split('.')[1], 10); if (s >= 16 && s <= 31) return true; }
if (ip.startsWith('169.254.')) return true;
if (ip.startsWith('fc') || ip.startsWith('fd')) return true;
if (ip === '::ffff:127.0.0.1') return true;
return false;
}
function isValidIP(ip) {
if (!ip || typeof ip !== 'string') return false;
const ipv4 = /^(?:(?:25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(?:25[0-5]|2[0-4]\d|1?\d{1,2})$/;
if (ipv4.test(ip)) return !isPrivateIP(ip);
const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
if (ipv6.test(ip)) return !isPrivateIP(ip);
return false;
}
function extractIP(candidate) {
if (!candidate) return null;
const parts = candidate.split(' ');
if (parts.length < 5) return null;
const typIdx = parts.findIndex(p => p === 'typ');
if (typIdx === -1) return null;
const typ = parts[typIdx + 1];
if (typ !== 'srflx' && typ !== 'prflx') return null;
return isValidIP(parts[4]) ? parts[4] : null;
}
function esc(str) {
if (str == null) return '';
return String(str).replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
}
function flagEmoji(cc) {
if (!cc) return '';
try { return String.fromCodePoint(...[...cc.toUpperCase()].map(c => 0x1F1E6 + c.charCodeAt(0) - 65)); } catch { return ''; }
}
function fmtOffset(off) {
if (off == null) return '—';
if (typeof off === 'string') {
const m = off.match(/([+-]?)\d{1,2}:\d{2}(?::\d{2})?/);
if (m) {
const sign = off.includes('-') ? -1 : 1;
const h = parseInt(m[0].split(':')[0].replace('+','').replace('-',''), 10);
const mn = parseInt(m[0].split(':')[1], 10);
const s = m[0].split(':')[2] ? parseInt(m[0].split(':')[2], 10) : 0;
const totalSec = sign * (h * 3600 + mn * 60 + s);
const h2 = Math.floor(Math.abs(totalSec) / 3600);
const m2 = Math.floor((Math.abs(totalSec) % 3600) / 60);
const sign2 = totalSec >= 0 ? '+' : '-';
return `${sign2}${h2.toString().padStart(2,'0')}:${m2.toString().padStart(2,'0')}`;
}
const n = Number(off.replace(/[^0-9.-]/g, ''));
if (!isNaN(n)) off = n; else return '—';
}
let s = Number(off);
if (isNaN(s)) return '—';
if (Math.abs(s) < 20) s = s * 3600;
const h = Math.floor(Math.abs(s) / 3600);
const m = Math.floor((Math.abs(s) % 3600) / 60);
const sign = s >= 0 ? '+' : '-';
return `${sign}${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`;
}
function mergeData(results) {
const merged = {};
for (const r of results) {
if (!r) continue;
for (const key of Object.keys(r)) {
if (r[key] != null && r[key] !== '' && r[key] !== undefined) {
if (merged[key] == null || merged[key] === '') {
if (key === 'currency' && typeof r[key] === 'object' && r[key].code) merged[key] = r[key].code;
else merged[key] = r[key];
}
}
}
}
return merged;
}
async function fetchGeo(ip) {
const apis = [
{ url: `https://get.geojs.io/v1/ip/geo/${encodeURIComponent(ip)}.json`, name: 'geojs' },
{ url: `https://free.freeipapi.com/api/json/${encodeURIComponent(ip)}`, name: 'freeipapi' },
{ url: `https://api.ipapi.is?q=${encodeURIComponent(ip)}`, name: 'ipapiis' }
];
let lastErr = '';
const promises = apis.map(async api => {
try {
const res = await fetch(api.url, { cache: 'no-store' });
if (!res.ok) { lastErr = `${api.name} HTTP ${res.status}`; return null; }
const data = await res.json();
if (!data) { lastErr = `${api.name} empty`; return null; }
if (data.success === false || data.error === true) { lastErr = `${api.name} error`; return null; }
if (!data.ip && !data.query && !data.ipAddress) { lastErr = `${api.name} no ip`; return null; }
return data;
} catch (e) { lastErr = `${api.name} ${e.message}`; return null; }
});
const results = (await Promise.all(promises)).filter(Boolean);
if (!results.length) throw new Error(lastErr || 'All geo endpoints failed');
return mergeData(results);
}
function countryName(cc) {
if (!cc) return '';
try { return new Intl.DisplayNames(['en'], { type: 'region' }).of(cc.toUpperCase()); } catch { return cc; }
}
const seenIPs = new Set();
let lastIP = null;
let currentData = null;
let lastRenderedIP = null;
let geoBusy = false;
let geoQueue = null;
let peerConnections = [];
function injectStyles() {
if (document.getElementById('gc-styles')) return;
if (!document.getElementById('gc-fonts')) {
const link = document.createElement('link');
link.id = 'gc-fonts';
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap';
document.head.appendChild(link);
}
const s = document.createElement('style');
s.id = 'gc-styles';
s.textContent = `
#gc-box{position:fixed;top:14px;right:14px;width:320px;background:rgba(11,15,20,.9);border:1px solid rgba(27,40,56,.6);color:#c8d6e0;border-radius:14px;padding:0;font-family:'Inter',system-ui,sans-serif;font-size:12px;z-index:2147483647;box-shadow:0 20px 60px rgba(0,0,0,.6),0 0 0 1px rgba(0,240,200,.06) inset;backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);line-height:1.5;overflow:hidden;}
#gc-hdr{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;border-bottom:1px solid rgba(27,40,56,.5);cursor:move;user-select:none;background:rgba(0,0,0,.15);}
#gc-hdr .gc-logo{display:flex;align-items:center;gap:8px;}
#gc-hdr .gc-icon{width:22px;height:22px;border-radius:5px;flex-shrink:0;animation:gcPulse 3s infinite;}
#gc-hdr .gc-title{color:${ACCENT};font-size:12px;font-weight:700;}
#gc-hdr .gc-ver{font-size:9px;color:${MUTED};background:rgba(0,240,200,.08);padding:1px 5px;border-radius:4px;margin-left:4px;}
#gc-hdr .gc-close{cursor:pointer;color:${MUTED};font-size:18px;line-height:1;padding:0 4px;transition:color .2s;}
#gc-hdr .gc-close:hover{color:${DANGER};}
#gc-body{padding:12px;}
.gc-row{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid rgba(27,40,56,.35);}
.gc-row:last-child{border-bottom:none;}
.gc-lbl{font-size:10px;color:${MUTED};text-transform:uppercase;letter-spacing:.04em;}
.gc-val{font-size:12px;color:#fff;text-align:right;word-break:break-word;max-width:65%;font-family:'JetBrains Mono',monospace;}
.gc-top{margin-bottom:10px;text-align:center;}
.gc-top .gc-big-ip{font-family:'JetBrains Mono',monospace;font-size:20px;color:#fff;font-weight:600;word-break:break-all;}
.gc-top .gc-sub{display:flex;align-items:center;justify-content:center;gap:5px;margin-top:4px;flex-wrap:wrap;}
.gc-top .gc-flag{font-size:18px;}
.gc-top .gc-loc{color:${MUTED};font-size:11px;}
.gc-badge{display:inline-flex;align-items:center;font-size:9px;font-weight:700;padding:2px 6px;border-radius:5px;border:1px solid;text-transform:uppercase;letter-spacing:.04em;}
.gc-badge.cc{background:rgba(0,240,200,.08);border-color:rgba(0,240,200,.25);color:${ACCENT};}
.gc-badge.clean{background:rgba(63,185,80,.08);border-color:rgba(63,185,80,.25);color:${OK};}
.gc-badge.warn{background:rgba(255,159,67,.08);border-color:rgba(255,159,67,.25);color:#ff9f43;}
.gc-badge.danger{background:rgba(255,71,87,.08);border-color:rgba(255,71,87,.25);color:${DANGER};}
.gc-actions{display:flex;gap:6px;margin-top:10px;}
.gc-actions button{flex:1;background:rgba(14,20,27,.6);border:1px solid rgba(27,40,56,.5);color:#c8d6e0;padding:7px 0;border-radius:8px;font-size:11px;font-weight:600;cursor:pointer;text-align:center;transition:all .2s ease;}
.gc-actions button:hover{border-color:rgba(0,240,200,.3);color:${ACCENT};background:rgba(0,240,200,.04);}
.gc-actions button.primary{background:linear-gradient(135deg,${ACCENT},${ACCENT2});color:#031411;border:none;font-weight:700;}
.gc-actions button.primary:hover{filter:brightness(1.15);color:#031411;}
.gc-wait{text-align:center;color:${MUTED};padding:20px 10px;font-size:11px;}
@keyframes gcFadeIn{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:translateY(0);}}
@keyframes gcPulse{0%{box-shadow:0 0 0 0 rgba(0,240,200,.35);}70%{box-shadow:0 0 0 8px rgba(0,240,200,0);}100%{box-shadow:0 0 0 0 rgba(0,240,200,0);}}
`;
document.head.appendChild(s);
}
function createUI() {
if ($('gc-box')) return;
injectStyles();
const box = document.createElement('div');
box.id = 'gc-box';
const saved = (() => { try { return JSON.parse(localStorage.getItem('gc_pos') || 'null'); } catch { return null; } })();
if (saved) { box.style.left = saved.l + 'px'; box.style.top = saved.t + 'px'; box.style.right = 'auto'; }
box.innerHTML = `
Waiting for peer connection...
`;
document.body.appendChild(box);
const hdr = $('gc-hdr');
let dragging = false, dx, dy;
hdr.addEventListener('mousedown', e => {
dragging = true;
const r = box.getBoundingClientRect();
dx = e.clientX - r.left;
dy = e.clientY - r.top;
});
document.addEventListener('mousemove', e => {
if (!dragging) return;
box.style.left = (e.clientX - dx) + 'px';
box.style.top = (e.clientY - dy) + 'px';
box.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
if (dragging) {
dragging = false;
try { localStorage.setItem('gc_pos', JSON.stringify({l: parseInt(box.style.left), t: parseInt(box.style.top)})); } catch {}
}
});
$('gc-x').addEventListener('click', () => box.remove());
}
function render(data) {
if (!data || !data.ip) return;
if (data.ip === lastRenderedIP && currentData) return;
currentData = data;
lastRenderedIP = data.ip;
if (data.location && typeof data.location === 'object') {
const loc = data.location;
if (!data.city && loc.city) data.city = loc.city;
if (!data.region && loc.state) data.region = loc.state;
if (!data.state && loc.state) data.state = loc.state;
if (!data.country && loc.country) data.country = loc.country;
if (!data.country_code && loc.country_code) data.country_code = loc.country_code;
if (!data.latitude && loc.latitude != null) data.latitude = loc.latitude;
if (!data.longitude && loc.longitude != null) data.longitude = loc.longitude;
if (!data.continent && loc.continent) data.continent = loc.continent;
}
const cc = esc((data.country_code || data.countryCode || data.country || '').toUpperCase());
const f = esc(flagEmoji(cc));
const cn = esc(countryName(cc) || data.country_name || data.country || 'Unknown');
const proxy = data.proxy ?? data.is_proxy ?? data.is_vpn ?? null;
const hosting = data.hosting ?? data.is_datacenter ?? null;
const tor = data.is_tor ?? null;
let threat = '';
if (proxy === true) threat += 'Proxy/VPN';
if (hosting === true) threat += 'Hosting';
if (tor === true) threat += 'Tor';
if (!threat && (proxy === false || hosting === false)) threat = 'Clean';
const tzRaw = data.timezone ?? data.location?.timezone ?? data.time_zone?.name ?? data.time_zone?.id ?? data.timeZone ?? (Array.isArray(data.timeZones) ? data.timeZones[0] : null);
const tz = esc((typeof tzRaw === 'string' ? tzRaw : tzRaw?.id ?? tzRaw?.name) || 'N/A');
const off = data.offset ?? data.timezone?.offset ?? data.time_zone?.offset ?? data.timezone_offset ?? data.timeZoneOffset ?? data.utc_offset ?? data.location?.utcoffset ?? null;
const curRaw = data.currency ?? data.location?.currency_code ?? (Array.isArray(data.currencies) ? data.currencies[0] : null);
const cur = esc((curRaw && typeof curRaw === 'object' ? curRaw.code : curRaw) || 'N/A');
const row = (l, v) => `${esc(l)}${esc(v)}
`;
$('gc-body').innerHTML = `
${esc(data.ip)}
${cc || '—'}
${threat}
${f}
${[data.city, data.region || data.regionName || data.state, cn].filter(Boolean).map(esc).join(', ')}
${row('ISP', data.organization_name || data.org || data.isp || 'N/A')}
${row('Timezone', tz)}
${row('UTC Offset', fmtOffset(off))}
${row('Currency', cur)}
${row('ASN', data.asn ? (String(data.asn).startsWith('AS') ? data.asn : 'AS' + data.asn) : data.as || 'N/A')}
`;
$('gc-copy').addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(data.ip);
} catch (e) {
const ta = document.createElement('textarea');
ta.value = data.ip;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
const btn = $('gc-copy'); btn.textContent = 'Copied'; setTimeout(() => btn.textContent = 'Copy IP', 1200);
});
const lat = parseFloat(data.latitude ?? data.lat);
const lon = parseFloat(data.longitude ?? data.lon);
const hasCoords = !isNaN(lat) && !isNaN(lon);
const mapBtn = $('gc-map');
if (hasCoords) {
mapBtn.addEventListener('click', () => window.open(`https://www.openstreetmap.org/?mlat=${lat}&mlon=${lon}#map=14/${lat}/${lon}`, '_blank'));
} else {
mapBtn.disabled = true; mapBtn.style.opacity = '.4'; mapBtn.style.cursor = 'not-allowed';
}
}
async function geo(ip) {
if (ip === lastRenderedIP && currentData) return;
createUI();
if (geoBusy) { geoQueue = ip; return; }
geoBusy = true;
const body = $('gc-body');
if (body && ip !== lastRenderedIP) body.innerHTML = `Found IP: ${esc(ip)}
Fetching geolocation...
`;
try {
const data = await fetchGeo(ip);
render(data);
} catch (e) {
console.warn('[GeoChecker] Geo fetch failed:', e.message);
if (body) body.innerHTML = 'Geo lookup failed. Retrying on next peer...
';
}
geoBusy = false;
if (geoQueue) { const next = geoQueue; geoQueue = null; geo(next); }
}
function checkCandidate(candidate, pc) {
const ip = extractIP(candidate);
if (!ip || seenIPs.has(ip)) return;
seenIPs.add(ip);
lastIP = ip;
const cnt = $('gc-count');
if (cnt) cnt.textContent = seenIPs.size + ' peer' + (seenIPs.size > 1 ? 's' : '');
geo(ip);
}
function cleanupPeerConnections() {
peerConnections = peerConnections.filter(pc => {
const state = pc.connectionState || pc.iceConnectionState;
return state !== 'closed' && state !== 'failed';
});
}
function checkSDP(sdp, pc) {
if (!sdp) return;
for (const line of sdp.split(/\r?\n/)) {
if (line.startsWith('a=candidate:')) checkCandidate(line, pc);
}
}
function hookInstance(pc) {
if (!pc || pc.__gc_hooked) return;
pc.__gc_hooked = true;
cleanupPeerConnections();
if (!peerConnections.includes(pc)) peerConnections.push(pc);
const orig = pc.addIceCandidate;
pc.addIceCandidate = function (candidate, ...rest) {
try { if (candidate && candidate.candidate) checkCandidate(candidate.candidate, pc); } catch {}
return orig.apply(this, arguments);
};
const origLocal = pc.setLocalDescription;
pc.setLocalDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) { checkSDP(desc.sdp, this); } } catch {}
return origLocal.apply(this, arguments);
};
const origRemote = pc.setRemoteDescription;
pc.setRemoteDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) { checkSDP(desc.sdp, this); } } catch {}
return origRemote.apply(this, arguments);
};
}
const GC_HOOK_VERSION = 3;
function hook() {
const NativeRTC = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
if (!NativeRTC) return;
if (!NativeRTC.prototype.__gc_hooked || NativeRTC.prototype.__gc_hooked < GC_HOOK_VERSION) {
NativeRTC.prototype.__gc_hooked = GC_HOOK_VERSION;
if (!NativeRTC.prototype.__gc_orig_addIceCandidate) NativeRTC.prototype.__gc_orig_addIceCandidate = NativeRTC.prototype.addIceCandidate;
if (!NativeRTC.prototype.__gc_orig_setLocalDescription) NativeRTC.prototype.__gc_orig_setLocalDescription = NativeRTC.prototype.setLocalDescription;
if (!NativeRTC.prototype.__gc_orig_setRemoteDescription) NativeRTC.prototype.__gc_orig_setRemoteDescription = NativeRTC.prototype.setRemoteDescription;
if (!NativeRTC.prototype.__gc_orig_createOffer) NativeRTC.prototype.__gc_orig_createOffer = NativeRTC.prototype.createOffer;
if (!NativeRTC.prototype.__gc_orig_createAnswer) NativeRTC.prototype.__gc_orig_createAnswer = NativeRTC.prototype.createAnswer;
NativeRTC.prototype.addIceCandidate = function (candidate, ...rest) {
try { if (candidate && candidate.candidate) checkCandidate(candidate.candidate, this); } catch {}
return NativeRTC.prototype.__gc_orig_addIceCandidate.apply(this, arguments);
};
NativeRTC.prototype.setLocalDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) checkSDP(desc.sdp, this); } catch {}
return NativeRTC.prototype.__gc_orig_setLocalDescription.apply(this, arguments);
};
NativeRTC.prototype.setRemoteDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) checkSDP(desc.sdp, this); } catch {}
return NativeRTC.prototype.__gc_orig_setRemoteDescription.apply(this, arguments);
};
NativeRTC.prototype.createOffer = function (...args) {
try { if (!peerConnections.includes(this)) { cleanupPeerConnections(); peerConnections.push(this); } } catch {}
return NativeRTC.prototype.__gc_orig_createOffer.apply(this, args);
};
NativeRTC.prototype.createAnswer = function (...args) {
try { if (!peerConnections.includes(this)) { cleanupPeerConnections(); peerConnections.push(this); } } catch {}
return NativeRTC.prototype.__gc_orig_createAnswer.apply(this, args);
};
}
if (!window.RTCPeerConnection || !window.RTCPeerConnection.__gc_ctor_hooked || window.RTCPeerConnection.__gc_ctor_hooked < GC_HOOK_VERSION) {
try {
const origCtor = NativeRTC;
const Wrapped = function (...args) {
const pc = (typeof Reflect !== 'undefined' && Reflect.construct)
? Reflect.construct(origCtor, args, new.target || Wrapped)
: new origCtor(...args);
hookInstance(pc);
return pc;
};
Wrapped.prototype = origCtor.prototype;
Object.setPrototypeOf(Wrapped, origCtor);
for (const k of Object.getOwnPropertyNames(origCtor)) { if (!Wrapped.hasOwnProperty(k)) try { Wrapped[k] = origCtor[k]; } catch {} }
Wrapped.__gc_ctor_hooked = GC_HOOK_VERSION;
window.RTCPeerConnection = Wrapped;
if (window.webkitRTCPeerConnection && window.webkitRTCPeerConnection !== Wrapped) window.webkitRTCPeerConnection = Wrapped;
if (window.mozRTCPeerConnection && window.mozRTCPeerConnection !== Wrapped) window.mozRTCPeerConnection = Wrapped;
} catch {}
}
function scan(obj, depth, seen) {
if (depth > 6 || !obj || typeof obj !== 'object') return;
if (seen.has(obj)) return; seen.add(obj);
try { if (obj.getStats && obj.addIceCandidate && (obj.setLocalDescription || obj.setRemoteDescription) && !obj.__gc_hooked) { hookInstance(obj); return; } } catch {}
try { for (const key of Object.keys(obj)) try { scan(obj[key], depth + 1, seen); } catch {} } catch {}
try {
const proto = Object.getPrototypeOf(obj);
if (proto && proto !== Object.prototype && proto !== Array.prototype) {
for (const key of Object.getOwnPropertyNames(proto)) {
try { scan(obj[key], depth + 1, seen); } catch {}
}
}
} catch {}
}
try { scan(window, 0, new WeakSet()); } catch {}
try {
for (const iframe of document.querySelectorAll('iframe')) {
if (iframe.contentWindow && iframe.contentWindow.RTCPeerConnection) {
const iRTC = iframe.contentWindow.RTCPeerConnection;
if (!iRTC.prototype.__gc_hooked || iRTC.prototype.__gc_hooked < GC_HOOK_VERSION) {
iRTC.prototype.__gc_hooked = GC_HOOK_VERSION;
if (!iRTC.prototype.__gc_orig_addIceCandidate) iRTC.prototype.__gc_orig_addIceCandidate = iRTC.prototype.addIceCandidate;
if (!iRTC.prototype.__gc_orig_setLocalDescription) iRTC.prototype.__gc_orig_setLocalDescription = iRTC.prototype.setLocalDescription;
if (!iRTC.prototype.__gc_orig_setRemoteDescription) iRTC.prototype.__gc_orig_setRemoteDescription = iRTC.prototype.setRemoteDescription;
iRTC.prototype.addIceCandidate = function (candidate, ...rest) {
try { if (candidate && candidate.candidate) checkCandidate(candidate.candidate, this); } catch {}
return iRTC.prototype.__gc_orig_addIceCandidate.apply(this, arguments);
};
iRTC.prototype.setLocalDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) checkSDP(desc.sdp, this); } catch {}
return iRTC.prototype.__gc_orig_setLocalDescription.apply(this, arguments);
};
iRTC.prototype.setRemoteDescription = function (desc, ...rest) {
try { if (desc && desc.sdp) checkSDP(desc.sdp, this); } catch {}
return iRTC.prototype.__gc_orig_setRemoteDescription.apply(this, arguments);
};
}
try {
for (const key of Object.keys(iframe.contentWindow)) {
const val = iframe.contentWindow[key];
if (val && typeof val === 'object' && val.addIceCandidate && !val.__gc_hooked) hookInstance(val);
}
} catch {}
}
}
} catch {}
}
setInterval(hook, 3000);
hook();
let lastUrl = location.href;
setInterval(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
seenIPs.clear();
lastIP = null;
currentData = null;
lastRenderedIP = null;
geoBusy = false;
geoQueue = null;
peerConnections = [];
window.__gc_deep_scan_done = false;
const body = $('gc-body');
if (body) body.innerHTML = 'Waiting for peer connection...
';
hook();
}
}, 2000);
createUI();
console.warn('[GeoChecker] Console inject v5.0 loaded. Waiting for WebRTC peer...');
})();