Files
musicmouse/python-backend/musicmouse/services/web/remote_settings.py
Martin Bauer 747c390303 Add IR remote control (LIRC) with a number-key content mapping
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>
2026-09-11 08:31:28 +02:00

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)