Skip to main content

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)

Source distribution for trackhound 1.5.1
File Size Uploaded
trackhound-1.5.1.tar.gz 225.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trackhound 1.5.1
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

2.1.0

2 release files

2.0.0

2 release files

This release

1.5.1 This release

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page