-
Notifications
You must be signed in to change notification settings - Fork 1
Radio
This page documents the current Mediabot v3 radio integration.
The radio stack is built around:
- Icecast status/public stream information;
- Liquidsoap telnet queue control;
- a local MP3 cache;
- cache-first playback through
m play; - optional non-blocking
yt-dlpdownloads; - safe production defaults.
The current implementation is a safe foundation. YouTube authenticated downloads are supported, but cookies/session handling remains operationally fragile and should not be treated as a guaranteed permanent mechanism.
The radio work provides:
- Liquidsoap queue control from IRC;
- Icecast status and listener commands;
- MP3 cache diagnostics and imports;
- cache-first
m play; - non-blocking
yt-dlpdownloads; - a download enable/disable toggle;
- cleaner IRC messages for common
yt-dlpfailures; - safer formatting for
m songandm listeners.
Most administrative radio commands are Master-only during rollout.
m play is also kept Master-only for now.
Use two different policies depending on the instance.
RADIO_DOWNLOAD_ENABLED=1The dev instance may download missing tracks through yt-dlp, populate the local MP3 cache, and validate Liquidsoap/Icecast behavior.
RADIO_DOWNLOAD_ENABLED=0Production instances should normally remain cache-only.
In this mode:
-
m playsearches the MP3 cache; - cache hits are pushed to Liquidsoap;
- cache misses return a clean message;
- no
yt-dlpprocess is started.
This prevents public bots from becoming accidental remote download endpoints.
Typical development configuration:
[radio]
YOUTUBEDL_INCOMING=/home/mediabot/mediabot_v3/mp3
RADIO_DOWNLOAD_ENABLED=1
YTDLP_PATH=/usr/local/bin/yt-dlp
YTDLP_TIMEOUT=180
YTDLP_COOKIES_FILE=/home/mediabot/.config/yt-dlp/youtube.cookies.txt
YTDLP_REMOTE_COMPONENTS=ejs:github
LIQUIDSOAP_TELNET_HOST=127.0.0.1
LIQUIDSOAP_TELNET_PORT=1235
LIQUIDSOAP_QUEUE_ID=mediabot_queue
RADIO_ICECAST_STATUS_BASE_URL=http://127.0.0.1:8000
RADIO_ICECAST_PUBLIC_BASE_URL=http://teuk.org:8000
RADIO_ICECAST_TIMEOUT=5
RADIO_ICECAST_PRIMARY_MOUNT=/radio.mp3For cache-only production use:
RADIO_DOWNLOAD_ENABLED=0| Key | Purpose |
|---|---|
RADIO_ICECAST_STATUS_BASE_URL |
Local/private Icecast base URL used by the bot to fetch status. |
RADIO_ICECAST_PUBLIC_BASE_URL |
Public base URL shown in IRC output. |
RADIO_ICECAST_TIMEOUT |
HTTP timeout for Icecast status requests. |
RADIO_ICECAST_PRIMARY_MOUNT |
Main mount, currently /radio.mp3 in the dev stack. |
The old historical fallback /radio160.mp3 should not be used as the default for the new dev stack.
| Key | Purpose |
|---|---|
LIQUIDSOAP_TELNET_HOST |
Liquidsoap telnet host, usually 127.0.0.1. |
LIQUIDSOAP_TELNET_PORT |
Liquidsoap telnet port, currently 1235 on the dev stack. |
LIQUIDSOAP_QUEUE_ID |
Queue id, currently mediabot_queue. |
The currently verified Liquidsoap commands are:
mediabot_queue.push <uri>
mediabot_queue.queue
mediabot_queue.skip
mediabot_queue.flush_and_skip
There is no known mediabot_queue.status command in the current Liquidsoap setup, so Mediabot does not depend on one.
The playback logic lives in:
Mediabot/Radio/Request.pm
When using:
m play <query>
Mediabot follows this order:
- search the local
MP3table/cache; - verify that the file referenced by the row is readable;
- push the cached file to Liquidsoap if available;
- only then consider
yt-dlp; - start
yt-dlponly ifRADIO_DOWNLOAD_ENABLED=1.
This protects production and keeps playback fast when the cache already contains the track.
m radioimport /absolute/path/file.mp3 [artist - title]
Example:
m radioimport /home/mp3/TeuK/ab.mp3 TeuK - ab
The command verifies the file, accepts MP3 files only, reads nearby .info.json metadata when available, and inserts or updates the MP3 table without creating avoidable duplicates.
m radioimportdir [directory]
Without an argument, the command uses YOUTUBEDL_INCOMING.
The directory import scans recursively and applies the same import/update logic as radioimport.
m radiocache
This reports DB rows, readable rows, broken rows, local MP3 files, and examples of missing DB entries.
Dry-run:
m radiocacheprune
Actual cleanup:
m radiocacheprune confirm
radiocacheprune confirm only deletes broken rows from the MP3 table. It does not delete MP3 files from disk.
m radioqueue
m radiopush /absolute/path/file.mp3
m radioskip
m radioflush
radiopush expects an absolute path to a readable MP3 file. Paths containing spaces are intentionally avoided for now because the current download/import workflow uses restricted filenames.
m radiodlstatus
Shows whether a non-blocking yt-dlp job is running.
It reports the query, PID, age, timeout, and temporary stdout/stderr files when a job exists.
m radiodlcancel
Cancels the current yt-dlp job, clears the internal state, and removes temporary job files when possible.
Mediabot starts yt-dlp in a child process and monitors it from the event loop.
Safeguards:
- only one active download per bot instance;
- configurable timeout with
YTDLP_TIMEOUT; - stdout/stderr captured to temporary files;
- completion updates/inserts the MP3 row;
- successful downloads are pushed to Liquidsoap;
- failures are classified into short IRC messages.
Current useful settings:
YTDLP_PATH=/usr/local/bin/yt-dlp
YTDLP_TIMEOUT=180
YTDLP_COOKIES_FILE=/home/mediabot/.config/yt-dlp/youtube.cookies.txt
YTDLP_REMOTE_COMPONENTS=ejs:githubYouTube cookies are optional but often required for YouTube requests.
The cookies file should be outside the repository:
/home/mediabot/.config/yt-dlp/youtube.cookies.txt
Recommended permissions:
chown mediabot:mediabot /home/mediabot/.config/yt-dlp/youtube.cookies.txt
chmod 600 /home/mediabot/.config/yt-dlp/youtube.cookies.txtDo not commit this file.
Do not put it in public snapshots.
Do not paste it into tickets, forums, or IRC.
radiocheck can verify that the file exists and is readable. It cannot guarantee that YouTube will accept the session.
If YouTube rejects the cookies, Mediabot should return a short message explaining that cookies.txt may be stale or rotated.
Recent yt-dlp versions may need remote components for YouTube challenge solving.
Recommended setting:
YTDLP_REMOTE_COMPONENTS=ejs:githubManual check:
/usr/local/bin/yt-dlp \
--cookies /home/mediabot/.config/yt-dlp/youtube.cookies.txt \
--remote-components ejs:github \
--skip-download \
--no-playlist \
--print "%(title)s" \
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"If this fails with cookie/session errors, refresh cookies first.
If it fails with challenge/EJS errors, check the JavaScript runtime and YTDLP_REMOTE_COMPONENTS.
A future direction may be:
yt-dlp --cookies-from-browser chromium:/home/mediabot/.config/chromium-mediabot-youtube
and a future config key such as:
YTDLP_COOKIES_FROM_BROWSER=chromium:/home/mediabot/.config/chromium-mediabot-youtubeThis is not implemented yet.
A fully automatic headless Google login is not a reliable target because Google can require 2FA, CAPTCHA, browser verification, or session rotation.
For now, keep production cache-only and treat cookies as an operational dependency for dev downloads.
m radiocheck
m radiostatus
m radiomounts
m song
m listeners
m song and m listeners use IRC formatting that avoids unsafe background colors and should be readable on both dark and light IRC clients.
m song does not print a [ LIVE ! ] badge.
m listeners uses English wording.
Use:
m radiocheck
Expected checks include:
- incoming directory readability/writability;
- download enabled/disabled state;
-
yt-dlppath/version; - cookies file readability;
- remote components setting;
- timeout;
- Liquidsoap host/port/queue;
- Icecast status/public URLs.
Example:
Radio check:
incoming: OK writable (/home/mediabot/mediabot_v3/mp3)
downloads: enabled
yt-dlp: OK 2026.03.17 (/usr/local/bin/yt-dlp)
cookies: OK readable (/home/mediabot/.config/yt-dlp/youtube.cookies.txt)
yt-dlp remote components: ejs:github
yt-dlp timeout: 180 seconds
Liquidsoap: OK 127.0.0.1:1235 queue=mediabot_queue
Icecast status base: http://127.0.0.1:8000
Icecast public stream: http://teuk.org:8000/radio.mp3
Radio commands can be discovered with:
m help commands radio
m help play
Large help output is paced to reduce flood risk.
From IRC on the dev instance:
m check
m radiocheck
m radiocache
m radiodlstatus
m radiostatus
m radiomounts
m song
m listeners
m radioqueue
m radioimport /home/mp3/TeuK/ab.mp3 TeuK - ab
m play ab
m radioskip
m radioflush
m play Rick Astley Never Gonna Give You Up
m radiodlstatus
m help commands radio
Also test a blank or whitespace-only IRC message. The bot should ignore it without warning noise.
| Symptom | Likely cause | First check |
|---|---|---|
| Cache hit does not play | Liquidsoap queue issue or unreadable file |
m radioqueue, m radiocheck
|
| Cache miss does not download | RADIO_DOWNLOAD_ENABLED=0 |
m radiocheck |
| YouTube rejects cookies | stale/rotated cookies | refresh youtube.cookies.txt
|
| 403/player-token challenge | cookies/EJS/YouTube policy change | check cookies and YTDLP_REMOTE_COMPONENTS
|
yt-dlp job stuck |
slow/hung download |
m radiodlstatus, then m radiodlcancel
|
| No Icecast info | wrong Icecast status URL or mount |
m radiostatus, m radiomounts
|
- YouTube cookies are fragile and may expire.
- Chromium/browser-profile cookie extraction is not implemented yet.
-
m playremains Master-only during rollout. - Production instances should stay cache-only until deliberately changed.
- No DB schema change was made for this integration.