News Bulletins (news)
The news deck is the station's spoken top-of-hour bulletin — the single
most "radio" element that was missing before bulletin-engine.js (2026-08-11).
Each bulletin is a R128-mastered Arabic spoken piece (~35–37 s) generated
entirely by the bulletin engine into media/news/NEWS_<ts>.mp3.
The bulletin recipe
A bulletin is four TTS segments concatenated with 0.55 s of silence between them:
| # | Segment | Content |
|---|---|---|
| 1 | Station open + Cairo time check | "إنها الآن الساعة التاسعة مساءً بتوقيت القاهرة" — word-hours + minutes + period (صباحاً / ظهراً / مساءً / ليلاً) |
| 2 | Weather | Open-Meteo Cairo: temperature + WMO description + wind |
| 3 | Headlines | "وأبرز العناوين: …" — up to 3 lines from E:\radionew\news.txt |
| 4 | Hand-back | "الآن عودة للموسيقى" |
TTS & loudness
- Voice:
ar-EG-ShakirNeural, rate +8 % (edge-tts). - Text is passed via a
-ftemp file, never shell args — Arabic text and backticks in headlines would break command quoting. - Weather from Open-Meteo (free, no key) for Cairo;
news.txtis editable, 1 headline per line, the first 3 are read.
The equations
Time-check sentence
Given hour h (0–23), minute m and period label, the Arabic sentence maps:
where [m ≠ 0] is an Iverson bracket — the minutes word is appended only when
the minute is non-zero, and period(h) selects صباحاً / ظهراً / مساءً / ليلاً
from the hour.
Loudness
Identical to every generator — two-pass EBU R128 to −14 LUFS / −1.5 dBTP / LRA ≤ 11, so a bulletin sits at exactly the same perceived volume as the songs:
How the scheduler slots it
- NEWS_EVERY cadence (~every 20–24 slots ≈ hourly) forces a news pick — same pattern as the AD_EVERY slot; news airs in all dayparts including deep night.
- Imaging cooldown (10 min);
liq_cross_duration = 0.5(below the ~35 s bulletin). - The news deck is exempt from the 45 s music-floor quality gate — a 35 s bulletin must not fail just because it is shorter than a song.
- Hourly auto-generation:
scheduleBulletinAutoGen()(boot +30 s, then everyBULLETIN_HOURS, default 1 h, chainedsetTimeout; 0 disables). A generated bulletin is immediately added to the deck and the rotation resynced.
The SYSTEM-session TTS gotcha
The engine runs as SYSTEM (ServerGuard, session 0) where bare python resolves
to the WindowsApps stub — edge-tts would fail silently. PYTHON_BIN defaults to
the absolute
C:/Users/omar/AppData/Local/Programs/Python/Python312/python.exe. If bulletin
generation reports all-tts-failed, check that path first.
Endpoints & CLI
POST /api/bulletin/generate(generate + resync rotation)GET /api/bulletin/status(latest file, headlines, live time-check sentence)- MCP:
generate_bulletin,bulletin_status
Verify on air
media/newsholdsNEWS_*.mp3(typically one, replaced hourly).- m3u:
annotate:type=news,liq_cross_duration=0.5:. - The bulletin appears ~once per hour in the rotation.
- ffprobe: ~35–37 s, Break-tagged, R128 ≈ −14 LUFS.
- To change headlines: edit
E:\radionew\news.txt, thenPOST /api/bulletin/generate(or wait for the next hourly run).