## v0.2.0 (2026-05-26) Production-readiness pass: security hardening, performance improvements, new services, and supporting integration plumbing. Three rounds of independent code review applied. ### Breaking Changes - `EmbyApiClient` and `EmbyWebSocket` constructors now require an injected `aiohttp.ClientSession` and a `device_id`. Both clients never own or close the session — Home Assistant owns it. Custom integrations or scripts importing these classes directly must update their call sites. ### Features - **WebSocket real-time updates** now drive entity state without firing a REST refresh on every `PlaybackProgress` event. Sessions update in place via `dataclasses.replace`; REST falls back to a 5-minute safety net while the WS is up. - **Image proxy**: artwork is fetched server-side with the API key in the `X-Emby-Token` header; the API key never appears in URLs returned to the browser. - **Per-instance device ID** derived from `instance_id.async_get(hass)` and the config-entry id — multiple Home Assistant installs no longer collide on the same Emby server. - **Self-signed HTTPS support** via a new `verify_ssl` toggle in the config flow (defaults to verifying). - **Reauth flow**: when the server rejects the API key, Home Assistant prompts for a new one inline instead of leaving the integration broken. - **Repeat mode control** wired through the standard `media_player.repeat_set` UI; HA `MediaPlayerEnqueue` mapped explicitly to Emby `PlayNow` / `PlayNext` / `PlayLast`. - **Per-client device class** inferred from the Emby client name (AndroidTV / Kodi / Roku → TV, music clients → Speaker, others → generic). - **Three new services**: - `emby_player.send_message` — display a banner on an Emby client (doorbells, alarms, laundry timers). - `emby_player.set_repeat` — set RepeatNone / RepeatOne / RepeatAll. - `emby_player.refresh_library` — trigger a server-side library scan. - **Diagnostics**: redacted entry + sessions JSON dump from Settings → Integrations → "..." → Download diagnostics. API key is redacted; session / device / user IDs are replaced with stable hashes. - **Hub device** registered for `via_device` linkage; per-session devices now appear under it. - **Zeroconf + SSDP discovery hints** so Home Assistant can find Emby servers. - **Stale device cleanup** removes devices for sessions absent over 30 minutes (with a 10-minute setup grace period); the coordinator's `forget_session` helper prevents the last-seen map from growing unbounded. ### Bug Fixes - WebSocket reconnect uses **exponential backoff with jitter** (capped at 5 min) instead of a fixed 30 s; auth failures no longer trigger infinite retry; the reconnect task is tracked and cancelled cleanly on unload. - `media_position_updated_at` now reflects the real coordinator update time, eliminating spurious state writes from returning `utcnow()` on every property read. - Authentication failures during a coordinator update now raise `ConfigEntryAuthFailed` so Home Assistant actually triggers the reauth flow. - WebSocket authentication moved into HTTP headers — the API key no longer appears in proxy access logs. - `MediaPlayerDeviceClass.TV` is no longer hardcoded for non-TV clients. - `_attr_has_entity_name = True` combined with `_attr_name` no longer double-prints the device name in the UI. - Browse media now raises `BrowseError` with context (and wraps unexpected exceptions instead of surfacing 500s). - Non-admin API keys fall back to `/Users/Public` instead of failing setup. - All session / item / user IDs are validated against `^[A-Za-z0-9_-]{1,128}$` before interpolation into REST paths (defense-in-depth against path traversal / SSRF). - `image_type` validated against a whitelist (`Primary`, `Backdrop`, `Thumb`, `Logo`, `Banner`, `Art`, `Disc`, `Box`). - `play_media` raises `ServiceValidationError` on bad input (not `ValueError`); validates `media_id` format and `position` type. - `async_remove_config_entry_device` refuses to remove the hub device and any session still present in the coordinator. - WebSocket `ForceKeepAlive` is now echoed as `KeepAlive` so the server doesn't drop idle connections. - `PlaySessionId` fallback removed from playback-event parsing — only `SessionId` is matched, eliminating cross-device false positives. - `_safe_int` helper hardens numeric field parsing against `null` / string / malformed payloads (`RunTimeTicks`, `PositionTicks`, `VolumeLevel`, etc.). - Image fetches get a dedicated 30 s timeout, separate from the 15 s REST default. - `manifest.json` `codeowners` corrected to an empty list (hassfest validates entries against GitHub handles). ### Performance - WebSocket / REST race resolved: `_async_update_data` records `request_started`, then merges REST results with any session whose `last_seen` is newer (WS state wins for in-flight progress). - REST poll interval automatically slows to 5 min while the WebSocket is connected, restoring the user-configured interval if it disconnects. - WebSocket callbacks may be sync or async; async ones are detached via `asyncio.create_task` so a slow consumer can't stall the reader. --- ### Development / Internal - Frozen dataclasses (`EmbyNowPlaying`, `EmbyPlayState`, `EmbySession`) across the coordinator state — safer for concurrency and immutability. - `manifest.json` declares `integration_type: hub`, `quality_scale: silver`, `loggers`, and discovery hints. - HACS minimum Home Assistant bumped to `2024.10.0`. - Client version sourced from `manifest.json` at startup via `loader.async_get_integration` (no more `DEVICE_VERSION` drift). - New `diagnostics.py`, `services.py`, `services.yaml`. - Strings + `translations/en.json` extended for `verify_ssl`, `reauth_confirm`, and the three new services. - `README.md` and `CLAUDE.md` rewritten to match the v0.2.0 state of the integration. ---
Files Changed | File | Status | |------|--------| | `CLAUDE.md` | Modified | | `README.md` | Modified | | `RELEASE_NOTES.md` | Modified | | `hacs.json` | Modified | | `custom_components/emby_player/__init__.py` | Modified | | `custom_components/emby_player/api.py` | Modified | | `custom_components/emby_player/browse_media.py` | Modified | | `custom_components/emby_player/config_flow.py` | Modified | | `custom_components/emby_player/const.py` | Modified | | `custom_components/emby_player/coordinator.py` | Modified | | `custom_components/emby_player/manifest.json` | Modified | | `custom_components/emby_player/media_player.py` | Modified | | `custom_components/emby_player/strings.json` | Modified | | `custom_components/emby_player/translations/en.json` | Modified | | `custom_components/emby_player/websocket.py` | Modified | | `custom_components/emby_player/diagnostics.py` | Added | | `custom_components/emby_player/services.py` | Added | | `custom_components/emby_player/services.yaml` | Added |
--- ## v0.1.0 (2026-03-26) Initial release of the **Emby Media Player** custom integration for Home Assistant (HACS). ### Features - Full Emby Server media player integration for Home Assistant ([46cb2fb](https://git.dolgolyov-family.by/alexei.dolgolyov/haos-hacs-emby-media-player/commit/46cb2fb)) ---
All Commits | Hash | Message | Author | |------|---------|--------| | [46cb2fb](https://git.dolgolyov-family.by/alexei.dolgolyov/haos-hacs-emby-media-player/commit/46cb2fb) | Initial commit for `Emby Media Player` HAOS HACS integration | alexei.dolgolyov |