Adds a TCP client for lircd's classic protocol: play/pause/next/prev/ volume/mute map to the same intents every other front-end already emits, and number keys 0-9 play an assigned album/audiobook from the start or a podcast show's newest episode, resolved fresh on every press. The mapping is configured in config.yml and editable from the frontend: a small "Taste zuweisen" button on the play screen (or the A+digit keyboard shortcut) opens a 10-key picker to assign whatever is currently playing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
"""Reading and writing the IR remote's number-key mapping.
|
|
|
|
Same job as :mod:`musicmouse.services.web.settings`, for a dict-shaped config section
|
|
rather than flat scalars: the ``remote:`` top-level key, not something under
|
|
``general``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from musicmouse.config import Digit, RemoteSlotConfig
|
|
from musicmouse.library import MusicLibrary
|
|
from musicmouse.services.web.schemas import RemoteMappingOut, RemoteSlotOut
|
|
from musicmouse.services.web.settings import atomic_write, load_document
|
|
|
|
__all__ = ["read_mapping", "write_mapping"]
|
|
|
|
|
|
def _resolve(slot: RemoteSlotConfig, library: MusicLibrary) -> str | None:
|
|
if slot.target_kind == "album":
|
|
album = library.get(slot.target)
|
|
else:
|
|
album = library.latest_episode(slot.target)
|
|
return album.id if album else None
|
|
|
|
|
|
def read_mapping(remote: dict[Digit, RemoteSlotConfig], library: MusicLibrary) -> RemoteMappingOut:
|
|
slots = [
|
|
RemoteSlotOut(
|
|
digit=digit,
|
|
target_kind=slot.target_kind,
|
|
target=slot.target,
|
|
resolved_album_id=_resolve(slot, library),
|
|
)
|
|
for digit, slot in sorted(remote.items())
|
|
]
|
|
return RemoteMappingOut(slots=slots)
|
|
|
|
|
|
def write_mapping(path: Path, mapping: dict[Digit, RemoteSlotConfig]) -> None:
|
|
document = load_document(path)
|
|
remote = {
|
|
digit: {"target_kind": slot.target_kind, "target": slot.target}
|
|
for digit, slot in mapping.items()
|
|
}
|
|
document["remote"] = remote
|
|
atomic_write(path, document)
|