nuc/jellyfin-client: document host-side input hotplug auto-recovery
Add udev rule + oneshot service + script on nuc that restart the container kiosk when the Logitech Unifying receiver is replugged, since hotplug uevents don't cross into the container's netns and cage only enumerates input at startup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
61e3606d33
commit
43ef0e5447
+58
-2
@@ -231,6 +231,60 @@ incus exec "$CNAME" -- systemctl daemon-reload
|
|||||||
incus exec "$CNAME" -- systemctl enable --now go-librespot
|
incus exec "$CNAME" -- systemctl enable --now go-librespot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Input hotplug auto-recovery (host side)
|
||||||
|
|
||||||
|
cage only enumerates input devices at startup, and udev hotplug events don't
|
||||||
|
cross into the container (see tricky-parts #2). So re-plugging the Unifying
|
||||||
|
receiver leaves the kiosk bound to the old, now-dead device node — no
|
||||||
|
keyboard/mouse until `jellyfin-kiosk` is restarted. These three files **on the
|
||||||
|
host** (`nuc`, not the container) automate that: the host *does* receive the
|
||||||
|
uevent, so a host udev rule fires on the receiver's USB `add` and restarts the
|
||||||
|
container's kiosk. Match is by vendor/product (`046d:c52b`), not sysfs path, so
|
||||||
|
it works regardless of which USB port the dongle lands on.
|
||||||
|
|
||||||
|
`/etc/udev/rules.d/99-jellyfin-kiosk-recover.rules`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Logitech Unifying receiver (re)plugged -> recover the jellyfin-client kiosk
|
||||||
|
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="046d", ATTR{idProduct}=="c52b", RUN+="/usr/bin/systemctl --no-block start jellyfin-kiosk-recover.service"
|
||||||
|
```
|
||||||
|
|
||||||
|
`/etc/systemd/system/jellyfin-kiosk-recover.service` — oneshot, so a burst of
|
||||||
|
udev events during one plug merges into a single restart (natural debounce):
|
||||||
|
|
||||||
|
```
|
||||||
|
[Unit]
|
||||||
|
Description=Restart jellyfin-client kiosk after Logitech receiver hotplug
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/jellyfin-kiosk-recover.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`/usr/local/bin/jellyfin-kiosk-recover.sh` — waits for the receiver to enumerate
|
||||||
|
its paired K400 node, then restarts the kiosk only if the container is up (so
|
||||||
|
host-boot coldplug events are a no-op):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# Restart the jellyfin-client Wayland kiosk after the Logitech Unifying
|
||||||
|
# receiver is (re)plugged, so cage/libinput re-enumerates the keyboard/mouse.
|
||||||
|
sleep 6
|
||||||
|
if ! incus info jellyfin-client 2>/dev/null | grep -qi 'Status:.*RUNNING'; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
incus exec jellyfin-client -- systemctl restart jellyfin-kiosk.service
|
||||||
|
logger -t jellyfin-kiosk-recover "Restarted jellyfin-kiosk after Logitech receiver hotplug"
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply, then watch it work by replugging the dongle:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
chmod +x /usr/local/bin/jellyfin-kiosk-recover.sh
|
||||||
|
udevadm control --reload-rules && systemctl daemon-reload
|
||||||
|
journalctl -t jellyfin-kiosk-recover -f
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -251,8 +305,10 @@ incus exec jellyfin-client -- udevadm info /dev/input/event0 # udev db visibl
|
|||||||
(#3); check `/etc/asound.conf` and the card name in `aplay -l`.
|
(#3); check `/etc/asound.conf` and the card name in `aplay -l`.
|
||||||
- **Keyboard plugged in after boot isn't seen** — the host udev db is live
|
- **Keyboard plugged in after boot isn't seen** — the host udev db is live
|
||||||
through the bind, but udev hotplug *events* don't cross the container's
|
through the bind, but udev hotplug *events* don't cross the container's
|
||||||
network namespace, so cage only enumerates at startup:
|
network namespace, so cage only enumerates at startup. Re-plugging the
|
||||||
`systemctl restart jellyfin-kiosk` after plugging new input hardware.
|
Unifying receiver is now handled automatically by the host-side recovery
|
||||||
|
rule (see "Input hotplug auto-recovery"); manual fallback for other input
|
||||||
|
hardware: `incus exec jellyfin-client -- systemctl restart jellyfin-kiosk`.
|
||||||
- **cage can't open card0** — something on the host holds DRM master; the
|
- **cage can't open card0** — something on the host holds DRM master; the
|
||||||
host must boot to `multi-user.target` with no display manager.
|
host must boot to `multi-user.target` with no display manager.
|
||||||
- **Jellyfin + Spotify at the same time** — the Pioneer PCM is exclusive;
|
- **Jellyfin + Spotify at the same time** — the Pioneer PCM is exclusive;
|
||||||
|
|||||||
Reference in New Issue
Block a user