- python-backend/README: track analysis is implemented (2e0e6ad); the cache layout, the module table (lirc, screen, timers, podcasts, tippen) and the route table (track analysis, HA proxy, typing game) were missing pieces. - docs/REPO_OVERVIEW: Mein Zimmer and the clock are implemented; Home Assistant is also reached over HTTP through the room page's proxy, not MQTT only; the IR remote, scripts/, the optional config sections and figure kind were not mentioned. - web/README: the key table was the mockup's (Ctrl transport keys, TAB over 'all'); ?pi=1 is now a preset with per-browser overrides, not a read-once flag; the room page and the typing game exist; eslint is part of the checks. - Docstrings that described earlier designs: HaConfig (written as browser-direct in the same commit that built the proxy,a8ed350), services/__init__, events, playback, media, colors, tippen progress and AppHeader, lowPower.ts, and the 'Hoerbuecher' spelling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
1.1 KiB
Python
47 lines
1.1 KiB
Python
"""Playlist model.
|
|
|
|
What the player plays: a name and the files, in order. The browse API serves
|
|
:class:`~musicmouse.library.models.Album` instead, which carries the tag metadata;
|
|
``Album.to_playlist()`` builds one of these from it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
__all__ = ["Playlist", "Track"]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Track:
|
|
path: Path
|
|
|
|
@property
|
|
def title(self) -> str:
|
|
return self.path.stem
|
|
|
|
def __repr__(self) -> str:
|
|
return f"Track({self.title!r})"
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Playlist:
|
|
name: str
|
|
tracks: tuple[Track, ...]
|
|
#: Set when this playlist came from a library album. It is how a front-end answers
|
|
#: "what is playing?" without keeping its own copy of that state.
|
|
album_id: str | None = None
|
|
|
|
def __len__(self) -> int:
|
|
return len(self.tracks)
|
|
|
|
def __bool__(self) -> bool:
|
|
return bool(self.tracks)
|
|
|
|
def __getitem__(self, index: int) -> Track:
|
|
return self.tracks[index]
|
|
|
|
def __repr__(self) -> str:
|
|
return f"Playlist({self.name!r}, {len(self.tracks)} tracks)"
|