From f98ceed10139a0f0894d7eebb8746a45a34cb85c Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Fri, 23 Oct 2026 13:48:58 -0700 Subject: [PATCH] fix(api): stop doubling the extension on stem zip filenames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stems with no orig_filename often carry the upload's extension in the title (" 🍕DRUMS.wav"), so the zip named them "DRUMS.wav.wav". Swap a trailing audio extension in the title for the one from the blob's content type. Co-Authored-By: Claude Opus 5.5 --- api/v1_track_stems_download.go | 23 +++++++++++++++++++---- api/v1_track_stems_download_test.go | 4 ++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/api/v1_track_stems_download.go b/api/v1_track_stems_download.go index 58e6bd58..54eaf617 100644 --- a/api/v1_track_stems_download.go +++ b/api/v1_track_stems_download.go @@ -240,14 +240,20 @@ var audioExtensions = map[string]string{ "audio/ogg": ".ogg", } -// stemsZipFilename is the download filename, except that an original with no -// recorded filename gets its extension from the blob's content type rather -// than createFilename's .mp3, since the bytes are the original upload. +// stemsZipFilename is the download filename, except for an original with no +// recorded filename. createFilename gives that title + ".mp3", but the bytes +// are the original upload, so the extension comes from the blob's content +// type. Such titles often already end in the upload's extension ("DRUMS.wav"). func stemsZipFilename(t *dbv1.Track, contentType string) string { name := sanitizeZipName(createFilename(t)) if t.OrigFileCid.String != "" && t.OrigFilename.String == "" { if ext, ok := audioExtensions[strings.ToLower(contentType)]; ok { - name = strings.TrimSuffix(name, path.Ext(name)) + ext + title := sanitizeZipName(t.Title.String) + titleExt := strings.ToLower(path.Ext(title)) + if isAudioExtension(titleExt) { + title = strings.TrimSuffix(title, path.Ext(title)) + } + name = title + ext } } if name == "" || strings.HasPrefix(name, ".") { @@ -256,6 +262,15 @@ func stemsZipFilename(t *dbv1.Track, contentType string) string { return name } +func isAudioExtension(ext string) bool { + for _, e := range audioExtensions { + if e == ext { + return true + } + } + return false +} + func sanitizeZipName(name string) string { name = strings.Map(func(r rune) rune { switch { diff --git a/api/v1_track_stems_download_test.go b/api/v1_track_stems_download_test.go index 3bf3a4a5..2726b16c 100644 --- a/api/v1_track_stems_download_test.go +++ b/api/v1_track_stems_download_test.go @@ -174,6 +174,10 @@ func TestStemsZipFilename(t *testing.T) { } assert.Equal(t, "🍕DRUMS.wav", stemsZipFilename(track(map[string]string{"orig_cid": "Qm", "orig_filename": " 🍕DRUMS.wav"}), "audio/wav")) assert.Equal(t, "Bass.wav", stemsZipFilename(track(map[string]string{"title": "Bass", "orig_cid": "Qm"}), "audio/x-wav")) + assert.Equal(t, "🍕DRUMS.wav", stemsZipFilename(track(map[string]string{"title": " 🍕DRUMS.wav", "orig_cid": "Qm"}), "audio/wav")) + assert.Equal(t, "Bass.wav", stemsZipFilename(track(map[string]string{"title": "Bass.WAV", "orig_cid": "Qm"}), "audio/wav")) + assert.Equal(t, "Bass.flac", stemsZipFilename(track(map[string]string{"title": "Bass.wav", "orig_cid": "Qm"}), "audio/flac")) + assert.Equal(t, "Mix v1.2.wav", stemsZipFilename(track(map[string]string{"title": "Mix v1.2", "orig_cid": "Qm"}), "audio/wav")) assert.Equal(t, "Bass.mp3", stemsZipFilename(track(map[string]string{"title": "Bass"}), "audio/wav")) assert.Equal(t, "a_b.mp3", stemsZipFilename(track(map[string]string{"title": "a/b"}), "")) }