Files
stemdeckapp--stemdeck/static
Tha.Les 41bd89d060 feat(export): name every export after its song (#340)
* feat(export): prefix exported stems with the song title

Stems exported as "bass.wav" or "vocals.wav" are ambiguous the moment they
leave the app. Dropping several songs' stems into one project folder makes
them indistinguishable and they overwrite each other.

Every stem the user receives is now named "<Song>_<stem>.<ext>":

- ZIP members, via a new prefix argument to _build_stems_zip
- Single-stem downloads, via the Content-Disposition filename
- Single-stem region trims, which keep both the song and the _region marker
- The MP3 variant of a stem

The server carries the name because Content-Disposition wins over an
<a download> attribute for same-origin requests, so setting the attribute
alone had no effect. The attribute is set too, as the fallback for any
response that does not send the header.

_safe_title is split into _title_slug, which returns "" for a title that
sanitizes to nothing, and _safe_title, which keeps the "stems" fallback for
the whole-archive filename. A per-file prefix has to be droppable, otherwise
an untitled job yields a leading underscore on every member. The slug is
restricted to [A-Za-z0-9_], so it stays safe as a ZIP member name.

Also fixes the desktop per-stem download, which routed through open_url and
handed the file to the OS handler: the stem opened in a browser or media
player and was never saved, so no filename applied at all. It now goes
through save_audio_file like every other export.

Closes #336

* fix(export): prefix the MP3 region stem download too

Missed in the previous commit: the trimmed-region branch of the MP3 stem
route still built a bare "{name}_region.mp3", so it was the one stem file
the user could receive without the song prefix.

Its ternary also had an unreachable branch. Only the trimmed case reaches
that line; the untrimmed one returns from the cached-file branch above.

* fix(export): name the mixdown after the song too

The mixdown endpoint hardcoded filename="mixdown.{ext}", so every song's
mix and every region export downloaded as "mixdown.wav". Exporting a few
songs into one folder produced mixdown.wav, mixdown(1).wav, mixdown(2).wav
-- the same collision #336 reports for stems.

Content-Disposition overrides the <a download> attribute, so the name the
frontend already built was discarded. Only desktop escaped it, because
save_audio_file uses the frontend's name rather than the header.

The video export was already doing this correctly, which left the mixdown
as the only export not named after its song.

Names mirror the frontend's: <Song>_exported_mix.<ext>, and <Song>_region.<ext>
when start/end trim to a loop region.
2026-08-09 08:43:18 +01:00
..