Creating a Radio Station with Docker

I love music. I have been curating and collecting tunes since the nineties, when I had to go to the library to download MIDI files, which I would bring home on 3.5in floppy disks.
My dad had an old Toyota Corolla filled with carefully hand-curated mix-tapes, but I was the one who figured out how to burn mixes on to CDs.
Opening Pandora's Box
I couldn't quite afford a proper iPod, but every picture of me from 2005 through 2008 contains a bright white iPod Shuffle — a now-embarrassing fashion choice, but that Shuffle was my constant companion and its mp3 mix was of critical importance.
Pandora changed how I listened to music again, exposing me to algorithmic analysis of my tunes and helping me to find new songs to jam to.
Rdio was better — I could listen to any tunes that I wanted and share them with my friends.
With Spotify I could sync them to my devices really easily.
With Google Music I could also add my own tracks, which let me load loads of OCRemixes and Soundcloud songs back into my playlists.
These services, though, took a lot of power away from me. I wasn't really curating my music anymore.
The Weighting Game
Okay, let's talk about the Cake problem. Or the Tragically Hip problem. Or the Madonna problem. Or the Harry Belafonte problem.
I want to have a Cake song in my playlist.
But I don't want that Cake song to be, uh, the _same_ Cake song every single time. They have a lot of good songs.
On the other hand, there are some songs — Lone Digger, or Violet Stars Happy Hunting / Many Moons that I can listen to again and again and again.
I want to listen to the song "Lone Digger" about as often as I want to listen to one song, selected randomly, from the entire Cake discography.
The problem with modern playlists is that a band's likelihood of coming up in the playlist is, uh, inherently tied to how many songs from that band you put in the playlist. Some bands have so many hits that when you drop them in to a playlist, the playlist becomes _theirs_.
Two Goals

I want to control not just the songs in my playlist, but their relative weights when being selected by the randomization algorithm.
I want to be able to control and stream my own music collection, from anywhere.
Those of you who are familiar with Icecast probably know where this story is headed. An open-source solution to this problem has existed for ages. I just had to build a streaming server.
The Laziest System Operator of Them All
Why Docker, though?
Okay, so, this is a different part of the story, but I run my own dedicated server, because I like burning money, and also because I run a lot of personal projects and I started to get frustrated trying to track down all of them.
There's one rule on the dedicated server to keep the process model neat and tidy: the only things it keeps running are Docker, and Nginx. If I want to run a service, it has to be containerized. It makes managing this beast _very easy_.
Bash, Secret King of the Automation Languages
So, the entire app is just a shell file that creates config files and boots up docker containers. That's it.
We start by killing the container, if it's running right now
sudo docker kill $ICECAST_CONTAINER_NAME
sudo docker rm $ICECAST_CONTAINER_NAME
Then we write an icecast.xml file:
cat >./icecast.xml <<END
<icecast>
...
</icecast>
END
Then, we boot up an icecast container — thanks, moul.
sudo docker run \
-p 127.0.0.1:$ICECAST_PORT:$ICECAST_PORT \
--name $ICECAST_CONTAINER_NAME \
-v `pwd`/icecast.xml:/etc/icecast2/icecast.xml \
-d moul/icecast
Icecast just exists to stream an audio (or video) source — it isn't, in and of itself, an audio source.
So, we need to do the same things we've just done with Icecast to a separate application, called LiquidSoap.
LiquidSoap contains a _powerful scripting language_. It is a scripting language for playlists — I have trouble imagining something more exciting than this specific technology.
So We Kill and Boot LiquidSoap in the Shell File, Too
sudo docker kill $LIQUIDSOAP_CONTAINER_NAME
sudo docker rm $LIQUIDSOAP_CONTAINER_NAME
cat >./liquidsoap.liq <<END
#!/usr/bin/liquidsoap
...
END
sudo docker run \
-p 127.0.0.1:$LIQUIDSOAP_PORT:$LIQUIDSOAP_PORT \
--name $LIQUIDSOAP_CONTAINER_NAME \
-v `pwd`/liquidsoap.liq:/tmp/config.liq \
-v $HOST_MUSIC_DIRECTORY:$MOUNT_MUSIC_DIRECTORY \
-d moul/liquidsoap \
sudo -H -u www-data bash -c 'liquidsoap --debug --verbose /tmp/config.liq'
Anyways, the Whole Thing is Simple Enough To Be A Github Gist
And here it is:
https://gist.github.com/classam/04d6d2931bf1a4ed92ce1b59d1b696bb
It _should_ be simple enough that you can read it and modify it to your own tastes, if you want to run your own internet radio station.
When That's Done
So, with that running on a server, we're running icecast on a port - 8000 - and we can connect to our server at serverdomain.com:8000/groove.ogg and listen to our tunes!

It works through a browser, although VLC does a more efficient job. I can also connect from my phone using an app called TuneIn Radio.
I can listen to my radio station from any computer, anywhere. I have cheap enough data on my phone that I can even keep the tunes going while I drive without needing to fall back to music that's loaded on the phone.
Security and Legality Concerns
I used nginx to hide my stream behind HTTPS and Cloudflare, and do some elementary password protection on the stream —
It's probably not legal to stream my music collection to _anybody who's not me_ on the internet, but my extremely cursory security pass should be enough to at least allow me to argue that the stream is intended for private use only.
For that same reason, I can't really share the final result with you. The radio station is for me!
A Web Interface
https://github.com/classam/radio-player
While I _usually_ just listen to the radio station on VLC media player, I thought I'd have some fun and build a web interface for the radio station.
With a visualizer, because I found a cool tutorial — shout-out to Soledad Penadés for writing the code in the first place.
Recording Loads of Fake Radio Promos and Ads

This was easily the least necessary part of the whole project, but I recorded a whole bunch of fake radio ads for my fake radio station.
It's not a real radio station if it doesn't have someone shouting at you between songs every now and again.
More Ideas
I've thought of doing the same thing with _video_, which would be the same kind of project but an order of magnitude more complex, I think.
I know it's possible to record stretches of radio play — I'd like to save about 10 hours of radio play on to my device for the odd plane trip or out-of-service area, and I'd like that 10 hours to update every now and again so that I don't get accidentally stuck with christmas music in July.
I'd like to build something that I could share with other people, although I guess it would have to be entirely creative commons music? I've found maybe five CC albums my entire life that I've liked, so it seems unlikely.
The original site didn't record this post's date; this one is approximate.
Tagged api-key, blog, cube drone