'Communication Revolution in Health: Media, Counseling, and Gender' from The National Library of Medicine. | Flickr (edited by the Author)
Announcing My New Radio Show (a Love Letter to Public Access Television)
There is something I adore about public access television. The often awkward, always underfunded shows broadcast by people out of passion rather than chasing a paycheque. The television nobody watched. Well, not nobody. There's the host's mom, or a third-shift worker with the sound off, or a sleepless teenager channel-surfing at 2am.
Public access television existed at the frequency of good intention. No ratings. No sponsors. No notes from the network. Just a person, a camera they'd borrowed from the community media centre, and heart goddammit.
I found myself watching these when I was a child. In Calgary, Shaw Community Television was on Channel 10, broadcast from studios on Macleod Trail and another on 27th Avenue Northeast. In Winnipeg, there was VPW 11, run by Videon Cable dating back to the late 1960s, only to be absorbed by Shaw in 2001.
I found something so comforting watching these everyday people on modest sets. The low fidelity camera equipment and questionable signal quality. By the time I was watching in the early 2000s, community access studios were running on consumer-grade Sony Hi8 and MiniDV camcorders, pedestal-mounted cameras with CCD sensors with automatic gain cranked up in low light, shadows turning into grey static snow. Character generators stamped text onto the bottom of the screen in thick, pixelated fonts. The flat, faintly greenish cast that made everyone look like they've just received bad news. Microphones were built into the camera itself. Every breath, rustling paper, and chair-squeak picked up with democratic impartiality.
Hand-lettered title cards. Sets made with whatever was available in the room. Hissing audio. A host looking to the left of the camera for the first minute before someone off-screen gestured. A show made by someone who cared about the content but had not yet been taught to care about the container.
An Oral History of Public Access
The Cable Communications Policy Act of 1984 mandated cable operators to set aside channels for public, educational, and government use as a condition of their municipal franchise agreements. Every city that let a cable company run wire through its streets was owed a channel—a commons.
These were shows run by public grassroots and non-profits. The cable company, as part of its agreement to have the franchise for the city, would put aside money for a "public access" studio where the community could air and produce its own videos, by using the studio or bringing in tapes. It could be anything. And that's what is so ideal and liberating about the concept—anybody in the community could create and share something with their city or state. Run for and by the locals.
Sure, there was the dry, sleep-inducing city council meetings, school board meetings, and educational programming on how the government operates. But there was so much more than that.
Paper Tiger Television, founded in 1981 out of New York, made the aesthetic into a politic. Shows featured media critics reading newspapers aloud and dismantling them in real time, the credits hand-drawn on cardboard, the budget posted on screen. Transparency about constraint was the argument itself. The expensive slickness of commercial television was not a neutral condition. It was a statement about who had resources and who didn't, whose speech came pre-validated by production value and whose didn't.
Guerrilla television was artists and activists in the late 1960s and 70s who got their hands on Sony Portapaks—the first consumer-grade video cameras, heavy as bricks—and ran with them. The Videofreex. TVTV. The Portapak cost around $1,500, weighed twenty-five pounds including battery and tape, and produced black-and-white images that would smear if you panned too fast. Point it at direct sunlight and you'd burn a permanent hole in the tube. None of that mattered. Video was a tool for the people who hadn't been allowed near a camera before. The pictures were grainy and framing was unstable, and it was television nonetheless.
The Manhattan Neighborhood Network was one of the largest expressions of this. Four channels in New York City where anyone could produce and broadcast. A chaotic archive of programming defying easy description. John Wallowitch played live requests on an out-of-tune studio piano every week, a brandy snifter full of money and a photo of his mother on the lid, calling it "the only piano bar of the airwaves." Beyond Vaudeville ran from 1987 to 1996, an odd talk show featuring what its host called "weird characters"—a rapping grandmother, a postal worker who whistled competitively—and became popular enough that MTV adapted it as Oddball in 1997. Weber Cooks was a cooking show where the host microwaved Rice-A-Roni and jars of Cheez Whiz. The Church of Shooting Yourself starred Rik Little as a faux-newsman reporting from the East Village, whose invented religion held that God was too busy to watch our every mistake and therefore we had to film ourselves and watch our own sins. Midnight Blue was Al Goldstein talking frankly about sex.
Mystery Science Theatre 3000 began on Minneapolis–St. Paul's KTMA. Alex Jones honed his indignant outrage on Austin public access before being given a platform that could do real damage. There were shows hosting local musicians performing originals in front of a backdrop made from bedsheets safety-pinned to the curtain rail.
My favourite shows included call-ins from the public, and these conversations were either level-headed and respectful, or far too opinionated and loud for the quiet existence of the genre. And of course, with live broadcasts and no budget for proper screeners, prank calls were inevitable. rAw TiMe out of Austin, Texas ran a music video show in the late 1990s and early 2000s where a host named Tinarina—a teenager in goth makeup—fielded an unrelenting stream of catcalls and insults from callers with indomitable, immaculate composure. Let's Paint TV had John Kilduff running on a treadmill and painting simultaneously while callers mocked his canvases, yelled gang affiliations, and told him to run faster. Flaccid Ego: Psychic Reading Call-in Show had CB Walker—pink turban, pink glasses, pink scarf—offering free psychic readings and received mostly people shouting "Your Mother!" before hanging up. I don't like cruel jokes where someone's punching down. But a prank call where the caller is just being absurd and deadpan enough to sustain it for a few minutes? Acting as an indignant foil for the host? That particular jester is after my own heart.
To me, I can't help but feel parallels between the IndieWeb and corporate social media comparable to public access television and cable networks, respectively. In Canada, this was called "community television," and I can't think of anything I value more. In a way, this is a natural next step for me and my independent publication, and I hope to be able to gain a new audience and point them towards education and advocacy just as much as I want to inspire and entertain them.
Things certainly have changed, haven't they? Nobody really watches television at all now. Nielsen's December 2025 Gauge report reported that streaming captured 47.5% of all US television viewing, which was the largest single share ever recorded. Cable held just 20.2% and broadcast 21.4%. In May 2025, streaming exceeded the combined viewership of cable and broadcast television for the first time ever. Cable TV household penetration has fallen from 88% in 2011 to around 34% today. A Pew Research Center report from July 2025 found only 36% of Americans still subscribe to cable or satellite at all. Among people aged 18 to 29, that number drops to 16%. 77 million American households have now cut the cord entirely.
This is exactly why I've decided to start my own radio show.
Radio is television's older sibling. The pirate stations, the micro-broadcasters, the people who went on air because they had something to say and commercial broadcasting was never going to give them a slot. My project is not pirate radio—I'm not breaking any rules—but the spirit is the same, I think. There is something that can only be said on air, in the middle of something, in real time.
I've been wanting to do a radio show for years. It's not public access television, alas, but that's something I still want to emulate at least in a way. I've been a huge fan of podcasts for years, but they just aren't the same. The difference matters to me. A podcast is a document. Radio is a presence. You tune in, you catch what's happening, you're in the middle of something. I want to do a variety show—music and interviews and call-ins. I want to give locals and people all over the independent web a platform. And I want it to be done open-source, free, and independent.
So, I finally decided to try to build one. This is how it works.
The Infrastructure
For the sake of ease, I've started this project on a DigitalOcean droplet. Ubuntu 24.04, 2GB RAM, 1 vCPU, 50GB SSD. About $12 USD/month. The streaming server is AzuraCast, a free, open-source, self-hosted radio management platform. It bundles three things into a single Docker container:
- Icecast2 (the actual audio server)
- Liquidsoap (the automation engine)
- A web UI for admin management.
DNS is split two ways:
radio.brennan.day→ the droplet IP directly (no CDN, no intermediary)fm.brennan.day→ Netlify, where the public-facing website lives
The website is built with Eleventy, same as brennan.day. It has a live player, an episodes archive, an about page, and a support page for the Toonie Club. The now-playing widget polls AzuraCast's public API every 15 seconds and updates in place without a page reload.
The Broadcasting Chain
When I go live, the signal travels like this:
Mic (USB) → PipeWire
Mixxx (music) → qpwgraph (virtual routing)
↓
BUTT encoder
↓
Liquidsoap harbor — radio.brennan.day:8005
↓
Icecast2 — /radio.mp3 mount
↓
https://radio.brennan.day/listen/brennan_fm/radio.mp3
BUTT (Broadcast Using This Tool) is a tiny open-source encoder with a hilarious name that takes audio input and pushes it to a streaming server. BUTT should connect to Liquidsoap's harbor on port 8005, not directly to Icecast on port 8000. When you bypass Liquidsoap and connect straight to Icecast, AzuraCast can't track that you're live, the now-playing API doesn't update, and Liquidsoap keeps crashing trying to reclaim its mount.
When I connect through BUTT, AzuraCast's API returns is_live: true and streamer_name: "Brennan (Kenny)". The site widget flips to a pulsing Live badge. Listeners hear the live stream. When I disconnect, Liquidsoap's AutoDJ takes over immediately.
Audio routing on Linux uses PipeWire with qpwgraph as a visual patchbay. Drag a wire from Mixxx's output to BUTT's input, drag the mic in alongside it.
The AutoDJ
When I'm not on air, I wanted something better than silence or a loop of six tracks, but I also didn't want to spend hours curating a library before the station was even live.
So, a Python cron job that scrapes the Internet Archive for public domain and Creative Commons recordings and drops them into AzuraCast's media folder hourly.
The Internet Archive has an enormous collection of freely usable audio: digitized 78rpm records from the 1920s–50s, Creative Commons music from netlabels and the Free Music Archive, old-time radio dramas, LibriVox poetry and short stories. All of it accessible via a simple search API and no key is required.
The script (/opt/refresh_autodj.py on the server) does this every hour:
1. Pick a random search query. There are about 30 in the list, things like:
'collection:78rpm mediatype:audio subject:(ragtime)',
'collection:oldtimeradio mediatype:audio subject:(science fiction)',
'collection:netlabels mediatype:audio subject:(ambient)',
'collection:librivoxaudio mediatype:audio subject:(poetry)',
The Archive's Advanced Search API takes these as plain URL parameters. The query string looks like:
https://archive.org/advancedsearch.php?q=collection:78rpm+subject:(ragtime)
&fl[]=identifier&fl[]=title&fl[]=creator
&rows=50&output=json&sort[]=random
2. Fetch MP3 metadata and filter by size. Once you have an identifier (like 78_tiger-rag_freeman-clark), a second call to archive.org/metadata/{identifier} returns the file list. The script filters to MP3s between 500KB and 60MB:
mp3s = [f for f in files
if f.get("name", "").lower().endswith(".mp3")
and 500_000 < int(f.get("size", 0)) < 60_000_000]
That way, you only get real recordings and not short jingles, intros, or anything else too short. But you also don't get any track too large.
3. Download 3 new tracks per run and save them to AzuraCast's Docker volume at /var/lib/docker/volumes/azuracast_station_data/_data/brennan_fm/media/, that's the path that's mounted inside the container (not the /var/azuracast/ path that appears inside Docker, which was my first mistake).
4. Run CheckMediaTask --force first, wait 5 seconds, then insert into the playlist. The order matters. CheckMediaTask is what scans files on disk into AzuraCast's station_media table. If you run the MariaDB INSERT before the scan completes, the new files don't exist in station_media yet and the INSERT silently skips them. The script waits 5 seconds after the scan before running:
INSERT IGNORE INTO station_playlist_media (playlist_id, media_id, weight)
SELECT 1, id, FLOOR(RAND()*100) FROM station_media
WHERE id NOT IN (
SELECT media_id FROM station_playlist_media WHERE playlist_id=1
);
5. Liquidsoap picks it up with no restart. The playlist file at /var/azuracast/stations/brennan_fm/playlists/playlist_default.m3u is configured with reload_mode="watch" in Liquidsoap, monitoring the file for changes and reloads without dropping the stream. New tracks silently enter rotation.
The manifest (a JSON file tracking every identifier seen) prevents re-downloading. The library caps at 500 tracks (~6GB), deleting the oldest tracks when full.
Right now my radio is playing Louis Prima from 1946, Dimension X sci-fi radio dramas from 1951, Mozart from a 1940s Royal Philharmonic recording, Sherlock Holmes with Basil Rathbone, ragtime piano rolls, Free Music Archive indie tracks, and CBC audio drama. A real variety show!
Troubleshooting
A few things that took longer than they should have:
- AzuraCast on a fresh DigitalOcean one-click install doesn't start. The
has_startedfield in the MariaDBstationtable defaults to0, which prevents Liquidsoap config from being generated. Fix:UPDATE station SET has_started=1 WHERE id=1;then restart. - Streamer passwords must be Argon2id-hashed. If you insert a DJ account directly into the database with a plain-text password (as I did the first time), authentication silently fails and BUTT hangs on "connecting." The fix is to hash via PHP inside the container:
php -r "echo password_hash('yourpassword', PASSWORD_ARGON2ID);"and store the result. - Docker volume paths are not the same as host paths. The media folder inside the container is
/var/azuracast/stations/brennan_fm/media/, but on the host that's actually/var/lib/docker/volumes/azuracast_station_data/_data/brennan_fm/media/. My cron script was writing to the host path that Docker doesn't mount, and files were downloading successfully but AzuraCast couldn't see them. CheckMediaTaskmust run before the playlist INSERT, not after. My first version of the script did the INSERT first, then triggered the media scan. New files hadn't been scanned intostation_mediayet, so the INSERT found nothing to add. Tracks downloaded, no errors logged, playlist unchanged. The fix is just order of operations: scan, sleep 5 seconds, insert.- Cron log paths can silently kill the whole job. The original cron entry redirected output to
/var/azuracast/stations/brennan_fm/config/autodj_refresh.logwhich is a path that exists inside the Docker container but not on the host. When bash can't open the redirect target, it exits before the command even runs and the script never ran. The fix is obvious in retrospect: log to/var/log/refresh_autodj.logor anywhere on the actual host filesystem.
What's Next
There are vast amounts of public domain and Creative Commons work that is gathering dust on the shelf. I want to expose people to art they wouldn't have come across on their own. 78rpm records, old-time radio dramas, spoken word pieces. And I also want to have the spontaneity and improvisation of live broadcasting.
Of course, that's all far easier said than done. I've figured out the technical logistics of setting up the site and backend, and I'm so thankful that other people have built and maintained the software needed for an endeavour like this. But now I need to get over my stage fright and actually start running shows! Thankfully, there will be barely any listeners, and I don't have to worry about editing and having to hear my own voice back.
And I want to be willing to fail in public. To stumble, to have technical difficulties. Kilduff's whole point on Let's Paint TV was that it's about showing up and persevering and failing and continuing. I believe that. I believe it about writing, I believe it about community organizing, and now I'm trying it as a beginner once again with something entirely new to me.
If you're interested in this, please let me know! If you have music or anything else you'd like on the show, hit me up! In addition, I would absolutely love to have guests to interview, or maybe even a co-host or two. That would make things a lot less intimidating for me. It's not like I can disc jockey for twenty-four hours a day anyways, so it would be good to have multiple people on board.
For now, the station is in soft pre-launch. The AutoDJ is running. The technical chain works end-to-end. The next step is recording a pilot answering why radio, why now, and what I want to do with the air.
The source code for the website and cron script is on GitLab. The stream is live right now at fm.brennan.day. Tune in!
Comments
To comment, please sign in with your website:
How it works: Your website needs to support IndieAuth. GitHub profiles work out of the box. You can also use IndieAuth.com to authenticate via GitLab, Codeberg, email, or PGP. Setup instructions.
Signed in as:
No comments yet. Be the first to share your thoughts!