Search for music, download it, tag it properly, and file it into a library — either a folder on your own machine or an AzuraCast station's request playlist.
It runs two ways from the same code: a portable Windows program you double-click, and a server deployment behind a reverse proxy.
- Search YouTube, Deezer, and optionally every musicdl platform from one box, or paste a URL to a track, album, playlist, or artist. How many results each source returns is a setting, and every search can ask for a different number
- Retries you can tune. Bulk imports get refused in batches by YouTube — 403 and "video unavailable" on tracks that download fine later. Extra attempts per track, a gap between tracks, a cooldown after repeated refusals, a final pass over what failed, and a retry button on every finished download
- Open any artist or YouTube channel to take everything, or tick only the releases, albums, and videos you actually want
- Upload a TXT, XLSX, or PDF list of music and it indexes the whole thing, then works through it
- Upload a playlist you already have — M3U, M3U8, PLS, XSPF, WPL, ASX, CUE, or foobar2000 FPL — and it fetches the tracks the playlist names, without needing the original files
- Finished files are readable by every account on the machine, with no permission fixing afterwards
- Clear the download history whenever you like; the music files are left alone
- With a Deezer subscriber ARL configured, downloads come from Deezer first — FLAC, or 320 kbps MP3 when FLAC is not offered — and YouTube is only the fallback
- Prefers Deezer's copy of a track's metadata when one matches cleanly, so artist, title, album, year, and ISRC come out right instead of guessed from a video title
- Artist-only lines take that artist's entire catalogue by default, or a cap you choose
- Preserves audio quality — the source stream is remuxed, never re-encoded, and the tests verify the audio packets come out bit-identical
- Writes proper tags and cover art for MP3, MP4/M4A, FLAC, Ogg, and WAV/AIFF
- Optionally uploads each finished file to AzuraCast and adds it to a request playlist
- Installs and updates its own tools. yt-dlp, ffmpeg, and Deno are fetched in the background on first run, and yt-dlp, Deno, and musicdl are kept up to date after that
- Python 3.11 or newer, if running from source
- yt-dlp, ffmpeg, and
Deno — RequestCast downloads yt-dlp and Deno itself on every platform,
and ffmpeg too on Windows, into a
toolsfolder beside the program. Install ffmpeg with your package manager elsewhere
Deno is not optional for YouTube. YouTube answers with JavaScript challenges that yt-dlp cannot solve on its own, so it hands them to an external JavaScript runtime and enables Deno by default. Without one, YouTube downloads lose the better formats and fail with 403 errors that retrying will not clear.
Download the release, unzip it anywhere, and run RequestCast.exe. The setup page opens in
your own default browser — RequestCast never downloads, installs, or copies a browser of
its own. Everything it writes — settings, the job database, downloaded music — stays inside
that folder, so the whole thing can live on a USB stick.
On first run it asks for:
- A download folder. The only required answer.
- AzuraCast details — optional. Leave the box unticked and RequestCast is a plain music downloader that saves tagged files to your download folder.
- A password — opens RequestCast.
- An admin password — protects Preferences.
Use Preferences to change these later.
Diagnostics are off. When they are on, RequestCast writes a request log and collects a
support ZIP of Windows networking evidence beside the program — tens of megabytes — so it
only does that when someone has asked you for one. Turn it on in Preferences, or start
with RequestCast.exe --diagnostics. --diagnose collects one bundle and exits.
pip install -r requirements.txt pyinstaller
python scripts/build_windows.py
The result is dist/RequestCast/.
pip install -r requirements.txt
python run.py
On a server, configure it with environment variables instead of the setup page — any variable that is set overrides the settings file, so the setup page never has to be exposed.
REQUESTCAST_DOWNLOAD_DIR=/var/lib/requestcast/downloads
REQUESTCAST_STATE_DIR=/var/lib/requestcast/state
REQUESTCAST_AZURACAST_API_BASE=http://127.0.0.1:12000/api
REQUESTCAST_AZURACAST_API_KEY=...
REQUESTCAST_STATION_ID=1
REQUESTCAST_REQUEST_PLAYLIST_ID=10
REQUESTCAST_SECRET_KEY=...
REQUESTCAST_PASSWORD_SALT=... # 32 bytes, hex
REQUESTCAST_PASSWORD_HASH=... # scrypt, hex
REQUESTCAST_ADMIN_PASSWORD_SALT=...
REQUESTCAST_ADMIN_PASSWORD_HASH=...
REQUESTCAST_DEEZER_ARL=... # optional Deezer subscriber ARL
REQUESTCAST_MUSICDL_ENABLED=1 # optional; musicdl fallback between Deezer and YouTube
REQUESTCAST_MUSICDL_SOURCES=MiguMusicClient,NeteaseMusicClient,QQMusicClient,KuwoMusicClient,QianqianMusicClient
REQUESTCAST_DIAGNOSTICS=1 # optional; collects a support bundle, off by default
REQUESTCAST_SEARCH_LIMIT=50 # results per source and per result type, 5 to 200
REQUESTCAST_SEARCH_MUSICDL=1 # optional; include musicdl platforms in name searches
REQUESTCAST_DOWNLOAD_RETRIES=2 # extra attempts per track, 0 to 10
REQUESTCAST_DOWNLOAD_RETRY_DELAY=20 # seconds before the first retry; doubles after that
REQUESTCAST_DOWNLOAD_GAP=2 # seconds between tracks in a queue, 0 to 120
REQUESTCAST_RATE_LIMIT_COOLDOWN=180 # pause after repeated refusals, 0 to 3600
REQUESTCAST_JOB_RETRY_LIMIT=1 # times to requeue a whole failed download
REQUESTCAST_DENO=/usr/local/bin/deno # optional; found on PATH or installed automatically
REQUESTCAST_AUTO_UPDATE_TOOLS=1 # keep yt-dlp, Deno, and musicdl current
REQUESTCAST_AUTO_UPDATE_HOURS=24 # hours between update checks, 1 to 720
Setting REQUESTCAST_AZURACAST_API_KEY turns the AzuraCast integration on. Serve it with
gunicorn or waitress behind nginx, and give it a generous request timeout and body size —
indexing happens inside the upload request, and uploads are accepted up to 64 MB.
systemd unit and nginx examples are in docs/deployment.md.
With a Deezer subscriber ARL configured (the settings page, or REQUESTCAST_DEEZER_ARL),
audio comes from the Deezer account first: FLAC when the account is offered it, then
320 kbps MP3, then 128 kbps MP3. Tracks the account cannot supply fall back to
musicdl — which searches the configured platforms (NetEase, QQ, Kugou, Kuwo, and
Migu by default; REQUESTCAST_MUSICDL_SOURCES changes the list, and
REQUESTCAST_MUSICDL_ENABLED=0 turns the fallback off) — and finally to YouTube,
fetched with yt-dlp. Without an ARL, YouTube is the last source and Deezer is used for
metadata only, through its public API.
musicdl also widens URL input: pasting a track or playlist URL from any platform it supports (NetEase, QQ Music, Kugou, Kuwo, Migu, Qianqian, Spotify, SoundCloud, TIDAL, Qobuz, Apple Music, JOOX, JioSaavn, Jamendo, and more) downloads it through musicdl directly.
The ARL is runtime configuration. It lives in the settings file or the environment, and must never be committed to the repository.
You are responsible for having the right to download and broadcast whatever you point it at.
Run the self-contained test suite from the repository root:
python tests/run_all.pyThis includes the Deezer quality, decryption, source-preference, YouTube-fallback, setup,
configuration, import, playlist-format, artist-browsing, job-history, download-permission,
default-browser, diagnostics, request, upload, audio-preservation, URL-input, search-limit,
download-retry, and tool-update checks. The
remaining scripts under tests/ are manual integration checks: they require either the private
playlist fixtures named in the script or a live RequestCast/AzuraCast deployment.
The interface is plain HTML with real headings, labelled form controls, and no scripted widgets. It is built to be usable with a screen reader.
MIT — see LICENSE.
yt-dlp, ffmpeg, and Deno are separate programs under their own licences; RequestCast runs them, and does not include them.