Music Decks (arabic_hits, egyptian_trends, arab_techno, english)
The four music decks are the heart of the rotation — real songs, fetched by yt-dlp against curated singer catalogs + trend queries, quality-gated, R128-mastered and tagged. Every non-imaging, non-cadence slot in the rotation is filled by one of these decks.
| Deck | File prefix | Live cap | Default genre weight |
|---|---|---|---|
arabic_hits | TRK_*.mp3 | 60 | 0.45 |
egyptian_trends | TRK_*.mp3 | 40 | 0.30 |
arab_techno | TRK_*.mp3 | 40 | 0.10 |
english | TRK_*.mp3 | 40 | 0.15 |
Files are stored in media/<category>/ as TRK_<epoch>_<hash>.mp3.
Acquisition & the junk gate
Each refresh:
- Runs singer-catalog queries (curated per category) plus generic trend
queries (
ytsearchNwhereN = max(10, needed + 3)). - Applies the junk gate at every stage — yt-dlp
--reject-titlepre-download, post-downloadBAD_TITLE/REJECT_TITLE,scrubCategory, and aderiveMetare-check. It kills concerts/shows/news/covers/karaoke/remixes, AI-slop (Suno/UDIO/Melovox/حمو القماش), and Shaabi terms. - Dedupes by song key (
artist | title), by YouTube ID, and bydupKey. - Masters to uniform format: 48 kHz, stereo, 320 k, R128 to −14 LUFS.
- Writes the
meta_registry.jsonentry and ID3 tags (clean titles — no "Video"/"Official" wording ever).
The genre-sampling equation
When a slot needs music, the scheduler picks a deck by Dirichlet-style sampling over the genre weights (subject to recent-category anti-fatigue and daypart multipliers):
w_c— the deck's base weight (GENRE_SPLIT).M_{daypart,c}— the daypart multiplier (e.g. english ×8 in deep night 02–05 with hard gate; techno ×3.5 late night; trends ×1.5 midday/evening).B_{crowd,c}— crowd energy bias: at ≥CROWD_SIZE_THRESHOLD = 5listeners,arab_techno ×1.70andarabic_hits ×1.35get boosted.
Track scoring (NN/VAE)
Candidates are scored by a neural/VAE blend — the classifier predicts how well a track fits the current energy:
with L2-regularised training on play feedback (reward from real listener deltas and crowd votes). The success predictor adds experience per on-air track.
Anti-repeat & spacing
- Cooldown: 3 h (
COOLDOWN_PERIOD) — a song never repeats inside ~3 h; on top of that,MUSIC_FRESH_MS(3 h) keeps it out of the rotation window. - Song-key dedup:
artist | titlenormalised (suffixes like "(TINI Version)" stripped) — catches the same song downloaded as two files. - Artist gap (
ARTIST_GAP = 12): no artist repeats within ~12 slots (~40 min) of their last appearance. - Least-recently-aired pick:
popFromchooses the never-aired or longest-waiting eligible candidate — not the first off-cooldown one — so rebuilds recycle variety instead of re-playing the newest tracks.
Pool health & rotation health
checkPoolHealth()runs every 15 min and restores any deck below 50 % of its cap from the archive (newest stamps first), triggering a full fetch-refresh if the archive is exhausted.- The 6 h auto-refresh keeps each deck near its cap;
updateM3Usorts fresh-first (newestaddedAtOffirst). - The 72 h staleness gate excludes music older than 72 h from the rotation while any younger track exists (relaxed valve fills ancient tracks rather than going silent).
Verify on air
- Deck sizes:
arabic_hits ≈ 60,egyptian_trends ≈ 40,arab_techno ≈ 40,english ≈ 40(English is legitimately thin right after a junk scrub — the next auto-refresh tops it up). - Rotation m3u: music entries have no
liq_cross_duration(full 2 s crossfade). /api/statusnow-playing shows clean titles — no "Video", no mojibake, no junk genres.- No banned artists/terms in the rotation (grep the m3u for the ban list).