mirror of
https://github.com/deadcxap/bs-overlay.git
synced 2026-07-02 05:43:39 +03:00
Add files via upload
add eng localization
This commit is contained in:
+129
-33
@@ -35,7 +35,7 @@
|
|||||||
#app-container {
|
#app-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
display: flex; /* Скрывается/показывается через JS */
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
<img id="bl-avatar" src="" alt="Avatar">
|
<img id="bl-avatar" src="" alt="Avatar">
|
||||||
</div>
|
</div>
|
||||||
<div id="bl-info">
|
<div id="bl-info">
|
||||||
<div id="bl-name">Loading...</div>
|
<div id="bl-name" data-i18n="loading">Loading...</div>
|
||||||
<div class="bl-stat-compact">Global: <span id="bl-global">#--</span></div>
|
<div class="bl-stat-compact">Global: <span id="bl-global">#--</span></div>
|
||||||
<div class="bl-stat-compact">Local: <span id="bl-local">#--</span></div>
|
<div class="bl-stat-compact">Local: <span id="bl-local">#--</span></div>
|
||||||
<div class="bl-stat-compact">PP: <span id="bl-pp">-- pp</span></div>
|
<div class="bl-stat-compact">PP: <span id="bl-pp">-- pp</span></div>
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
<img id="cover" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" alt="Cover">
|
<img id="cover" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" alt="Cover">
|
||||||
</div>
|
</div>
|
||||||
<div id="text-block">
|
<div id="text-block">
|
||||||
<div id="title">Waiting for song...</div>
|
<div id="title" data-i18n="waitingSong">Waiting for song...</div>
|
||||||
<div id="artist-mapper">-</div>
|
<div id="artist-mapper">-</div>
|
||||||
<div id="meta-line">
|
<div id="meta-line">
|
||||||
<span id="difficulty">-</span>
|
<span id="difficulty">-</span>
|
||||||
@@ -453,13 +453,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="settings-modal">
|
<div id="settings-modal">
|
||||||
<h2>SYSTEM SETUP [F2]</h2>
|
<h2 data-i18n="sysSetup">SYSTEM SETUP [F2]</h2>
|
||||||
|
|
||||||
|
<div class="setting-row">
|
||||||
|
<label style="font-size: 12px; color: #ccc;" data-i18n="langLabel">Language / Язык</label>
|
||||||
|
<div class="radio-grid">
|
||||||
|
<label class="radio-label"><input type="radio" name="lang" value="en"> English</label>
|
||||||
|
<label class="radio-label"><input type="radio" name="lang" value="ru"> Русский</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<label style="font-size: 12px; color: #ccc;">WebSocket URL</label>
|
<label style="font-size: 12px; color: #ccc;">WebSocket URL</label>
|
||||||
<input type="text" id="inp-ws" placeholder="ws://127.0.0.1:2947/socket">
|
<input type="text" id="inp-ws" placeholder="ws://127.0.0.1:2947/socket">
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<label style="font-size: 12px; color: #ccc;">Layout (Выравнивание)</label>
|
<label style="font-size: 12px; color: #ccc;" data-i18n="layoutLabel">Layout</label>
|
||||||
<div class="radio-grid">
|
<div class="radio-grid">
|
||||||
<label class="radio-label"><input type="radio" name="layout" value="top-left"> Top Left</label>
|
<label class="radio-label"><input type="radio" name="layout" value="top-left"> Top Left</label>
|
||||||
<label class="radio-label"><input type="radio" name="layout" value="top-right"> Top Right</label>
|
<label class="radio-label"><input type="radio" name="layout" value="top-right"> Top Right</label>
|
||||||
@@ -468,40 +477,92 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<label style="font-size: 12px; color: #ccc;">Scale (0.5 - 2.0)</label>
|
<label style="font-size: 12px; color: #ccc;" data-i18n="scaleLabel">Scale</label>
|
||||||
<input type="number" step="0.1" id="inp-scale">
|
<input type="number" step="0.1" id="inp-scale">
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<label style="font-size: 12px; color: #ccc;">BeatLeader ID / Nickname</label>
|
<label style="font-size: 12px; color: #ccc;" data-i18n="blLabel">BeatLeader ID / Nickname</label>
|
||||||
<input type="text" id="inp-bl" placeholder="Например: 76561198029377687">
|
<input type="text" id="inp-bl">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<label style="font-size: 12px; color: #ccc; margin-top: 5px;">Модули отображения (Вкл/Выкл)</label>
|
<label style="font-size: 12px; color: #ccc; margin-top: 5px;" data-i18n="modulesLabel">Display Modules</label>
|
||||||
<div class="modules-grid">
|
<div class="modules-grid">
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-bl"> BeatLeader Меню</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-bl"> <span data-i18n="modBl">BeatLeader Menu</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-cover"> Обложка трека</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-cover"> <span data-i18n="modCover">Track Cover</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-title"> Название трека</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-title"> <span data-i18n="modTitle">Track Title</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-artist"> Исполнитель / Маппер</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-artist"> <span data-i18n="modArtist">Artist / Mapper</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-meta"> Сложность и BPM</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-meta"> <span data-i18n="modMeta">Difficulty & BPM</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-bsr"> BSR код и Дата</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-bsr"> <span data-i18n="modBsr">BSR & Date</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-progress"> Прогресс-бар</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-progress"> <span data-i18n="modProg">Progress Bar</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-hp"> HP Бар (Здоровье)</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-hp"> <span data-i18n="modHp">HP Bar</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-stats"> Miss / Combo</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-stats"> <span data-i18n="modStats">Miss / Combo</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-acc"> Точность (Acc)</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-acc"> <span data-i18n="modAcc">Accuracy (Acc)</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-glow-avatar"> Неоновое свечение</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-glow-avatar"> <span data-i18n="modGlow">Neon Glow</span></label>
|
||||||
<label class="checkbox-row"><input type="checkbox" id="inp-show-debug"> Debug сообщения</label>
|
<label class="checkbox-row"><input type="checkbox" id="inp-show-debug"> <span data-i18n="modDebug">Debug Msgs</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<button onclick="saveSettings()">APPLY & RECONNECT</button>
|
<button onclick="saveSettings()" data-i18n="applyBtn">APPLY & RECONNECT</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="debug">System init...</div>
|
<div id="debug">System init...</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// === TRANSLATIONS / ЛОКАЛИЗАЦИЯ ===
|
||||||
|
const i18n = {
|
||||||
|
en: {
|
||||||
|
sysSetup: "SYSTEM SETUP [F2]",
|
||||||
|
langLabel: "Language / Язык",
|
||||||
|
layoutLabel: "Layout (Alignment)",
|
||||||
|
scaleLabel: "Scale (0.5 - 2.0)",
|
||||||
|
blLabel: "BeatLeader ID / Nickname",
|
||||||
|
blPlaceholder: "Example: 76561198029377687",
|
||||||
|
modulesLabel: "Display Modules (On/Off)",
|
||||||
|
modBl: "BeatLeader Menu",
|
||||||
|
modCover: "Track Cover",
|
||||||
|
modTitle: "Track Title",
|
||||||
|
modArtist: "Artist / Mapper",
|
||||||
|
modMeta: "Difficulty & BPM",
|
||||||
|
modBsr: "BSR Code & Date",
|
||||||
|
modProg: "Progress Bar",
|
||||||
|
modHp: "HP Bar (Health)",
|
||||||
|
modStats: "Miss / Combo",
|
||||||
|
modAcc: "Accuracy (Acc)",
|
||||||
|
modGlow: "Neon Glow",
|
||||||
|
modDebug: "Debug Messages",
|
||||||
|
applyBtn: "APPLY & RECONNECT",
|
||||||
|
waitingSong: "Waiting for song...",
|
||||||
|
loading: "Loading..."
|
||||||
|
},
|
||||||
|
ru: {
|
||||||
|
sysSetup: "СИСТЕМНЫЕ НАСТРОЙКИ [F2]",
|
||||||
|
langLabel: "Язык / Language",
|
||||||
|
layoutLabel: "Выравнивание (Layout)",
|
||||||
|
scaleLabel: "Масштаб (0.5 - 2.0)",
|
||||||
|
blLabel: "BeatLeader ID / Никнейм",
|
||||||
|
blPlaceholder: "Например: 76561198029377687",
|
||||||
|
modulesLabel: "Модули отображения (Вкл/Выкл)",
|
||||||
|
modBl: "BeatLeader Меню",
|
||||||
|
modCover: "Обложка трека",
|
||||||
|
modTitle: "Название трека",
|
||||||
|
modArtist: "Исполнитель / Маппер",
|
||||||
|
modMeta: "Сложность и BPM",
|
||||||
|
modBsr: "BSR код и Дата",
|
||||||
|
modProg: "Прогресс-бар",
|
||||||
|
modHp: "HP Бар (Здоровье)",
|
||||||
|
modStats: "Промахи и Комбо",
|
||||||
|
modAcc: "Точность (Acc)",
|
||||||
|
modGlow: "Неоновое свечение",
|
||||||
|
modDebug: "Сообщения отладки",
|
||||||
|
applyBtn: "ПРИМЕНИТЬ И ПЕРЕПОДКЛЮЧИТЬ",
|
||||||
|
waitingSong: "Ожидание трека...",
|
||||||
|
loading: "Загрузка..."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const els = {
|
const els = {
|
||||||
app: document.getElementById('app-container'),
|
app: document.getElementById('app-container'),
|
||||||
menuOverlay: document.getElementById('menu-overlay'),
|
menuOverlay: document.getElementById('menu-overlay'),
|
||||||
@@ -543,6 +604,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
let config = {
|
let config = {
|
||||||
|
lang: 'ru', // Язык по умолчанию
|
||||||
ws: 'ws://127.0.0.1:2947/socket',
|
ws: 'ws://127.0.0.1:2947/socket',
|
||||||
layout: 'top-left',
|
layout: 'top-left',
|
||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
@@ -567,12 +629,10 @@
|
|||||||
let debugTimeout = null;
|
let debugTimeout = null;
|
||||||
let duration = 0;
|
let duration = 0;
|
||||||
|
|
||||||
// Переменные для BeatLeader
|
|
||||||
let lastBlFetch = 0;
|
let lastBlFetch = 0;
|
||||||
let isFetchingBL = false;
|
let isFetchingBL = false;
|
||||||
let currentProxyIdx = 0;
|
let currentProxyIdx = 0;
|
||||||
|
|
||||||
// Массив прокси (первый элемент пустой - попытка загрузки напрямую, т.к. API BL поддерживает CORS)
|
|
||||||
const proxies = [
|
const proxies = [
|
||||||
"",
|
"",
|
||||||
"https://api.codetabs.com/v1/proxy?quest=",
|
"https://api.codetabs.com/v1/proxy?quest=",
|
||||||
@@ -581,16 +641,42 @@
|
|||||||
"https://thingproxy.freeboard.io/fetch/"
|
"https://thingproxy.freeboard.io/fetch/"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function applyLanguage() {
|
||||||
|
const t = i18n[config.lang];
|
||||||
|
|
||||||
|
// Проверяем, стоят ли сейчас плейсхолдеры, или уже загружены реальные данные
|
||||||
|
const isDefaultTitle = els.title.textContent === i18n.en.waitingSong || els.title.textContent === i18n.ru.waitingSong || els.title.textContent === "Waiting for song...";
|
||||||
|
const isDefaultLoading = els.blName.textContent === i18n.en.loading || els.blName.textContent === i18n.ru.loading || els.blName.textContent === "Loading...";
|
||||||
|
|
||||||
|
// Замена текстов во всех элементах с data-i18n
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||||
|
const key = el.getAttribute('data-i18n');
|
||||||
|
if (t[key]) {
|
||||||
|
// Пропускаем динамические поля, если в них уже есть данные игрока или трека
|
||||||
|
if (el.id === 'title' && !isDefaultTitle) return;
|
||||||
|
if (el.id === 'bl-name' && !isDefaultLoading) return;
|
||||||
|
|
||||||
|
el.textContent = t[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Плейсхолдеры
|
||||||
|
document.getElementById('inp-bl').placeholder = t.blPlaceholder;
|
||||||
|
|
||||||
|
// Динамический HTML атрибут
|
||||||
|
document.documentElement.lang = config.lang;
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
els.app.style.display = 'none';
|
els.app.style.display = 'none';
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
applyLanguage();
|
||||||
applyLayout();
|
applyLayout();
|
||||||
applyModules();
|
applyModules();
|
||||||
applyGlow();
|
applyGlow();
|
||||||
connectWS();
|
connectWS();
|
||||||
|
|
||||||
// Фоновое обновление профиля каждые 15 минут
|
|
||||||
setInterval(() => fetchBL(), 900000);
|
setInterval(() => fetchBL(), 900000);
|
||||||
|
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
@@ -611,7 +697,6 @@
|
|||||||
document.getElementById('inp-glow-avatar').checked = config.glowAvatar !== false;
|
document.getElementById('inp-glow-avatar').checked = config.glowAvatar !== false;
|
||||||
|
|
||||||
document.getElementById('inp-show-cover').checked = config.showCover !== false;
|
document.getElementById('inp-show-cover').checked = config.showCover !== false;
|
||||||
|
|
||||||
document.getElementById('inp-show-title').checked = config.showTitle !== false;
|
document.getElementById('inp-show-title').checked = config.showTitle !== false;
|
||||||
document.getElementById('inp-show-artist').checked = config.showArtist !== false;
|
document.getElementById('inp-show-artist').checked = config.showArtist !== false;
|
||||||
document.getElementById('inp-show-meta').checked = config.showMeta !== false;
|
document.getElementById('inp-show-meta').checked = config.showMeta !== false;
|
||||||
@@ -622,8 +707,11 @@
|
|||||||
document.getElementById('inp-show-stats').checked = config.showStats !== false;
|
document.getElementById('inp-show-stats').checked = config.showStats !== false;
|
||||||
document.getElementById('inp-show-acc').checked = config.showAcc !== false;
|
document.getElementById('inp-show-acc').checked = config.showAcc !== false;
|
||||||
|
|
||||||
const radio = document.querySelector(`input[name="layout"][value="${config.layout}"]`);
|
const layoutRadio = document.querySelector(`input[name="layout"][value="${config.layout}"]`);
|
||||||
if(radio) radio.checked = true;
|
if(layoutRadio) layoutRadio.checked = true;
|
||||||
|
|
||||||
|
const langRadio = document.querySelector(`input[name="lang"][value="${config.lang}"]`);
|
||||||
|
if(langRadio) langRadio.checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
@@ -636,7 +724,6 @@
|
|||||||
config.glowAvatar = document.getElementById('inp-glow-avatar').checked;
|
config.glowAvatar = document.getElementById('inp-glow-avatar').checked;
|
||||||
|
|
||||||
config.showCover = document.getElementById('inp-show-cover').checked;
|
config.showCover = document.getElementById('inp-show-cover').checked;
|
||||||
|
|
||||||
config.showTitle = document.getElementById('inp-show-title').checked;
|
config.showTitle = document.getElementById('inp-show-title').checked;
|
||||||
config.showArtist = document.getElementById('inp-show-artist').checked;
|
config.showArtist = document.getElementById('inp-show-artist').checked;
|
||||||
config.showMeta = document.getElementById('inp-show-meta').checked;
|
config.showMeta = document.getElementById('inp-show-meta').checked;
|
||||||
@@ -647,16 +734,25 @@
|
|||||||
config.showStats = document.getElementById('inp-show-stats').checked;
|
config.showStats = document.getElementById('inp-show-stats').checked;
|
||||||
config.showAcc = document.getElementById('inp-show-acc').checked;
|
config.showAcc = document.getElementById('inp-show-acc').checked;
|
||||||
|
|
||||||
const checkedRadio = document.querySelector('input[name="layout"]:checked');
|
const checkedLayout = document.querySelector('input[name="layout"]:checked');
|
||||||
if(checkedRadio) config.layout = checkedRadio.value;
|
if(checkedLayout) config.layout = checkedLayout.value;
|
||||||
|
|
||||||
|
const checkedLang = document.querySelector('input[name="lang"]:checked');
|
||||||
|
if(checkedLang) config.lang = checkedLang.value;
|
||||||
|
|
||||||
localStorage.setItem('bsCyberConfig', JSON.stringify(config));
|
localStorage.setItem('bsCyberConfig', JSON.stringify(config));
|
||||||
els.settings.classList.remove('show');
|
els.settings.classList.remove('show');
|
||||||
|
|
||||||
|
applyLanguage();
|
||||||
applyLayout();
|
applyLayout();
|
||||||
applyModules();
|
applyModules();
|
||||||
applyGlow();
|
applyGlow();
|
||||||
connectWS();
|
connectWS();
|
||||||
|
|
||||||
|
// ПРИНУДИТЕЛЬНО обновляем данные BeatLeader при сохранении настроек
|
||||||
|
if (config.showBL) {
|
||||||
|
fetchBL(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyLayout() {
|
function applyLayout() {
|
||||||
@@ -855,11 +951,11 @@
|
|||||||
showDebug(`BL Profile Loaded Successfully!`);
|
showDebug(`BL Profile Loaded Successfully!`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
attempts++;
|
attempts++;
|
||||||
currentProxyIdx++; // Пробуем следующий прокси
|
currentProxyIdx++;
|
||||||
showDebug(`BL Error: ${err.message}. Retrying...`);
|
showDebug(`BL Error: ${err.message}. Retrying...`);
|
||||||
|
|
||||||
if (attempts < maxAttempts) {
|
if (attempts < maxAttempts) {
|
||||||
await new Promise(r => setTimeout(r, 2000)); // Задержка 2 сек перед следующей попыткой
|
await new Promise(r => setTimeout(r, 2000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user