// ─── Safe Mode (Recording Mode for Streamers/Bloggers) ───────────────────── // Replaces gambling terms with YouTube-safe synonyms const SafeMode = (() => { const STORAGE_KEY = 'safe_mode'; const DICT = [ // Currency [/₽(?=\s*\d)/g, 'тугриков'], [/(\d+)\s*₽/g, (_, n) => { const num = parseInt(n); const last = num % 10; const lastTwo = num % 100; if (lastTwo >= 11 && lastTwo <= 19) return n + ' тугриков'; if (last === 1) return n + ' тугрик'; if (last >= 2 && last <= 4) return n + ' тугрика'; return n + ' тугриков'; }], [/₽(?!\d)/g, 'тугриков'], // Cases [/\b(открыть|открывай|открыл)\s+кейс/gi, (m) => m.replace(/кейс/i, 'бокс')], [/\bкейс[а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'кейс') return 'бокс'; if (lower === 'кейса') return 'бокса'; if (lower === 'кейсу') return 'боксу'; if (lower === 'кейсом') return 'боксом'; if (lower === 'кейсе') return 'боксе'; if (lower === 'кейсы') return 'боксы'; if (lower === 'кейсов') return 'боксов'; if (lower === 'кейсам') return 'боксам'; if (lower === 'кейсами') return 'боксами'; if (lower === 'кейсах') return 'боксах'; return m; }], // Case (English) [/\bcase\b/gi, 'box'], // Skins [/\bскин[а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'скин') return 'облик'; if (lower === 'скина') return 'облика'; if (lower === 'скину') return 'облику'; if (lower === 'скином') return 'обликом'; if (lower === 'скине') return 'облике'; if (lower === 'скины' || lower === 'скин') return 'облики'; if (lower === 'скинов') return 'обликов'; if (lower === 'скинам') return 'обликам'; if (lower === 'скинами') return 'обликами'; if (lower === 'скинах') return 'обликах'; return m; }], // Contract [/\bконтракт[а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'контракт') return 'сделка'; if (lower === 'контракта') return 'сделки'; if (lower === 'контракту') return 'сделке'; if (lower === 'контрактом') return 'сделкой'; if (lower === 'контракте') return 'сделке'; if (lower === 'контракты' || lower === 'контракт') return 'сделки'; if (lower === 'контрактов') return 'сделок'; if (lower === 'контрактам') return 'сделкам'; if (lower === 'контрактами') return 'сделками'; if (lower === 'контрактах') return 'сделках'; if (lower === 'контрактная' || lower === 'контрактный' || lower === 'контрактное') return 'договорная'; return m; }], // Upgrade [/\bапгрейд[а-я]*\b/gi, (m) => { if (m.toLowerCase() === 'апгрейд') return 'улучшение'; if (m.toLowerCase() === 'апгрейда') return 'улучшения'; if (m.toLowerCase() === 'апгрейду') return 'улучшению'; if (m.toLowerCase() === 'апгрейдом') return 'улучшением'; if (m.toLowerCase() === 'апгрейде') return 'улучшении'; if (m.toLowerCase() === 'апгрейды') return 'улучшения'; if (m.toLowerCase() === 'апгрейдов') return 'улучшений'; return m; }], [/\bupgrade\b/gi, 'upgrade'], // Float [/\bfloat\b/gi, 'состояние'], // Rarity [/\bредкост[ьи][а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'редкость') return 'класс'; if (lower === 'редкости') return 'классы'; if (lower === 'редкостью') return 'классом'; if (lower === 'редкостей') return 'классов'; if (lower === 'редкостям') return 'классам'; return m; }], // Chance [/\bшанс[а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'шанс') return 'вероятность'; if (lower === 'шанса') return 'вероятности'; if (lower === 'шансу') return 'вероятности'; if (lower === 'шансом') return 'вероятностью'; if (lower === 'шансе') return 'вероятности'; if (lower === 'шансы') return 'вероятности'; if (lower === 'шансов') return 'вероятностей'; return m; }], // Bet [/\bставк[а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'ставка') return 'вход'; if (lower === 'ставки') return 'входы'; if (lower === 'ставку') return 'вход'; if (lower === 'ставкой') return 'входом'; if (lower === 'ставок') return 'входов'; if (lower === 'ставкам') return 'входам'; return m; }], // Win / Lose [/\bвыигрыш[а-я]*\b/gi, (m) => { if (m.toLowerCase() === 'выигрыш' || m.toLowerCase() === 'выигрыша') return 'приз'; if (m.toLowerCase() === 'выигрышу') return 'призу'; if (m.toLowerCase() === 'выигрышем') return 'призом'; if (m.toLowerCase() === 'выигрыше') return 'призе'; return m; }], [/\b(выиграл|выиграла|выиграли)\b/gi, (m) => { if (m.toLowerCase() === 'выиграл' || m.toLowerCase() === 'выиграла') return 'получил(a)'; if (m.toLowerCase() === 'выиграли') return 'получили'; return m; }], // Lose [/\bпроиграл[а-я]*\b/gi, 'не получилось'], // Crash game [/\b(краш|crash)\b/gi, 'риск-игра'], // Open case [/\bоткры[тв][а-я]+\s+кейс/gi, (m) => m.replace(/кейс/i, 'бокс')], // Wear [/\bизнос\b/gi, 'состояние'], // Probability display [/\bвероятность\b/gi, 'шанс'], // Quick mode tooltips [/\bбыстрый режим\b/gi, 'турбо-режим'], // Balance [/\bбаланс\b/gi, 'счёт'], // Sell [/\bпрода[жв][а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'продажа' || lower === 'продать') return 'обменять'; if (lower === 'продал') return 'обменял'; if (lower === 'продайте') return 'обменяйте'; return m; }], // Inventory [/\bинвентар[ьи][а-я]*\b/gi, (m) => { const lower = m.toLowerCase(); if (lower === 'инвентарь') return 'коллекция'; if (lower === 'инвентаря') return 'коллекции'; if (lower === 'инвентаре') return 'коллекции'; if (lower === 'инвентарём') return 'коллекцией'; return m; }], // Trade up [/\btrade.?up\b/gi, 'treyd-ap'], // Premium [/\bпремиум\b/gi, 'эксклюзив'], // Rare names in English [/\bcovert\b/gi, 'covert'], [/\bclassified\b/gi, 'classified'], [/\bconsumers?\b/gi, 'consumer'], [/\bindustrials?\b/gi, 'industrial'], [/\bmil-spec\b/gi, 'mil-spec'], [/\brestricted\b/gi, 'restricted'], ]; let observer = null; let active = false; function isActive() { return localStorage.getItem(STORAGE_KEY) === 'true'; } function setActive(val) { localStorage.setItem(STORAGE_KEY, val ? 'true' : 'false'); active = val; } function replaceText(node) { if (node.nodeType === Node.TEXT_NODE) { let text = node.textContent; let changed = false; for (const [pattern, replacement] of DICT) { const newText = text.replace(pattern, replacement); if (newText !== text) { text = newText; changed = true; } } if (changed) { node.textContent = text; } } else if (node.nodeType === Node.ELEMENT_NODE) { // Don't process script, style, input, textarea, canvas elements const tag = node.tagName.toLowerCase(); if (tag === 'script' || tag === 'style' || tag === 'input' || tag === 'textarea' || tag === 'canvas' || tag === 'svg' || tag === 'code' || tag === 'pre') { return; } // Process title and alt attributes if (node.hasAttribute('title')) { let t = node.getAttribute('title'); for (const [pattern, replacement] of DICT) { t = t.replace(pattern, replacement); } node.setAttribute('title', t); } if (node.hasAttribute('alt')) { let a = node.getAttribute('alt'); for (const [pattern, replacement] of DICT) { a = a.replace(pattern, replacement); } node.setAttribute('alt', a); } // Process children for (let i = 0; i < node.childNodes.length; i++) { replaceText(node.childNodes[i]); } } } function apply() { replaceText(document.body); // Update document title if (document.title) { let t = document.title; for (const [pattern, replacement] of DICT) { t = t.replace(pattern, replacement); } document.title = t; } // Update safe mode button appearance const btn = document.getElementById('safeModeToggle'); if (btn) { btn.textContent = active ? '🛡️' : '🎙️'; btn.title = active ? 'Режим записи активен' : 'Режим записи'; btn.style.borderColor = active ? 'var(--success-color)' : ''; } } function startObserver() { if (observer) observer.disconnect(); observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { replaceText(node); } else if (node.nodeType === Node.TEXT_NODE) { replaceText(node); } } } }); observer.observe(document.body, { childList: true, subtree: true, characterData: true }); } function toggle() { active = !isActive(); setActive(active); if (active) { apply(); startObserver(); } else { if (observer) { observer.disconnect(); observer = null; } // Reload to restore original text location.reload(); } return active; } function init() { active = isActive(); if (active) { // Wait for DOM to be ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { apply(); startObserver(); }); } else { apply(); startObserver(); } } // Set initial button state const btn = document.getElementById('safeModeToggle'); if (btn) { btn.textContent = active ? '🛡️' : '🎙️'; btn.title = active ? 'Режим записи активен' : 'Режим записи'; if (active) btn.style.borderColor = 'var(--success-color)'; } } return { init, toggle, isActive }; })(); // Global toggle function for onclick in navbars function toggleSafeMode() { SafeMode.toggle(); } // Auto-init if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => SafeMode.init()); } else { SafeMode.init(); }