Files
haos-hacs-emby-media-player/custom_components/emby_player/diagnostics.py
T
alexei.dolgolyov 6ae0ed1787
Release / release (push) Successful in 2s
chore: release v0.2.0
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.
2026-05-26 13:16:36 +03:00

66 lines
2.3 KiB
Python

"""Diagnostics support for Emby Media Player."""
from __future__ import annotations
import hashlib
from dataclasses import asdict
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.core import HomeAssistant
from . import EmbyConfigEntry
from .const import CONF_API_KEY
TO_REDACT_ENTRY = {CONF_API_KEY}
# Session-level fields that could allow Emby command injection if leaked
# alongside the API key.
TO_REDACT_SESSION = {"session_id", "device_id", "user_id"}
def _stable_token(value: str) -> str:
"""Stable, irreversible token for a session identifier.
The first 10 chars of an MD5 are enough to correlate entries in a single
diagnostics dump without exposing the real Emby ID.
"""
return "sid-" + hashlib.md5(value.encode("utf-8")).hexdigest()[:10] # noqa: S324
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: EmbyConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
runtime = entry.runtime_data
coordinator = runtime.coordinator
sessions_dump: dict[str, Any] = {}
if coordinator.data:
for sid, session in coordinator.data.items():
session_dict = asdict(session)
# Convert datetimes to isoformat for JSON friendliness.
for key, value in list(session_dict.items()):
if hasattr(value, "isoformat"):
session_dict[key] = value.isoformat()
# Nested play_state.updated_at may also be a datetime.
if isinstance(value, dict):
for sub_k, sub_v in list(value.items()):
if hasattr(sub_v, "isoformat"):
value[sub_k] = sub_v.isoformat()
sessions_dump[_stable_token(sid)] = async_redact_data(
session_dict, TO_REDACT_SESSION
)
return {
"entry": {
"title": entry.title,
"data": async_redact_data(dict(entry.data), TO_REDACT_ENTRY),
"options": dict(entry.options),
"unique_id": entry.unique_id,
},
"server_id": runtime.server_id,
"websocket_connected": coordinator.websocket_connected,
"last_update_success": coordinator.last_update_success,
"sessions": sessions_dump,
}