4 Commits

Author SHA1 Message Date
2fb290b146 Build and install the native front-end on musicdolphin
slint-frontend/ in the app repo is a native front-end for the same backend, written
because the React UI is sluggish on this device. This installs it beside the web UI,
never instead of it: the systemd unit is installed but not enabled, so the device still
boots into the kiosk browser and the two can be compared on the same screen.

  systemctl start musikdelfin     # takes over the display
  systemctl stop  musikdelfin     # back to the browser underneath

Unlike pi_musicmouse, which builds the web front-end on the control machine and rsyncs
dist/, this builds on the device. A Rust binary is not portable, and the reason it has
to be built here rather than cross-compiled is worth writing down: these Pis run 32-bit
armhf Raspbian on a 64-bit kernel. `uname -m` says aarch64 and it is misleading;
`dpkg --print-architecture` says armhf and that is the one that matters. Cross-compiling
to armv7-unknown-linux-gnueabihf needs a sysroot, the devices carry no -dev packages to
build one from, and reconstructing one from the Debian archive means owning a glibc skew
risk indefinitely. Spending the device's own CPU once is the smaller liability. The
build is stamped with the commit it came from, so it only runs again when that changes.

The same fact rules out the Skia renderer that the app's own kiosk profile prefers:
rust-skia publishes no prebuilt binaries for armhf. This builds --features desktop -
winit, FemtoVG and the software renderer - and runs as an X client in the existing
session. Worth noting after the fact: the FemtoVG bug that makes Skia the upstream
recommendation (slint-ui/slint#11785, album covers drawn as solid black) was reported on
a Pi 5 with a 64-bit userland and does not reproduce here - covers render correctly.

Three things had to be found by running it rather than reading anything:

The X session belongs to `kiosk`, not root, so the launcher needs that user's cookie and
the unit runs as them. Without it winit fails with "could not initialize backend", which
says nothing about authorization.

winit and glutin dlopen every windowing and GL library they use, so none of them appear
in `ldd` and the binary links happily without them - then aborts on first run with
"Library libxkbcommon-x11.so could not be loaded". The runtime packages are listed
explicitly for that reason.

Raspbian ships no font containing the emoji the design uses as iconography, so the shelf
badges rendered as empty boxes until fonts-noto-color-emoji went in.

First build took 63 minutes: 570 crates, two jobs, nice'd, which bounds peak memory on
musicdolphin's 1.8 GB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 00:44:54 +02:00
831a1b50a4 Run the kiosk on Chromium, and take the stray media server off musicdolphin
Chromium: same page, same machine, idle, Firefox 24.2% of a core against Chromium's
11.4%. The build comes from archive.raspberrypi.com (a "+rpt" version) and is patched
for this board's V3D GPU; Debian ships a much older chromium, so the archive matters.
The whole userland here is 32-bit armhf on a 64-bit kernel, which Firefox handles worse
than Chromium does. --use-gl=egl, --enable-gpu-rasterization, --ignore-gpu-blocklist
and --enable-zero-copy are what keep rasterization on the GPU: Chromium's blocklist
does not recognise this driver and silently falls back to software without them.
pi_kiosk_browser: firefox still works, as the fallback if an update ever regresses.

Debug mode also gains xdotool, scrot and --remote-debugging-port=9222 (on 127.0.0.1),
because firing XTEST key events at a window lands about half the time and a benchmark
you cannot verify the state of is worse than none.

pi_squeezeserver gains an absent path, and mediapis.yml derives its state from
mediapi_has_squeezeserver, which defaults to false for the whole group. false means
"actively remove", not "skip": musicdolphin has been running a Logitech Media Server
that no playbook installs and nothing talks to - every squeezelite in the fleet points
at pi_squeezelite_squeezeserver (192.168.178.80, the server) - while costing ~30 MB
resident and ~47 MB of swap on a 2 GB Pi that also drives the kiosk. The absent path
stops it, purges the package, unregisters it from sysdweb, drops the port 80 -> 9000
redirect and deletes its database and logs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 15:13:16 +02:00
9b1d01115b Deploy rearchitected MusicMouse backend + web frontend
The app grew a python-backend/ and a web/ frontend, so pi_musicmouse no
longer matches it. Rework the role:

- Install a pinned uv and build the venv with Python 3.13; Raspbian
  Bookworm's python3 is 3.11 and the backend uses PEP 695 syntax.
- pip install python-backend/ instead of a requirements.txt, and take
  the systemd unit straight from the checkout so it can't drift.
- Build web/ on the control machine (no npm on the Pi) and rsync
  web/dist over. Chain the checkout -> install -> build -> sync -> restart
  steps through handlers so a run with no repo change does nothing.
- Per-host config files (config-<host>.yml); the schema now differs
  between a host with a real mouse and a display-only one.
- Version to deploy is per host (musicmouse_version), no default.

Add pi_kiosk: autologin user running startx with Firefox in kiosk mode
and no window manager, for a Pi with a monitor attached. Enabled by
mediapi_has_monitor, defaulting off.

Turn musicdolphin into a display-only instance: serial and audio
simulated, driven entirely through the kiosk page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 17:58:51 +02:00
85a26db46b single playbook for mediapis 2026-09-10 21:33:19 +02:00