v0.48.0: web mixes upload to a web server (rsync over ssh), and the player shuffles

Export Web Mix gets an 'Upload to web server' box: the mix is built in a
cache staging folder and mirrored with rsync --delete into <path>/<slug>/
on the host set in Preferences → Integrations → Web Server (config.json,
this machine only). An ssh check asks before replacing an existing mix;
a status window follows check, export and upload. The web player gains a
shuffle button (and the S key).
This commit is contained in:
2026-10-10 23:23:56 -07:00
parent d4cf3f95c2
commit e9488c5289
11 changed files with 1308 additions and 25 deletions
+17
View File
@@ -644,6 +644,23 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
untouched export still renders the original `#8c764a`. Templates are
registered in `setup.py` via `package_data`; loaded with
`importlib.resources` so an installed copy finds them.
**Upload to web server** (Round 81, `export/upload.py`): a ticked box in
the web-mix dialog builds the mix in `$XDG_CACHE_HOME/lintunes/webmix/
<slug>/` (no folder picker) and mirrors it with `rsync -a --checksum
--delete` over ssh to `<host>:<path>/<slug>/`. rsync, not scp: scp re-sends
everything and never deletes, so a song taken out of the playlist would
stay online forever. Host and path live in **`config.json`** only (the
host is usually this machine's `~/.ssh/config` alias, and trav's server
must never appear in the repo or the synced share — tests use
`example-host`). `--delete` only ever reaches the slug folder
(`remote_dir` validates the slug), staging is wiped first
(`reset_staging`, guarded to stay inside the staging root) so a removed
song can't survive the mirror, and ssh runs with `BatchMode=yes`, since
nobody can answer a prompt. Steps: `ServerCheckWorker` (`ssh test -d`; an
existing folder asks before replacing it), `ExportWorker`, then
`UploadWorker`, all shown in `gui/web_upload_progress.py`. The web
player has a **shuffle** button (and the S key): a shuffled walk that starts at
the current song and plays every song once.
- **`lintunes/cassette/`** — friend library sharing (Round 63+; the spec is
`Cassette friend library.md`). LinTunes never talks to a friend: it drives