Trackhound
Paste a link, get tagged music. Trackhound downloads albums, singles, playlists and
single tracks by link from Spotify, Apple Music, Deezer, YouTube, SoundCloud, Last.fm and
sites such as Bandcamp. A name works too: "Daft Punk - Discovery".
Titles, artists, track numbers, the year and the cover are read from the page behind the link, with no accounts or API keys. When the service streams the audio openly (YouTube, SoundCloud, Bandcamp), the track is taken from there; otherwise the same track is looked for on YouTube Music, SoundCloud and among YouTube videos. yt-dlp downloads it, and mutagen writes the tags and the cover art.
This package is the engine and the command line. Windows users who want the program with its window and everything bundled should take the installer from Releases instead.
Installing
pip install trackhound # the engine and the `trackhound` command
pip install "trackhound[gui]" # adds the window, started with `trackhound-gui`
ffmpeg and a JavaScript runtime (Deno, or Node.js 22+) have to be on PATH. yt-dlp needs
the runtime to get audio from YouTube, and ffmpeg is needed for mp3, opus and ReplayGain.
trackhound --check says what it found.
Command line
trackhound https://open.spotify.com/album/2noRn2Aes5aoNVsU6iWThc
trackhound "Daft Punk - Discovery" -f mp3 -o ~/Music
trackhound --dry-run https://www.deezer.com/playlist/908622995
trackhound --help
As a library
from pathlib import Path
from trackhound.engine import Downloader, Options, resolve
release = resolve("https://www.deezer.com/album/302127")
print(release.album.name, [track.title for track in release.tracks])
downloader = Downloader(Options(output_dir=Path("Music"), audio_format="m4a"))
report = downloader.download_link("https://www.deezer.com/album/302127")
print(report.summary())
The names importable from trackhound.engine are the public interface and keep working
across minor versions; the modules behind it may change. Messages come in the system's
language, Russian or English; set_language("en") fixes it. The engine writes to the
trackhound logger and sets up no handlers of its own. Where Spotify refuses its pages to
the network, use_relay(address) reads them through a relay abroad; the one-file relay is
in the repository.
Errors
A message is for a person and may be reworded in any release. A program should look at the code instead, which is the same in either language and across minor versions:
from trackhound.engine import SourceError
try:
release = resolve(link)
except SourceError as error:
print(error.code, error.details) # http_error {'service': 'Deezer', 'code': 503, 'url': ...}
for failure in report.failures: # the tracks that did not arrive
print(failure.track.title, failure.code, failure.message)
DownloaderError has the same .code and .details. ERROR_CODES holds the list:
| Code | Meaning |
|---|---|
unsupported_link |
the link leads to no music, or to a kind of page the service is not read from |
login_required |
the service shows its music only to a signed-in account |
not_found |
the service has nothing under this link or id, or not in this country |
not_in_album |
the link names a track its album does not have |
empty |
the release or playlist has no tracks that can be read, or it is private |
unreadable |
the page or the service's answer is not in the shape it is read in |
short_link_broken |
a short link could not be followed to the page behind it |
empty_query |
neither a link nor a name to search for was given |
no_title |
the link carries no track title to search for |
link_failed |
the link could not be opened |
http_error |
the service answered with an HTTP error |
offline |
the service could not be reached |
service_error |
the service answered with an error of its own |
unknown_format |
the audio format asked for is not one of FORMATS |
ffmpeg_missing |
the format asked for needs ffmpeg, which was not found |
no_source |
the track was found neither on YouTube Music nor on SoundCloud |
age_restricted |
the video is age-restricted: it takes a signed-in YouTube account |
cookies_locked |
the browser's cookies could not be copied while it is open |
cookies_unreadable |
the browser's cookies could not be decrypted |
no_cookies |
the browser holds no YouTube cookies |
preview_only |
only a preview of the track could be downloaded |
wrong_file |
the download did not end in a file of the format asked for |
download_failed |
the download failed for any other reason |
unknown |
an error raised without a code |
Licence
GPL-2.0-or-later. Use it for music you have the rights to, and respect copyright law and the terms of service of the services involved.
Metadata
Release files for trackhound 1.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| trackhound-1.5.1.tar.gz | 225.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| trackhound-1.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 405.4 kB
Release files / trackhound-1.5.1.tar.gz
| Download URL | trackhound-1.5.1.tar.gz |
|---|---|
| Size | 225.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a1e0e2f0eacbf742017ded9cf5cee5090b5b853281f0f64f37f7fbee484a2cfd
|
|
BLAKE2b-256 checksum How to use checksums |
9dfee1672bd292aca9fb07a922e7b1b4ec6bab083fd79ae405d190d56536d6d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / trackhound-1.5.1-py3-none-any.whl
| Download URL | trackhound-1.5.1-py3-none-any.whl |
|---|---|
| Size | 179.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
af93b9a5e283babf49199901e4fb490cdd04f027ffcd58588d18dd3b889d5b25
|
|
BLAKE2b-256 checksum How to use checksums |
a045d9a9a71304ce6f09876c00ca6ff34d914d73df822eaab29b33386d4098e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency log