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>
6.5 KiB
Changelog
All notable changes to TTS Voice Creator — Clone and Design are documented here. Format follows Keep a Changelog.
[Unreleased] — 2026-05-29
Security
-
Fixed path traversal in
/api/browse-dirs— Added a_BROWSE_BLOCKEDblocklist (/proc,/sys,/dev,/run,/boot). Requests for paths under these directories now return HTTP 403 instead of listing kernel/system files. -
Hardened yt-dlp output path — After a YouTube download completes the resolved output path is verified to be inside
TEMP_DIRwith.relative_to(). A file written outside the temp directory is rejected with an SSE error event and never registered. -
Removed CORS wildcard on
/api/proxy-audio— TheAccess-Control-Allow-Origin: *header was unnecessary (all callers are same-origin) and exposed proxied audio to arbitrary cross-origin requests. Header removed. -
Temp file registry now enforces a TTL —
_registryis now adict[str, tuple[Path, float]]storing each entry with a creation timestamp._registry_gc()evicts entries older thanTEMP_FILE_TTL_SECONDS(default 2 hours, configurable via env var) and unlinks their files, preventing unbounded disk growth.
Performance
- Settings and routing rules cached in memory —
_load_settings()and_load_tts_routes()previously read from disk on every API request. Both now use mtime-checked in-memory caches (_settings_cache,_routes_cache) that are invalidated automatically on write. Eliminates dozens of redundant file reads per TTS synthesis call.
Added
- Container name field on Docker stack TTS/STT cards — The engine cards rendered
dynamically in the Engines → Text to Speech and Engines → Speech to Text sections
(Qwen3 Voice Clone, Voice Design, Custom Voice, Streaming, NVIDIA Magpie, Parakeet ASR)
now show the same container name (optional) input row that the Other Local TTS/STT
cards already had. Typing a container name immediately enables Stop / Start / Restart
buttons wired to the Docker API. The static STT cards (faster-whisper-server,
whisper.cpp) received the same treatment via
initStaticDockerManagement().
Refactored
Backend — server.py split into core/ + routes/ packages
server.py went from 5,560 lines to a 43-line entry point that creates the
FastAPI app, registers routers, and mounts static files. All logic was extracted into
single-responsibility modules:
core/ — pure utilities (no FastAPI decorators)
| Module | Responsibility |
|---|---|
constants.py |
Boot-time env defaults, CONFIG_DIR/CONFIG_FILE/STATIC_DIR paths, in-memory log buffer |
registry.py |
TEMP_DIR, TTL-based temp file registry (_registry_put/get/gc) |
validation.py |
_validate_http_url, _normalize_service_url, _copy_limited, _safe_child_path |
docker_client.py |
Raw Unix-socket Docker HTTP client (_docker_get_json, _docker_post) |
config.py |
Settings load/save/normalize, TTS stability helpers, backend URL resolution |
routing.py |
TTS route rules load/save/resolve, language detection, routing log |
audio.py |
_to_wav_24k/16k, _trim, _duration, _normalize_segment, auto-trim scoring |
voice.py |
Voice metadata helpers, backup management, benchmark helpers |
presets.py |
Voice Design preset load/save, virtual voice resolution |
tts_helpers.py |
TTS request helpers, streaming, NVIDIA/VibeVoice/XTTS backends, audio proxy |
routes/ — FastAPI APIRouter modules
| Module | Routes |
|---|---|
admin.py |
GET /, GET /favicon.ico, GET /api/browse-dirs, GET /robots.txt |
settings.py |
/api/settings, /api/tts-routes, /api/tts-routing-log, /api/logs, /api/voice-design-presets |
library.py |
All /api/voice* and /api/voices*, /api/save, /api/upload, /api/route-sounds*, /api/audio/{fid}, /api/auto-trim, /api/process |
stt.py |
/api/stt-backends, /api/transcribe, /api/transcribe-bytes |
sources.py |
/api/voice-sources, /api/import-source-audio, /api/proxy-audio, /api/quick-import-voice, /api/download-yt, /api/elevenlabs/voices |
docker.py |
/api/local-containers/*, /api/probe-url |
tts.py |
/api/tts-preview, /api/tts-style-variation, /api/tts-stream-*, /api/voice-design, /v1/*, /api/tts-voices, /api/tts-backends, restart endpoints |
conversation.py |
/api/refine-text, /api/rewrite-with-persona, /api/audio/effects, /api/voices/export, /api/voices/import, /speak*, /mcp, /api/conversation/* |
Dockerfile updated to COPY core/ core/ and COPY routes/ routes/.
docker-compose.yml updated to mount ./core:/app/core:ro and ./routes:/app/routes:ro.
Frontend — static/app.js split into static/js/ modules
app.js (8,744 lines) split into 16 focused modules totalling the same 8,744 lines.
static/loader.js updated to load them sequentially in dependency order.
| Module | Lines | Responsibility |
|---|---|---|
utils.js |
364 | $, toast, escHtml, debounce, theme, language/flag helpers, searchable picker, tab helpers |
voice-inspector.js |
397 | 3-pane voice workbench (selectVoice, updateInspector) |
voice-sources.js |
277 | External voice source scraping UI (loadGetVoices, renderGetVoices) |
integrations.js |
211 | Code snippet generation for SillyTavern, Open WebUI, HA, curl, MCP |
routing.js |
542 | TTS routing rules editor |
settings.js |
385 | loadSettings, applyAndSaveSettings, settings panel |
voice-clone.js |
774 | WaveSurfer waveform, drop zone, microphone, trim UI, voice design dialog |
voice-library.js |
2654 | Full voice library: list, row rendering, operations (save, rename, delete, normalize, benchmark) |
tts-preview.js |
528 | fetchTtsPreviewBlob, createTtsAudioSource, preview panel |
benchmark.js |
218 | Batch benchmark section |
stt.js |
287 | STT→TTS playground, refreshSttBackends |
init.js |
49 | App bootstrap (calls loadSettings, syncs UI state) |
engines.js |
625 | ElevenLabs browser, custom engine cards, Docker container management |
ai-backends.js |
520 | AI backend cards, LLM snippet collapse, initStaticDockerManagement, collapsible cards |
generation.js |
393 | WAV merge, chunked TTS, generation history, playlist, audio effects, LLM refinement |
conversation.js |
520 | Settings logs/about, voices import, conversation playground |
Earlier history
See git log for the full commit history prior to this release.