«Send denne kl. 18:00.» Engangs, ikke gjentakende.
Dette er den første delen av appen som må ligge på disk. Kø og historikk har
alltid bare levd i minnet, og det har gått bra fordi en melding spilles med en
gang. En melding planlagt til 18:00 må overleve at containeren startes om
17:45, så schedule.py lagrer i data/scheduled.json – skrevet til side og
flyttet på plass, så fila aldri er halvskrevet.
Ingen database, med vilje: dette er en håndfull meldinger på et arrangement,
og en fil man kan lese med cat er verdt mer her enn indekser. En ødelagt fil
hindrer ikke oppstart; da er det bedre å miste planene og si det i loggen.
Modulen vet ingenting om Flask eller avspilling. Den lagrer, og den svarer på
«hva skal sendes nå?». _scheduler() i announcer.py eier tråden som spør hvert
20. sekund og legger forfalte meldinger i den vanlige køen – derfra oppfører de
seg nøyaktig som en melding sendt for hånd.
Gikk den glipp av, spilles den ikke. due() skiller på grace_seconds (120):
innenfor den sendes meldingen, utenfor markeres den missed og vises som det.
Nådefristen er slingringsmonn for at tråden våkner med mellomrom og for en
kjapp omstart, ikke en policy om å ta igjen etterslep – «turneringen starter om
ti minutter» skal ikke ut på anlegget en time etter at maskina kom tilbake.
due() endrer ingenting selv; markeringen skjer først etter at meldingen
faktisk er i kø, så ingenting kan stå som «sendt» uten å ha blitt det.
Klienten sender absolutt tidspunkt (epoch), så tidssoner spiller ingen rolle
for selve planleggingen. TZ settes likevel fra .env, ellers står loggen i UTC
mens man selv står i CEST.
Planlegging er låst til samme forhåndslytt-nøkkel som «Send ut»: man planlegger
bare det man har hørt. Det gir en bonus – forhåndslytt varmer cache/, så WAV-en
ligger ferdig på disk, og en planlagt edge-tts-melding spiller kl. 18:00 selv
om nettet er nede da.
Sine egne kan man alltid avbryte. Andres krever clear, samme rett som å tømme
køen, siden det er samme slags inngrep i noe andre har satt i gang.
23 nye tester. Verifisert i container: sending fyrer og spiller, overlever en
omstart av containeren, og en melding som forfalt mens maskina var av blir
markert missed uten å bli spilt.
Merk ved oppgradering: schedule er en ny handling, og et oppsett med eksplisitt
[roles] i config.toml får den ikke automatisk. Den må legges inn selv.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Alt som gjorde appen «Sauda Gathering» – tittel, undertittel, aksentfarge,
hurtigfraser – var hardkodet i index.html. Dette legger grunnlaget for å
flytte det ut, så samme kode kan brukes på et annet arrangement uten å
redigere HTML.
Tre lag, siste vinner: DEFAULTS -> config.toml -> ANNOUNCER_*
config.toml er valgfri. Uten den gjelder DEFAULTS, som er dagens oppførsel
bit for bit. Det er et krav, ikke en forglemmelse: tjenesten skal kunne
settes opp på en kveld uten at noe må konfigureres først.
Hemmeligheter hører i env-laget, så de kan stå i systemd-enheten istedenfor
i en fil i repoet. config.toml er gitignorert; config.example.toml er malen.
Egen modul og ikke en del av announcer.py fordi auth-koden som kommer
trenger den også, og det ville blitt en import-sirkel.
Ingenting bruker den ennå – det skjer i neste commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>