Files

348 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ─── 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();
}