feat: write an m3u playlist to preserve playlist track order

Playlist file names carry no ordering information, so the sequence a
user curated on Deezer was lost once the tracks landed on disk (unlike
albums, which get a zero padded track number prefix). downloadTrack
now reports the output path on success as well as on skip, and
downloadAllTracks collects the per-track paths for playlist downloads
and writes them, in order, to an extended m3u file next to the audio.
Failed tracks are left out since there is nothing on disk to point at;
a write failure is reported as a warning rather than failing the run.
This commit is contained in:
2026-08-14 21:00:08 +02:00
parent 765595133f
commit b1c15341fd
3 changed files with 76 additions and 1 deletions
+15
View File
@@ -134,6 +134,8 @@ func (d *Downloader) downloadAllTracks(ctx context.Context, resource deezer.Reso
progress := newProgressTracker(len(tracks), d.kind)
var m3uEntries []m3uEntry
for i, track := range tracks {
if ctx.Err() != nil {
return ctx.Err()
@@ -148,6 +150,19 @@ func (d *Downloader) downloadAllTracks(ctx context.Context, resource deezer.Reso
}
progress.handleResult(i, track, result)
if d.kind == deezer.KindPlaylist && result.err == nil {
m3uEntries = append(m3uEntries, m3uEntry{track: track, path: result.path})
}
}
// Written after the loop, not per track, so a run that fails partway
// through still produces a playlist covering whatever did make it to
// disk instead of no playlist at all.
if d.kind == deezer.KindPlaylist {
if err := writeM3U(outputDir, m3uEntries); err != nil {
fmt.Printf("\nWarning: failed to write m3u playlist: %v\n", err)
}
}
progress.printSummary(outputDir, time.Since(startTime))