diff --git a/nuc/jellyfin-client.md b/nuc/jellyfin-client.md index 3eb883b..f9a5be8 100644 --- a/nuc/jellyfin-client.md +++ b/nuc/jellyfin-client.md @@ -231,6 +231,60 @@ incus exec "$CNAME" -- systemctl daemon-reload 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 ```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`. - **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 - network namespace, so cage only enumerates at startup: - `systemctl restart jellyfin-kiosk` after plugging new input hardware. + network namespace, so cage only enumerates at startup. Re-plugging the + 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 host must boot to `multi-user.target` with no display manager. - **Jellyfin + Spotify at the same time** — the Pioneer PCM is exclusive;