Skip to content

Releases: Stensel8/streamrip

streamrip v2.5.0

Choose a tag to compare

@Stensel8 Stensel8 released this 11 Oct 15:23
d6baf73

2.5.0

Thanks to @berettavexee for the unified progress
bar below, and to @Multipixelone for the Nix
flake below.

Progress

  • One overall progress bar, counting tracks, for every download. An artist
    or label download used to get a top bar counting albums (3/37 albums), and
    a single album or playlist only the per-track rows of what was downloading
    right then, so on a 59-track playlist you could not tell whether you were at
    track 5 or 50. From the user's side those are the same thing: a lot of tracks,
    and you want to see the overall progress. The album-count bar, the resolve
    spinner ("Obtaining album info…") and the per-source bars are gone; in their
    place is one bar (Overall, 12/15 tracks) that album, playlist and artist
    downloads all share: an artist's total grows as each of its albums starts,
    because its tracks are only known then. A track counts on it whatever its
    outcome, resolved or not, so the bar never stalls on a failure. The bar is
    reset between runs, and its running total is kept by streamrip, not read back
    from Rich's task list, which is reindexed when a task is removed. (#47)

Nix

  • A Nix flake (nix build, nix run, nix develop, nix flake check) for
    x86_64-linux, with nixpkgs pinned in flake.lock, on Python 3.14: the
    package with an explicit dependency list kept in sync with pyproject.toml, a
    development shell with the same dependencies plus Poetry and Ruff, and
    FFmpeg, Deno and Chromium on PATH. The package runs the non-browser test
    suite and offline CLI smoke checks (--version, --help, loading a config).
    Renovate keeps the nixpkgs pin up to date, and CI runs nix flake check on
    every change. (#46)

streamrip v2.4.11

Choose a tag to compare

@Stensel8 Stensel8 released this 07 Oct 14:55
6c9c678

2.4.11

Spotify

  • Spotify links can be downloaded: tracks, albums, artists and playlists, as
    open.spotify.com links or spotify: URIs, and streamrip search spotify track|album|artist|playlist .... Spotify encrypts its own audio, so streamrip
    does what spotDL does: Spotify
    supplies the track list, tags (title, artists, album, track and disc numbers,
    date, copyright, ISRC) and cover, and the audio is the same recording on
    YouTube Music, found by ISRC and then by artist, title and length, and
    downloaded with yt-dlp. It is AAC (kept as it is) or MP3, never lossless, and a
    track YouTube Music only has as another version (live, remix, ...) is reported
    as not found. See the new Spotify section of the README, which also lists what
    Spotify allows an app.
  • You make a Spotify app of your own, and log in once. Since February 2026
    Spotify's API is only open to apps whose owner has Premium, with a client id
    and no secret: streamrip asks for the Client ID the first time, explains where
    to make the app (the redirect URI, ticking Web API), opens your browser to log
    in (OAuth with PKCE) and catches the answer on 127.0.0.1:9900, or lets you
    paste the address where the browser ends up, on a server without a browser. The
    login renews itself and is saved in the new [spotify] section.
  • Playlists are limited by Spotify to the ones you own or collaborate on. Other
    playlists, and podcasts and local files, are skipped, with a message that says
    why. Searching is capped at 50 results (Spotify gives ten per request).
  • The new [spotify] options: audio_format (m4a or mp3), audio_bitrate
    (for audio that has to be re-encoded), match_videos (accept an official music
    video when YouTube Music has no matching song) and redirect_uri.
  • A config from before this release has no [spotify] section: it is added from
    the template, and written the next time the config is saved. No config reset.
  • New dependencies: ytmusicapi and yt-dlp[default]. yt-dlp wants a
    JavaScript runtime (Deno or Node.js) for YouTube; a download that fails saying
    so is explained as such.
  • Credits are at the bottom of the README: the login and API handling and the
    matching are those of Music-Sync, the
    idea of metadata from Spotify and audio from YouTube Music is spotDL's, and
    MediaHarbor was read as a
    reference. Its decryption of Spotify's Widevine-protected audio is not used.

CSV lists

  • streamrip csv list.csv downloads the tracks of a CSV list, found by
    searching a source, which it asks for ("Where should I search and download them
    from?", with what each source gives) unless --source says. --fallback-source
    gives a second source for the tracks the first does not have. The columns of
    Music-Sync and of Exportify,
    TuneMyMusic and the like are understood, a file without a header row is read
    as artist,title, and commas, semicolons and tabs work as separators. The first
    five results of each search are scored on title, artist and length, as
    Music-Sync does, so a live version, a remix or another artist's cover is not
    taken for the track. The tracks go in a folder named after the file, as a
    playlist.

Lyrics

  • The lyrics of tracks whose source sent none are looked up on
    LRCLIB, a free, open database of lyrics that needs no
    account: Qobuz, SoundCloud and Spotify send none, and Deezer not for every
    track. It tells LRCLIB the artist, title and length of those tracks, so lyrics = false
    under [downloads] turns it off, and streamrip logs "No lyrics found for ..."
    for a track LRCLIB does not have. It asks with the length of the file
    just downloaded, as synced lyrics only fit one edit of a song, and a search
    result of another version, of another artist or of another length is not taken.
    Synced (LRC) lyrics are used, plain ones for MP3. LRCLIB being slow or down
    costs nothing: after three failures in a row it is left alone for the run, and
    a lyric that cannot be found never fails a track. Its session is a plain one of
    its own, never a source's, which holds that source's login.

Notices

  • The first time Spotify is used in a run, streamrip says its audio comes from
    YouTube Music and is lossy, and recommends moving the playlist first with
    Music-Sync (to Tidal, or to a CSV for
    streamrip csv), with a link.
  • The first time Deezer is used with lyrics on, streamrip says that Deezer does
    has no lyrics for every track, so the others are looked up on LRCLIB, and how to
    turn that off. The
    README and the comment in the config say so too. Deezer's answer that it has no lyrics for a
    track is no longer a warning for every track; a lyrics request that really
    fails still is.

Tests

  • find_ffmpeg is cached, and test_ffmpeg_utils left a fake path, or none, in
    the cache for the tests after it. They are forgotten after each test now.

streamrip v2.4.10

Choose a tag to compare

@Stensel8 Stensel8 released this 06 Oct 21:22
648d2a8

2.4.10

Security

  • An album folder can no longer end up outside the downloads folder. Names from
    a streaming service decided where it went: a field that came out empty in a
    folder format like {albumartist}/{title} gave /Title, a folder in the root
    of the filesystem, and an artist or uploader called .. (SoundCloud names are
    free text) gave ../Title. Empty parts of a folder path are dropped now,
    . and .. become underscores, both kinds of slash separate folders, and a
    folder that is not below the downloads folder is refused.

Downloading

  • SoundCloud tracks are skipped when already downloaded. They were downloaded
    again on every run.
  • The downloads database keeps ids per source (tidal_2430924980, not
    2430924980). A track was skipped as downloaded as soon as one of another
    source with the same id had been, which gets likelier the more you download.
    Entries from before hold the bare id, cannot be told apart and still count for
    every source, so nothing is downloaded again after updating;
    streamrip database clear downloads forgets them.
    streamrip database browse downloads shows the source.
  • The failed downloads database is unique per source too. A failure of one
    source kept another's with the same id out of it, and streamrip repair
    removed both. An existing database is converted on first use.

Configuration

  • Saving the config is atomic. A crash, Ctrl-C or full disk could leave an empty
    file with your logins gone. A symlinked config stays a symlink.
  • no_update_check = true under [cli] turns the update check off. It is
    commented out in the config by default.

Command line

  • A config that does not load ends the command with exit code 1, not 0.
  • The update notice says its command needs git.

Tests

  • The browser login tests are skipped without a Chrome-family browser, and
    fail on CI, instead of waiting for an answer on stdin.
    pytest -m "not real_browser" leaves them out.

streamrip v2.4.9

Choose a tag to compare

@Stensel8 Stensel8 released this 04 Oct 12:58
1c7f848

2.4.9

Thanks to @berettavexee for the resume check,
the SoundCloud fallback, the Deezer playlist fix and the traceback fix below.

Search

  • One menu for every OS. The separate Linux/macOS and Windows menus
    (simple-term-menu, pick, windows-curses) are replaced by a single
    Textual menu that works the same everywhere.
    Filter the results with /, mark several with SPACE; ENTER downloads the
    marked results and the highlighted one. The mouse works too.
  • The selected result's cover shows beside its details. Terminals with SIXEL or
    Kitty graphics support (Konsole, foot and Windows Terminal, for example) get
    the image, the others colored sextant blocks, which are less sharp. Detection
    is automatic, and the choice is logged with -v. Covers are fetched on demand
    with a small cache, and moving on cancels the pending request. A source's
    larger artwork is tried first, its smaller sizes are the fallbacks.

Downloading

  • A resumed download is checked against the server's Content-Range. A server
    answering from another offset, a remainder that does not add up to the
    announced total, a close-delimited answer cut short, or a 416 taken as
    "already complete" whatever the partial file's size, used to end as a corrupt
    file. Now the partial file is removed and the track fails with
    IncompleteDownloadError, so the next attempt starts from scratch instead of
    resuming onto the same mismatch
    (PR #28, by
    @berettavexee).

Deezer

  • A geoblocked or delisted playlist track, which Deezer serves from another
    release, is tagged from the track that is served. It kept the requested
    track's metadata before, so the file got the album, title and cover of a
    release it does not come from. For such releases Deezer has no cover, only a
    grey placeholder, and that is what ended up embedded. The cover is fetched
    after the track is resolved, so only the right one is downloaded
    (PR #36, by
    @berettavexee).

SoundCloud

  • A track marked downloadable no longer fails outright. Its original now comes
    back as a 401 with an empty body when asked anonymously, which crashed with a
    ContentTypeError. The track's MP3 stream is used instead, and a track
    without one is reported as not streamable instead of failing an assertion
    (PR #34, by
    @berettavexee).

Command line

  • -v tracebacks no longer print local variables. They included the Deezer
    arl after a failed login and every config, credentials and all, and a
    traceback is exactly what people paste into an issue. The stack itself is
    unchanged
    (PR #35, by
    @berettavexee).

Python

  • streamrip supports Python 3.14 and 3.15, not newer: requires-python is now
    >=3.14,<3.16. CI runs the tests and the install check on both.

streamrip v2.4.8

Choose a tag to compare

@Stensel8 Stensel8 released this 03 Oct 16:26
1e435cb

2.4.8

Thanks to @berettavexee for the Deezer quality fix and the FLAC cover fix below. (#26 and #27).

Deezer

  • Logging in no longer means digging the arl cookie out of DevTools. streamrip
    offers a choice: an isolated browser window where you log in yourself and
    streamrip keeps only the arl cookie and never sees your password, or entering it by
    hand, with the steps printed. Entering it by hand is the default, because the
    browser option may have to download a browser first. Deezer has no sign-in for
    outside apps, and its email and password login is behind a captcha.
  • The quality comes from asking Deezer, not from FILESIZE_*. Those fields are
    often 0 for a format Deezer does serve, which made streamrip download such
    tracks as MP3 320, or skip them ("Missing download info"). Each quality is
    requested from the wanted one down and the first that returns a URL is used;
    the file extension comes from the CDN URL. A quality Deezer lists a size for
    but gives no URL for (a rate limit, say) fails the track instead of silently
    falling back to a lower one
    (PR #26, by
    @berettavexee, with a follow-up for the
    rate-limit case).
  • Album folders and labels name the quality the tracks come in. They always said
    [FLAC] [16B-44.1kHz], so -q 1 gave a FLAC-named folder full of MP3s. It is
    now your configured quality within what your subscription allows, lowered to
    the best quality every track of the album has: one track without FLAC makes it
    an MP3 album. Such a folder can still hold a FLAC, since every track is asked
    for the best quality it has.
  • Lossy albums leave the empty [UnknownB-UnknownkHz] out of the folder name.
    This also applies to Tidal AAC and SoundCloud.

Tagging

  • Qobuz writes several track artists as separate ARTIST values, main artists
    first and then the featured ones, in the same order as Tidal. Qobuz lists
    credits in no fixed order, so the clean and the explicit edition of a track
    used to tag different artists.
  • Several album artists are written as separate ALBUMARTIST values for every
    source, instead of one A, B, C string. Libraries that split multi-valued
    tags (Music Assistant reads them through ffprobe) showed a release credited to
    several artists as one extra artist. Folder names still use the joined string.
  • Tagging a FLAC a second time after conversion (FLAC to FLAC) no longer embeds
    the cover twice (PR #27, by
    @berettavexee).

Tidal

  • Singles and playlist tracks are tagged with their album's own metadata. A
    track response only names its album, so a feature credit ended up in the album
    artist, the track count was missing and the stream date stood in for the
    release date. The album is fetched once per album; if that request fails, the
    old behaviour is the fallback.
  • The device login waits for the link's real lifetime (5 minutes, not the
    "10 minutes" it announced), says so when the link expired, and a real
    rejection includes Tidal's own description.

SoundCloud

  • Small playlists, which come with every track's metadata up front, no longer
    fail every track with "not enough values to unpack".

Search

  • The preview in streamrip search shows the same details for every source, next
    to the cover: a track's album, number, release date, length, genre, label,
    composer, BPM, key and quality, and likewise for albums, artists and
    playlists. Covers are drawn with quadrant blocks, twice the detail across of
    half blocks.

Logging in and progress

  • Qobuz and Deezer log in through the same browser helper: the same window, the
    same 5-minute wait (Qobuz's was 2 minutes) and the same "Credentials saved to
    config file" message.
  • A download whose size is unknown gets a pulsing bar. A total of 0 made it look
    finished: a full bar without a spinner.

Config

  • [misc] check_for_updates is gone: the update check runs before every command
    by design and never read it. Config files with a [misc] section still load,
    and so do ones without.

Internals

  • Cleanups: Downloadable is a plain base class, the media types are one
    table, the redundant album semaphore is gone, playlists hold track ids instead
    of full metadata, and the progress bars, Tidal client and SoundCloud helpers
    share their code. The live Qobuz tests run again (set QOBUZ_USER_ID and
    QOBUZ_AUTH_TOKEN).
  • streamrip.metadata no longer exports AlbumSummary, ArtistSummary,
    TrackSummary, PlaylistSummary and LabelSummary; one Summary replaces
    them.

streamrip v2.4.7

Choose a tag to compare

@Stensel8 Stensel8 released this 01 Oct 03:29
1bc2bba

2.4.7

Downloading several artists

  • Items download one after another: a selected artist's (or label's) whole
    discography finishes before the next one starts, one album at a time. This also helps to keep rate-limits under control.
    Several artists used to run at once, which mixed their tracks together on
    screen and ran into the rate limit until everything stalled.
  • A progress bar per artist or label shows how far through its discography
    the run is (32% • 12/37 albums), and the screen is cleared when the next
    artist starts. Track rows show whose track they are.
  • Every album gets a Finished <artist> - <album> [quality] line when done.
    Albums of three tracks or fewer (singles, EPs) used to get no line at all.
  • The summary at the end counts tracks, downloaded, already downloaded and
    failed, instead of "1 item(s) downloaded" for a whole discography, and
    points to streamrip repair when something failed. The empty
    "Downloading" line no longer stays behind after the run.

Qobuz

  • Artist discographies leave out releases by other artists now.
  • A release listed twice (a clean and an explicit copy, or two quality
    tiers) downloads once, as Tidal already did.
  • Email/password login is gone; Qobuz stopped accepting it long ago. In the
    config, use_auth_token, email_or_userid and password_or_token are
    replaced by user_id and auth_token. Existing users should delete their config file.

Network

  • requests_per_minute spaces requests evenly over time, instead of sending them all at once. This helps to avoid hitting rate limits.
  • Qobuz and SoundCloud requests now retry connection errors, timeouts, 5xx
    and rate limits (429) the way Tidal's already did. A single timeout used
    to cost a Qobuz album or track. SoundCloud now honours
    requests_per_minute at all.
  • Cover art downloads retry network errors, so a brief DNS or connection
    failure no longer leaves an album without artwork. This is in line with the retry behavior for the track and album downloads that we already did.
  • Every request uses the same, current user agent (Chrome 155), including
    Deezer's API calls, which still sent Chrome 79's before this change.
  • New Features

    • Queue artist and label discographies for sequential downloads, with per-album progress and clearer track-level completion summaries.
    • View totals for downloaded, skipped, and failed tracks.
    • Qobuz artist listings exclude releases credited only to other artists and prioritize preferred editions.
  • Bug Fixes

    • Improved resilience to network interruptions and rate limits with retries for music and cover-art downloads.
    • Qobuz login requires a user ID and authentication token; email-and-password login is no longer supported.
    • Improved request pacing to help avoid rate limits.
    • Standardized the browser user agent across supported services.

streamrip v2.4.6

Choose a tag to compare

@Stensel8 Stensel8 released this 30 Sep 19:14
e242391

2.4.6

  • Update notices show which environment will be upgraded and use its active
    Python (or uv) for the suggested command. A failed update check no longer
    prevents the CLI from starting.
  • Install scripts install from the local source archive and report the full
    paths to the environment and executable. The README clarifies which release
    archive includes those scripts.

streamrip v2.4.5

Choose a tag to compare

@Stensel8 Stensel8 released this 30 Sep 18:48
9095161

2.4.5

  • Qobuz login now offers a choice: an isolated browser that logs in and
    captures the token automatically, pasting a short script into your own
    browser's console, or entering it by hand. Falls back to manual entry if
    the automatic options time out.
  • Qobuz search accepts the result limit loaded from the TOML config, fixing
    the crash when searching without --num-results.
  • Tidal hi-res (DASH) downloads no longer leak MP4 container metadata
    (major_brand, ffmpeg's encoder stamp, ...) into the FLAC's tags.
  • Removed the config version/migration system: an incompatible config now
    just says to run streamrip config reset, instead of being silently
    rewritten through a growing pile of per-option migration cases.
  • max_connections (tracks downloaded at once) defaults to 5, down from 6.
  • A fully successful download now reports completion too, not just failures.
  • The update check now runs, with a spinner, before every download command
    (url, file, search, lastfm, id) instead of only url. The
    suggested upgrade command pins the detected release instead of installing
    whatever dev currently has.

streamrip v2.4.4

Choose a tag to compare

@Stensel8 Stensel8 released this 30 Sep 09:06
f144616

2.4.4

  • ffmpeg is required and checked before any login. Without it streamrip stops
    with install instructions and exit status 1, instead of failing every
    hi-res Tidal track one by one.