RadioServer runs SHOUTcast DNAS with Liquidsoap for AutoDJ. It provides commands for installation, playback, playlist scheduling, metadata and log management.
- Node.js
>=22.0.0; use a maintained LTS release with current security patches - A compatible SHOUTcast DNAS executable; see the platform notes below
- Liquidsoap >=2.2.5 (>=2.4.5 for playlist schedules) with FFmpeg support and the configured audio codecs
- FFmpeg on Linux, macOS and FreeBSD; included in the managed Windows Liquidsoap package
- A dedicated service account with write access to the repository and its data directories
Run commands from the repository root as the service account. Use elevated privileges only to install system dependencies. Startup and maintenance require Node.js 22 or newer; help, diagnostics, status, console and stop commands remain available on older versions for recovery.
| Platform | Runtime installation |
|---|---|
| Linux | Official SHOUTcast x64/x86 packages; Liquidsoap from an official package or a private OPAM build |
| Windows | Official SHOUTcast x64/x86 installer; Liquidsoap x64 portable package |
| FreeBSD x64 | Linux x64 SHOUTcast through Linuxulator; native Liquidsoap built with OPAM |
| macOS | Native Node.js, Liquidsoap and FFmpeg; no current native SHOUTcast package |
| Other FreeBSD architectures | Requires a compatible SHOUTcast executable supplied separately |
The installer selects Debian/Ubuntu packages for the exact distribution release and architecture. Unix systems without a matching package build Liquidsoap from source. Native 32-bit Windows requires a compatible Liquidsoap build supplied separately.
Current SHOUTcast server downloads target Linux and Windows. FreeBSD x64 can use the Linux executable after Linuxulator is configured. It is not a native FreeBSD build, and the installer does not enable Linuxulator itself. On macOS, run the complete radio in a Linux virtual machine with a compatible CPU architecture. The same applies to FreeBSD architectures without a compatible DNAS binary. Older Mac/BSD DNAS builds are not downloaded automatically.
Read the SHOUTcast DNAS license
before installing. The npm install and update scripts include
--accept-license; acceptance is saved in bin/shoutcast/license.json.
npm install
npm run installnpm install does not install the radio runtimes. Use npm run install to install
or reinstall them in bin/. This includes Liquidsoap's standard library and local
FFmpeg. Executables selected through SC_SERV_BIN or LIQUIDSOAP_BIN are checked,
not replaced. Active configurations stay in the repository root.
During install and update, system dependencies appear above the runtime list.
SHOUTcast and Liquidsoap have separate library checks. FOUND is green,
MISSING is red, and suggested OS installation commands are yellow. Run those
commands separately, then retry as the service account. RadioServer does not
install OS packages. Colors are disabled for redirected output and NO_COLOR.
Library checks are marked NOT CHECKED until the executable has been downloaded
or supplied. Its libraries are checked before activation. Archive tools are listed
separately; source builds also list compiler tools, development libraries and
version requirements. Package installation commands are shown where a mapping
is known. Libraries outside the system paths must be visible to pkg-config.
Official binary packages do not require the source-build tools.
Unix installations build the latest supported stable FFmpeg release in
bin/ffmpeg/<os>-<arch>/ from signed sources at ffmpeg.org. The system FFmpeg is
left unchanged. update reuses a working local build when it is current;
install rebuilds it. Windows uses the FFmpeg libraries bundled with Liquidsoap.
The platform requirements above still apply to the complete installation.
Copy the templates only when the corresponding active files do not exist:
cp sc_serv.conf.example sc_serv.conf
cp autodj.config.json.example autodj.config.json
cp playlist.config.json.example playlist.config.jsonUse copy instead of cp in Windows Command Prompt. Both Bash and PowerShell
accept the commands above.
- Replace active placeholders in
sc_serv.conf, including source and administrator passwords - Set the source host and matching password in
autodj.config.json;server.portmust equal DNASPortBase - Match each enabled AutoDJ output's
streamIdto a configured DNAS stream - Add audio files to
playlists/universal/ - Validate the configuration and start both engines
npm run doctor
npm start
npm run autodj:startICY needs PortBase + 1 as well as PortBase. Title publication requires
the matching streamadminpassword_N or global adminpassword in sc_serv.conf.
The installer checks native libraries with ldd on Linux and FreeBSD, otool
on macOS, and the executable's PE imports on Windows. Linux SHOUTcast on FreeBSD
uses the Linux loader instead of native ldd. On macOS, otool requires Xcode
Command Line Tools. Damaged managed Windows packages can be reinstalled, then
must pass the same checks.
Suggested dependency commands use APT, DNF, pacman, FreeBSD pkg, Homebrew
or WinGet, where a package mapping is known. Run Homebrew without sudo.
Unknown libraries or incompatible library versions require a matching vendor
build; do not substitute DLLs or symlink incompatible library versions.
On FreeBSD x64, enable Linuxulator and install its Linux userland as root before installing the radio runtimes:
sysrc linux_enable="YES"
service linux start
pkg install linux_base-rl9Then run npm run install:freebsd as the service account. The installer checks
kernel support, the Linux loader and userland execution before downloading or
compiling anything. SHOUTcast stays in bin/shoutcast/freebsd-x64/; its Linux
libraries are checked through the loader under /compat/linux, not native FreeBSD
ldd. Liquidsoap and FFmpeg remain native FreeBSD builds. No CPU emulation is
provided for FreeBSD ARM or 32-bit hosts. Externally supplied SHOUTcast binaries,
including older installations without a managed Linuxulator manifest, are preserved.
When no matching binary exists for the latest Liquidsoap release, the installer
uses OPAM
to build it from official sources. Install OPAM 2.1 or newer, a C compiler, Bash,
make (gmake on FreeBSD), pkg-config, and development files for curl and libffi.
FFmpeg compilation also needs GnuPG, tar, xz, NASM on Intel CPUs, and development
files for LAME, OpenSSL and zlib.
-dev and -devel packages contain compilation headers for released libraries;
they are not nightly builds.
FFmpeg's own headers and libraries are installed locally. Ubuntu 22.04 can keep its system FFmpeg 4.x: source-built Liquidsoap uses the compatible local FFmpeg instead. Its launcher sets the required library paths, including when started by a service manager. Official precompiled or externally supplied Liquidsoap binaries still require the library versions they were built against.
To remove FFmpeg development packages installed by an earlier setup on Ubuntu, first preview APT's removal plan:
sudo apt-get -s remove libavutil-dev libavformat-dev libavcodec-dev libavdevice-dev libavfilter-dev libswresample-dev libswscale-devIf the plan does not remove anything else you need, repeat without -s.
Do not remove the curl, libffi, LAME, OpenSSL or zlib development packages needed
for future builds. No autoremove is needed. Runtime FFmpeg libraries and the
system ffmpeg package can remain installed.
Source builds run as the service account with a private OPAM root inside the
platform directory, for example bin/liquidsoap/linux-x64/opam/. The launcher
and manifest live in bin/liquidsoap/linux-x64/runtime/; macOS and FreeBSD use
their own platform directories. Official binary packages do not use OPAM.
The account's existing OPAM switches are untouched. Builds take time and need
extra disk space; a failed build leaves the previous runtime in place. Use a
project path without spaces or shell-special characters, and keep that absolute
path after building. Rebuild Liquidsoap if the repository moves. Do not run OPAM
as root or move its folders manually.
Older layouts are migrated during reinstall or a required source update, not
just because a newer layout exists. The old shared bin/liquidsoap/opam/ is
removed only when it has no remaining switches or unrecognized files.
Successful source installations clean unused managed switches and build caches.
Older FFmpeg builds are kept until Liquidsoap uses the current build and no
uncertain switches or recovery directories remain. This preserves the libraries
needed by the previous Liquidsoap if an update fails. Unrecognized directories
and redirected paths are left alone; cleanup failures produce a warning.
For a POSIX shell:
export SC_SERV_BIN="/absolute/path/to/sc_serv"
npm run install
npm run doctorUse SC_SERV_BIN for a manually installed DNAS binary, including one inside
bin/, to prevent the installer from replacing it. To supply Liquidsoap, set
LIQUIDSOAP_BIN and keep its runtime libraries and service environment available.
Installation checks it against the latest stable release; update an outdated
override or unset it to use the managed version.
| Action | SHOUTcast | AutoDJ |
|---|---|---|
| Start in background | npm start |
npm run autodj:start |
| Stop | npm run stop |
npm run autodj:stop |
| Restart | npm run restart |
npm run autodj:restart |
| Status | npm run status (both engines) |
npm run autodj:status |
| Follow logs | npm run console |
npm run autodj:console |
| Clear active logs | npm run logs:clear |
npm run autodj:logs:clear |
For Screen or a service manager, run each foreground command in its own session:
node server.js
node autodj.jsDo not use background start commands inside restart loops. Configure a service manager for boot and crash recovery. On Unix-like hosts, quitting Screen or closing the foreground terminal stops the managed engine; detaching leaves it running. Shutdown allows up to 10 seconds before forced termination.
Console commands only follow logs. Ctrl+C closes the viewer, not the engine. Restart prevalidates the executable and configuration before stopping the current engine; AutoDJ also checks its generated Liquidsoap script. Prevalidation failures leave the existing engine running.
Run npm run help, npm run autodj:help or
npm run playlist -- --help for command details. Use -- to pass arguments
to an npm script, for example npm run playlist -- --dry-run. Platform-specific
install:*, update:*, start:* and autodj:start:* scripts select
linux, windows, macos or freebsd, for example npm run start:windows.
SHOUTcast also has windows:x86 variants. The selection must match the host.
Start, stop, restart and maintenance commands share .run/control.lock and wait
up to 30 seconds. Waiting messages show the operation and PID.
.run/control-locks/ tracks pending startups and helps recover abandoned locks.
Use one local run directory for all commands controlling an instance.
The controller does not take a lock from a running process. It recovers an abandoned lock only after the owner and pending startups have exited or finished. Corrupt records, interrupted external installers and uncertain startups require manual checks.
Before removing a reported lock or registration, stop restart loops and confirm both engines and all controller operations are stopped. Never remove the registration directory while commands are running.
Settings and defaults are documented in the root .example files. The SHOUTcast
template targets DNAS 2.6.1.777; check older builds against their shipped
documentation. AutoDJ and playlist configurations accept JSON comments and
trailing commas. Unknown keys and invalid values are rejected.
universal is the default playlist. Add libraries in playlist.config.json
with unique IDs and .lst output files. Every enabled library must contain
supported audio files. weight sets its contribution per rotation round and
has no effect with one library. Set enabled: false to exclude a library.
Each enabled AutoDJ output needs a unique id and DNAS streamId. Its
playlists field selects IDs from playlist.config.json:
| Output selection | Tracks used |
|---|---|
["universal"] |
Default library only |
["universal", "pop"] |
Both named libraries |
[] or omitted |
All enabled libraries |
IDs are case-sensitive. Unknown, disabled and duplicate IDs are rejected for enabled outputs; selection order defines rotation order. Different selections have independent playback and metadata. Identical ordered selections share decoding, but each stream has its own encoder and title recovery. Outputs share the source host, password and station settings.
AutoDJ avoids consecutive tracks with the same filename, ignoring extension, case and equivalent Unicode forms. A different name is a different track, even if its audio is identical. Anti-repeat takes priority over weights; repetition is allowed only when no differently named playable track is available in the current playlist selection. Unplayable files are retried after a cooldown.
AutoDJ regenerates playlists before starting. After adding tracks to existing libraries, run:
npm run playlistThe default reload interval is 300 seconds. Reloading preserves queued audio and the last selected track name. Restart AutoDJ after changing output selections or adding/disabling libraries. Crossfade, normalization, playback mode and reload settings apply to every playback programme.
Set schedule on a playlist in playlist.config.json. Scheduling requires
Liquidsoap >=2.4.5 on all supported platforms. This example runs Monday to
Friday, 09:00–21:00:
{
"id": "weekday",
"enabled": true,
"directory": "playlists/weekday",
"outputFile": "playlists/weekday.lst",
"weight": 1,
"schedule": [
{
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start": "09:00",
"end": "21:00"
}
]
}Use lowercase day names from monday to sunday. Add entries to schedule
for different hours on other days. To run for whole days, omit both times:
"schedule": [{ "days": ["saturday", "sunday"] }].
When using times, supply both start and end in HH:MM format. The start is
included and the end is excluded; 24:00 is allowed only as an end. An end
earlier than the start continues into the next day: Friday 22:00–02:00 ends on
Saturday. Times use scheduleTimezone in autodj.config.json, which defaults
to "UTC". Use an IANA name such as "Europe/Bucharest" or "America/New_York",
or "local" to follow the system clock. Restart AutoDJ after changing this setting.
On Windows, named timezones use Node.js to read the schedule clock before each
track selection; UTC and local time use Liquidsoap directly.
UTC has no daylight-saving changes. With other timezones, skipped hours are skipped and repeated hours follow the schedule again.
For consecutive playlists, use start: "12:00", end: "13:00" on one playlist
and start: "13:00", end: "24:00" on the other, both with days: ["friday"].
At 13:00 AutoDJ finishes the current track before selecting from the second
playlist. Overlapping scheduled playlists share playback according to their
weights and anti-repeat rules; one does not override the other.
Scheduled playlists take priority during their active hours. Otherwise, or if
none has playable audio, AutoDJ uses playlists without schedule or with [].
Keep a regular playlist such as universal for these gaps. If nothing is
available, AutoDJ outputs silence and retries. A playlist outside its scheduled
hours is never used as fallback.
Scheduled playback resolves tracks at each transition instead of prefetching.
Slow or unreadable files can delay the next track. With crossfade enabled, the
schedule is checked when the transition is prepared, before the audible end;
use crossfadeSeconds: 0 to check at the end of the track. Playback without
schedules keeps its existing prefetch behavior.
The output's playlists selection must include the scheduled and regular
playlist IDs, or be empty to include all enabled playlists. Apply schedule
changes with npm run autodj:restart; npm run playlist only updates track lists.
Default output is stereo MP3 at 320 kbps / 48 kHz. Higher-rate input is decoded and resampled. MP3 output does not support 96/192 kHz; the AutoDJ template lists valid bitrate/sample-rate combinations.
Valid Unicode tags are preserved. Titles use Artist - Title when both tags
exist, falling back to the filename without its extension when tags are missing.
AutoDJ publishes through ICY and the DNAS administration API. The supervisor
retains the current title and restores it after SHOUTcast reconnects.
The administration endpoint follows destip and PortBase. HTTP is permitted
only for loopback or local interface addresses. Set RADIO_DNAS_URL to an HTTPS
URL for remote administration and keep administrator credentials private.
RADIO_METADATA_REPAIR=1 enables repair of recoverable mojibake from external
sources. It cannot restore characters already replaced with �; correct those
source tags instead.
AutoDJ and SHOUTcast logging are independent.
| Log family | Settings | Default retention |
|---|---|---|
AutoDJ autodj.log |
logging in autodj.config.json |
Level 2; 10 MiB per file, 5 archives |
SHOUTcast sc_serv.stdout.log and sc_serv.error.log |
SC_LOG_MAX_SIZE_MB, SC_LOG_MAX_FILES |
10 MiB per file, 5 archives per family |
| Native DNAS and W3C logs | sc_serv.conf |
Example: daily rotation, 5 archives |
Controller logs rotate at startup and at the size limit in foreground and
background mode. Archives use names such as autodj_1.log. Default retention
allows up to 60 MiB of newly written data per controller log family; existing
oversized archives remain until retention removes them.
Native DNAS rotation is time-based, not size-based. Monitor disk usage and keep native log paths separate from controller capture files. Do not run two rotators against the same file.
Clear-log commands require the relevant engine to be stopped. They irreversibly empty active logs and retain archives. Retention deletes expired archives; copy required logs before clearing or reducing limits. Log-write failures stop the affected engine.
Stop both engines with the existing controller before replacing code or binaries. Disable supervisor restart loops during maintenance and back up active configs and known-working runtimes.
FTP/archive installations can update from
evopixelro/radioserver, branch main:
npm run autodj:stop
npm run stop
npm run code:update
npm ci --ignore-scripts
npm run doctor
npm start
npm run autodj:startNo Git installation is required. The updater downloads one pinned commit,
checks each file against its Git blob hash and prints a summary of the changes.
File statuses are colored: SKIP gray, ADDED/UPDATED green,
REMOVED/RESTORE yellow and LOCAL red.
Managed files include app/, tests/, entrypoints, package metadata,
Git attributes/ignore rules and .example templates. README.md and LICENSE
are excluded, including from --force and --rollback. Active configs,
playlists, audio, binaries, logs, state and external start scripts are preserved.
Migrate template changes manually. Use Git's deployment workflow for Git checkouts.
The first update backs up and replaces differing managed code. Later updates
stop on local edits unless --force is supplied. Only previously managed files
can be removed when deleted upstream; untracked files are left alone.
npm run code:update -- --check
npm run code:update -- --force
npm run code:update -- --rollback--check previews without writing and can run while streaming. --rollback
requires stopped engines and refuses to overwrite subsequent local edits.
Failed replacements trigger rollback. Interrupted updates block startup until
recovery; if the controller cannot run, restore the saved transaction and backup.
Backups and state live in .run/code-update/, independent of RADIO_RUN_DIR.
Keep the latest transaction and backup until deployment is validated.
Code updates do not install dependencies, update runtimes, execute downloaded
scripts or restart services. Hashes verify the download; review code changes
before deploying them.
npm run update checks managed SHOUTcast, Liquidsoap and FFmpeg for updates:
npm run autodj:stop
npm run stop
npm run update
npm run doctor
npm start
npm run autodj:startinstall and update use stable official releases, not rolling or prerelease
builds. A matching Liquidsoap binary is preferred; Unix hosts without one build
the same version through OPAM. Failed release lookups or missing prerequisites
stop the operation rather than selecting an older or mismatched package.
install reinstalls managed components, even at the same version. update
keeps working, current components and installs missing, changed or damaged ones.
FFmpeg and Liquidsoap updates refuse an automatic downgrade. When a local FFmpeg
build changes, source-built Liquidsoap is rebuilt against it. Configurations and
playlists are preserved. On Windows, FFmpeg is updated with the Liquidsoap bundle.
Liquidsoap assets are checked against published SHA-256 digests or recorded
checksums. SHOUTcast uses the official HTTPS distribution and a locally recorded
digest, not a separate vendor signature. Its latest package is downloaded for
comparison during update; an identical digest skips installation, and the download
is then cleaned up. Keep TLS verification enabled.
Successful installations remove recognized downloads, including older archives, and their empty directories. Unrelated files are kept. Failed installations keep their packages for troubleshooting. Liquidsoap's Debian package dependencies are saved in its runtime manifest; older installations keep their active archive until a reinstall records that information.
Packages are staged and validated where supported. Windows SHOUTcast uses the vendor's interactive installer. The two engine updates are separate operations, not one transaction. If Liquidsoap activation and restoration both fail, the previous runtime is kept outside staging; the error reports its recovery path.
Explicit SC_SERV_BIN/LIQUIDSOAP_BIN overrides are never overwritten. Missing
overrides stop installation, and an outdated Liquidsoap override stops it with
an update message. Without an override, old system or user OPAM binaries are
left untouched while a current private runtime is installed in the project.
Debian/Ubuntu package-owned Liquidsoap can migrate to bin/; its OS libraries
remain external. After validating the local runtime, an old APT installation
can be removed with sudo apt-get purge liquidsoap. Review the proposed removals
and retain shared libraries used by the local binary.
Before putting a host into service:
- Run
npm run doctorand resolve every failed check - Verify audio,
/stats?sid=1,/currentsong?sid=1and the listener application; repeat with each configured stream ID - Restart SHOUTcast mid-track and confirm audio and the Unicode title recover
- Check rapid stop/start, supervisor shutdown, log retention and restart after reboot
- Restrict administration/source ports, protect credentials and use HTTPS for remote administration
- Run a sustained streaming test; monitor disk usage, process exits and stream availability
Doctor validates configuration, native dependencies and generated Liquidsoap scripts without replacing active playlists or logs. Public routing, reverse proxies, listener load and runtime compatibility need checks on the target host.
app/ Controller modules
bin/ Managed runtimes and download cache
playlists/universal/ Default audio library
tests/ Unit and integration tests
autodj.config.json.example AutoDJ settings
playlist.config.json.example Playlist settings
sc_serv.conf.example SHOUTcast settings
autodj.js AutoDJ entrypoint
server.js SHOUTcast entrypoint
State lives in .run/, logs in logs/, and DNAS access lists in control/
by default. Active configs, audio, binaries and generated files are excluded
from Git. No build step is required.
Run npm test for unit and integration tests. Platform tests cover detection,
command routing and installer decisions. Set LIQUIDSOAP_TEST_BIN to enable
native tests against local test servers (scheduled playback tests require
Liquidsoap >=2.4.5); LIQUIDSOAP_TEST_RESOURCES also tests
the relocated Linux standard library. Set SHOUTCAST_TEST_BIN to check DNAS
startup, restart and shutdown through the controller. With both executables set,
tests also check MP3 streaming and UTF-8 metadata on isolated local ports.
Tests without a required runtime are skipped. Test results do not replace
deployment checks.
GitHub Actions runs one job each for Ubuntu 22.04, Windows Server 2022, macOS 14, FreeBSD 14.4 and Fedora 44. All jobs check the Liquidsoap/FFmpeg installer, run the test suite and repeat the native playback tests. FreeBSD and Fedora run in virtual machines. Ubuntu also checks that the system FFmpeg 4.x remains unchanged.
Real SHOUTcast installation and streaming tests run on Ubuntu and FreeBSD x64. FreeBSD uses Linuxulator for DNAS, with native Liquidsoap and FFmpeg. The Windows, macOS and Fedora jobs test the controller and Liquidsoap but do not run a real DNAS stream. A passing macOS job does not imply native SHOUTcast support.
| Variables | Purpose |
|---|---|
SC_SERV_BIN, LIQUIDSOAP_BIN |
External executable paths or commands |
SC_SERV_CONFIG |
DNAS configuration path |
RADIO_PLATFORM |
Host profile; automatic by default |
RADIO_RUN_DIR, RADIO_LOG_DIR |
State and log directories |
SC_SERV_ARGS_JSON |
Additional SHOUTcast arguments as a JSON string array |
SC_LOG_MAX_SIZE_MB, SC_LOG_MAX_FILES |
SHOUTcast capture limits: 1–1024 MiB, 1–100 archives |
AUTODJ_ROOT |
AutoDJ working directory |
RADIO_DNAS_URL, RADIO_DNAS_PORT, RADIO_ADMIN_PASSWORD |
Metadata administration endpoint and credentials |
RADIO_STREAM_ID |
Stream selection for optional metadata repair |
RADIO_METADATA_INTERVAL_MS, RADIO_METADATA_REPAIR |
Metadata check interval and encoding repair |
Relative config, state and log paths resolve from the repository root.
Use absolute playlist paths when changing AUTODJ_ROOT.
The controller is licensed under GPL-3.0-only. SHOUTcast, Liquidsoap and their dependencies retain their own licenses. Vendor binaries are not included in this repository.