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.

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.0

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.0
File Size Uploaded
trackhound-1.5.0.tar.gz 211.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trackhound 1.5.0
File Interpreter ABI Platform
trackhound-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 381.5 kB

Release files / trackhound-1.5.0.tar.gz

Download URL trackhound-1.5.0.tar.gz
Size 211.2 kB
Tags Source
SHA-256 checksum
How to use checksums
781ba0e1a8bc16c4a4c99b87e2dd9d395e38802577f8633a46707523655d21c7
BLAKE2b-256 checksum
How to use checksums
dc83e8a1449da598350f477ece3737e543dde78cef8cd61c2e7730d4749bfdc3
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.0-py3-none-any.whl

Download URL trackhound-1.5.0-py3-none-any.whl
Size 170.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c99debd979fba43136c66955eea14b2a4b42aa0849e88e67b275c7a3741f90ac
BLAKE2b-256 checksum
How to use checksums
3ec324415c474df6b595730b5d89e6b4a15434f26da6971e0b4d597d4c7cdcb0
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

1.5.1

2 release files

This release

1.5.0 This release

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