Security fixes: - Block /proc /sys /dev /run /boot in /api/browse-dirs (path traversal) - Verify yt-dlp output stays inside TEMP_DIR before registration - Remove Access-Control-Allow-Origin: * from /api/proxy-audio - TTL-based temp file registry (default 2h) to prevent disk fill Performance: - Cache settings + routing rules in memory (mtime-checked); eliminates per-request disk reads on every TTS call UI: - Add container name (optional) field to Docker stack TTS/STT engine cards (Qwen3 Voice Clone, Voice Design, Custom Voice, Streaming, NVIDIA Magpie, Parakeet) — enables Stop/Start/Restart buttons on all engine cards, matching the existing Other Local TTS/STT cards Refactor — backend: - server.py: 5560 lines → 43-line entry point - core/ package: constants, registry, validation, docker_client, config, routing, audio, voice, presets, tts_helpers - routes/ package: admin, settings, library, stt, sources, docker, tts, conversation (FastAPI APIRouter modules) - Dockerfile + docker-compose.yml updated to include core/ and routes/ Refactor — frontend: - static/app.js: 8744 lines → 16 modules in static/js/ utils, voice-inspector, voice-sources, integrations, routing, settings, voice-clone, voice-library, tts-preview, benchmark, stt, init, engines, ai-backends, generation, conversation - static/loader.js updated to load modules sequentially Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
2.0 KiB
JavaScript
57 lines
2.0 KiB
JavaScript
(async function () {
|
|
'use strict';
|
|
|
|
const SECTIONS = ['s-voices', 's-clone', 's-design', 's-studio', 's-tryout', 's-performance', 's-routing', 's-connect', 's-settings', 's-llms', 's-conversation'];
|
|
|
|
function loadScript(src) {
|
|
return new Promise(function (resolve, reject) {
|
|
var s = document.createElement('script');
|
|
s.src = src;
|
|
s.onload = resolve;
|
|
s.onerror = function () { reject(new Error('Failed to load ' + src)); };
|
|
document.body.appendChild(s);
|
|
});
|
|
}
|
|
|
|
// 1. Fetch all section partials in parallel and inject into their shells
|
|
await Promise.all(SECTIONS.map(async function (id) {
|
|
try {
|
|
var res = await fetch('/static/sections/' + id + '.html');
|
|
if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
|
|
var html = await res.text();
|
|
var el = document.getElementById(id);
|
|
if (el) el.innerHTML = html;
|
|
} catch (e) {
|
|
console.error('[loader] section', id, 'failed:', e.message);
|
|
var el = document.getElementById(id);
|
|
if (el) el.innerHTML = '<p style="color:var(--red);padding:24px">Failed to load section <b>' + id + '</b>: ' + e.message + '</p>';
|
|
}
|
|
}));
|
|
|
|
// 2. Load main application logic (runs init immediately on parse — sections must exist first)
|
|
const JS_MODULES = [
|
|
'/static/js/utils.js',
|
|
'/static/js/voice-inspector.js',
|
|
'/static/js/voice-sources.js',
|
|
'/static/js/integrations.js',
|
|
'/static/js/routing.js',
|
|
'/static/js/settings.js',
|
|
'/static/js/voice-clone.js',
|
|
'/static/js/voice-library.js',
|
|
'/static/js/tts-preview.js',
|
|
'/static/js/benchmark.js',
|
|
'/static/js/stt.js',
|
|
'/static/js/init.js',
|
|
'/static/js/engines.js',
|
|
'/static/js/ai-backends.js',
|
|
'/static/js/generation.js',
|
|
'/static/js/conversation.js',
|
|
];
|
|
for (const src of JS_MODULES) {
|
|
await loadScript(src);
|
|
}
|
|
|
|
// 3. Apply scroll-based navigation overrides (must run after app.js defines switchTab etc.)
|
|
await loadScript('/static/nav.js');
|
|
})();
|