Skip to content

Configuration

The service is configured by a TOML file named config.toml in the current working directory. A template with sensible defaults lives at config.example.toml in the repository root.

cp config.example.toml config.toml

The schema is validated at startup by Pydantic (passive_music_dl/config/models.py); a malformed config exits with code 1.

Full reference

[download]
output_dir = "/srv/music"      # Base directory for downloads (required)
file_format = "mp3"            # Output format: mp3, m4a, ogg, flac, opus
audio_quality = "best"         # Audio quality (0-10 for yt-dlp)

[schedule]
interval_minutes = 15          # How often to check for new tracks

[spotify]
enabled = true
client_id = "your_spotify_client_id"      # Required
client_secret = "your_spotify_client_secret"  # Required
redirect_uri = "http://127.0.0.1:8080"
playlists = [
    "37i9dQZEVXbNG2KDcFcKOF"   # Bare playlist IDs, not URIs
]

[spotify.auth]
cache_path = ".spotipy-cache"  # Directory holding spotipy's cached OAuth token

[youtube_music]
enabled = true
# auth_headers = "auth.json"   # Optional: needed for private playlists
playlists = [
    "PL4fGSI1pDJn6puJdseH2Rt9sMvt9E2M4i"
]

[logging]
level = "info"                 # notset, debug, info, warning, error, critical

Sections

[download]

The download section is required. All keys are required.

Key Required Default Description
output_dir yes - Directory that tracks are downloaded into. ~ is expanded.
file_format yes - Output codec: mp3, m4a, ogg, flac, or opus.
audio_quality yes - Quality argument passed to yt-dlp (0-10 for VBR codecs, or best).

Tracks are written directly into output_dir as {track_title}.{file_format}; there is no per-playlist subdirectory.

[schedule]

The schedule section is optional and defaults to an empty one.

Key Required Default Description
interval_minutes no 15 Interval between sync cycles.

[spotify]

Spotify sync is optional; omit the section to disable it. client_id and client_secret are required when the section is present. Secrets are read literally from the file; there is no environment-variable expansion. config.toml is git-ignored, so the file can be kept out of version control.

Key Required Default Description
enabled no true Set to false to skip Spotify.
client_id yes - (required) Spotify app client ID.
client_secret yes - (required) Spotify app client secret.
redirect_uri no http://127.0.0.1:8080 Must match the app's registered redirect URI.
playlists no [] Bare Spotify playlist IDs.
auth.cache_path no .spotipy-cache Directory spotipy uses to cache its OAuth token.

On first run the app prompts to authenticate (headed or headless); the token is cached in cache_path and auto-refreshes afterwards.

[youtube_music]

YouTube Music sync is optional; omit the section to disable it.

Key Required Default Description
enabled no true Set to false to skip YouTube Music.
auth_headers no None Path to a ytmusicapi auth file, required for private playlists.
playlists no [] Bare YouTube Music playlist IDs.

Public playlists work without auth. For private playlists (e.g. Liked Songs), generate an auth file with ytmusicapi oauth --file auth.json and point auth_headers at it.

[logging]

The logging section is optional and defaults to an empty one.

Key Required Default Description
level no info One of notset, debug, info, warning, error, critical.

Keeping secrets out of version control

config.toml holds the Spotify client secret in plain text and is git-ignored; .spotipy-cache (the cached OAuth token) is also git-ignored. There is no environment-variable expansion in the config — put the real secret in config.toml and rely on .gitignore to keep it out of the repository.