- Add CallbackConfig model for callback scripts - Add callbacks section to config for optional command execution - Add turn_on/turn_off/toggle endpoints (callback-only) - Add callbacks for all media actions (play, pause, stop, next, previous, volume, mute, seek) - Update README with callbacks documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
476 lines
10 KiB
Markdown
476 lines
10 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
Required packages: `winsdk`, `pywin32`, `pycaw`, `comtypes`
|
|
|
|
### Linux
|
|
|
|
```bash
|
|
# Install system dependencies
|
|
sudo apt-get install python3-dbus python3-gi libdbus-1-dev libglib2.0-dev
|
|
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### macOS
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
No additional dependencies - uses built-in `osascript`.
|
|
|
|
### Android (Termux)
|
|
|
|
```bash
|
|
# In Termux
|
|
pkg install python termux-api
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
Requires Termux and Termux:API apps from F-Droid.
|
|
|
|
## Quick Start
|
|
|
|
1. Generate configuration with API token:
|
|
```bash
|
|
python -m media_server.main --generate-config
|
|
```
|
|
|
|
2. View your API token:
|
|
```bash
|
|
python -m media_server.main --show-token
|
|
```
|
|
|
|
3. Start the server:
|
|
```bash
|
|
python -m media_server.main
|
|
```
|
|
|
|
4. Test the connection:
|
|
```bash
|
|
curl http://localhost:8765/api/health
|
|
```
|
|
|
|
5. Test with authentication:
|
|
```bash
|
|
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
|
|
|
|
```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_`):
|
|
|
|
```bash
|
|
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:**
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"platform": "Windows",
|
|
"version": "1.0.0"
|
|
}
|
|
```
|
|
|
|
### Get Media Status
|
|
|
|
```
|
|
GET /api/media/status
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"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) |
|
|
| `/api/media/turn_on` | POST | - | Execute on_turn_on callback |
|
|
| `/api/media/turn_off` | POST | - | Execute on_turn_off callback |
|
|
| `/api/media/toggle` | POST | - | Execute on_toggle callback |
|
|
|
|
### Script Execution
|
|
|
|
The server supports executing pre-defined scripts via API.
|
|
|
|
#### List Scripts
|
|
|
|
```
|
|
GET /api/scripts/list
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"script": "lock_screen",
|
|
"exit_code": 0,
|
|
"stdout": "",
|
|
"stderr": ""
|
|
}
|
|
```
|
|
|
|
### Configuring Scripts
|
|
|
|
Add scripts in your `config.yaml`:
|
|
|
|
```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 |
|
|
| `icon` | No | Custom MDI icon (e.g., `mdi:power`) |
|
|
| `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) |
|
|
|
|
### Configuring Callbacks
|
|
|
|
Callbacks are optional commands executed after media actions. Add them in your `config.yaml`:
|
|
|
|
```yaml
|
|
callbacks:
|
|
# Media control callbacks (run after successful action)
|
|
on_play:
|
|
command: "echo Play triggered"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_pause:
|
|
command: "echo Pause triggered"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_stop:
|
|
command: "echo Stop triggered"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_next:
|
|
command: "echo Next track"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_previous:
|
|
command: "echo Previous track"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_volume:
|
|
command: "echo Volume changed"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_mute:
|
|
command: "echo Mute toggled"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_seek:
|
|
command: "echo Seek triggered"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
# Turn on/off/toggle (callback-only actions, no default behavior)
|
|
on_turn_on:
|
|
command: "echo PC turned on"
|
|
timeout: 10
|
|
shell: true
|
|
|
|
on_turn_off:
|
|
command: "rundll32.exe user32.dll,LockWorkStation"
|
|
timeout: 5
|
|
shell: true
|
|
|
|
on_toggle:
|
|
command: "echo Toggle triggered"
|
|
timeout: 10
|
|
shell: true
|
|
```
|
|
|
|
Available callbacks:
|
|
|
|
| Callback | Triggered by | Description |
|
|
|----------|--------------|-------------|
|
|
| `on_play` | `/api/media/play` | After play succeeds |
|
|
| `on_pause` | `/api/media/pause` | After pause succeeds |
|
|
| `on_stop` | `/api/media/stop` | After stop succeeds |
|
|
| `on_next` | `/api/media/next` | After next track succeeds |
|
|
| `on_previous` | `/api/media/previous` | After previous track succeeds |
|
|
| `on_volume` | `/api/media/volume` | After volume change succeeds |
|
|
| `on_mute` | `/api/media/mute` | After mute toggle |
|
|
| `on_seek` | `/api/media/seek` | After seek succeeds |
|
|
| `on_turn_on` | `/api/media/turn_on` | Callback-only action |
|
|
| `on_turn_off` | `/api/media/turn_off` | Callback-only action |
|
|
| `on_toggle` | `/api/media/toggle` | Callback-only action |
|
|
|
|
Callback configuration options:
|
|
|
|
| Field | Required | Description |
|
|
|-------|----------|-------------|
|
|
| `command` | Yes | Command to execute |
|
|
| `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:
|
|
|
|
```powershell
|
|
.\media_server\service\install_task_windows.ps1
|
|
```
|
|
|
|
To remove the scheduled task:
|
|
|
|
```powershell
|
|
Unregister-ScheduledTask -TaskName "MediaServer" -Confirm:$false
|
|
```
|
|
|
|
### Windows Service
|
|
|
|
Install:
|
|
```bash
|
|
python -m media_server.service.install_windows install
|
|
```
|
|
|
|
Start/Stop:
|
|
```bash
|
|
python -m media_server.service.install_windows start
|
|
python -m media_server.service.install_windows stop
|
|
```
|
|
|
|
Remove:
|
|
```bash
|
|
python -m media_server.service.install_windows remove
|
|
```
|
|
|
|
### Linux (systemd)
|
|
|
|
Install:
|
|
```bash
|
|
sudo ./service/install_linux.sh install
|
|
```
|
|
|
|
Enable and start for your user:
|
|
```bash
|
|
sudo systemctl enable media-server@$USER
|
|
sudo systemctl start media-server@$USER
|
|
```
|
|
|
|
View logs:
|
|
```bash
|
|
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
|
|
|
|
1. **Use HTTPS in production** - Set up a reverse proxy (nginx, Caddy) with SSL
|
|
2. **Strong tokens** - Default tokens are 32 random characters; don't use weak tokens
|
|
3. **Firewall** - Only expose the port to trusted networks
|
|
4. **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_ADDRESS` must be set correctly
|
|
|
|
### Volume control not working
|
|
- Windows: Run as administrator if needed
|
|
- Linux: Ensure PulseAudio/PipeWire is running
|
|
|
|
## License
|
|
|
|
MIT License
|