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>
This commit is contained in:
2026-02-04 14:36:23 +03:00
parent 5519e449cd
commit e26df64e4b
44 changed files with 367 additions and 105 deletions

View File

@@ -1,50 +0,0 @@
# Media Server for Home Assistant
## Project Overview
A server-client system to control PC media playback from Home Assistant.
- **Server**: FastAPI REST API on Windows controlling system-wide media via WinRT
- **Client**: Home Assistant custom integration exposing a media player entity
## Running the Server
### Manual Start
```bash
cd c:\Users\Alexei\Documents\haos-integration-media-player
python -m media_server.main
```
### Auto-Start on Boot (Windows Task Scheduler)
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
```
## Home Assistant Integration
Copy `custom_components/remote_media_player/` to your Home Assistant config folder.
Integration files location: `U:\custom_components\remote_media_player`
## API Token
The API token is generated on first run and displayed in the console output.
Configure the same token in Home Assistant integration settings.
## Server Port
Default: `8765`
## Git Rules
Always ask for user approval before committing changes to git.

View File

@@ -1,33 +1,35 @@
# Remote Media Player for Home Assistant
# Remote Media Player
Control your PC's media playback from Home Assistant.
This monorepo contains two separate components designed to be split into independent repositories:
## Components
| Component | Description | Documentation |
|-----------|-------------|---------------|
| [Media Server](media_server/) | REST API server for your PC | [README](media_server/README.md) |
| [HAOS Integration](custom_components/remote_media_player/) | Home Assistant custom component | [README](custom_components/remote_media_player/README.md) |
| Component | Description | Future Repository |
|-----------|-------------|-------------------|
| [Media Server](media-server/) | REST API server for your PC | `media-server` |
| [HAOS Integration](haos-integration/) | HACS-ready Home Assistant integration | `haos-remote-media-player` |
## Overview
```
┌─────────────────────┐ HTTP/REST ┌─────────────────────┐
│ Home Assistant │◄────────────────────────►│ Your PC │
│ │ (Token Auth) │ │
│ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ Media Player │ │ │ │ Media Server │ │
│ │ Entity │ │ │ │ (FastAPI) │ │
│ └───────────────┘ │ │ └───────┬───────┘ │
│ │ │
└─────────────────────┘ │ ┌───────▼───────┐ │
│ │ Media Control │ │
│ │ - Windows │ │
│ │ - Linux │ │
│ │ - macOS │ │
│ │ - Android │ │
│ └───────────────┘ │
└─────────────────────┘
┌─────────────────────┐ HTTP/WebSocket ┌─────────────────────┐
│ Home Assistant │◄────────────────────────►│ Your PC │
│ │ (Token Auth) │ │
│ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ Media Player │ │ │ │ Media Server │ │
│ │ Entity │ │ │ │ (FastAPI) │ │
│ └───────────────┘ │ │ └───────┬───────┘ │
┌───────────────┐ │ │ │ │
│ │ Script Button │ │ │ ┌───────▼───────┐ │
Entities │ │ Media Control │ │
└───────────────┘ │ │ │ - Windows │ │
│ │ - Linux │ │
└─────────────────────┘ │ │ - macOS │ │
│ │ - Android │ │
│ └───────────────┘ │
└─────────────────────┘
```
## Features
@@ -37,56 +39,49 @@ Control your PC's media playback from Home Assistant.
- Volume control and mute
- Seek within tracks
- Display current track info (title, artist, album, artwork)
- Real-time updates via WebSocket
- Script buttons (shutdown, restart, lock, sleep, hibernate, custom)
- Secure token-based authentication
## Supported Platforms
| Platform | Media Control | Volume Control | Status |
|----------|---------------|----------------|--------|
| Windows | WinRT Media Transport | pycaw | Fully tested |
| Linux | MPRIS D-Bus | PulseAudio/PipeWire | Not tested |
| macOS | AppleScript | System volume | Not tested |
| Android | Termux:API | Termux volume | Not tested |
> **Note:** Windows is the primary supported platform. Linux, macOS, and Android implementations exist but have not been thoroughly tested and may have limited functionality.
## Quick Start
### 1. Set up the Server (on your PC)
### 1. Set up the Media Server (on your PC)
```bash
cd media_server
cd media-server
pip install -r requirements.txt
python -m media_server.main --generate-config
python -m media_server.main
```
See [Media Server README](media_server/README.md) for detailed instructions.
See [Media Server README](media-server/README.md) for detailed instructions.
### 2. Set up Home Assistant Integration
1. Copy `custom_components/remote_media_player/` to your HA config
2. Restart Home Assistant
3. Add integration via UI with your server's IP and token
Copy `haos-integration/custom_components/remote_media_player/` to your HA config folder, or install via HACS.
See [Integration README](custom_components/remote_media_player/README.md) for detailed instructions.
See [HAOS Integration README](haos-integration/README.md) for detailed instructions.
## Project Structure
```
haos-integration-media-player/
├── media_server/ # Server component
│ ├── main.py # Entry point
│ ├── routes/ # API endpoints
│ ├── services/ # Platform media controllers
│ └── service/ # Service installers
/
├── media-server/ # Standalone Media Server
│ ├── README.md # Server documentation
│ ├── requirements.txt # Python dependencies
│ ├── config.example.yaml # Example configuration
│ └── media_server/ # Python package
│ ├── main.py # Entry point
│ ├── routes/ # API endpoints
│ ├── services/ # Platform media controllers
│ └── service/ # Service installers
├── custom_components/
── remote_media_player/ # HAOS Integration
├── media_player.py # Media player entity
└── config_flow.py # UI configuration
├── haos-integration/ # HACS-ready HA Integration
── README.md # Integration documentation
├── hacs.json # HACS configuration
│ └── custom_components/
│ └── remote_media_player/ # Integration code
└── README.md
└── README.md # This file
```
## License

48
haos-integration/.gitignore vendored Normal file
View File

@@ -0,0 +1,48 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
ENV/
env/
.venv/
# IDE
.idea/
.vscode/
.claude/
*.swp
*.swo
*~
# Config files with secrets
config.yaml
config.json
.env
# Logs
*.log
logs/
# OS
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,25 @@
# HAOS Integration - Development Guide
## Overview
HACS-ready Home Assistant custom integration for controlling remote PC media playback.
## Installation
Copy `custom_components/remote_media_player/` to your Home Assistant config folder.
Or install via HACS as a custom repository.
## Requirements
Requires Media Server running on the target PC.
Media Server Repository: `TODO: Add repository URL`
## Integration Location
Integration files location: `U:\custom_components\remote_media_player`
## Git Rules
Always ask for user approval before committing changes to git.

View File

@@ -0,0 +1,98 @@
# Remote Media Player - Home Assistant Integration
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg)](https://github.com/hacs/integration)
[![GitHub Release](https://img.shields.io/github/v/release/YOUR_USERNAME/haos-remote-media-player)](https://github.com/YOUR_USERNAME/haos-remote-media-player/releases)
A Home Assistant custom integration that allows you to control a remote PC's media playback as a media player entity.
## Features
- Full media player controls (play, pause, stop, next, previous)
- Volume control and mute
- Seek support with smooth timeline updates
- Displays current track info (title, artist, album, artwork)
- Real-time updates via WebSocket (with HTTP polling fallback)
- **Script buttons** - Execute pre-defined scripts (shutdown, restart, lock, sleep, etc.)
- Configurable via Home Assistant UI
## Requirements
- Home Assistant 2024.1.0 or newer
- A running **Media Server** on your PC
### Media Server
This integration requires the Media Server to be running on the PC you want to control.
**Media Server Repository:** `TODO: Add repository URL`
See the Media Server documentation for installation and setup instructions.
## Installation
### HACS (Recommended)
1. Open HACS in Home Assistant
2. Click the three dots menu > **Custom repositories**
3. Add this repository URL: `https://github.com/YOUR_USERNAME/haos-remote-media-player`
4. Select category: **Integration**
5. Click **Add**
6. Search for "Remote Media Player" and click **Download**
7. Restart Home Assistant
### Manual Installation
1. Download the latest release from the [Releases](https://github.com/YOUR_USERNAME/haos-remote-media-player/releases) page
2. Extract and copy the `custom_components/remote_media_player` folder to your Home Assistant `config/custom_components/` directory
3. Restart Home Assistant
## Configuration
1. Go to **Settings** > **Devices & Services**
2. Click **+ Add Integration**
3. Search for "Remote Media Player"
4. Enter the connection details:
- **Host**: IP address or hostname of your PC running Media Server
- **Port**: Server port (default: 8765)
- **API Token**: The authentication token from your Media Server
- **Name**: Display name for this media player (optional)
## Usage
Once configured, the integration creates:
### Media Player Entity
A full-featured media player entity with:
- Play/Pause/Stop controls
- Next/Previous track
- Volume control and mute
- Seek functionality
- Current track information
### Script Button Entities
Button entities for each script defined on your Media Server:
- Lock/unlock workstation
- Shutdown, restart, sleep, hibernate
- Custom scripts
## Example Lovelace Card
```yaml
type: media-control
entity: media_player.remote_media_player
```
## Documentation
For detailed documentation, see [custom_components/remote_media_player/README.md](custom_components/remote_media_player/README.md).
## Support
- [Report an Issue](https://github.com/YOUR_USERNAME/haos-remote-media-player/issues)
- [Media Server Repository](TODO)
## License
MIT License

View File

@@ -14,8 +14,8 @@ A Home Assistant custom component that allows you to control a remote PC's media
## Requirements
- Home Assistant 2023.1 or newer
- A running [Media Server](../../media_server/README.md) on your PC
- Home Assistant 2024.1.0 or newer
- A running Media Server on your PC (see Media Server repository)
## Installation

View File

@@ -38,6 +38,7 @@ async def async_setup_entry(
script_name=script["name"],
script_label=script["label"],
script_description=script.get("description", ""),
script_icon=script.get("icon"),
)
for script in scripts
]
@@ -59,6 +60,7 @@ class ScriptButtonEntity(ButtonEntity):
script_name: str,
script_label: str,
script_description: str,
script_icon: str | None = None,
) -> None:
"""Initialize the script button."""
self._client = client
@@ -70,7 +72,8 @@ class ScriptButtonEntity(ButtonEntity):
# Entity attributes
self._attr_unique_id = f"{entry.entry_id}_script_{script_name}"
self._attr_name = script_label
self._attr_icon = self._get_icon_for_script(script_name)
# Use custom icon if provided, otherwise auto-resolve from script name
self._attr_icon = script_icon or self._get_icon_for_script(script_name)
def _get_icon_for_script(self, script_name: str) -> str:
"""Get an appropriate icon based on script name."""

View File

@@ -4,7 +4,7 @@
"codeowners": [],
"config_flow": true,
"dependencies": [],
"documentation": "https://github.com/your-username/haos-integration-media-player",
"documentation": "https://github.com/YOUR_USERNAME/haos-remote-media-player",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["aiohttp>=3.8.0"],

View File

@@ -0,0 +1,5 @@
{
"name": "Remote Media Player",
"render_readme": true,
"homeassistant": "2024.1.0"
}

48
media-server/.gitignore vendored Normal file
View File

@@ -0,0 +1,48 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
ENV/
env/
.venv/
# IDE
.idea/
.vscode/
.claude/
*.swp
*.swo
*~
# Config files with secrets
config.yaml
config.json
.env
# Logs
*.log
logs/
# OS
.DS_Store
Thumbs.db

39
media-server/CLAUDE.md Normal file
View File

@@ -0,0 +1,39 @@
# Media Server - Development Guide
## Overview
Standalone REST API server (FastAPI) for controlling system-wide media playback on Windows, Linux, macOS, and Android.
## Running the Server
### Manual Start
```bash
python -m media_server.main
```
### Auto-Start on Boot (Windows Task Scheduler)
Run in **Administrator PowerShell** from the media-server directory:
```powershell
.\media_server\service\install_task_windows.ps1
```
To remove the scheduled task:
```powershell
Unregister-ScheduledTask -TaskName "MediaServer" -Confirm:$false
```
## Configuration
Copy `config.example.yaml` to `config.yaml` and customize.
The API token is generated on first run and displayed in the console output.
Default port: `8765`
## Git Rules
Always ask for user approval before committing changes to git.

View File

@@ -258,6 +258,7 @@ Script configuration options:
| `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) |

View File

@@ -0,0 +1,47 @@
# Media Server Configuration
# Copy this file to config.yaml and customize as needed.
# A secure token will be auto-generated on first run if not specified.
# API Token (generate a secure random token)
api_token: "your-secure-token-here"
# Server settings
host: "0.0.0.0"
port: 8765
# Custom scripts
scripts:
lock_screen:
command: "rundll32.exe user32.dll,LockWorkStation"
label: "Lock Screen"
description: "Lock the workstation"
timeout: 5
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
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 immediately"
timeout: 10
shell: true

View File

@@ -16,6 +16,7 @@ class ScriptConfig(BaseModel):
command: str = Field(..., description="Command or script to execute")
label: Optional[str] = Field(default=None, description="User-friendly display label")
description: str = Field(default="", description="Script description")
icon: Optional[str] = Field(default=None, description="Custom icon (e.g., 'mdi:power')")
timeout: int = Field(default=30, description="Execution timeout in seconds", ge=1, le=300)
working_dir: Optional[str] = Field(default=None, description="Working directory")
shell: bool = Field(default=True, description="Run command in shell")

View File

@@ -38,6 +38,7 @@ class ScriptInfo(BaseModel):
name: str
label: str
description: str
icon: str | None = None
timeout: int
@@ -53,6 +54,7 @@ async def list_scripts(_: str = Depends(verify_token)) -> list[ScriptInfo]:
name=name,
label=config.label or name.replace("_", " ").title(),
description=config.description,
icon=config.icon,
timeout=config.timeout,
)
for name, config in settings.scripts.items()