Repository navigation
Releases: Stensel8/streamrip
Releases · Stensel8/streamrip
Release list
streamrip v2.5.0
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 inflake.lock, on Python 3.14: the
package with an explicit dependency list kept in sync withpyproject.toml, a
development shell with the same dependencies plus Poetry and Ruff, and
FFmpeg, Deno and Chromium onPATH. 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 runsnix flake checkon
every change. (#46)
streamrip v2.4.11
2.4.11
Spotify
- Spotify links can be downloaded: tracks, albums, artists and playlists, as
open.spotify.comlinks orspotify:URIs, andstreamrip 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 on127.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(m4aormp3),audio_bitrate
(for audio that has to be re-encoded),match_videos(accept an official music
video when YouTube Music has no matching song) andredirect_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. Noconfig reset. - New dependencies:
ytmusicapiandyt-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.csvdownloads 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--sourcesays.--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
asartist,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, solyrics = 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
lyricson, 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_ffmpegis cached, andtest_ffmpeg_utilsleft a fake path, or none, in
the cache for the tests after it. They are forgotten after each test now.
streamrip v2.4.10
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 downloadsforgets them.
streamrip database browse downloadsshows 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, andstreamrip 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 = trueunder[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
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 withSPACE;ENTERdownloads 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
-vtracebacks no longer print local variables. They included the Deezer
arlafter 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-pythonis now
>=3.14,<3.16. CI runs the tests and the install check on both.
streamrip v2.4.8
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
arlcookie out of DevTools. streamrip
offers a choice: an isolated browser window where you log in yourself and
streamrip keeps only thearlcookie 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 1gave 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
ARTISTvalues, 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
ALBUMARTISTvalues for every
source, instead of oneA, B, Cstring. 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 searchshows 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_updatesis 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:
Downloadableis 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 (setQOBUZ_USER_IDand
QOBUZ_AUTH_TOKEN). streamrip.metadatano longer exportsAlbumSummary,ArtistSummary,
TrackSummary,PlaylistSummaryandLabelSummary; oneSummaryreplaces
them.
streamrip v2.4.7
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 tostreamrip repairwhen 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_useridandpassword_or_tokenare
replaced byuser_idandauth_token. Existing users should delete their config file.
Network
requests_per_minutespaces 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_minuteat 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
2.4.6
- Update notices show which environment will be upgraded and use its active
Python (oruv) 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
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'sencoderstamp, ...) into the FLAC's tags. - Removed the config version/migration system: an incompatible config now
just says to runstreamrip 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 onlyurl. The
suggested upgrade command pins the detected release instead of installing
whateverdevcurrently has.
streamrip v2.4.4
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.