APITuner — ADB-free virtual tuner for Android TV / Google TV

Hi everyone,

I wanted to share a project I've been working on called APITuner — a virtual tuner for Channels DVR that works similarly to ADBTuner, but without ADB, root, or developer mode.

First, a huge thank you to @turtletank and everyone who's contributed to ADBTuner over the years. That project (and the community thread around it) is what made this whole approach possible — HDMI encoders, deep links, M3U custom channel sources, importable channel lists, the works. APITuner wouldn't exist without that foundation.

And more broadly, thank you to the Channels community — the folks in the HDMI for Channels threads, everyone who shared encoder setups, channel exports, deep link discoveries, and troubleshooting tips over the years. This ecosystem of tinkerers is what makes custom channel tuning work at all. I'm hoping APITuner can be a useful addition for anyone who wants the same workflow without ADB.

What it does

APITuner controls your Android TV devices over the network, launches the right app/deep link when Channels requests a channel, and relays the MPEG-TS stream from your HDMI encoder back to Channels as a Custom Channels (M3U) source.

Channels DVR → APITuner → Android TV device (launches app)

HDMI encoder ← device HDMI out

Same basic hardware setup as ADBTuner: one HDMI encoder per device. Streaming apps are DRM-protected, so screen capture inside the device isn't an option — the encoder captures HDMI output.

Why not just use ADB?

ADB works great — and ADBTuner is excellent at it. But ADB requires developer options, can be finicky across devices and updates, and isn't always practical on shared household TVs. APITuner offers an ADB-free path using pluggable control backends:

  • http_agent (recommended) — a small Agent APK on each device that sends package-pinned deep links (like ADB's am start). This is the reliable path for YouTube TV and similar apps, avoiding the "Open with" chooser dialog.
  • androidtv_remote — uses the standard Android TV Remote protocol (pair once, no APK). Simpler setup, but can't pin the target app on deep links, so it's better for simpler use cases.

If you're already running ADBTuner and happy with it, keep using it! APITuner is meant as an alternative for folks who want to drop ADB, not a replacement for a working setup.

Channels DVR integration

APITuner exposes an M3U playlist compatible with ADBTuner:

http://:6592/channels.m3u

(or /channels.m3u8 — same playlist)

Add it in Channels under Settings → Add Source → Custom Channels → M3U URL.

You can also filter by provider with ?provider=YouTube%20TV if you use provider_name on your channels.

Channel lists are ADBTuner-compatible — you can import your existing ADBTuner channel JSON export directly. A big thank you to everyone who's built and shared those channel lists over the years; that shared knowledge is a huge part of what makes migration easy.

Quick start

Server (Docker):

mkdir -p apituner-data

docker run -d \

--name apituner \

-p 6592:6592 \

-v "$(pwd)/apituner-data:/data" \

--restart unless-stopped \

Dashboard: http://<docker-host>:6592

Per device:

  1. Download and install the Agent APK from Releases
  2. Grant Display over other apps (required) and Usage Access (recommended)
  3. In the dashboard, add a tuner with backend http_agent, device IP, port 9092, and your encoder stream URL

Then import or add your channels, copy the M3U URL from the dashboard, and add it to Channels.

A few notes

  • Default port is 6592 (so it can run alongside ADBTuner on the same host if you're migrating gradually)
  • Stream modes: proxy (default, like ADBTuner) or redirect (Channels hits the encoder directly)
  • The dashboard/API has no authentication — keep it on a trusted LAN only

Get it

Releases & setup guide: GitHub - matthewfkoch/APITuner: ADB-free virtual tuner for Channels DVR — control Android TV / Google TV devices and relay HDMI-encoder streams as an HDHomeRun-compatible tuner. · GitHub

This is still early (v0.1.3) — I'd love feedback from anyone trying it, especially folks migrating from ADBTuner. Questions and issues welcome on the releases repo.

Thanks again to @turtletank, the ADBTuner contributors, and everyone in this community who's pushed custom channel tuning forward.

1 Like

Always curious about new approaches to importing our sources into channels. I'm the furthest thing from an expert in how all this works, but try and underatand the basics.

Looks like you have to sideload the APK correct? And any updates would require a subsequent download/install (no upgrade from within the app itself)? Not a poison pill, just want to make sure that I'm clear on what the install and maintenance activities will look like before I pull the trigger and install.

Also, any experience with API's tuning time vs. ADBTuner? I use various flavors of ONN and although not TVE fast, it's not horrible either. Just curious if the API has similar or better response time.

Thanks for building and sharing, I look forward to learning more about this.

1 Like

I'll take a look at it. I have an onn puck on hand connected to a poe so its a pain in the ass to reconnect the adb connection from that. Just using this may alleviate that

Cool! Can apituner tune channel with numbers? ( no deeplink,
always have app open in forground running)

@waltgrace I see you haven't published any of the source code for this project. Are you planning to make it open source?

Thanks for the feedback, In general I plan to add some quality of life stuff like in app updates and such. I've been doing a lot of testing locally but I'm hoping to surface any bugs before I add any additional features. There are a few things I am looking to build soon so I can prioritize the APK updates as well. Let me know if you run into any issues.


I'm getting an error that my ONN isn't reachable.

I’m not a true developer so I was being cautious to make sure everything went well. If I found some devs that wanted to help or use it I planned to open it up.

From your server running APITuner can you try to hit http://192.168.0.140:9092/api/health.

The server running APITuner is Synology NAS.
When I run http://192.168.0.140:9092/api/health I get:

Success: true
Message: "APITuner Agent running"

I'm not fsmiliar with running docker on Synology but you may benefit from using host networking.

docker run -d \
  --name apituner \
  --network host \
  -v "$(pwd)/data:/data" \
  -e APITUNER_PORT=6592 \
  -e APITUNER_DATA_DIR=/data \
  -e APITUNER_LOG_LEVEL=INFO \
  --restart unless-stopped \
  ghcr.io/matthewfkoch/apituner:latest

No offense but it’s never a good idea to run closed source code in host network mode.

1 Like

Same result, Agent unreachable

I'll dig out an ONN box and see if I run into the same issue. My current setup is all Google Chromecast with Google TV.

This is a brilliant idea but please consider open sourcing it so we can audit it.
Especially if it was something that was completely vibe-coded which I am not against because everything I do is vibe-coded, but I make sure I open source it and put a good license on it. I'm not a qualified developer either, so I want other people to be able to review what I'm putting out there. Personally I would not run something that is closed source that I could not have an independent agent audit before putting it on my devices.

So I think this is a brilliant idea and thank you for putting the time and energy into building it.

2 Likes

Yeah...thats a security hazard waiting to happen. I only use host networking for a finite amount of containers but those are the containers I can trust (ie. Channels).

This one here? I don't know. I'm content using bridge networking instead

1 Like

The repo is now public

3 Likes


I have the same result with a Chromecast, unreachable

From SSH on the Synology (or Container Manager → terminal on the apituner container):

from host

curl -v --connect-timeout 5 http://192.168.0.70:9092/api/health

from inside the container

docker exec apituner curl -v --connect-timeout 5 http://192.168.0.70:9092/api/health

curl -v --connect-timeout 5 http://192.168.0.70:9092/api/health

GET /api/health HTTP/1.1
Host: 192.168.0.70:9092
User-Agent: curl/7.86.0
Accept: /

< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Tue, 14 Jul 2026 23:02:05 GMT
< Connection: keep-alive
< Content-Length: 51
<
{"success":true,"message":"APITuner Agent running"

sudo docker exec apituner curl -v --connect-timeout 5 http://192.168.0.70:9092/api/health
OCI runtime exec failed: exec failed: unable to start container process: exec: "curl": executable file not found in $PATH: unknown