Skip to content

Releases

Wondarr 0.1.18

Choose a tag to compare

@github-actions github-actions released this 08 Nov 00:01

Wondarr stops downloading the same wrong song over and over, and the "Grabbed" notifications that came with each copy stop with it. Update by pulling :0.1 (or :0.1.18), from ghcr.io/wulfftech/wondarr or wulfftech/wondarr on Docker Hub.

Upgrading from 0.1.17:

  • No database migration.
  • What was refused before the update is not looked at again. A song keeps learning from its next refused download, so one more wrong copy may be fetched before the repeats stop.

Fixed

  • Wondarr stops downloading the same wrong song over and over. The fingerprint check refused each wrong file, but the next search downloaded another copy, and each grab sent a "Grabbed" notification: on one install, 80 copies of Phil Collins' "Please Come Out Tonight" for Phil's "Please Come Tonight" in three days. When AcoustID names a download as a recording with another title, no file with that title is downloaded for the song again, whoever shares it. And when two files on a compilation path ("Various Artists", "VA", "Compilations") that only their title let through turn out to be other artists' songs, that song stops accepting such files without the artist's name, which ends the stream of jazz and rock songs called "Out on a Limb" and "Be My Friend". Both are entries on Activity → Blocklist that you can remove.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.18 (linux/amd64, linux/arm64)

Wondarr 0.1.17

Choose a tag to compare

@github-actions github-actions released this 06 Nov 16:39

Wondarr no longer fills a song AcoustID does not know with another artist's song of the same title, and Remove file… on the song page takes a wrong file away. Also in this release: the fixes from a code review of the whole project. Update by pulling :0.1 (or :0.1.17), from ghcr.io/wulfftech/wondarr or wulfftech/wondarr on Docker Hub.

Upgrading from 0.1.16:

  • No database migration.
  • With auth: none, open Wondarr by a local name, or allow yours. Wondarr now answers the web UI under auth: none only for an IP address, localhost, a name without a dot, or one ending in .local, .lan, .home.arpa or .internal. If you open it by another name, add that name to server.allowed_hosts, or turn off Only answer local host names under Settings → General → Security. With auth: forms nothing changes.
  • Files already in your library are not checked again. A song AcoustID did not know may hold someone else's song of the same title: its File tab shows no verified fingerprint. Use Remove file… on its page to take the file away, and Wondarr looks for the song again.

Added

  • Remove file… on the song page takes a wrong file away from its song. The file and its lyrics file go to the recycle bin, the song is missing again so the next search looks for it, and the download it came from is blocklisted for the song unless you untick that. The dialog can start a search straight away. A reference library's file, or a copy adopted from one, is never removed. The API is DELETE /api/v1/song/{id}/file?blocklist=true.

Changed

  • With auth: none, Wondarr answers the web UI only when it is opened by a local name. Otherwise a page on the internet could point its own domain at your Wondarr (DNS rebinding), read the API key from /initialize.json and use the whole API. A local name is an IP address, localhost, a name with no dot, one ending in .local, .lan, .home.arpa or .internal, or a name in server.allowed_hosts; any other name gets a short page saying which name was used and what to do. If you run with auth: none and open Wondarr by a name that is not local (such as wondarr.ad.example.com), add that name to server.allowed_hosts or turn off Only answer local host names under Settings → General → Security (server.require_local_host: false; the switch shows only with auth: none). Tools that send the API key (Prowlarr, autobrr and the like) work under any name, and forms and external are unchanged.

Fixed

  • A song AcoustID does not know is no longer filled with another artist's song of the same title. Such a file passed on its length alone, and same-titled songs are everywhere: on one install, 11 of 16 files imported that way were someone else's (Artur's "Wonderland" for The Saddle Club's, a Deep House "Money (Can't Buy)" for "Money Can't Buy"). The file now has to name the song's artist in its artist or album-artist tag, or failing those in its file name. One that names another artist is refused and the next candidate is tried; one that names no artist at all is imported marked for review, or refused with acoustid.strict on. The same applies when no AcoustID key is set. Files already in your library are not re-checked.
  • One word of an artist's name no longer counts as the artist. "Penny To The Grave" by The Miles Away Club passed for The Saddle Club's "When the Penny Drops" on the word "club". A candidate now needs the whole name, or a shorter form of it that adds no other words, such as "Beethoven" for Ludwig van Beethoven.
  • A file on a compilation path that names another artist is no longer downloaded. On a "Various Artists", "VA", "OST" or soundtrack path, a file whose title matched the song's in full skipped the artist check, even when its own name named someone else (18 The Cryan Shames - Sugar and Spice.flac). Each one was downloaded and then refused by its fingerprint.
  • The same wrong file from another Soulseek user is skipped. When AcoustID identifies a download as a different recording, its folder and file name are blocklisted for the song too, so the same rip shared by someone else is not downloaded again. The entry shows on Activity → Blocklist and can be removed there.
  • A search whose every download was refused now counts as fruitless. Any grab reset the re-search wait, so a song whose downloads were all refused, or failed to import, was searched again at the shortest interval and downloaded more wrong files. Such a run now lengthens the wait like a search that found nothing.
  • A file that fails tagging is skipped for a week, and the log says so. It ended the run as before, but the next search grabbed the same file again, three times in two days on one install, and nothing above Debug level said why. The failure is now a Warning, and that one file is blocklisted for the song for 7 days.
  • An MP3 import no longer prints a stack trace to the log. Stripping the old tags asked the tag library to remove a tag system MP3 does not have; it carried on, but printed "The method or operation is not implemented" with its stack trace on every MP3.
  • An email the mail server turns away for now is sent again. A temporary refusal (an SMTP 4xx reply, such as greylisting or a rate limit) is retried once after 20 seconds. Two immediate notifications were lost to a 450 that way.
  • Settings → YouTube saves a 44.1 or 48 kHz sample rate. Choosing either answered 400 and nothing was saved, and a rate already stored showed as "Keep", so saving any other field on the page reset it. The page now sends and reads the rate as a number.
  • Interactive search runs once per open. It re-ran the Soulseek search whenever the queue changed or the connection reconnected, which swapped the results out from under you and spent the shared search budget, and a grab waited for that re-run before it finished. Opening the search runs it once.
  • A song's page shows a blocklisted item and a grab at once. Removing an item with "blocklist" on the song page's Queue & blocklist tab left the Blocklist table below it saying "Nothing is blocked", and a grab from the song's interactive search left no "grabbed" row in its History tab, until you left the tab and came back. Both lists now refresh straight away.
  • Changing a reference library's folder keeps its songs. After remounting a share at a new path, every song the library owned still pointed at the old one: a file you then deleted never freed its song, and Adopt skipped everything. The owned songs' paths now move with the folder, and a file that is not at the new path goes through the usual wait for a missing file.
  • A song with a second copy of its recording keeps a file. Skipping a reference file, accepting a different song for it, or a rescan finding that it belongs to another song could leave a song that had a second copy of the recording with no file at all. The song's file now follows the second copy.
  • A reference file overwritten with a broken copy no longer keeps its song for good. When the file is still unreadable on a later scan and was last written more than 24 hours ago, the song lets go of it. That is the wait a missing file gets, so a copy still in progress, or one failed check, does not count. The song follows a second copy of the recording if there is one, and is wanted again if not.
  • A pasted or synced list no longer stops at a bad line. A Deezer track with an ISRC in an odd shape (hyphens, or too short), or a line that was the all-zero MusicBrainz id, left the list due and failing at the same line every run. A hyphenated ISRC is cleaned up before the lookup and an invalid one skips the ISRC lookup. The all-zero id is reported as not supported. Any line a lookup refuses is marked failed and the rest of the list carries on.
  • An upgrade or a renamed download that was in flight when Wondarr stopped is picked up on restart. An automatic upgrade that replaced a song's file at the same path, with Wondarr stopped before it saved, was never recorded: a second download was grabbed and filed over it, and the song never showed the upgrade. A YouTube download renamed to .ogg (Opus container set to ogg) and stopped mid-check made the restart look for the old .opus name, fail the import and download the song again, leaving the .ogg behind. Restart recovery now recognises the upgraded file and records it, and the rename is saved straight away so the import resumes from the renamed file.
  • An import whose finished download cannot be removed keeps the library copy. When the downloads folder was on a different file system and Wondarr could not delete the finished download after copying it into the library (the file was busy, or Wondarr could not write to the download folder), the import failed and left an untracked copy in the library that Plex scanned. Wondarr now records the copied file as the song's, keeps it in place and leaves the replaced file in the recycle bin. A half-written copy left that way is deleted and the download kept.
  • A replaced file stays in the recycle bin for import.recycle_bin_cleanup_days. When Wondarr could not set the time on a replaced file it moved there (the library files belong to another user), the next daily Housekeeping deleted that file within a day. The recycle bin now replaces such a file with its own copy, so the retention starts when it was recycled. If that copy fails too, the log says the file may be removed at the next cleanup.
  • One stuck sign-in no longer blocks everyone else. Two slow or half-sent POST /login requests took both password-check slots and made every other sign-in, the owner's included, fail with "Wondarr is busy checking other sign-ins". Only the password check itself is now limited to two at a time, and a login form over 8 KB is refused (413).
  • A page number far past the end returns an empty page. For example ?page=2147483647 made the API behin...
Read more

Wondarr 0.1.16

Choose a tag to compare

@github-actions github-actions released this 03 Nov 08:11

A setting for installs whose music and downloads are not mounted at /data. Update by pulling :0.1 (or :0.1.16), from ghcr.io/wulfftech/wondarr or wulfftech/wondarr on Docker Hub.

Upgrading from 0.1.15:

  • No database migration. The one new setting, WONDARR_MEDIA_ROOT, is off unless you set it, and an existing library keeps its root when you do.

Added

  • WONDARR_MEDIA_ROOT moves the default music and download folders. Set it when your music and downloads are mounted somewhere other than /data, for example /storage alongside DockSTARTer's other apps. The library a new database starts with is created at <root>/music, and the defaults move to match: the Soulseek share, slskd's download and incomplete folders, yt-dlp's download folder and import.container_staging_path. A path set in config.yml, by an APP__ variable or in the web UI is used as it is, and an existing library keeps its root. Unset, nothing changes.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.16 (linux/amd64, linux/arm64)

Wondarr 0.1.15

Choose a tag to compare

@github-actions github-actions released this 27 Oct 02:49

Fixes for reference libraries and for torrent and usenet searches on a busy machine, dependency updates, and the image on Docker Hub. Update by pulling :0.1 (or :0.1.15), from ghcr.io/wulfftech/wondarr or now wulfftech/wondarr on Docker Hub.

Upgrading from 0.1.14:

  • No database migration, no new settings.

Added

  • The image is on Docker Hub too, as wulfftech/wondarr: a mirror of ghcr.io/wulfftech/wondarr with the same tags and digests, copied once a release has passed its checks. It's for the NAS container apps and guides that only search Docker Hub.

Fixed

  • A torrent or usenet search no longer fails on a busy machine. Finding the song's file inside a release's file list ran four name patterns with a 100 ms limit, and that limit counts time spent waiting for the CPU: on a loaded server an ordinary name could run out of time, and the whole indexer search failed. They now get the 1 s every other name parser has.
  • A song whose reference file is let go of keeps a library copy imported at that moment. A reference scan lets go of a song whose file has been missing for a day, and Skip in the Match queue does the same, so that the song is wanted again. If an import of that song (a grab, a Replace, or an upgrade of a file below the cutoff) recorded its new copy in the instant between the release reading the song's file and deleting it, the delete took the new copy's record with it: the file stayed in the library while the song looked missing. A release now deletes the song's file record only while it still points at the reference file, and does so in the same commit that updates the reference file's row. No migration.
  • A library copy imported while a reference library changes the song's file keeps its record. Three more steps read a song's file record and wrote it back later: a scan pointing a song whose file went missing at a second copy, identification refreshing a changed reference file or following a renamed one, and deleting a reference library. An import of that song recorded in between could have its library copy pointed back at the reference file, or deleted by the library delete: the file stayed in the library, unrecorded. Each now writes the record only while it is still the reference file it read, in the same commit as the rest of its changes. No migration.
  • An import no longer fails with "recording it failed" when a reference library changed the song's file meanwhile. The import read the song's file when it started and recorded over it at the end. If a reference scan let go of the song's reference file in between, the record failed and the new file stayed in the library unrecorded (a restart does not pick up a failed import); if identification linked a reference file to a song that had none, the record collided with it. The import now reads the song's file again when it records, under the database's write lock: a file record that has gone is added again, and a reference file linked since is replaced, as any grab replaces a reference file. No migration.

Changed

  • Dependencies updated: .NET 10.0.14 servicing (ASP.NET Core, EF Core, Microsoft.Extensions, the SignalR client and the dotnet-ef tool), ATL 7.19 (the tag library: a FLAC file with a malformed comment length can no longer hang a reference scan, and an MP3's comment language is kept when tags are written), MailKit 4.18.2, Scalar 2.18.3, Mantine 9.7.3, react-router 8.5, @tanstack/react-query 5.104.5, and build tooling (typescript-eslint, postcss, docker/login-action).

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.15 (linux/amd64, linux/arm64)

Wondarr 0.1.14

Choose a tag to compare

@github-actions github-actions released this 22 Oct 14:58

Songs MusicBrainz does not have can now be added there from the Match queue, and the file is settled when MusicBrainz sends you back. Update by pulling :0.1 (or :0.1.14).

Upgrading from 0.1.13:

  • No database migration, no new settings.

Added

  • Add to MusicBrainz, from the Match queue. For a song MusicBrainz does not have (one released only on YouTube, say), the review drawer's Add to MusicBrainz… opens MusicBrainz' release editor in a new tab with the song filled in as a digital single: the title, the artist and the file's length, plus a YouTube link if you give one. Read video fills in the upload date from the link while the YouTube source is on. You link or add the artist, check the rest and submit under your own MusicBrainz account; MusicBrainz then sends you back to Wondarr, which settles the file with the new release. Wondarr never edits MusicBrainz itself.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.14 (linux/amd64, linux/arm64)

Wondarr 0.1.13

Choose a tag to compare

@github-actions github-actions released this 22 Oct 10:22

Reference libraries now spot likely YouTube rips and can have any of their files replaced by a better copy: Replace in the Match queue, or Replace files below the cutoff on a reference library. Update by pulling :0.1 (or :0.1.13).

Upgrading from 0.1.12:

  • An additive migration adds three columns and, from what earlier scans stored, flags the likely YouTube rips already in your reference libraries and re-rates their files OPUS-160. A song owned through a reference file is still never searched for until you ask.
  • Adopt libraries: the copies of likely rips are re-rated too. They are ordinary library files, so the scheduled Upgrade Search starts looking for better copies of them, as it does for any library file below its cutoff.

Added

  • Likely YouTube rips in reference libraries. YouTube serves its audio at 48 kHz, while CDs and download stores use 44.1 kHz, so a reference file that is lossy at 48 kHz is flagged a likely YouTube rip and rated no better than OPUS-160, the quality of a YouTube download, even when it was re-encoded to a high-bitrate MP3 (by bitrate alone such a file rated MP3 V0). The Match queue shows a Likely YouTube rip badge and the sample rate, and Only likely YouTube rips narrows it to them; the reference library table counts them. A lossless file at 48 kHz is never flagged.
  • Replacing reference files with better copies. Replace in the Match queue (and Replace selected) accepts the recording and searches for a better copy now when the file is below its cutoff; a reference library's new Replace files below the cutoff setting (off by default) lets the scheduled Upgrade Search and Wanted → Cutoff Unmet treat every song held by one of its files like a library song. The copy goes into the managed library and the song points at it; your file is never written, moved or deleted. Before this, a reference-owned song was never searched for.
  • Replaced by a library copy, on Settings → Reference libraries, lists the reference files whose song now uses a library file, with both qualities and a button that copies their paths, so you can delete them (a file that rates higher than its library copy is marked and left out). A deleted replaced file never counts towards the "share not mounted" warning, and its row is dropped after 24 hours.
  • A replacement an interrupted import had already placed is recorded after a restart, as for any other song, instead of being downloaded again.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.13 (linux/amd64, linux/arm64)

Wondarr 0.1.12

Choose a tag to compare

@github-actions github-actions released this 21 Oct 14:08

Dependency updates only: Quartz 4.6, Microsoft.Extensions.Http.Resilience 10.11, Mantine 9.7.2 and TanStack Query 5.104.3, with newer test and build tooling. Nothing you see or set changes. Update by pulling :0.1 (or :0.1.12).

Upgrading from 0.1.11:

  • No database migration, no new settings.

Changed

  • Dependencies updated: Quartz.Extensions.Hosting 4.6.0 (its database migrations are for persistent job stores; Wondarr's schedule lives in memory, so nothing changes), Microsoft.Extensions.Http.Resilience 10.11.0, Mantine 9.7.2, @tanstack/react-query 5.104.3, and test and build tooling.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.12 (linux/amd64, linux/arm64)

Wondarr 0.1.11

Choose a tag to compare

@github-actions github-actions released this 21 Oct 12:18

The feedback button now needs a GitHub token, and the token can be added in the web UI: Settings → General → Contribute with feedback shows how to make one, tests it and stores it. Update by pulling :0.1 (or :0.1.11).

Upgrading from 0.1.10:

  • No database migration, no new settings. Without feedback.github_token the header no longer shows the feedback button; with it (or APP__FEEDBACK__GITHUB_TOKEN) nothing changes.
  • Use a classic token with public_repo unless you own or collaborate on wulfftech/wondarr: GitHub lets fine-grained tokens open issues only where their owner can push.

Changed

  • The feedback button shows only once a GitHub token is set, and the token can now be added in the web UI: Settings → General → Contribute with feedback walks through making one (a classic token with the public_repo scope; GitHub lets fine-grained tokens open issues only on repositories you own or collaborate on), stores it in config.yml without ever showing it again, and Test asks GitHub whether it is accepted and has that scope, without opening anything. Saving or removing the token adds or removes the button at once. A token set by APP__FEEDBACK__GITHUB_TOKEN stays read-only there (set but empty, the card says to remove it, because it would hide a token saved here). The card says what the scope allows: public_repo can change any of your public repositories, Wondarr only opens issues with it, and the token is stored as plain text in config.yml. A token is checked at most 10 times every 10 minutes, and only one GitHub accepts is treated as a secret in the logs. No migration.

Fixed

  • The browser no longer offers to fill a saved password into a key field on Settings → General (the AcoustID and Last.fm keys, and the new GitHub token). The fields asked for no autofill in a way browsers ignore on password fields, so a saved Wondarr login password could land in one and be sent to that service as a key; they now ask the way browsers honour. No migration.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.11 (linux/amd64, linux/arm64)

Wondarr 0.1.10

Choose a tag to compare

@github-actions github-actions released this 20 Oct 14:32

A feedback button in the header turns a bug report or an idea into a GitHub issue. Update by pulling :0.1 (or :0.1.10).

Upgrading from 0.1.9:

  • No database migration. One new, optional setting: feedback.github_token (environment APP__FEEDBACK__GITHUB_TOKEN). Without it the button hands you GitHub's issue form, filled in, to submit yourself; with it Wondarr opens the issue for you. See Configuration → feedback.

Added

  • A feedback button in the header, beside the theme toggle. It opens one text box, Bug or Idea, and sends it with the page you are on and the Wondarr version. Every submission is written to the log first. With feedback.github_token set (APP__FEEDBACK__GITHUB_TOKEN; a GitHub token that may open issues on wulfftech/wondarr), Wondarr opens the issue itself, labelled bug or enhancement, and links it. Without a token, or when GitHub refuses the token, is rate limiting or cannot be reached, the dialog links GitHub's new-issue form with everything filled in, and you press Create there. Known secrets (the API key, indexer and client keys, tokens) and home folders are removed from what goes to the public issue. The request is never retried; when GitHub took it but did not answer, the dialog says the issue may exist and links the issue list. GitHub's rate limit and Retry-After are honoured, and Wondarr opens at most 5 issues every 10 minutes. No migration.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.10 (linux/amd64, linux/arm64)

Wondarr 0.1.9

Choose a tag to compare

@github-actions github-actions released this 18 Oct 13:00

Reference libraries forgive a few bad MP3 frames, and the usenet indexer pause from 0.1.8 now covers grabs and pushed releases too. Update by pulling :0.1 (or :0.1.9).

Upgrading from 0.1.8:

  • No database migration, no new settings.
  • Reference files that were "unreadable" get another look on the next scan. A file that plays through but has a few bad frames (at most about 20 lines of decode errors, with at least 98 % of it decoding) is now identified and, in adopt mode, adopted like any other. Downloads are checked as strictly as before.
  • A grab from an indexer that is pausing NZB downloads ends that song's search run. Nothing is blocklisted; the song is searched again later.

Changed

  • Dependencies updated: Quartz.Extensions.Hosting 4.5.1 (4.4 code runs unchanged; no schema change).
  • The repository no longer carries internal planning and research notes; public docs no longer cite them.

Fixed

  • Soulseek no longer searches for a pseudo-album as if it were an album. The "artist + album" query was skipped only for an album literally titled "Singles", so a Singles album you had renamed, or the library-wide compilation album, still cost a wasted search (it never picked a wrong file). The query is now left out whenever the song's album is a pseudo-album by kind, whatever its title; a real album that happens to be titled "Singles" is searched. A search request that carries no kind (one stored by an older version) keeps the old title check. YouTube builds no album query, so it is unchanged. No migration.
  • A grab no longer asks an indexer that is cooling down for an NZB, and a refusal during a grab starts the cool-down. Only searches knew the cool-down. A grab of a post whose NZB was not kept in memory still downloaded it, and when the indexer answered 429 or 403 (or its limit message) the grab failed without cooling the indexer down, so the next search spent more downloads. Now such a grab fails at once, without a request, with "indexer is cooling down until time after refusing NZB downloads", and the post is not blocklisted: the post is fine, the indexer is resting. The grab run for that song ends there, as it does for any failure that is the source's own bad moment, instead of failing the indexer's remaining posts one by one; the song's own backoff tries again. A refusal during a grab starts the cool-down exactly as a search's does. A post whose NZB is kept is grabbed as before. A pushed release names no indexer row, so it has no cool-down. No migration.
  • A grab and a search that need the same NZB at once download it once. The searches already shared one download per post; a grab now joins it (or is joined by a search, or by another grab) instead of making a second request against the indexer's daily quota. No migration.
  • A pushed usenet release is no longer retried on a 429. The link of a pushed NZB is an NZB download like an indexer's, so a spent quota is answered once instead of being retried. Pushed torrents are retried as before. No migration.
  • A failed NZB download is retried once, after at most 5 seconds. This covers a 5xx, a 408, a dropped connection and a timeout. A 502 or 503 with a long Retry-After used to be waited out inside the retry handler, held the search or the grab until the 30-second request timeout and ended as "The indexer could not be reached.", with no status; now the download is asked a second time after the shorter of the header and 5 seconds, and a second 5xx is reported as the indexer's own answer ("The indexer answered 503."). Before, a download could be asked three times. Searches and capability requests are retried as before. No migration.
  • A reference file with a few bad MP3 frames is scanned instead of being left unreadable. The decode check treated any ffmpeg error as "does not decode", which is right for a download (a damaged one is replaced) but not for your own files: the live check left Eddie Grant - Electric Avenue.mp3 (6 bad frames) and Supertramp - Give A Little Bit.mp3 (1 bad frame) unreadable, although both play to the end. A reference scan now puts up with a file that fails the strict decode when ffmpeg, told to skip past bad frames, writes at most 20 error lines (a bad frame is two or three) and gets through at least 98 % of the length ffprobe measured; it then goes on to identification like any other file, the scan logs "decodes with N errors … scanned anyway", and the file's row says "Decodes with N errors" until identification replaces it. A file with more damage than that, a damaged file that also ends early, and a file with no audio stream stay unreadable. Downloads, imports, conversions and upgrades are as strict as before. Adopt mode copies such a file as it lies. An unreadable file that now passes is picked up by the next scan without being touched. So that such a file can be fingerprinted too, the fingerprint step now has a second try: fpcalc reads a file straight through and gives up at the first bad frame, so when it cannot fingerprint the start of a file, Wondarr cuts the same window out with ffmpeg (which skips bad frames) and fingerprints that. A file fpcalc could read is fingerprinted exactly as before. No migration.

Image: docker pull ghcr.io/wulfftech/wondarr:0.1.9 (linux/amd64, linux/arm64)