- HTML 65.6%
- Python 29.2%
- Shell 5.2%
A single phone-friendly web page that proxies to per-device backend services (Cast, Fire TV, Apple TV, TCL, Sonos) to search, play, and control a whole living-room media stack from one panel. Standard-library Python, no cloud, LAN-only. |
||
|---|---|---|
| .github/workflows | ||
| deploy | ||
| scripts | ||
| systemd | ||
| tests | ||
| .gitignore | ||
| .sanity-patterns.json | ||
| index.html | ||
| LICENSE | ||
| qa-panel.md | ||
| README.md | ||
| server.py | ||
| WHITEPAPER.md | ||
Home Media Control
One phone-friendly web page to drive your whole living-room media stack: search across your devices, pick where to watch, and control playback, volume, and power, all from your phone on the home network. No app to install, no cloud, no account.
The panel is a single, dependency-free Python file (server.py) plus one static
page (index.html). It does not talk to your TV hardware directly. Instead it
proxies to a handful of small local backend services you run alongside it, one
per device type. You enable only the backends you own; the panel degrades
gracefully when any of them is offline.
What it controls
| Source | Backend service (companion project) | What you get |
|---|---|---|
| Cast (Google TV / Chromecast) | google-cast-control (:4530) |
YouTube search + play, exact-second seek |
| Fire TV | firetv-nowplaying (:4490) |
now-playing, seek, runtime, universal search, deep-links |
| Apple TV | tcl-tv-mcp (:4480) + optional Apple TV helper |
input switch, key presses, now-playing, YouTube |
| TCL Google TV | tcl-tv-mcp (:4480) |
power, app, D-pad / remote keys |
| Sonos | a Sonos HTTP service (:52546) |
room volume, per-speaker volume, mute, surround grouping |
The companion backends are separate projects; this repo is just the unified panel and the proxy in front of them. The panel speaks plain HTTP/JSON to each backend, so you can swap any of them for your own implementation as long as it exposes the same routes.
Requirements
- Python 3.9+ (standard library only; no
pip installfor the panel itself) - One or more device backend services reachable over HTTP on your LAN
Install
git clone https://github.com/nidamen/home-media-control.git
cd home-media-control
That is it for the panel. Each device backend is its own project with its own setup.
Run
HOME_MEDIA_PORT=4520 python3 server.py
Open http://<this-machine-ip>:4520/ on your phone. The service binds to
0.0.0.0 by default so any phone on the LAN can reach it at the machine's
current IP, with no hard-coded address in the page.
Configure
Everything is set with environment variables, so there are no IPs or secrets
baked into the code. Point each *_BASE at wherever you run that backend:
| Variable | Default | Purpose |
|---|---|---|
HOME_MEDIA_PORT (or PORT) |
4520 |
Port the panel listens on |
HOME_MEDIA_HOST |
0.0.0.0 |
Bind address |
TCL_BASE |
http://127.0.0.1:4480 |
TCL / Apple TV remote backend |
FIRE_NOW_BASE |
http://127.0.0.1:4490 |
Fire TV now-playing backend |
CAST_BASE |
http://127.0.0.1:4530 |
Google Cast backend |
SONOS_BASE |
http://127.0.0.1:52546 |
Sonos backend |
SEARCH_BASE |
http://127.0.0.1:4540 |
Optional unified-search backend |
DRDABBER_BASE |
http://127.0.0.1:4477 |
Optional extra device probe |
APPLE_TV_MCP_PY |
python3 |
Python for the optional Apple TV YouTube helper |
APPLE_TV_MCP_SRC |
(unset) | PYTHONPATH for that helper, if used |
APPLE_TV_MCP_MODULE |
apple_tv_mcp.watch |
Module run as python -m <module> "<query>" |
Device IPs live in your backends (and in the example Environment= lines in
deploy/), never in this panel.
Deploy
Run the panel (and your backends) as managed, auto-restarting services. See
deploy/README.md:
- macOS:
sh deploy/install-mac.shinstalls LaunchAgents. - Linux / Raspberry Pi:
sudo deploy/install-pi.shinstalls systemd units. - Single service only:
systemd/home-media-control.serviceruns just the panel.
Health check: scripts/healthcheck.sh http://127.0.0.1:4520.
API
The panel exposes a small JSON API (full reference in
WHITEPAPER.md):
GET /api/state- aggregated state of every backendGET /api/health- 200 if all backends are up, 503 otherwiseGET /api/search?q=- unified search across catalog + YouTubePOST /api/source,/api/key- switch input, send remote keysPOST /api/cast/*,/api/fire/*,/api/atv/*,/api/sonos/*- per-device control
Tests
python3 -m unittest discover -s tests
The tests cover the routing and aggregation logic and need no hardware.
License
MIT. See LICENSE.