Skip to content

ADR-0009: Multi-Format Output with a Flat Download Layout

Status

Accepted

Date

2026-08-12

Context

Two independent changes to download output were made in the rewrite.

Format. The pre-rewrite code produced MP3 only. The rewrite supports MP3, M4A, OGG, FLAC, and Opus. The motivation was straightforward: users should be able to choose between lossless (FLAC) and lossy (MP3/M4A/OGG/Opus) output depending on whether they are archiving or saving space. Adding formats was cheap because yt-dlp's FFmpegExtractAudio postprocessor performs the conversion and mutagen handles tagging of each container.

Layout. The pre-rewrite code wrote each playlist into its own sanitised subdirectory (output_dir/{playlist-name}/...). The rewrite writes every track flat into output_dir as {title}.{ext}.

The flat layout is a direct consequence of the dedup goal (ADRs 0005 and 0006): a track that appears in several playlists must exist on disk exactly once. Per-playlist directories would force either duplicated files or a directory-to-track mapping to reconcile the same song across playlists. A flat directory is just a set of files whose identity lives in their tags, not in their location. This is also why the playlist name field was dropped from the config — there is no directory name to derive from it.

Decision

  • Output format is configurable (mp3, m4a, ogg, flac, or opus), converted by yt-dlp's FFmpegExtractAudio postprocessor in the same pipeline that downloads and applies metadata.
  • All tracks are written directly into output_dir as {title}.{ext}; there are no per-playlist subdirectories.
  • Tagging is dispatched by container: ID3 for MP3, MP4 tags for M4A, and Vorbis comments for OGG/FLAC/Opus, behind a single AsyncAudioFile interface that reads a file into memory, tags it, and writes it back. Each tagger uses the format's native scheme, which matches the per-format Picard conventions of ADR-0006.

Consequences

Positive

  • Lossless and lossy output options.
  • Cross-playlist dedup falls out of the file model: one file per track, keyed by tags.
  • Adding a format is cheap (new tagger + config value).
  • Download, conversion and metadata happen in one yt-dlp pipeline with no separate conversion step, and FFmpeg remains the only system dependency (ADR-0001).

Negative

  • Filenames are title-based, so two different tracks with the same title can collide in the same directory.
  • No playlist organisation is preserved on disk.

Neutral

  • The startup full scan (ADR-0005) is a flat iteration of output_dir.

Alternatives Considered

Per-playlist subdirectories (the old approach)

Rejected: conflicts with the dedup goal — the same track in two playlists would need to be duplicated or mapped across directories.

Artist/album-based directory structure

Rejected: moves library organisation into the application and fights the flat-files-with-tags model; user reorganisation would break the FilePath tracking noted in ADR-0005.

Single format (MP3 only)

Rejected: does not serve the lossless-archive use case.