v0.8.0: export a playlist — as a folder, or as a whole website
File → Export Playlist…, and the same item on a playlist's right-click
menu. A sibling of device_sync: pure plan_export() first, then a worker
on a daemon thread sharing the status-bar progress widgets. The manifest
(index.html / .m3u) is written last, so an interrupted export never
leaves a page naming files that aren't there.
Two destinations. A folder gives the audio under "Artist - Title" names
plus an extended .m3u. A web mix gives a self-contained static site
reproducing the hand-made yearly mixes, with a dialog for title,
description and hero image.
audio.js and jQuery are gone. The old pages shipped ~293 KB: a build of
audio.js whose upstream hasn't moved since 2012, plus jQuery 3.2.1
(CVE-2019-11358, CVE-2020-11022, CVE-2020-11023 — unexploitable on a
static page, since nothing untrusted reaches a jQuery HTML sink, but
dead weight regardless). audio.js never used jQuery; jQuery was there
for ~25 lines of tracklist glue. Both are replaced by a dependency-free
player.js plus a player.css transcribed from the customized audio.js
skin, so the page looks identical — same 250px #c7b563 bar, same
player-graphics.gif (byte-identical: it's an animated GIF whose loading
frame is a spinner), same shortcuts. ~293 KB → ~6 KB. The Flash
fallback went too; audio.js gated it on !canPlayType("audio/mpeg;"),
unreachable since ~2010.
Conversion happens only when a browser genuinely can't decode a file,
never because of bitrate — a 320 kbps MP3 is copied verbatim. Everything
that does convert targets FLAC, so a conversion cannot cost a bit; a
test asserts the exported FLAC's decoded PCM hashes identical to the
ALAC source. Against the real library that's 105 Apple Lossless and 8
AIFF out of 21,382 tracks. DRM'd tracks are reported in a confirmation
dialog, never silently dropped and never attempted. ffmpeg is the CLI
binary here, not Qt's ffmpeg backend, so it's detected at runtime.
Verified in Chromium 151 and Firefox 153 over CDP/Marionette: every
exported format decodes including the converted FLAC, the player builds,
click / space / arrows / scrubber-seek / autoplay-next all work, and the
network log shows no request for jquery, audio.min.js or any .swf.
mix-example/ removed; the template reproduces it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,58 @@
|
||||
## Done
|
||||
|
||||
### Round 37 (2026-08-19) — Export a playlist: a folder, or a whole website (v0.8.0)
|
||||
|
||||
`File → Export Playlist…`, and the same item on a playlist's right-click menu.
|
||||
Two destinations behind one planner, built as a sibling of `device_sync` (same
|
||||
shape: a pure `plan_export`, then a worker on a daemon thread reporting through
|
||||
signals, sharing the status-bar progress widgets and the cancel button).
|
||||
|
||||
- [x] **Folder export** — the audio files under `Artist - Title.ext` names next
|
||||
to an extended `.m3u`. No `.pls`; nothing reads it any more. Files are
|
||||
copied byte-for-byte, never re-encoded.
|
||||
- [x] **Web mix export** — a self-contained static site reproducing the
|
||||
hand-made yearly mixes: `index.html`, `audios/`, a hero image, and a
|
||||
dialog for title / description / image. The description is deliberately
|
||||
passed through raw (the mixes lean on inline links right there); the title
|
||||
and track labels are escaped. Per-track liner notes stay hand-edited —
|
||||
`index.html` carries a commented-out block in the right spot.
|
||||
- [x] **audio.js and jQuery are gone.** The old pages shipped ~293 KB: a build of
|
||||
audio.js whose upstream hasn't moved since 2012, plus jQuery 3.2.1
|
||||
(CVE-2019-11358, CVE-2020-11022, CVE-2020-11023 — not exploitable on a
|
||||
static page, since nothing untrusted ever reaches a jQuery HTML sink, but
|
||||
dead weight either way). The decisive detail: **audio.js never used
|
||||
jQuery** — jQuery was there for ~25 lines of tracklist glue. Replaced by a
|
||||
~180-line dependency-free `player.js` + a `player.css` transcribed from
|
||||
the customized audio.js skin, so the page looks the same: same 250px
|
||||
`#c7b563` bar, same `player-graphics.gif` (shipped byte-identical — it's
|
||||
an *animated* GIF, the loading state is a spinner), same click-to-play,
|
||||
autoplay-next and ←/→/space shortcuts. **~293 KB → ~6 KB.** The Flash
|
||||
fallback went with it; audio.js gated it on `!canPlayType("audio/mpeg;")`,
|
||||
unreachable in any browser since ~2010.
|
||||
- [x] **Conversion only when a browser genuinely can't play it, and never lossy.**
|
||||
`export/web_support.py` is a deny-by-default gate modelled on
|
||||
`cast/support.py`, using the iTunes `kind` string to disambiguate `.m4a`
|
||||
(plain AAC / Apple Lossless / FairPlay all wear that suffix). Bitrate is
|
||||
**not** a trigger — a 320 kbps MP3 is copied verbatim. Everything that
|
||||
does convert targets **FLAC**, so a conversion cannot cost a bit; a test
|
||||
asserts the exported FLAC's decoded PCM hashes identical to the ALAC
|
||||
source. Against the real library that is 105 Apple Lossless + 8 AIFF out
|
||||
of 21,382 tracks. DRM'd tracks (6 Protected AAC) are reported in a
|
||||
confirmation dialog, never silently dropped and never attempted.
|
||||
- [x] **ffmpeg is detected, not assumed** — it's the CLI binary, which is a
|
||||
different thing from Qt Multimedia's ffmpeg backend. Missing, the export
|
||||
offers to go ahead without the affected tracks.
|
||||
- [x] **The manifest is written last.** A cancelled or interrupted export leaves
|
||||
no `index.html` and no `.m3u`, so a half-finished folder never advertises
|
||||
files that aren't there. Cancel also removes the in-flight partial file.
|
||||
- [x] Verified in **Chromium 151 and Firefox 153** driven over CDP/Marionette:
|
||||
all four exported formats decode (including the converted FLAC), the
|
||||
player builds, the gold bar and sprite render, click / space / ←→ /
|
||||
scrubber-seek / autoplay-next all work, and the network log shows no
|
||||
request for jquery, audio.min.js or any `.swf`.
|
||||
- [x] `mix-example/` removed — it was the reference for the template and the
|
||||
template now reproduces it.
|
||||
|
||||
### Round 35 (2026-08-19) — Startup speed: the 21k-track library stops freezing (v0.7.0)
|
||||
|
||||
Reported as three separate complaints — "startup takes a minute or two and GNOME
|
||||
|
||||
Reference in New Issue
Block a user