Station Server
Puts a station-studio playlist on air. It plays the week's tracks in order, in real time, and sends them straight to your SHOUTcast or Icecast server with each song's title. That replaces iTunes playing out of the headphone jack, the loopback cable, and Winamp with the SHOUTcast DSP plugin.
No sound card is involved: the music files are decoded, joined and encoded inside Station Server. Nothing else playing on the computer (a YouTube video, system sounds) can reach the broadcast, and one computer can run both stations.
Status: 0.4: an app you download and install, running as many stations as you like on one computer, that updates itself. Each station has its own playlist, server and play log. See the plan.
Install
Download (no Python or terminal needed): a Mac .dmg (Apple Silicon
or Intel) or a Windows setup .exe, each with its own ffmpeg. They're on
each server-v… release of this repository. They're also built for
every pull request that changes Station Server: open the pull request's
Checks › Station Server installers run, and download from its
Artifacts.
- Mac: open the
.dmgand drag Station Server to Applications. The first time, macOS says it can't check the app: open System Settings › Privacy & Security and click Open Anyway (the app isn't signed with a paid Apple certificate). - Windows: run the setup. If SmartScreen stops it, click More info › Run anyway. It installs for you only, with no administrator password, and adds Station Server to the Start menu.
Then, on the station's computer, turn on Settings › Start Station Server when I log in, so that after a restart, a power cut or Windows updates it starts in the background and puts the stations that were on air back on air. On a Mac it's also started again if it ever stops unexpectedly.
From a checkout (for development, or Linux): you need Python 3.11 or
newer and ffmpeg with its MP3 encoder (macOS: brew install ffmpeg;
Windows: winget install ffmpeg; or point Station Server at one with
--ffmpeg PATH or $STATION_SERVER_FFMPEG).
python -m venv .venv
.venv/bin/pip install ./player ./server # Windows: .venv\Scripts\pip
Station Server reads playlists with station-player's code, so both are
installed. Then run .venv/bin/station-server (Windows:
.venv\Scripts\station-server).
You'll also need the music on the computer, and the playlists exported from station-studio (or any iTunes / Music XML).
The app
.venv/bin/station-server
opens Station Server in a window of its own (with Chrome, Edge or Brave; otherwise a browser tab). It keeps running in the background: closing the window doesn't take a station off air, and running the command again just opens the window. Quit in the sidebar stops it.
- Add a station. Give it a name and its playlist: a station-studio
export, or better its exports folder
(
~/.station-studio/exports/rebirth-classics), so the newest week is played and next week's is picked up by itself at the end of a track. - Server. SHOUTcast or Icecast, the address and port, and the source password. Test connection checks them without going on air.
- Go on air. The station page shows the track playing, the running order with the time each track goes out, and any tracks whose files can't be found.
Joining the week by the clock. The playlist's first track is pinned to the start of the week (Monday 00:00 unless you change it), and the tracks' lengths say when each of the others airs. Go on air on Wednesday afternoon, or restart after a power cut, and the station joins where the clock says, part way into a track. Choose From the top to start at track 1 instead. A playlist shorter than a week loops.
A station that was on air when the app quit goes back on air when it starts. If no track in the playlist can be read, it sends silence and keeps trying rather than dropping off the server.
Play log. Every track played is logged; download a date range as CSV for PRS and PPL returns (the same format as station-player's).
Dock and taskbar icon. In the app window, Settings → Install as app
gives Station Server its own icon in the Dock or taskbar, with Add a
station and Play log on its menu, and it opens that way from then on.
Opened from there while Station Server isn't running, the window starts it
(through the station-server:// link the app registers) and waits.
New versions. As in Station Player and Station Studio, a note at the foot of the sidebar says when a new version is out, and Settings › Updates has Check for updates and Update now: the downloaded app fetches the new version from its GitHub release, checks it's the genuine file, and restarts; stations that were on air go back on air. It asks GitHub once a day; turn that off in Settings.
Two stations on one computer. Add a station for each; they run side
by side, each with its own playlist, server, clock and play log, and go on
and off air separately. Rebirth Classics to shoutcast://…:8000 and
Rebirth Radio to shoutcast://…:8002, say, from one PC.
Settings, passwords, play logs and the log file station-server.log are kept in ~/.station-server
($STATION_SERVER_HOME to change it); the settings file is readable by
you only. station-server app --port N uses another port than 8770.
From the command line
Check that ffmpeg is found and the playlist's music is all there:
station-server check ~/.station-studio/exports/rebirth-classics-week-12.xml
Record what listeners would hear to an MP3 (and the titles to a .txt beside it):
station-server play week-12.xml --to test.mp3 --once
Go on air
The password is the source password (the one Winamp's DSP plugin uses).
Give it with --password, or set STATION_SERVER_PASSWORD so it isn't
typed on the command line.
SHOUTcast (DNAS 1.9.x or 2.x). Use the listener port, the one in the station's link; Station Server connects to the port above it, as Winamp does.
station-server play week-12.xml --to shoutcast://81.150.147.206:8000 \
--name "Rebirth Classics" --genre "Vintage Oldies / Club Classics" \
--url https://www.rebirthclassics.uk
For stream 2 on a DNAS 2.x add ?sid=2: shoutcast://host:8002?sid=2.
Icecast (2.4 or later), to a mount:
station-server play week-12.xml --to icecast://source@my.server:8000/classics
While it plays, the window shows each track as it starts. Type s and
Enter to skip a track; Ctrl+C stops.
Trying it on a Mac with your own Icecast
No station needed: run Icecast on the same Mac and listen in station-player.
brew install ffmpeg icecast
mkdir -p "$(brew --prefix)/var/log/icecast" # Homebrew doesn't make it
icecast -c "$(brew --prefix)/etc/icecast.xml" # leave running; Ctrl+C stops
http://localhost:8000 shows Icecast's status page. Its source password is
hackme until you change <source-password> (and <admin-password>) in
that icecast.xml. In a second terminal run .venv/bin/station-server,
add a station with the playlist folder
~/.station-studio/exports/rebirth-classics, server Icecast,
localhost, port 8000, mount /classics, password hackme, and go on
air. Or from the command line:
.venv/bin/station-server play ~/.station-studio/exports/rebirth-classics/012.xml \
--to icecast://localhost:8000/classics --password hackme --name "Rebirth Classics"
Then add the station http://localhost:8000/classics in station-player.
The title changes with each track, and the status page shows the stream.
No music to hand? python server/tools/make_test_station.py makes a
folder of short test songs and a week's station-studio export in
~/station-server-test, and prints the exports folder to use as the
playlist. --week 13 adds next week's, to watch the switch-over;
--missing adds a song whose file isn't there.
Trying it next to Winamp
Only one source can feed a stream at a time. To compare without taking the
station off air, send Station Server to a spare stream: a second DNAS on
another port, stream 2 on a DNAS 2.x (?sid=2, set up in its config), or a
test Icecast mount. Listen to both in station-player.
Command-line options
| Option | What it does |
|---|---|
--playlist NAME |
Which playlist, when the XML has several (a full library export) |
--music-folder DIR |
Where to look for tracks that have moved since the XML was made (repeatable) |
--remap FROM=TO |
Rewrite a path prefix, e.g. a Mac library played on a PC: --remap "/Users/rob/Music=D:/Music" |
--start N |
Start at track N |
--once |
Stop at the end of the playlist instead of starting again |
--bitrate KBPS |
MP3 bitrate, 128 by default |
--no-level |
Turn off volume levelling |
--name, --genre, --url |
What the server shows about the station |
--public |
Ask the server to list the station in its directory |
How it works
playlist XML ─► each track decoded by ffmpeg ─► mixer (gapless, levelled)
─► held to real time ─► one MP3 encoder ─► SHOUTcast / Icecast
- Gapless. Tracks are joined as raw audio before one encoder, so there's no gap and no reconnect between songs.
- Volume levelling uses the ReplayGain or iTunes Sound Check values in each file (read by station-player), never boosting more than 10 dB or past the track's peak. Files without them play as they are for now.
- Titles reach the server when the track is actually heard, not when its audio is first sent.
- Dropped connection. If the server goes away, Station Server keeps playing and reconnects every 5 seconds. A track it can't read is skipped.
Releasing
Bump the version in server/pyproject.toml and
server/station_server/__init__.py, merge, then run Actions ›
Publish Station Server on main. It tests, makes a draft
server-v<version> release, builds the Mac and Windows downloads onto
it, and publishes it once they're all there.
Development
cd server
python -m pytest -q
The tests run without ffmpeg, skipping the end-to-end ones; with ffmpeg installed they also play real audio through fake SHOUTcast and Icecast servers.
Metadata
Release files for station-server 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| station_server-0.4.0.tar.gz | 234.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| station_server-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 477.4 kB
Release files / station_server-0.4.0.tar.gz
| Download URL | station_server-0.4.0.tar.gz |
|---|---|
| Size | 234.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
abc5964b934dfa9ffea137c12f5c461f782d025f51495d231abcc283aed03fef
|
|
BLAKE2b-256 checksum How to use checksums |
e009da59f0f4d55f2c4135a621eaf077c6e925dfd02b31136a433fd2cd509e53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / station_server-0.4.0-py3-none-any.whl
| Download URL | station_server-0.4.0-py3-none-any.whl |
|---|---|
| Size | 242.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a57e29359a82b12d7674cdc60d8c33141fbb1b57b0f688038720a7e40d21507d
|
|
BLAKE2b-256 checksum How to use checksums |
e35d2a3213fcb6479d58563ebab2caa45da6e075ce7f52b890d1365c2fe7e2b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for station-server 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for station_server-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.