160 kilobits per second, 44,100 hertz, and one shared pointer on the server - that, roughly, is what the continuous stream on /radio is built from. "Music without stopping," in everyday speech, means "press play and don't touch it." In technical speech it means something else entirely: a stream where the track position does not live in your browser but in the broadcaster's database. The gap between those two meanings is exactly why some services drop out on the move and others don't.
The MP3 the stream rides on is a codec with nearly thirty years of history. MPEG-1 Audio Layer III was developed by a working group at the Fraunhofer Institute under Karlheinz Brandenburg; the algorithm was tuned on Suzanne Vega's "Tom's Diner," which is why Vega is half-jokingly called the "mother of MP3." On 23 April 2017 the last patents on the format expired and licensing fees for manufacturers stopped. At 128 kbit/s a file shrinks roughly elevenfold against uncompressed CD-Audio (1,411.2 kbit/s); the working bitrate range is 8-320 kbit/s.
Codec, bitrate and two files per track
Every track in the catalog has two audio files. One is full-size, for download; the other is re-encoded for streaming. The transcode is done by ffmpeg through the libmp3lame library: the source is run into MP3 at a 44,100 Hz sample rate with ID3v2.3 tags. The stream bitrate is pulled from configuration and clamped to a hard corridor of 96-224 kbit/s; the default is 160 kbit/s.
Why LAME specifically, and not any other encoder: in public listening tests run by Roberto Amorim in 2004, LAME produced the closest-to-original sound at medium bitrates from 128 kbit/s and up. 160 kbit/s lands squarely in that zone - there is no audible degradation on ordinary speakers, and the file stays light enough to load over a mobile network.
Detail: only sources up to 1,800 seconds long get re-encoded. Longer tracks receive a stream copy trimmed at that threshold - a rarity for dance music, where six to eight minutes is normal and thirty is already an outlier.

The channel catalog itself is not an arbitrary list but a generated grid. Decade channels are hard-bound to years: decade:80s is tracks from 1980 through 1989, decade:90s from 1990 through 1999, all the way to decade:20s (2020-2029). Genre channels are built from the genres table and deduplicated by canonical slug: variants like "italo-disco" and "italo-disco-remix" collapse into one channel so the grid does not sprout visual duplicates. The /radio pages ship two flavors of schema.org markup - RadioBroadcastService and MusicPlaylist: the first describes the broadcasting service, the second the air content as a playlist, without listing hundreds of tracks by hand.
Music without stopping: how rotation works on the server
There are several dozen channels on /radio, and they split into two types by who holds the position. Broadcast channels - all, fresh, top, by decade, by genre, by similar tracks and mood scenarios - are synchronous: a single pointer to the current track for all listeners sits in the radio_broadcasts table. There is exactly one personal channel - favorites - and there each listener has their own queue.
Synchronicity works like this. Every 20 seconds the browser hits the /api/radio/sync endpoint and gets back four numbers: the track id, started_at_ms (when the track started on the server), duration_ms (its length), and server_time_ms (server time at the moment of response). The difference between server time and start gives the position in the track; the client adds the elapsed local time, corrected for clock skew, and seeks to that point. The result: two listeners who join the same channel a minute apart hear the same second of the same song.
To avoid pulling a full payload every time, sync returns an HTTP ETag header. As long as the track has not changed, the server answers 304 Not Modified with no body - that is 19 of every 20 requests. The precise re-fetch fires 500 milliseconds before the track ends: the server catches the rollover and hands out the next record. After the end a 750 ms grace window remains, in case the client lagged slightly.
- Broadcast channels (synchronous): all, fresh, top, decade:70s-20s, genre:*, mood:v-mashinu, mood:dance, similar:*. One pointer - everyone hears the same thing.
- Personal channel (favorites only): each listener has their own queue, no shared position. Requires login.
- Genre channels appear in the grid only if the genre has ≥ 3 published tracks - otherwise it is not radio but one or two songs under a label.
- Thin decade channels (fewer than 5 tracks) stay reachable by direct URL but drop under
noindex,follow- indexing one or two songs as "radio" is dishonest.
The 5-track threshold is not pulled from thin air: at that line decade:70s (two records) and decade:20s (four) go under noindex, while decade:10s (five) stays indexed - five tracks is the minimum where a listener gets through the whole air before a repeat. The genre threshold is stricter: below three published tracks a channel does not enter the grid or sitemap at all, though it still opens by direct link.
Why the stream breaks specifically on mobile
Between the "load track" command and actual sound, HTML5 audio eats 1-3 seconds on buffering. On home internet that is invisible; on a mobile network, where latency jumps, those seconds let the server pointer run ahead, and the listener starts playing earlier than everyone else. To let a newcomer catch the shared air, the client makes two fast drift corrections - at 1,500 ms and 4,000 ms after start - and pulls the position toward the server's. The goal is to fit inside the shared stream within 300-500 ms.
Drift is watched constantly: if the local position drifts more than 700 ms from the server's, the client seeks back. 700 ms is a compromise. The human ear, without a "track playing right next to me" reference, notices desync from about 150 ms - but seeking on every tick is audible as micro-jumps. The threshold keeps "everyone in unison" without yanking the audio on every network hiccup.
If the network drops entirely, the sync request hangs to a 10-second timeout and aborts. Three network errors in a row on a personal channel and the client stops; on broadcast the player finishes the buffered chunk and waits for the network to return. Here lies the main difference from classic internet radio: your buffer does not accumulate stream "for later," the way Icecast stations do - you have the current track in full and a pointer to where the shared air sits inside it.

The personal "favorites" channel is built differently, and the difference is worth seeing. Each listener has their own queue, and a shared pointer is meaningless here. The browser remembers the last 50 played tracks in localStorage under the key dm.radio.recent and passes their ids in the exclude parameter of the /api/radio/personal/next endpoint - the server returns the next track from your likes, without repeating what just played. Thirty seconds before the current track ends, the client preloads the next one so the handoff has no loading pause. The exclude limit is 100 ids, so the URL does not bloat.
Not Icecast, and not a crossfade
Classic internet radio is built differently: a station generates a continuous audio stream, a replicator server (Nullsoft's Shoutcast or the free Icecast) distributes copies to all clients, and server traffic grows proportional to the listener count. There the listener connects to a "pipe" and catches whatever is playing right now. Disco Magic has no pipe - the browser pulls a track's MP3 file over HTTP, and an API with a pointer provides synchronicity. It is cheaper on traffic and lets the stream copy go out at 160 kbit/s while the full version ships as a separate download file.
There is no crossfade here either, and that is deliberate. A crossfade - the smooth blending of one track's tail into the next's intro - is standard for a DJ set and hour-long mixes, but for radio, where you came to hear songs whole, it cuts endings. Instead a server-side rollover does the work: 500 ms before the end the client re-asks the server, gets the next track and loads it. There is a seam, but an honest one - you hear the track from the first bar to the last, not a fading tail under the next intro.
The same mechanism runs on filtered pools for mood scenarios. The mood:v-mashinu channel gathers tracks at 120-140 BPM from three dance genres - not a random "whatever's next" but a tempo selection suited to driving. The tempo angle is unpacked separately in the disco BPM guide, and how to build such a stream by hand as a playlist is in the italo-disco playlist breakdown.
So that the channel does not show an empty "now playing" card for the 200-600 milliseconds the first sync spends in flight, the server bakes an initial air snapshot straight into the page: the current track, its offset and length ship in the HTML, and the player draws the progress bar immediately, without waiting for the API. Then the heartbeat takes over and the card updates through sync. This pairing of "server snapshot + client synchronisation" is what makes the stream feel continuous - you never catch the moment of "radio loading," only a track already playing.
Where the continuous stream has edges
The stream has boundaries worth knowing in advance. Cross-tab relay: if you open a channel in a second tab, the first stops quietly - two streams do not hammer the API at once. Login is required only for favorites; every broadcast channel listens anonymously. A rate limit sits on the personal-next endpoint: under request flooding from one IP the server answers 429 with a Retry-After header, and the client backs off exponentially. That is abuse protection, not a paywall.
The semantics of "continuous stream" here are literal: track follows track by the server pointer, with no ads and no listener intervention. How European stations built retro broadcasting in the same genre is covered separately in the survey of European retro radio stations. And if you want not the shared air but your own order - the same catalog ships as a playlist, and the difference between the two ways to listen comes down to one thing: who holds the position, the server or you.