github BlizzHacker/romarr v0.9.0
v0.9.0 — Friends, 28 download clients, and downloads that die properly

latest releases: v1.8.0, v1.7.0, v1.6.0...
one month ago

79 commits since v0.8.0. The headline is federation — two ROMarr servers that can see each other's shelves and agree on which bytes to play — but the change most installs will feel first is that a dead download no longer costs you the same dead download again.

Upgrade note: an unreadable state file used to unclaim your install

romarr.json holds the API key, the password hash and your request history. If the process could not read it — the usual cause being a root-owned file under a container running as PUID — ROMarr started from defaults, and the next save overwrote the real file. The install came back unclaimed, so whoever reached the port next got to set the password.

It now refuses to start and tells you to fix the ownership. An outage costs you nothing; the old behaviour cost you the install.

Friends: federation, shared libraries and cross-server netplay

Peer two ROMarr servers with a link invitation and you get the other shelf: browse it, filter it, and see per-title whether netplay would actually work. Matching is on ROM hashes, not titles, because two people with "Super Metroid" may not have the same bytes, and a netplay session that desyncs on frame one is worse than one that never started.

The peering protocol is written down as a standalone spec — docs/FEDERATION-PROTOCOL.md — and was proven between two live servers before it shipped, not mocked.

When a download dies, something happens (#27)

A stalled torrent used to be a loop. The Blocklist existed, nothing ever added to it, and the scorer is deterministic — so pulling the dead torrent out of your client and waiting for the next sweep scored the same results the same way and grabbed the same dead file again.

Worse: the Blocklist was decorative even when you filled it in by hand. reload_policy built one and every call to best_release and judge left it out, so a blocked release went on being chosen — and excluded_terms / required_terms did nothing either. Both are wired in now, at all four call sites.

A download the client refused, one that finished with no ROM in it, or one still unfinished past stalled_timeout_minutes (default three hours) is blocklisted with the reason attached, the game goes back on Wanted, and the next best release is grabbed. Capped at three replacement grabs per sweep, because each costs a full indexer search.

What is deliberately not blocklisted: no download client configured. That one is your install's fault, not the release's.

Activity survives a restart (#26)

The queue lived in memory only, so a restart — or any k8s Recreate — emptied it while your client carried on seeding. That lost more than a list: the import sweep matches a finished download to its queue row by release title, so once the rows were gone it could not tell which game a completed torrent belonged to, and skipped the file it had just downloaded.

The queue is now in romarr.json with everything else. Rows carry the release identity they took, which is what makes failed-download handling possible at all.

A request can be dropped (#25)

Wanted could only ever be emptied by an import, so a typo kept costing an indexer search on every missing sweep and every RSS pass, forever, for a game that does not exist. There is now a Remove button on every Wanted row and a DELETE /api/v1/wanted/missing to match. It records its own event, because "it arrived" and "I changed my mind" are not the same thing to read back later.

Eighteen more download clients — 10 types to 28

qBittorrent, Transmission, Deluge, rTorrent, Synology DS, aria2, Flood, Freebox, Hadouken, uTorrent, porla, Vuze, BiglyBT; Real-Debrid, AllDebrid, Premiumize, TorBox, Debrid-Link, Offcloud, put.io, Linksnappy; SABnzbd, NZBGet, NZBVortex; and blackhole folders for anything not on the list.

Fourteen platforms that were blocking 70,151 indexed games

Plus Switch via TitleDB, PlayStation spelled as words, and Neo Geo left ambiguous on purpose rather than guessed wrong.

DATs read the way people actually have them

ClrMamePro DATs, not only Logiqx XML, and DATs inside .zip — which is how No-Intro distributes them.

Compressatorium: batch decompression, DAT-gated (#22)

Bulk-decompress archives already in the library, with deletion of the original gated on a DAT verification of what came out. Nothing is deleted on the strength of a filename.

Fixes worth naming

  • qBittorrent sessions expire. The SID has a finite lifetime and ROMarr keeps its client for the life of the process, so the first expired session turned every health check and import poll into a permanent 401 until restart.
  • Torrents qBittorrent emptied are detected and repaired instead of imported as nothing.
  • Scheduled jobs never ran on a freshly booted host.
  • Plugin catalogue was empty in Docker, and ROM Hub was not confined correctly.
  • GG Requestz request delivery, and media bind-mount permissions.
  • Robots is checked where the file is, not only where the page was.

Full changelog: v0.8.0...v0.9.0

Don't miss a new romarr release

NewReleases is sending notifications on new releases.