* fix: handle null/missing fields in Video API responses
Tidal's API returns some Video objects (lyric/visualiser videos on
artist pages) with fields that don't match the current strict models:
- `imageId` can be null instead of a string
- The nested `album` object can be present but missing `id`, `title`,
and `cover`
These validation failures cause the entire `ArtistVideosItems` page
to be rejected by Pydantic before any video can be parsed, resulting
in 0 downloads when targeting an artist with `--videos`.
A second independent bug causes an `AttributeError` on every video:
the default template `{album.artist}/{album.title}/{item.title}` is
shared with videos, but many videos have no album. When `album=None`
is passed to `format_template`, Python's `str.format()` evaluates
`None.artist` and raises `AttributeError: 'NoneType' object has no
attribute 'artist'`, which is caught and printed as an error for
every single video.
Fix:
- `resources.py`: make `Video.imageId` and `Video.Album.{id,title,
cover}` optional so incomplete API responses pass validation
- `format.py`: give `AlbumTemplate` field defaults so it can be
instantiated empty; use `AlbumTemplate()` as fallback instead of
`None` when no album is present, so `{album.*}` tokens render as
empty strings rather than raising AttributeError
- `download/__init__.py`: guard `video.album.id` accesses against
`None` (now possible after the model fix) in both video code paths
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: add tests for Video model null fields and AlbumTemplate fallback
Covers the two bugs fixed in the previous commit:
- Video model accepts null/missing imageId and partial album objects
- format_template does not raise AttributeError when album is None
and the template references {album.*} tokens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Tidal Downloader
Download tracks and videos from Tidal with max quality! tiddl is CLI app written in Python.
Warning
This app is for personal use only and is not affiliated with Tidal. Users must ensure their use complies with Tidal's terms of service and local copyright laws. Downloaded tracks are for personal use and may not be shared or redistributed. The developer assumes no responsibility for misuse of this app.
Installation
tiddl is available at python package index and you can install it with your favorite Python package manager.
Important
Also make sure you have installed
ffmpeg- it is used to convert downloaded tracks to proper format.
uv
We recommend using uv
uv tool install tiddl
pip
You can also use pip
pip install tiddl
docker
coming soon
Usage
Run the app with tiddl
$ tiddl
Usage: tiddl [OPTIONS] COMMAND [ARGS]...
tiddl - download tidal tracks ♫
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --omit-cache --no-omit-cache [default: no-omit-cache] │
│ --debug --no-debug [default: no-debug] │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or customize │
│ the installation. │
│ --help Show this message and exit. │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ auth Manage Tidal authentication. │
│ download Download Tidal resources. │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Authentication
Login to app with your Tidal account: run the command below and follow instructions.
tiddl auth login
Downloading
You can download tracks / videos / albums / artists / playlists / mixes.
$ tiddl download url <url>
Tip
You don't have to paste full urls, track/103805726, album/103805723 etc. will also work
Run tiddl download to see available download options.
Error Handling
By default, tiddl stops when encountering unavailable items in collections such as playlists, albums, artists, or mixes (e.g., removed or region-locked tracks).
Use --skip-errors to automatically skip these items and continue downloading:
tiddl download url <url> --skip-errors
Skipped items are logged with track/album name and IDs for reference.
Quality
| Quality | File extension | Details |
|---|---|---|
| LOW | .m4a | 96 kbps |
| NORMAL | .m4a | 320 kbps |
| HIGH | .flac | 16-bit, 44.1 kHz |
| MAX | .flac | Up to 24-bit, 192 kHz |
Output
You can format filenames of your downloaded resources and put them in different directories.
For example, setting output flag to "{album.artist}/{album.title}/{item.number:02d}. {item.title}"
will download tracks like following:
Music
└── Kanye West
└── Graduation
├── 01. Good Morning.flac
├── 02. Champion.flac
├── 03. Stronger.flac
├── 04. I Wonder.flac
├── 05. Good Life.flac
├── 06. Can't Tell Me Nothing.flac
├── 07. Barry Bonds.flac
├── 08. Drunk and Hot Girls.flac
├── 09. Flashing Lights.flac
├── 10. Everything I Am.flac
├── 11. The Glory.flac
├── 12. Homecoming.flac
├── 13. Big Brother.flac
└── 14. Good Night.flac
Note
Learn more about file templating
Configuration files
Files of the app are created in your home directory. By default, the app is located at ~/.tiddl.
You can (and should) create the config.toml file to configure the app how you want.
You can copy example config from docs config.example.toml
Environment variables
Custom app path
You can set TIDDL_PATH environment variable to use custom path for tiddl app.
Example CLI usage:
TIDDL_PATH=~/custom/tiddl tiddl auth login
Auth stopped working?
Set TIDDL_AUTH environment variable to use another credentials.
TIDDL_AUTH=<CLIENT_ID>;<CLIENT_SECRET>
Development
Clone the repository
git clone https://github.com/oskvr37/tiddl
cd tiddl
You should create virtual environment and activate it
uv venv
source .venv/Scripts/activate
Install package with --editable flag
uv pip install -e .