Post

I Bought a Denon for My Wedding. Twelve Years Later, I Vibe-Coded Its Radio Back to Life.

Twelve years ago today, I bought my first audio amplifier.

The email is still in my Amazon archive. May 4, 2014. Order #202-6562632-2973945. Denon AVR-X3000. £429, one-day delivery to a small flat in Gerrards Cross. I was getting married the following week. Buying this thing felt like part of building a home — even though half our boxes were still sealed and the speakers were leaning against the wall.

Amazon order confirmation, 4 May 2014: Denon AVR-X3000, £429.00, one-day delivery The receipt. (Address redacted; we don’t live there anymore.)

I have not loved many objects in my life as much as I have loved that receiver.

Twelve years on, it sounds exactly as good as it did the day it arrived. The remote still works. The HDMI inputs pass through 4K — which felt like the future in 2014 and feels normal now. The amplifier section is the same beautifully analog electronics it was at launch. Everything that was good about it is still good.

Except the Internet Radio button.

My Denon AVR-X3000, twelve years after it arrived Still warm. Display: PLII C, source TV. Someone is watching cartoons. (We’ll come back to that.)

The Quiet Shutdown

About a year ago I selected Internet Radio on the remote and got a polite empty screen suggesting I visit denon.vtuner.com to learn about a “full access” service for $3 a year.

Wait. What?

The service in question — vTuner — was the directory my AVR phoned home to every time it loaded the station list. Around 2020 it began contracting. By 2023 it was largely gone for older receivers. Denon stopped firmware updates for the AVR-X3000 in mid-2023, which means there will never be an official fix.

This is the failure mode you don’t think about when you buy nice things.

The hardware is a beautiful, durable physical object. The hardware also depends on a server somewhere that the manufacturer has no incentive to maintain past the warranty.

The Venn diagram of “things that survive a decade” and “things that depend on a third-party API” is approximately disjoint.

A perfectly working £429 amplifier was now half a brick — not because anything broke, but because someone in a meeting decided to shut down a service.

I wanted my radio back.

The Protocol Is Friendlier Than It Looks

Here’s the first interesting thing I learned: “internet radio” isn’t actually a proprietary protocol.

The receiver picks up a stream URL — plain HTTP MP3 or AAC, sometimes a playlist file — and decodes it the same way it decodes a CD. Once it has a URL, it just works.

What’s missing is the list of stations.

The receiver has a hardcoded hostname, denon.vtuner.com, where it expects to fetch a tree — Genres, Countries, Languages, Most Popular — formatted as a specific flavor of XML. Each leaf is a station with a stream URL, name, codec, bitrate, logo. That’s the entire interface. The shutdown is the disappearance of that XML directory.

So. The plan, sketched over a morning coffee:

  1. Intercept the DNS lookup for denon.vtuner.com on my LAN. Answer with the IP of a small server I run.
  2. Speak the vTuner XML dialect from that server — same shape, different content.
  3. Wire it to a free station databaseradio-browser.info, a community project with about 50,000 streams.

How hard can it be? (Famous last words, right?)

Two Hours with Claude Code

I opened Claude Code and started.

The community has been here before. There are two existing OSS projects that do something similar — YCast (Python) and YTuner (Go). When I asked Claude to recommend an approach, the first answer was: “just install YTuner.”

Reasonable. But not what I wanted.

So I told it: let’s write our own. Cross-platform. Single Go binary. Both DNS and HTTP in one process. Use YCast and YTuner as protocol references; clean-room re-implementation.

I was vibe-coding hard. Claude drafted, I reviewed, I redirected, Claude drafted again. The thing I’d expected to take all day turned into a working prototype well before lunch.

A flavor of how it went:

  • I’d describe the next layer (XML structs, HTTP routes, DNS interception, radio-browser client). Claude would scaffold it.
  • I’d run it. Something would break. Logs would tell me what — or, more often, the failure was in something I hadn’t thought to log yet.
  • I’d point Claude at the problem. It’d produce a fix in three keystrokes.

The most satisfying bug: /play was returning 502s when I tried to actually start a stream. The radio-browser API documentation in my head said the response was "ok": "true" (string). The actual API returns "ok": true (boolean). Two characters of code change. We caught it because of one line of structured log output.

Roughly two hours later — idea to live radio on the receiver — I had:

  • A DNS server intercepting *.vtuner.com, radiodenon.com, radiomarantz.com, and a few others
  • An HTTP server speaking the vTuner XML protocol
  • A radio-browser.info client with mirror discovery (the community project’s mirrors rotate via DNS — you have to do a slightly weird forward-then-reverse lookup dance to get a TLS-valid hostname)
  • Cross-compiled binaries for macOS and Linux on amd64 and arm64
  • A curl | sh installer that auto-detects your LAN IP and installs as a LaunchDaemon (Mac) or systemd unit (Linux)

About 900 lines of Go. About 250 of shell installer.

On Vibe-Coding

I know “vibe coding” is a contested term. Some people hear it and assume the author cargo-cult-pasted the AI’s output without reading. That isn’t what happened here, and it isn’t what happens in any serious AI-assisted project I’ve seen.

What it actually feels like is closer to working with a tireless mid-level engineer who has read the entire internet but has never seen this codebase.

They produce a correct draft of almost anything if you can describe what you want with enough specificity. Producing that specificity is most of the work — exactly like writing a good ticket for a human teammate.

I read every diff. I deleted maybe a third of what got written. The architecture decisions — Go vs Rust, one binary vs two, bundle a DNS server vs rely on Pi-hole, YAML config vs flags — were mine. The boilerplate was Claude’s.

Reverse-engineering a quasi-documented protocol against a frozen-firmware appliance is a perfect job for an AI pair. The receiver isn’t going to grow new bugs. The protocol isn’t going to change. The vibe is just: keep iterating until the AVR is happy.

If You’re Not a Developer, This Is Your Project Too

Total time on this, end to end, idea to internet radio playing on the receiver, including this blog post: about two hours. I wasn’t even fully focused on it — I stepped away to eat, to shower, to context-switch into other projects I have running in parallel. The work happened in the gaps.

That’s the part I most want non-developers to hear.

The cost of attempting something used to be weeks of feeling stupid before you even knew if it was going to work. The cost now is the time it takes to describe what you want clearly enough.

If you have an old gadget that’s been “bricked” because some company shut something down — a smart bulb without an app, a speaker without a cloud, a thermostat that lost its server — there’s a non-zero chance the fix looks a lot like this one. And there’s a fully zero chance you need to be a programmer to start a conversation with an AI coding agent about it.

Try it. The worst that happens is you learn the shape of the problem.

What I Actually Typed

You might be wondering what kind of carefully crafted prompts produce a project like this.

Reader, here are the literal prompts I sent. Typos and all. I have edited nothing.

I’ll be honest: publishing my unedited prompts is slightly humbling. They’re not pretty. They’re not “well-engineered.” They’re how I actually talk to a computer when I’m half-distracted between other things. I’m posting them anyway, because seeing what “good enough” really looks like is what makes it easier to try yourself.

The very first one:

“so I have a Denon audio amplifier in my network, it also has a radio option via internet that no longer works as they discontinued it. How can I fix it”

After Claude walked me through several options to consider:

“fix 1, the proper one, you could also host the list here on mac studio”

After it tried to talk me into using an existing OSS project:

“no lets create our own for mac, or even better cross platform”

That’s the entire architectural decision tree. Three messages, total. No “act as a senior systems engineer.” No 500-word spec document. No “let’s think step by step.” Just sentences I would type in a Slack channel asking a colleague.

The prompt for this blog post was longer, because it had goals embedded in it:

“need a really interesting story about it and how this weeken project is reviving my radio station on it, something worth the HN frontepage as I plan to submit it if its good enough, also blog post will touch the Claude code and Vibe coding at its fullest”

Yes. With the typos. I left them in. The agent didn’t care.

That is the message I most want non-technical readers to leave with:

The bar is lower than you think it is.

The skill that matters now isn’t knowing how to phrase a prompt. It’s knowing what you want to exist, and being willing to type that out plainly.

One Command to Bring It Back

The repo is at github.com/victorantos/denon. MIT-licensed. If you have an old AVR with a dark Internet Radio menu, the install is one line:

1
curl -fsSL https://raw.githubusercontent.com/victorantos/denon/main/install.sh | sh

Run it on any always-on machine on your network — Mac, Linux box, Raspberry Pi, your home-lab Ubuntu instance. Auto-detects your LAN IP, downloads the right binary, installs a system service that survives reboots.

Then on the receiver:

  1. Settings → Network → DNS → Manual
  2. Primary DNS: the IP of the machine you just installed on
  3. Secondary DNS: same IP
  4. Reboot the receiver
  5. Open Internet Radio

The menu populates with Most Popular, Genres, Countries, Languages, and Search, all backed by radio-browser.info’s community-curated database. Tap a station; it plays.

Confirmed working on most Denon, Marantz, Yamaha, Onkyo, and Pioneer AVRs from roughly 2011 to 2017. If your receiver hits an exotic hostname, file an issue with a tcpdump capture and I’ll add it to the defaults.

On the Way Out

The ratio of hardware lifespan to service lifespan is going to keep getting worse.

Cars. Fridges. Doorbells. Treadmills. Baby monitors. Smart locks. All of these are now somebody’s “platform,” and the platform is somebody’s quarter. There will be a great deal of expensive landfill in the next decade — entirely durable hardware, “bricked” by service decisions made in some headquarters far away.

The mitigation isn’t refusing to buy connected things; that ship has sailed.

The mitigation is preferring open protocols when you have the choice, and being grateful to the people who reverse-engineer the closed ones when you don’t.

radio-browser.info is mostly volunteers. YCast and YTuner are mostly volunteers. The vTuner shutdown took two hours of attention to undo, riding on years of work other people did first.

If you have an old AVR with a dark Internet Radio menu, the fix is real and it’s there. If you don’t — you might want to think about which other things in your house are an API call away from being half a brick.

A Confession

I have not, at the moment of typing this sentence, actually tested any of this on the receiver.

My four-year-old is watching cartoons in exactly the room the AVR lives in, and I am not going to interrupt his TV time to yank the DNS out from under the household. (See the photo at the top. Source: TV. Cartoons.)

By the time you read this, I will have tested it. Promise.

If the post is live, it worked. ✌️

A small coda. When I did go to test it — cartoons over, household consent acquired — the very first thing I did was open this blog post to find the install steps. I’d already written everything I needed to know, here, more clearly than anywhere else. The post became its own user manual. I had to stop and laugh at that for a second.


The receiver is playing BBC Radio 6 right now.

The amplifier is twelve years old and sounds exactly as good as it did the day it arrived in Gerrards Cross.

Sound is good.

This post is licensed under CC BY 4.0 by the author.
SpaceX Launch Countdowns Starship Flight 12 Countdown