Ads (ads)
The ads deck is the station's commercial spots: downloaded Egyptian radio
ads that air on a fixed cadence (AD_EVERY) rather than in a block. Files live
in media/ads as AD_*.mp3, are Break-tagged and R128-mastered.
Acquisition
Ads come from yt-dlp searches — not the music queries. content-pipeline.js
defines an ad query set:
اعلانات مصرية جديدة 2026
اعلان تجاري مصري 2026
yields AD_<timestamp>.mp3 into media/ads. The fetch target is 24 per refresh,
the purge cap 24, and ADS_MAX_AGE_DAYS = 35 — a spot older than 35 days is
retired at the next refresh.
Ad-aware dedup (why ads are refetchable)
Music uses a permanent download archive (logs/yt_download_archive.txt) that
blocks re-downloading an ID forever. Ads instead use a per-run temporary
archive (logs/yt_download_archive_ads_tmp.txt, deleted after the fetch), so an
archived ad ID is never blocked forever — a purged spot can be re-adopted within
the 45-day window. The duplicate check only blocks when the matched registry
file is still live.
How the scheduler slots them
Ads air on a guaranteed cadence slot:
so a 120-track rotation gets a spot roughly every 15 slots (~every 40–60 min),
with a guard that an ad never immediately follows an ad
(lastType !== 'ads'). Ads are imaging elements: 10 min cooldown, and
liq_cross_duration = 0.5 (spots run 10–30 s).
Refresh budget & pool health
server.js refresh defaults ads: o.ads ?? 16; the pool-health monitor keeps
the deck near its 30-file cap (restores from pro_archive if it drops below
50 %). The HEADROOM.ads purge margin keeps stale promos from surviving.
Verify on air
media/adsholds a healthy deck (10–30 files) ofAD_*.mp3.- m3u entries:
annotate:type=ads,liq_cross_duration=0.5:. - Rotation cadence: an ad about every
AD_EVERYslots. /api/upnextshows an ad correctly typed (not listed as a song).