Replace HTTP polling with WebSocket push notifications for instant state change responses. Server broadcasts updates only when significant changes occur (state, track, volume, etc.) while letting Home Assistant interpolate position during playback. Includes seek detection for timeline updates and automatic fallback to HTTP polling if WebSocket disconnects. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Media Server
A REST API server for controlling system media playback on Windows, Linux, macOS, and Android.
Features
- Control any media player via system-wide media transport controls
- Play/Pause/Stop/Next/Previous track
- Volume control and mute
- Seek within tracks
- Get current track info (title, artist, album, artwork)
- Token-based authentication
- Cross-platform support
Requirements
- Python 3.10+
- Platform-specific dependencies (see below)
Installation
Windows
pip install -r requirements.txt
Required packages: winsdk, pywin32, pycaw, comtypes
Linux
# Install system dependencies
sudo apt-get install python3-dbus python3-gi libdbus-1-dev libglib2.0-dev
pip install -r requirements.txt
macOS
pip install -r requirements.txt
No additional dependencies - uses built-in osascript.
Android (Termux)
# In Termux
pkg install python termux-api
pip install -r requirements.txt
Requires Termux and Termux:API apps from F-Droid.
Quick Start
-
Generate configuration with API token:
python -m media_server.main --generate-config -
View your API token:
python -m media_server.main --show-token -
Start the server:
python -m media_server.main -
Test the connection:
curl http://localhost:8765/api/health -
Test with authentication:
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8765/api/media/status
Configuration
Configuration file locations:
- Windows:
%APPDATA%\media-server\config.yaml - Linux/macOS:
~/.config/media-server/config.yaml
config.yaml
host: 0.0.0.0
port: 8765
api_token: your-secret-token-here
poll_interval: 1.0
log_level: INFO
Environment Variables
All settings can be overridden with environment variables (prefix: MEDIA_SERVER_):
export MEDIA_SERVER_HOST=0.0.0.0
export MEDIA_SERVER_PORT=8765
export MEDIA_SERVER_API_TOKEN=your-token
export MEDIA_SERVER_LOG_LEVEL=DEBUG
API Reference
Health Check
GET /api/health
No authentication required. Returns server status and platform info.
Response:
{
"status": "healthy",
"platform": "Windows",
"version": "1.0.0"
}
Get Media Status
GET /api/media/status
Authorization: Bearer <token>
Response:
{
"state": "playing",
"title": "Song Title",
"artist": "Artist Name",
"album": "Album Name",
"album_art_url": "https://...",
"duration": 240.5,
"position": 120.3,
"volume": 75,
"muted": false,
"source": "Spotify"
}
Media Controls
All control endpoints require authentication and return {"success": true} on success.
| Endpoint | Method | Body | Description |
|---|---|---|---|
/api/media/play |
POST | - | Resume playback |
/api/media/pause |
POST | - | Pause playback |
/api/media/stop |
POST | - | Stop playback |
/api/media/next |
POST | - | Next track |
/api/media/previous |
POST | - | Previous track |
/api/media/volume |
POST | {"volume": 75} |
Set volume (0-100) |
/api/media/mute |
POST | - | Toggle mute |
/api/media/seek |
POST | {"position": 60.0} |
Seek to position (seconds) |
Script Execution
The server supports executing pre-defined scripts via API.
List Scripts
GET /api/scripts/list
Authorization: Bearer <token>
Response:
[
{
"name": "lock_screen",
"label": "Lock Screen",
"description": "Lock the workstation",
"timeout": 5
}
]
Execute Script
POST /api/scripts/execute/{script_name}
Authorization: Bearer <token>
Content-Type: application/json
{"args": []}
Response:
{
"success": true,
"script": "lock_screen",
"exit_code": 0,
"stdout": "",
"stderr": ""
}
Configuring Scripts
Add scripts in your config.yaml:
scripts:
lock_screen:
command: "rundll32.exe user32.dll,LockWorkStation"
label: "Lock Screen"
description: "Lock the workstation"
timeout: 5
shell: true
shutdown:
command: "shutdown /s /t 0"
label: "Shutdown"
description: "Shutdown the PC immediately"
timeout: 10
shell: true
restart:
command: "shutdown /r /t 0"
label: "Restart"
description: "Restart the PC"
timeout: 10
shell: true
hibernate:
command: "shutdown /h"
label: "Hibernate"
description: "Hibernate the PC"
timeout: 10
shell: true
sleep:
command: "rundll32.exe powrprof.dll,SetSuspendState 0,1,0"
label: "Sleep"
description: "Put PC to sleep"
timeout: 10
shell: true
Script configuration options:
| Field | Required | Description |
|---|---|---|
command |
Yes | Command to execute |
label |
No | User-friendly display name (defaults to script name) |
description |
No | Description of what the script does |
timeout |
No | Execution timeout in seconds (default: 30, max: 300) |
working_dir |
No | Working directory for the command |
shell |
No | Run in shell (default: true) |
Running as a Service
Windows Task Scheduler (Recommended)
Run in Administrator PowerShell from the project root:
.\media_server\service\install_task_windows.ps1
To remove the scheduled task:
Unregister-ScheduledTask -TaskName "MediaServer" -Confirm:$false
Windows Service
Install:
python -m media_server.service.install_windows install
Start/Stop:
python -m media_server.service.install_windows start
python -m media_server.service.install_windows stop
Remove:
python -m media_server.service.install_windows remove
Linux (systemd)
Install:
sudo ./service/install_linux.sh install
Enable and start for your user:
sudo systemctl enable media-server@$USER
sudo systemctl start media-server@$USER
View logs:
journalctl -u media-server@$USER -f
Command Line Options
python -m media_server.main [OPTIONS]
Options:
--host TEXT Host to bind to (default: 0.0.0.0)
--port INTEGER Port to bind to (default: 8765)
--generate-config Generate default config file and exit
--show-token Show current API token and exit
Security Recommendations
- Use HTTPS in production - Set up a reverse proxy (nginx, Caddy) with SSL
- Strong tokens - Default tokens are 32 random characters; don't use weak tokens
- Firewall - Only expose the port to trusted networks
- Secrets management - Don't commit tokens to version control
Supported Media Players
Windows
- Spotify
- Windows Media Player
- VLC
- Groove Music
- Web browsers (Chrome, Edge, Firefox)
- Any app using Windows Media Transport Controls
Linux
- Any MPRIS-compliant player:
- Spotify
- VLC
- Rhythmbox
- Clementine
- Web browsers
- MPD (with MPRIS bridge)
macOS
- Spotify
- Apple Music
- VLC (partial)
- QuickTime Player
Android (via Termux)
- System media controls
- Limited seek support
Troubleshooting
"No active media session"
- Ensure a media player is running and has played content
- On Windows, check that the app supports media transport controls
- On Linux, verify MPRIS with:
dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep mpris
Permission errors on Linux
- Ensure your user has access to the D-Bus session bus
- For systemd service, the
DBUS_SESSION_BUS_ADDRESSmust be set correctly
Volume control not working
- Windows: Run as administrator if needed
- Linux: Ensure PulseAudio/PipeWire is running
License
MIT License