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>
This commit is contained in:
2026-09-11 08:31:28 +02:00
parent 57afc32f4a
commit 747c390303
32 changed files with 1603 additions and 33 deletions

View File

@@ -21,6 +21,10 @@ interface Props {
onMute: () => void;
onBrowse: () => void;
onOpenAlbum: () => void;
/** Assigning the current album/show to a remote key. `assignPending` is true right
* after "A" is pressed, waiting for the digit that completes the shortcut. */
onOpenAssign: () => void;
assignPending: boolean;
}
export function PlayView({
@@ -34,6 +38,8 @@ export function PlayView({
onMute,
onBrowse,
onOpenAlbum,
onOpenAssign,
assignPending,
}: Props) {
const position = usePlaybackClock(state.position, state.playing);
const book = album ? isBook(album) : false;
@@ -245,6 +251,32 @@ export function PlayView({
</span>
Zurück zur Suche
</button>
{album && (
<button
onClick={onOpenAssign}
title="Einer Fernbedienungs-Taste zuweisen (oder: A und dann eine Zahl)"
style={{
position: "absolute",
top: 28,
right: 84,
border: "none",
cursor: "pointer",
background: assignPending ? "var(--accent)" : "oklch(97% 0.01 210 / .95)",
borderRadius: 999,
padding: "11px 20px",
fontSize: 14,
fontWeight: 800,
color: assignPending ? "#fff" : "var(--ink)",
display: "flex",
alignItems: "center",
gap: 8,
boxShadow: "0 8px 24px oklch(15% 0.05 210 / .4)",
}}
>
🎛 {assignPending ? "Zahl drücken …" : "Taste zuweisen"}
</button>
)}
</div>
</div>
);