Files
media-player-mixed/media-server
alexei.dolgolyov e26df64e4b Refactor project into two standalone components
Split monorepo into separate units for future independent repositories:
- media-server/: Standalone FastAPI server with own README, requirements,
  config example, and CLAUDE.md
- haos-integration/: HACS-ready Home Assistant integration with hacs.json,
  own README, and CLAUDE.md

Both components now have their own .gitignore files and can be easily
extracted into separate repositories.

Also adds custom icon support for scripts configuration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:36:23 +03:00
..

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

  1. Generate configuration with API token:

    python -m media_server.main --generate-config
    
  2. View your API token:

    python -m media_server.main --show-token
    
  3. Start the server:

    python -m media_server.main
    
  4. Test the connection:

    curl http://localhost:8765/api/health
    
  5. 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
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)

Running as a Service

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

  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