Production-readiness pass: security hardening, performance improvements, new services (send_message, set_repeat, refresh_library), diagnostics, reauth flow, image proxy, per-instance device IDs, exponential WS reconnect backoff, ID validation, stale device cleanup, and supporting integration plumbing. Three rounds of independent code review applied. See RELEASE_NOTES.md for the full changelog.
This commit is contained in:
@@ -1,96 +1,190 @@
|
||||
# Emby Media Player
|
||||
|
||||
[](https://github.com/hacs/integration)
|
||||
[](RELEASE_NOTES.md)
|
||||
[](https://www.home-assistant.io/)
|
||||
|
||||
A Home Assistant custom integration that exposes Emby media server clients as media players with full playback control, media metadata, and library browsing capabilities.
|
||||
A Home Assistant custom integration that exposes Emby Server clients as media players with full playback control, real-time WebSocket updates, library browsing, repeat-mode control, and on-screen messaging.
|
||||
|
||||
## Features
|
||||
|
||||
- **Media Player Control**: Play, pause, stop, seek, volume control, mute, next/previous track
|
||||
- **Real-time Updates**: WebSocket connection for instant state synchronization with polling fallback
|
||||
- **Media Metadata**: Display currently playing media information including:
|
||||
- Title, artist, album (for music)
|
||||
- Series name, season, episode (for TV shows)
|
||||
- Thumbnail/artwork
|
||||
- Duration and playback position
|
||||
- **Media Browser**: Browse your Emby library directly from Home Assistant
|
||||
- Navigate through Movies, TV Shows, Music libraries
|
||||
- Play any media directly from the browser
|
||||
- **Dynamic Session Discovery**: Automatically discovers and creates media player entities for active Emby clients
|
||||
### Playback & metadata
|
||||
|
||||
- **Full media-player control**: play, pause, stop, seek, volume, mute, next/previous track, repeat mode.
|
||||
- **Real-time updates over WebSocket** with a slow REST poll as a safety net — `PlaybackStart`, `PlaybackProgress`, and `PlaybackStopped` events update the entity in place.
|
||||
- **Now-playing metadata**: title, artist, album, series / season / episode, artwork, duration, position, play method (DirectPlay / DirectStream / Transcode).
|
||||
- **Per-client device class** inferred from the Emby client (AndroidTV / Kodi / Roku → TV, music clients → speaker, others → generic).
|
||||
- **Enqueue semantics** mapped to Emby commands: HA's `play` / `replace` → `PlayNow`, `next` → `PlayNext`, `add` → `PlayLast`.
|
||||
|
||||
### Library
|
||||
|
||||
- **Browse the Emby library** from Home Assistant's media browser — Movies, TV Shows, Music, Playlists, user views.
|
||||
- **Server-side image proxy** — artwork is fetched with the API key in an HTTP header and never leaks into URLs in the browser.
|
||||
|
||||
### Security & reliability
|
||||
|
||||
- **API key never appears in URLs** (no query-string leakage to proxy logs or browser history).
|
||||
- **Per-instance device IDs** derived from the Home Assistant UUID — multiple HA installs no longer collide on the same Emby server.
|
||||
- **Self-signed HTTPS** support via a `verify_ssl` toggle.
|
||||
- **Reauth flow** prompts for a fresh API key when the server rejects the current one.
|
||||
- **Exponential backoff with jitter** for WebSocket reconnects; auth failures stop the retry loop.
|
||||
- **ID validation** on all session / item / user identifiers (defense in depth against path traversal in REST paths).
|
||||
- **Stale device cleanup** removes media-player devices for sessions that disappear for over 30 minutes (with a 10-minute grace period after startup).
|
||||
|
||||
### Integration plumbing
|
||||
|
||||
- **Diagnostics** — Settings → Integrations → "..." → Download diagnostics for a redacted JSON dump (API key and session IDs are hashed/redacted).
|
||||
- **Hub device** linked to per-session devices via `via_device` — easier to clean up.
|
||||
- **Zeroconf + SSDP discovery hints** so Emby servers can be found by HA.
|
||||
- **Three services**: `send_message`, `set_repeat`, `refresh_library`.
|
||||
|
||||
## Installation
|
||||
|
||||
### HACS (Recommended)
|
||||
|
||||
1. Open HACS in Home Assistant
|
||||
2. Click on "Integrations"
|
||||
3. Click the three dots menu and select "Custom repositories"
|
||||
4. Add this repository URL and select "Integration" as the category
|
||||
5. Click "Install"
|
||||
6. Restart Home Assistant
|
||||
1. Open HACS in Home Assistant.
|
||||
2. Click on **Integrations**.
|
||||
3. Click the three-dots menu and select **Custom repositories**.
|
||||
4. Add this repository URL and select **Integration** as the category.
|
||||
5. Click **Install**.
|
||||
6. Restart Home Assistant.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
1. Download the `custom_components/emby_player` folder
|
||||
2. Copy it to your Home Assistant `custom_components` directory
|
||||
3. Restart Home Assistant
|
||||
1. Download the `custom_components/emby_player` folder.
|
||||
2. Copy it to your Home Assistant `custom_components` directory.
|
||||
3. Restart Home Assistant.
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Go to **Settings** > **Devices & Services**
|
||||
2. Click **Add Integration**
|
||||
3. Search for "Emby Media Player"
|
||||
4. Enter your Emby server details:
|
||||
- **Host**: Your Emby server hostname or IP address
|
||||
- **Port**: Emby server port (default: 8096)
|
||||
- **API Key**: Your Emby API key (found in Dashboard > Extended > API Keys)
|
||||
- **Use SSL**: Enable if your server uses HTTPS
|
||||
5. Select the Emby user account to use
|
||||
6. Click **Submit**
|
||||
1. Go to **Settings → Devices & Services**.
|
||||
2. Click **Add Integration** and search for **Emby Media Player**.
|
||||
3. Enter your Emby server details:
|
||||
- **Host** — Emby server hostname or IP address.
|
||||
- **Port** — default `8096` (HTTP) or `8920` (HTTPS).
|
||||
- **API Key** — created in Emby Dashboard → Extended → API Keys.
|
||||
- **Use SSL** — enable if your server uses HTTPS.
|
||||
- **Verify SSL certificate** — disable only when using a self-signed certificate that HA's CA bundle doesn't trust.
|
||||
4. Select the Emby user account to use for browsing & playback.
|
||||
5. Click **Submit**.
|
||||
|
||||
### Getting an API Key
|
||||
### Getting an API key
|
||||
|
||||
1. Open your Emby Server Dashboard
|
||||
2. Navigate to **Extended** > **API Keys**
|
||||
3. Click **New API Key** (+ button)
|
||||
4. Give it a name (e.g., "Home Assistant")
|
||||
5. Copy the generated key
|
||||
1. Open your Emby Server Dashboard.
|
||||
2. Navigate to **Extended → API Keys**.
|
||||
3. Click **New API Key** (+ button).
|
||||
4. Give it a name (e.g., `Home Assistant`).
|
||||
5. Copy the generated key.
|
||||
|
||||
> Admin keys list all users automatically. Non-admin keys fall back to the
|
||||
> public users endpoint — the integration handles both.
|
||||
|
||||
### Reauthentication
|
||||
|
||||
If you regenerate the API key on the Emby server, Home Assistant will flag
|
||||
the integration as needing attention and walk you through entering the new
|
||||
key — no need to remove and re-add the integration.
|
||||
|
||||
## Options
|
||||
|
||||
After configuration, you can adjust the following options:
|
||||
After configuration, open **Configure** on the integration to adjust:
|
||||
|
||||
- **Scan Interval**: Polling interval in seconds (5-60, default: 10). Used as a fallback when WebSocket connection is unavailable.
|
||||
- **Scan Interval** (5–60 s, default `10`). Used as the polling cadence while
|
||||
the WebSocket is unavailable. When the WebSocket is connected, the
|
||||
integration drops to a 5-minute REST safety-net poll automatically.
|
||||
|
||||
## Supported Features
|
||||
|
||||
| Feature | Support |
|
||||
|---------|---------|
|
||||
| Play/Pause | Yes |
|
||||
| Stop | Yes |
|
||||
| Volume Control | Yes |
|
||||
| Volume Mute | Yes |
|
||||
| Seek | Yes |
|
||||
| Next Track | Yes |
|
||||
| Previous Track | Yes |
|
||||
| Media Browser | Yes |
|
||||
| Play Media | Yes |
|
||||
| Feature | Support |
|
||||
| ------------------- | ------- |
|
||||
| Play / Pause | Yes |
|
||||
| Stop | Yes |
|
||||
| Volume Control | Yes |
|
||||
| Volume Mute | Yes |
|
||||
| Seek | Yes |
|
||||
| Next Track | Yes |
|
||||
| Previous Track | Yes |
|
||||
| Repeat Mode | Yes |
|
||||
| Media Browser | Yes |
|
||||
| Play Media | Yes |
|
||||
| Enqueue / Play Next | Yes |
|
||||
|
||||
## Entity Attributes
|
||||
|
||||
Each media player entity exposes the following attributes:
|
||||
|
||||
- `session_id`: Emby session identifier
|
||||
- `device_id`: Device identifier
|
||||
- `device_name`: Name of the playback device
|
||||
- `client_name`: Emby client application name
|
||||
- `user_name`: Emby user name
|
||||
- `item_id`: Currently playing item ID
|
||||
- `item_type`: Type of media (Movie, Episode, Audio, etc.)
|
||||
| Attribute | Description |
|
||||
| -------------- | -------------------------------------------------------------------------- |
|
||||
| `session_id` | Emby session identifier |
|
||||
| `device_id` | Device identifier |
|
||||
| `device_name` | Name of the playback device |
|
||||
| `client_name` | Emby client application name |
|
||||
| `user_name` | Emby user currently signed in on the client (when available) |
|
||||
| `item_id` | Currently playing item ID (only while playing) |
|
||||
| `item_type` | Type of media (`Movie`, `Episode`, `Audio`, …) |
|
||||
| `play_method` | `DirectPlay`, `DirectStream`, or `Transcode` (only while playing) |
|
||||
|
||||
## Services
|
||||
|
||||
### `emby_player.send_message`
|
||||
|
||||
Display a banner notification on an Emby client. Great for doorbells, alarms,
|
||||
laundry timers, etc.
|
||||
|
||||
| Field | Required | Description |
|
||||
| ------------ | -------- | -------------------------------------------- |
|
||||
| `entity_id` | Yes | One or more Emby media-player entities. |
|
||||
| `message` | Yes | Text to display. |
|
||||
| `header` | No | Optional header / title. |
|
||||
| `timeout_ms` | No | How long to show the message (100–60000 ms). |
|
||||
|
||||
```yaml
|
||||
service: emby_player.send_message
|
||||
target:
|
||||
entity_id: media_player.emby_living_room_tv
|
||||
data:
|
||||
header: "Doorbell"
|
||||
message: "Someone's at the front door"
|
||||
timeout_ms: 5000
|
||||
```
|
||||
|
||||
### `emby_player.set_repeat`
|
||||
|
||||
Set the repeat mode on the current playback.
|
||||
|
||||
| Field | Required | Description |
|
||||
| ------------- | -------- | -------------------------------------------------------- |
|
||||
| `entity_id` | Yes | One or more Emby media-player entities. |
|
||||
| `repeat_mode` | Yes | One of `RepeatNone`, `RepeatOne`, or `RepeatAll`. |
|
||||
|
||||
```yaml
|
||||
service: emby_player.set_repeat
|
||||
target:
|
||||
entity_id: media_player.emby_living_room_tv
|
||||
data:
|
||||
repeat_mode: RepeatAll
|
||||
```
|
||||
|
||||
> The standard HA media-player repeat control is also wired up — `media_player.repeat_set` will work without using this service.
|
||||
|
||||
### `emby_player.refresh_library`
|
||||
|
||||
Trigger a server-side library scan. If `entity_id` is omitted, all configured
|
||||
Emby servers are refreshed.
|
||||
|
||||
```yaml
|
||||
service: emby_player.refresh_library
|
||||
```
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Open **Settings → Integrations → Emby Media Player → "..." → Download diagnostics** to get a redacted JSON dump containing the entry, the current sessions, server id, and WebSocket connection status. Useful when filing bug reports.
|
||||
|
||||
The dump redacts the API key and replaces real session / device / user IDs with stable hashes so it's safe to share.
|
||||
|
||||
## Automation Examples
|
||||
|
||||
### Dim lights when playing a movie
|
||||
### Dim lights when a movie starts
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
@@ -110,7 +204,7 @@ automation:
|
||||
brightness_pct: 20
|
||||
```
|
||||
|
||||
### Pause playback when doorbell rings
|
||||
### Pause playback when the doorbell rings, then notify the screen
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
@@ -123,32 +217,62 @@ automation:
|
||||
- service: media_player.media_pause
|
||||
target:
|
||||
entity_id: media_player.emby_living_room_tv
|
||||
- service: emby_player.send_message
|
||||
target:
|
||||
entity_id: media_player.emby_living_room_tv
|
||||
data:
|
||||
header: "Doorbell"
|
||||
message: "Someone is at the door"
|
||||
timeout_ms: 8000
|
||||
```
|
||||
|
||||
### Toggle shuffle/repeat from a script
|
||||
|
||||
```yaml
|
||||
script:
|
||||
emby_repeat_all:
|
||||
sequence:
|
||||
- service: media_player.repeat_set
|
||||
target:
|
||||
entity_id: media_player.emby_living_room_tv
|
||||
data:
|
||||
repeat: all
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
### Connection issues
|
||||
|
||||
- Verify the Emby server is accessible from Home Assistant
|
||||
- Check that the API key is valid and has appropriate permissions
|
||||
- Ensure the port is correct (default is 8096)
|
||||
- Verify the Emby server is reachable from the Home Assistant host (try `ping` / `curl http://<host>:8096/emby/System/Info` from a terminal on the HA box).
|
||||
- Check that the API key is valid and not revoked in Emby Dashboard → Extended → API Keys.
|
||||
- For HTTPS with a self-signed certificate, toggle **Verify SSL certificate** off in the integration config.
|
||||
- If reauth keeps failing, regenerate the API key on the server and try again.
|
||||
|
||||
### No Media Players Appearing
|
||||
### No media players appearing
|
||||
|
||||
- Media player entities are only created for **active sessions** that support remote control
|
||||
- Start playback on an Emby client and wait for the entity to appear
|
||||
- Check the Home Assistant logs for any error messages
|
||||
- Media-player entities are only created for **active sessions that support remote control**. Start playback on an Emby client first.
|
||||
- Browser-based Emby Web sessions usually do not support remote control and won't appear as entities.
|
||||
- Check **Settings → System → Logs** in Home Assistant for messages from `custom_components.emby_player`.
|
||||
|
||||
### WebSocket Connection Failed
|
||||
### WebSocket connection failed
|
||||
|
||||
If WebSocket connection fails, the integration will fall back to polling. Check:
|
||||
- Firewall rules allow WebSocket connections
|
||||
- Reverse proxy is configured to support WebSocket
|
||||
- Server logs in Home Assistant for specific errors
|
||||
If the WebSocket can't connect, the integration falls back to REST polling at the configured **Scan Interval**. To restore real-time updates:
|
||||
|
||||
- Allow WebSocket traffic to TCP `8096` / `8920` from the HA host.
|
||||
- If you run Emby behind a reverse proxy, make sure `Upgrade` / `Connection` headers are forwarded for `/embywebsocket`.
|
||||
- For HTTPS proxies (Caddy / Traefik / nginx), confirm the WebSocket path is included in the proxy config.
|
||||
|
||||
### Stale devices in the registry
|
||||
|
||||
Devices for sessions that haven't been seen for 30 minutes are removed automatically (after a 10-minute startup grace). You can also manually delete a device from **Settings → Devices & Services → Emby Media Player → Device → Delete**.
|
||||
|
||||
## Versioning
|
||||
|
||||
See [RELEASE_NOTES.md](RELEASE_NOTES.md) for the full changelog.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please open an issue or submit a pull request.
|
||||
Contributions are welcome. Please open an issue or submit a pull request.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user