tidalpy: a Python library for Tidal#
tidalpy (distribution binary-tidal-py) is a clean-room
reimplementation of the proven Tidal-Media-Downloader core, as a Python library: a catalog
and playback API, the OAuth device flow, stream resolution, resumable
downloads, FLAC-in-MP4 remuxing, and metadata tagging. All of the CLI
baggage is gone.
It is a library, not a tool. The client can be anything: a real-time search UI, an indexer, a player, a Django/Celery sync job, a plain download script. Each one gets the same small, structured, in-process API. The hard parts of Tidal are inside the library: two parallel catalog APIs (v1 and v2), the quality-downgrade chain, rate limiting with retry, and atomic file writes.
What it does#
Catalog and real-time search. Full search, the keystroke suggest endpoint, the genre “Discover” browse, artist discographies, playlists, mixes, lyrics, and track credits. Results are plain JSON-safe dicts or typed models.
Ids-first fetching.
tracks_by_ids,albums_by_ids,artists_by_ids, andplaylists_by_idsresolve N ids in one catalog round trip per 50, and the key-based siblings — singletrack_by_isrc/album_by_upc, bulktracks_by_isrcs/albums_by_upcs— answer the same question from CDDB ISRCs or barcodes, for hosts that hold keys instead of links.Streaming, without disk.
streamanditer_streamshand plaintext audio bytes to the host (S3, a database, a pipe, a player).playbacktells you what will be played before you stream a single byte.Downloading. Resumable runs, quality downgrade when a profile is unavailable, per-item failure isolation. Files land through
.partwith atomic promotion, so a rerun skips what is already complete.Auth. The device flow (approve in a browser), adopting a token from a web session, refresh, and logout.
How it behaves#
No global state. Every
TidalClientowns its session, token, and caches. Two clients in one process never share credentials, so the library is safe under Django multi-worker and Celery prefork.Per-item failure isolation. A collection download never dies on one bad item. Failures land in a structured
DownloadReportwith a machine code and a reason for each.Standard ``logging`` only. Nothing is printed to stdout. Progress arrives as a callback that receives plain JSON-safe dicts.
Best effort is labelled. A missing or corrupt side file degrades to a documented default. It never crashes a run, and it never silently changes the result.
Contents#
Getting started
Reference
History
Key classes#
TidalClient— the entry pointConfig— all settings, injected per clientQuality— quality profiles and the downgrade chainDownloadReport— structured resultsMediaStream— bytes to the host, no diskTokenStore/FileTokenStore— where the login livesDeviceAuth— the device-flow hand-off