Gjennomgang: Stopp under syntese, planstatus, waitress, tester på HTTP-laget
Sju ting fra en gjennomgang av det som ble bygd i går. Stopp virket ikke mens lyden ble laget. Player.stop() drepte self.proc, men under syntesen finnes ingen prosess ennå – det er de første sekundene av hver edge-tts-melding – så knappen gjorde ingenting, og meldingen gikk ut etterpå. Nå har køen statusen preparing, stop() setter stopped på den, og run_once() sjekker det før den starter avspilling. UI-et viser «Lager lyd …» i stedet for å late som det spilles i stillhet. Planlagte sendinger løy om status. De ble markert «sendt» idet de ble lagt i kø, og ble stående slik selv om avspillingen feilet. Player har fått en on_finished-callback, og planen følger nå meldingen helt i mål: sent, failed eller stopped – det som faktisk skjedde. Statusene i schedule.py er utvidet tilsvarende (queued er «lagt i kø», sent er «spilt ferdig»). Flask sin utviklingsserver er byttet ut med waitress. Én prosess med mange tråder, med vilje: Player og planleggeren er singletons, så gunicorn med flere workere ville gitt flere køer som snakker i munnen på hverandre. HTTP-laget hadde null tester. import announcer startet tråder og dro inn Piper, så rutene lot seg ikke prøve. Trådene startes nå i main(), og run_once() driver køen ett steg om gangen. tests/test_routes.py dekker rutene, valideringen, køen, Stopp i begge faser, revisjonsloggen og hele planleggingsflyten gjennom HTTP. 30 nye tester, 110 totalt. Kappløp i synthesize(): tmp-fila hadde fast navn, så to som forhåndslyttet samme tekst samtidig skrev til samme fil, og den ene rename feilet. Unik tmp-fil per kall. verify_signature = false er fjernet. Det var en felle: én feilskrevet linje i config, og alle tokens ble godtatt. Ingen trenger den. docker compose up uten install.sh krasjet kryptisk ved første utrop, fordi Docker lagde data/ som root. check_writable() sier nå klart fra ved oppstart, med hva som må gjøres. Verifisert live i container: Stopp under edge-tts-syntese gir stopped, ikke done. Server-headeren er waitress sin, ikke werkzeugs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
04b3712ef5
commit
eb27a162d5
9 changed files with 565 additions and 81 deletions
16
index.html
16
index.html
|
|
@ -76,6 +76,7 @@
|
|||
font: inherit; font-size: 13px; padding: 0 4px; }
|
||||
ul.list li button.x:hover { color: var(--danger); }
|
||||
ul.list li.cancelled .s, ul.list li.missed .s { color: var(--warn); }
|
||||
.now .t { color: var(--muted); font-size: 13px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -422,7 +423,8 @@ btnAnnounce.addEventListener('click', async () => {
|
|||
$('#btnStop').addEventListener('click', () => api('/api/stop').then(poll).catch(onError));
|
||||
$('#btnClear').addEventListener('click', () => api('/api/clear').then(poll).catch(onError));
|
||||
|
||||
const STATUS = { done: 'sendt', failed: 'feilet', stopped: 'stoppet', queued: 'i kø' };
|
||||
const STATUS = { done: 'sendt', failed: 'feilet', stopped: 'stoppet', queued: 'i kø',
|
||||
preparing: 'lager lyd', playing: 'spiller' };
|
||||
function hhmm(ts) { return new Date(ts * 1000).toLocaleTimeString('no', { hour: '2-digit', minute: '2-digit' }); }
|
||||
function li(it) {
|
||||
const l = document.createElement('li'); l.className = it.status;
|
||||
|
|
@ -434,7 +436,8 @@ function li(it) {
|
|||
l.querySelector('.s').textContent = (STATUS[it.status] || it.status) + (it.error ? ' · ' + it.error : '');
|
||||
return l;
|
||||
}
|
||||
const SCHED_STATUS = { sent: 'sendt', missed: 'gikk glipp av', cancelled: 'avbrutt' };
|
||||
const SCHED_STATUS = { queued: 'i kø', sent: 'sendt', failed: 'feilet', stopped: 'stoppet',
|
||||
missed: 'gikk glipp av', cancelled: 'avbrutt' };
|
||||
function schedLi(it) {
|
||||
const l = document.createElement('li');
|
||||
l.className = it.status;
|
||||
|
|
@ -468,7 +471,14 @@ async function poll() {
|
|||
const rows = [...sc.pending, ...sc.done];
|
||||
$('#schedcard').classList.toggle('hidden', rows.length === 0);
|
||||
$('#sched').replaceChildren(...rows.map(schedLi));
|
||||
if (s.current) { now.className = 'now'; now.innerHTML = '<span class="pulse"></span>'; now.append(document.createTextNode(s.current.text)); }
|
||||
if (s.current) {
|
||||
// «Lager lyd» er de første sekundene av hver edge-tts-melding: det
|
||||
// er stille, og uten dette så det ut som avspillingen hang.
|
||||
const preparing = s.current.status === 'preparing';
|
||||
now.className = 'now' + (preparing ? ' idle' : '');
|
||||
now.innerHTML = preparing ? '<span class="t">Lager lyd … </span>' : '<span class="pulse"></span>';
|
||||
now.append(document.createTextNode(s.current.text));
|
||||
}
|
||||
else { now.className = 'now idle'; now.textContent = (cfg.app && cfg.app.idle_text) || ''; }
|
||||
$('#queue').replaceChildren(...s.queued.map(li));
|
||||
$('#history').replaceChildren(...s.history.map(li));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue