This commit is contained in:
Home Assistant Version Control
2026-09-25 04:10:30 +00:00
parent 56c80f896e
commit ad634c1b84
60 changed files with 2895 additions and 794 deletions
+69 -1
View File
@@ -1,9 +1,13 @@
from __future__ import annotations
import asyncio
from dataclasses import dataclass, field
from typing import Callable
from typing import Callable, Iterable
from homeassistant.helpers.storage import Store
from .const import (
DOMAIN,
DEFAULT_SLIDE_INTERVAL,
DEFAULT_REFRESH_HOURS,
DEFAULT_FILL_MODE,
@@ -52,8 +56,72 @@ class SlideshowStore:
# the previous slide instantly across a camera reload.
last_frame: bytes | None = None
hidden_photo_ids: frozenset[str] = field(default_factory=frozenset, init=False)
last_hidden_photo_ids: tuple[str, ...] = field(default=(), init=False)
hidden_revision: int = field(default=0, init=False)
_hidden_storage: Store | None = field(default=None, init=False, repr=False)
_hidden_lock: asyncio.Lock = field(default_factory=asyncio.Lock, init=False, repr=False)
_listeners: list[Listener] = field(default_factory=list)
async def async_load_hidden_photos(self, hass, entry_id: str) -> None:
self._hidden_storage = Store(hass, 1, f"{DOMAIN}.{entry_id}.hidden")
data = await self._hidden_storage.async_load()
if data is None:
return
if not isinstance(data, dict):
raise ValueError("Invalid hidden-photo storage")
hidden = data.get("hidden", [])
last_hidden = data.get("last_hidden", [])
revision = data.get("revision", 0)
if type(revision) is not int or revision < 0:
raise ValueError("Invalid hidden-photo revision")
if any(
not isinstance(values, list)
or any(not isinstance(photo_id, str) or not photo_id for photo_id in values)
for values in (hidden, last_hidden)
):
raise ValueError("Invalid hidden-photo identifiers")
self.hidden_photo_ids = frozenset(hidden)
self.hidden_revision = revision
self.last_hidden_photo_ids = tuple(
dict.fromkeys(photo_id for photo_id in last_hidden if photo_id in self.hidden_photo_ids)
)
async def async_set_photos_hidden(
self, photo_ids: Iterable[str], *, hidden: bool
) -> bool:
requested = frozenset(photo_ids)
if any(not isinstance(photo_id, str) or not photo_id for photo_id in requested):
raise ValueError("Invalid photo identifier")
async with self._hidden_lock:
if self._hidden_storage is None:
raise RuntimeError("Photo exclusions have not been loaded")
updated = (
self.hidden_photo_ids | requested
if hidden
else self.hidden_photo_ids - requested
)
if updated == self.hidden_photo_ids:
return False
last_hidden = (
tuple(sorted(updated - self.hidden_photo_ids))
if hidden
else tuple(photo_id for photo_id in self.last_hidden_photo_ids if photo_id in updated)
)
await self._hidden_storage.async_save(
{
"hidden": sorted(updated),
"last_hidden": list(last_hidden),
"revision": self.hidden_revision + 1,
}
)
self.hidden_photo_ids = updated
self.last_hidden_photo_ids = last_hidden
self.hidden_revision += 1
self.last_frame = None
self.notify()
return True
def add_listener(self, cb: Listener) -> None:
if cb not in self._listeners:
self._listeners.append(cb)