SpotiFLAC Python Module

June 18, 2026 · View on GitHub

PyPI - Version PyPI - Python Version Pepy Total Downloads

Integrate SpotiFLAC directly into your Python projects. Perfect for building custom Telegram bots, automation tools, bulk downloaders, downloading music for Jellyfin or web interfaces.

Looking for a standalone app?

SpotiFLAC (Desktop)

Download music in true lossless FLAC from different providers for Windows, macOS & Linux

SpotiFLAC (Mobile)

SpotiFLAC for Android & iOS — maintained by @zarzet


Installation

pip install SpotiFLAC

Quick Start

SpotiFLAC can be used in multiple ways. Choose the mode that fits your needs:

Launch the graphical user interface with the --gui flag:

spotiflac --gui

(Or python launcher.py --gui if running from source)

Interactive Mode (Step-by-step wizard)

SpotiFLAC features a smart Interactive Wizard that guides you step-by-step. To launch the wizard, use the --interactive flag:

spotiflac --interactive

(Or python launcher.py --interactive if running from source)

On launch it automatically runs a service health check before asking any questions, so you always know which providers are reachable.

What the wizard does at startup:

  1. Service Health Check — probes provider endpoints and shows provider availability inline (✅ / ❌) before asking anything
  2. URL History — shows your last 8 downloads so you can re-run one with a single keypress
  3. Folder Memory — remembers your last output directory and offers it as the default
  4. Profile Load — optionally restores a full saved configuration

Smart URL Detection: If you input an Artist URL, it will ask if you want to download "Featuring" tracks. It skips this question for albums or playlists.

Smart File Paths: If you input a Single Track URL, it will ask if you want to set a specific .flac output path. If you do, it intelligently skips all questions about filename formatting and subfolder organization.

Unified Quality Profiles: Automatically translates your desired quality tier across different services (like Tidal and Qobuz).

CLI Generator: At the end of the configuration, it generates and prints the exact CLI command for your specific setup, so you can copy and reuse it in your automated scripts.

Profile Save: After confirming the download, you can save the entire configuration as a named profile to reuse later.


Docker Usage

A CLI-focused Docker image is available for running SpotiFLAC without the desktop GUI.

Build the image:

docker build -t spotiflac .

Run a download with a mounted local output directory:

docker run --rm -v "$(pwd)/downloads:/app/downloads" spotiflac \
  https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT \
  ./downloads -s tidal -q LOSSLESS

The Docker image is intended for CLI mode only; it does not launch the webview GUI.

For interactive terminal mode, run with -it:

docker run --rm -it -v "$(pwd)/downloads:/app/downloads" spotiflac \
  --interactive

Published image (GHCR)

Official images are published to GitHub Container Registry (GHCR) via GitHub Actions. You can pull them with:

docker pull ghcr.io/ShuShuzinhuu/SpotiFLAC-Module-Version:latest

Run a pulled image:

docker run --rm -v "$(pwd)/downloads:/app/downloads" ghcr.io/ShuShuzinhuu/SpotiFLAC-Module-Version:latest \
    https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT ./downloads -s tidal -q LOSSLESS

from backend import SpotiFLAC

# Simple Download
SpotiFLAC(
    url="https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
    output_dir="./downloads"
)

CLI usage:

spotiflac url ./out --service tidal

Supported URL Types

SpotiFLAC supports the following URL formats for Spotify, Tidal, Apple Music, SoundCloud, YouTube and Pandora:

TypeSpotifyTidalApple MusicSoundCloudYouTube / YT MusicPandora
Trackopen.spotify.com/track/...listen.tidal.com/track/...music.apple.com/.../song/...soundcloud.com/artist/track-slugyoutube.com/watch?v=... · youtu.be/...pandora.com/artist/.../song/TR:... · pandora.app.link/...
Album / Setopen.spotify.com/album/...listen.tidal.com/album/...music.apple.com/.../album/...soundcloud.com/artist/sets/set-slugmusic.youtube.com/playlist?list=OLAK5uy_...
Playlistopen.spotify.com/playlist/...listen.tidal.com/playlist/...music.apple.com/.../playlist/...youtube.com/playlist?list=PL...
Discography (via artist URL)open.spotify.com/artist/...listen.tidal.com/artist/.../discography/albumsmusic.apple.com/.../artist/...

Note: SoundCloud and YouTube tracks are downloaded as MP3 (neither platform distributes lossless audio). Apple Music downloads as M4A/ALAC (lossless) or AAC depending on the selected quality. Pandora downloads as MP3 (mp3_192 by default) or M4A (aac_64 / aac_32). All other services deliver FLAC.

Joox, NetEase, Migu and Kuwo are download-only services — they cannot be used as input URL sources. Use a Spotify or Tidal link and set one of these as the service. These providers are primarily available in select Asian markets and may require a VPN outside those regions.

SoundCloud short links (on.soundcloud.com/...) and mobile links (m.soundcloud.com/...) are automatically resolved. Tracking parameters (e.g. ?utm_source=...) are stripped before processing.

Apple Music track links with an ?i= song parameter (e.g. music.apple.com/us/album/album-name/id?i=trackid) are also supported.

Pandora app links (pandora.app.link/...) are automatically resolved to their canonical web URL. Pandora pretty URLs (e.g. pandora.com/artist/artist-name/album-name/song-name/TR:...) are fully supported.


Advanced Configuration

You can customize the download behavior, prioritize specific streaming services, and organize your files automatically into folders.

from backend import SpotiFLAC

SpotiFLAC(
    url="https://open.spotify.com/album/41MnTivkwTO3UUJ8DrqEJJ",
    output_dir="./MusicLibrary",
    services=["qobuz", "amazon", "tidal"],
    filename_format="{year} - {album}/{track}. {title}",
    use_artist_subfolders=True,
    use_album_subfolders=True,
    loop=60,                     # retry duration in minutes
    track_max_retries=2,         # extra per-track retries on failure
    post_download_action="notify"
)

Service Health Check

SpotiFLAC can probe all provider endpoints before downloading to verify which ones are currently reachable.

In Interactive Mode this runs automatically at startup. In code or scripts you can call it directly:

from backend.core.health_check import (
    run_health_check,
    print_health_report,
    get_working_providers,
)

results = run_health_check(["tidal", "qobuz", "deezer", "soundcloud", "pandora"])
print_health_report(results)

working = get_working_providers(results)
print("Available providers:", working)
# CLI: check all services then download
spotiflac https://open.spotify.com/track/... ./out --service tidal qobuz

The health check runs in parallel with a configurable timeout (default: 5 s per endpoint) and never blocks your download if a check fails. In the GUI, the check reports provider-level availability and endpoint counts, without exposing individual raw endpoint URLs.


Configuration Profiles

Save and reuse complete download configurations without re-typing them every time.

Save a profile

# Save current flags as "hires-tidal"
spotiflac https://... ./out \
  --service tidal \
  --quality HI_RES_LOSSLESS \
  --use-album-subfolders \
  --filename-format "{year} - {album}/{track}. {title}" \
  --save-profile hires-tidal

Load a profile

# Load "hires-tidal" — flags override profile values when both are present
spotiflac https://... ./out --profile hires-tidal

In Python

from backend.core.profiles import save_profile, get_profile, list_profiles

# Save
save_profile("hires-tidal", {
    "services":             ["tidal"],
    "quality":              "HI_RES_LOSSLESS",
    "use_album_subfolders": True,
    "filename_format":      "{year} - {album}/{track}. {title}",
})

# Load and use
cfg = get_profile("hires-tidal")
print(list_profiles())  # ['hires-tidal']

Profiles are stored at ~/.cache/spotiflac/profiles.json. In the Interactive Wizard, you are prompted to load a profile at startup and optionally save one at the end.


Batch Downloads

Pass a list of URLs to download them all in sequence. Failed tracks per URL are collected and can be retried with loop.

from backend import SpotiFLAC

SpotiFLAC(
    url=[
        "https://open.spotify.com/album/41MnTivkwTO3UUJ8DrqEJJ",
        "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M",
        "https://listen.tidal.com/album/364272512",
    ],
    output_dir="./MusicLibrary",
    services=["tidal", "qobuz"],
    use_album_subfolders=True,
)

Auto-Retry on Failure

Set track_max_retries (Python) or --retries (CLI) to automatically retry failed tracks. Each retry cycles through all configured providers from the beginning, waiting exponentially longer between attempts (2 s → 4 s → 8 s …, capped at 30 s).

from backend import SpotiFLAC

SpotiFLAC(
    url="https://open.spotify.com/album/...",
    output_dir="./downloads",
    services=["tidal", "qobuz", "deezer"],
    track_max_retries=3,   # up to 3 extra attempts per track
)
spotiflac https://open.spotify.com/album/... ./out \
  --service tidal qobuz deezer \
  --retries 3

Tip: Combine --retries with --loop for maximum resilience — --retries handles transient errors on individual tracks, while --loop re-queues permanently failed tracks after N minutes.


Per-Track Timeout

Set timeout_s (Python) or --timeout (CLI) to cap the time SpotiFLAC will spend downloading a single track. If the download does not complete within the specified number of seconds, the process is terminated and the track is marked as failed — allowing the next provider or retry to take over.

# CLI — skip any track that takes more than 3 minutes
spotiflac https://open.spotify.com/album/... ./out --service tidal --timeout 180
 
# Python API
from backend import SpotiFLAC
SpotiFLAC(
    url="https://open.spotify.com/album/...",
    output_dir="./downloads",
    services=["tidal", "qobuz"],
    timeout_s=120,
)

Tip: Pair --timeout with --retries so that a stalled track is automatically re-attempted against the next provider instead of blocking the entire queue indefinitely.


Post-Download Actions

ActionDescription
noneDo nothing (default)
open_folderOpen the output folder in the system file manager
notifySend an OS desktop notification with a summary
commandRun a custom shell command — placeholders: {folder}, {succeeded}, {failed}
SpotiFLAC(url="...", output_dir="./downloads", post_download_action="open_folder")

SpotiFLAC(url="...", output_dir="./downloads",
          post_download_action="command",
          post_download_command="rsync -av {folder}/ user@nas:/music/")
spotiflac https://... ./out --post-action notify
spotiflac https://... ./out --post-action command --post-command "rsync -av {folder}/ user@nas:/music/"

Discography Download

Download the complete discography of an artist. Duplicate tracks (same ISRC across different releases) are automatically skipped.

from backend import SpotiFLAC

# Spotify — albums + singles
SpotiFLAC(url="https://open.spotify.com/artist/1Xyo4u8uXC1ZmMpatF05PJ", output_dir="./MusicLibrary",
          services=["qobuz", "tidal"], use_album_subfolders=True, filename_format="{year} - {album}/{track}. {title}")

# Tidal — full discography (append /discography/albums or /discography/singles to filter)
SpotiFLAC(url="https://listen.tidal.com/artist/7804", output_dir="./MusicLibrary",
          services=["tidal"], use_album_subfolders=True, filename_format="{year} - {album}/{track}. {title}")
spotiflac https://open.spotify.com/artist/... ./MusicLibrary \
  --service tidal --include-featuring \
  --use-album-subfolders --filename-format "{year} - {album}/{track}. {title}"

Recommended layout: --use-album-subfolders + --filename-format "{year} - {album}/{track}. {title}".


Custom Output Path (single tracks)

For single track downloads you can specify the exact file path instead of relying on output_dir + filename_format.

from backend import SpotiFLAC

SpotiFLAC(
    url="https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
    output_dir="./downloads",
    output_path="files/song.flac"
)

Note: output_path is automatically ignored when the URL points to an album, playlist, or artist/discography.


Qobuz Local API URL (Optional)

SpotiFLAC can use an optional self-hosted Qobuz stream API for improved reliability and reduced rate limits. If you do not provide a local API URL, Qobuz requests are attempted anonymously.

How to deploy your own instance: github.com/BartolomeoRusso9/qobuz-api

How to Apply Qobuz Local API URL in SpotiFLAC

Interactive Wizard: The wizard prompts you to enter your local Qobuz API URL during configuration.

Environment Variable:

export QOBUZ_LOCAL_API_URL="https://localhost:8000"

Python:

from backend import SpotiFLAC

SpotiFLAC(
    url="URL",
    output_dir="./downloads",
    qobuz_local_api_url="https://localhost:8000",
)

config.json:

{
    "qobuz_local_api_url": "https://localhost:8000"
}

Custom Tidal API Instance

SpotiFLAC connects to a shared pool of public hifi-api mirrors to fetch Tidal streams. If you want guaranteed availability and full control, you can self-host your own instance and point SpotiFLAC to it — it will always be tried first, before any public mirror.

How to deploy your own instance: github.com/binimum/hifi-api

Python

from backend import SpotiFLAC

SpotiFLAC(
    url="https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
    output_dir="./downloads",
    services=["tidal"],
    tidal_custom_api="https://your-instance.example.com",
)

CLI

spotiflac https://open.spotify.com/track/... ./downloads \
  --service tidal \
  --tidal-api "https://your-instance.example.com"

Interactive Wizard

The wizard prompts for a custom Tidal API URL at step 12.5, right after the optional tokens section.

config.json

{
    "tidal_custom_api": "https://your-instance.example.com"
}

Note: The custom instance is also saved and restored when using --save-profile / --profile.


CLI program usage

Program can be downloaded for Windows, Linux (x86 and ARM) and MacOS. The downloads are available under the releases.
Program can also be ran by downloading the python files and calling python launcher.py with the arguments.

Windows example usage:

./SpotiFLAC-Windows.exe url
                        output_dir
                        [--service tidal qobuz deezer amazon soundcloud youtube apple pandora joox netease migu kuwo]
                        [--filename-format "{title} - {artist}"]
                        [--output-path "files/song.flac"]
                        [--quality LOSSLESS]
                        [--use-track-numbers]
                        [--use-album-track-numbers]
                        [--use-artist-subfolders]
                        [--use-album-subfolders]
                        [--first-artist-only]
                        [--qobuz-local-api URL]
                        [--tidal-api URL]
                        [--timeout seconds]
                        [--loop minutes]
                        [--verbose]
                        [--no-lyrics]
                        [--lyrics-providers spotify apple musixmatch amazon lrclib]
                        [--no-enrich]
                        [--enrich-providers deezer apple qobuz tidal soundcloud]
                        [--retries N]
                        [--post-action none|open_folder|notify|command]
                        [--post-command "CMD with {folder} {succeeded} {failed}"]
                        [--profile NAME]
                        [--save-profile NAME]

Linux / Mac example usage:

chmod +x SpotiFLAC-Linux-arm64
./SpotiFLAC-Linux-arm64 url
                        output_dir
                        [--service tidal qobuz deezer amazon soundcloud youtube apple pandora joox netease migu kuwo]
                        [--filename-format "{title} - {artist}"]
                        [--output-path "files/song.flac"]
                        [--quality LOSSLESS]
                        [--use-track-numbers]
                        [--use-album-track-numbers]
                        [--use-artist-subfolders]
                        [--use-album-subfolders]
                        [--first-artist-only]
                        [--qobuz-local-api URL]
                        [--tidal-api URL]
                        [--timeout seconds]
                        [--loop minutes]
                        [--verbose]
                        [--no-lyrics]
                        [--lyrics-providers spotify apple musixmatch amazon lrclib]
                        [--no-enrich]
                        [--enrich-providers deezer apple qobuz tidal soundcloud]
                        [--retries N]
                        [--post-action none|open_folder|notify|command]
                        [--post-command "CMD with {folder} {succeeded} {failed}"]
                        [--profile NAME]
                        [--save-profile NAME]

(For ARM devices like Raspberry Pi, replace x86_64 with arm64)


API Reference

SpotiFLAC() Parameters

ParameterTypeDefaultDescription
urlstr / list[str]RequiredA single URL or a list of URLs (batch mode) for Spotify, Tidal, Apple Music, SoundCloud, YouTube or Pandora.
output_dirstrRequiredThe destination directory path where the audio files will be saved.
output_pathstrNoneExact destination file path for single track downloads. Overrides output_dir + filename_format. Automatically ignored for albums, playlists and artist discographies.
serviceslist["tidal"]Specifies which services to use and their priority order. Choices: tidal, qobuz, deezer, amazon, soundcloud, youtube, apple, pandora, joox, netease, migu, kuwo.
filename_formatstr"{title} - {artist}"Format for naming downloaded files. See placeholders below.
use_track_numbersboolFalsePrefixes the filename with the track number.
use_album_track_numbersboolFalseUses the track's original album number instead of the download queue position.
use_artist_subfoldersboolFalseAutomatically organizes downloaded files into subfolders by artist.
use_album_subfoldersboolFalseAutomatically organizes downloaded files into subfolders by album.
first_artist_onlyboolFalseUses only the first artist in tags and filename.
include_featuringboolFalseWhen downloading an artist discography, also includes tracks where the artist appears as a featured artist.
tidal_custom_apistrNoneURL of a self-hosted hifi-api instance. Takes priority over all public mirrors.
timeout_sintNonePer-track download timeout in seconds. If a single track download does not complete within this time, the process is terminated and the track is marked as failed. SpotiFLAC then moves on to the next provider or retry. Set to None (default) to disable the timeout.
loopintNoneDuration in minutes to keep retrying permanently failed tracks after a full session completes.
track_max_retriesint0Extra download attempts per track when all providers fail on the first try. Each retry cycles through all providers again with exponential backoff (2 s → 4 s → 8 s …, capped at 30 s).
qualitystr"LOSSLESS"Download quality. Tidal: "DOLBY_ATMOS", "HI_RES_LOSSLESS", "LOSSLESS", "HIGH", "LOW". Qobuz: "6" (CD), "7" (Hi-Res), "27" (Hi-Res Max). Apple Music: "alac", "atmos", "ac3", "aac", "aac-legacy". Pandora: "mp3_192", "aac_64", "aac_32".
allow_fallbackboolTrueAutomatically falls back to the next available quality tier if the requested quality is unavailable.
log_levelintlogging.WARNINGPython logging level.
embed_lyricsboolTrueWhether to fetch and embed synchronized lyrics (LRC) into the audio file.
lyrics_providerslist["spotify", "apple", "musixmatch", "lrclib", "amazon"]Priority order of lyrics providers to attempt.
enrich_metadataboolTrueEnables multi-provider metadata enrichment (HD covers, BPM, Labels, etc.).
enrich_providerslist["deezer", "apple", "qobuz", "tidal", "soundcloud"]Priority order of metadata providers to attempt.
qobuz_local_api_urlstrNoneOptional local Qobuz stream API URL. When set, the provider uses this endpoint for Qobuz stream requests.
post_download_actionstr"none"Action after all downloads finish: "none", "open_folder", "notify", "command".
post_download_commandstr""Shell command to run when post_download_action="command". Supports {folder}, {succeeded}, {failed} placeholders.

Filename Format Placeholders

When customizing the filename_format string, you can use the following dynamic tags:

  • {title} — Track title
  • {artist} — Track artist(s)
  • {album} — Album name
  • {album_artist} — The artist(s) of the entire album
  • {disc} — The disc number
  • {track} — The track's original number in the album
  • {position} — Download queue / Playlist position (zero-padded, e.g. 01)
  • {date} — Full release date (e.g., YYYY-MM-DD)
  • {year} — Release year (e.g., YYYY)
  • {isrc} — Track ISRC code

CLI Flag Reference

FlagShortDefaultDescription
--service-stidalOne or more providers in priority order. Choices: tidal, qobuz, deezer, amazon, soundcloud, youtube, apple, pandora, joox, netease, migu, kuwo.
--filename-format-f{title} - {artist}Filename template with placeholders.
--output-path-oNoneExact output file path for single track downloads. Ignored for albums, playlists and discographies.
--quality-qLOSSLESSAudio quality. Tidal: DOLBY_ATMOS, HI_RES_LOSSLESS, LOSSLESS, HIGH, LOW. Qobuz: 6, 7, 27. Apple Music: alac, atmos, ac3, aac, aac-legacy. Pandora: mp3_192, aac_64, aac_32.
--use-track-numbersFalsePrefix filenames with track numbers.
--use-album-track-numbersFalseUse the track's original album number instead of queue position.
--use-artist-subfoldersFalseOrganize files into per-artist subfolders.
--use-album-subfoldersFalseOrganize files into per-album subfolders.
--first-artist-onlyFalseUse only the first artist in tags and filename.
--include-featuringFalseInclude tracks where the artist appears as a featured artist. Only applies to artist/discography URLs.
--qobuz-local-apiNoneOptional local Qobuz stream API URL.
--tidal-apiNoneURL of a self-hosted hifi-api instance. Takes priority over the built-in public mirror pool.
--timeoutNonePer-track download timeout in seconds. If a track download stalls or takes longer than this limit, it is forcibly terminated and marked as failed, then SpotiFLAC moves to the next provider or retry.
--loop-lNoneKeep retrying permanently failed tracks every N minutes.
--retries0Extra per-track download attempts on failure. Cycles through all providers with exponential backoff.
--verbose-vFalseEnable debug logging.
--no-lyricsFalseDisable lyrics embedding (lyrics are embedded by default).
--lyrics-providersspotify apple musixmatch lrclib amazonLyrics provider priority order.
--no-enrichFalseDisable multi-provider metadata enrichment (enrichment is enabled by default).
--enrich-providersdeezer apple qobuz tidal soundcloudMetadata enrichment provider priority order.
--post-actionnoneAction after all downloads finish: none, open_folder, notify, command.
--post-command""Shell command for --post-action=command. Placeholders: {folder}, {succeeded}, {failed}.
--profileNoneLoad a saved profile. CLI flags override profile values.
--save-profileNoneSave current CLI configuration as a named profile after the run.

MusicBrainz Enrichment

SpotiFLAC automatically queries MusicBrainz in the background (when an ISRC is available) while the audio is being downloaded, adding professional-grade tags at no extra time cost. Fields written when found:

TagDescription
GENREGenre(s), sorted by popularity (up to 5)
BPMBeats per minute
LABEL / ORGANIZATIONRecord label name
CATALOGNUMBERCatalog number
BARCODERelease barcode / UPC
ORIGINALDATE / ORIGINALYEARFirst-ever release date
RELEASECOUNTRYCountry of release
RELEASESTATUSRelease status (e.g. Official)
RELEASETYPERelease type (e.g. Album, Single)
MEDIAMedia format (e.g. CD, Digital Media)
SCRIPTScript of the release text
ARTISTSORTArtist sort name for file managers
MUSICBRAINZ_TRACKIDMusicBrainz recording ID
MUSICBRAINZ_ALBUMIDMusicBrainz release ID
MUSICBRAINZ_ARTISTIDMusicBrainz artist ID
MUSICBRAINZ_RELEASEGROUPIDMusicBrainz release group ID
MUSICBRAINZ_ALBUMARTISTIDMusicBrainz album artist ID
ALBUMARTISTSORTAlbum artist sort name for file managers

Download Validation

After each download, SpotiFLAC validates the file to detect common issues:

  • Preview detection — if the expected duration is ≥ 60 s but the downloaded file is ≤ 35 s, the file is deleted and the download is retried with the next provider.
  • Duration mismatch — for tracks longer than 90 s, a deviation greater than 25% (or 15 s minimum) from the expected duration is treated as a corrupt download and the file is removed.

Want to support the project?

If this software is useful and brings you value, consider supporting the project by buying us a coffee. Your support helps keep development going.

Ko-fi Ko-fi

API Credits

Song.link · hifi-api · qobuz-api ·dabmusic.xyz · GD Studio Music API · Music Wjhe API · afkarxyz · MusicBrainz · SoundCloud · Apple Music · YouTube Music · Pandora · squid.wtf · flacdownloader.com

Tip

Star Us, You will receive all release notifications from GitHub without any delay