Skip to content

Releases: Arediss/Oscarr

v0.8.3 — Plugin engine compat fix (Docker image was reporting wrong version)

Choose a tag to compare

@Arediss Arediss released this 19 May 22:00

Patch — fixes plugin engine compat in the Docker image

This release fixes a release-process bug that has been silently breaking plugin installs on every Docker deployment since 0.8.0.

The bundled Docker image swaps packages/backend/package.json for a static runtime manifest (package.prod.json) at build time — and that manifest still carried "version": "0.7.2" from three releases ago. getOscarrVersion() (used by plugin compat checks) read from that file, so every plugin requiring Oscarr >=0.8.x was silently refused at install time on Docker — including Quotas which requires >=0.8.2. The in-app version banner correctly showed 0.8.2 because it reads from a different file, masking the bug.

Fixes

  • Compat reads the root package.json (the only file shipped fresh on every release, already used by other version readers). The version field is dropped from package.prod.json — no more double-bump to forget.
  • Discover catalog surfaces engine compatibilityGET /plugins/registry now returns compat per entry, the Install button on incompatible plugins is disabled and the label switches to Requires Oscarr <range>. No more downloads triggered for plugins that can't load.
  • Reload button force-refreshes the Discover catalog — previously only the update-check cache was bypassed. A newly-registered plugin (e.g. Quotas which just landed in the registry) wouldn't surface until the 30 min cache expired. GET /plugins/registry now accepts ?force=true and the Reload button uses it.

🐳 Image: ghcr.io/arediss/oscarr:0.8.3

v0.8.2 — Install wizard 2.0, migrate from Overseerr/Jellyseerr/Seerr

Choose a tag to compare

@Arediss Arediss released this 19 May 22:00

Highlights

This release is centered on the install experience. The wizard was rewritten from scratch with a guided 7-step flow, picks up where Overseerr / Jellyseerr / Seerr left off if you're migrating, and now leaves a fully-wired instance behind — no more half-finished setups landing on the home page with a noisy setup-checklist.

It also drops the post-install process restart, so Oscarr no longer needs a supervisor (docker --restart, systemd, kubernetes restartPolicy) just to come back online.

Plugin authors: @oscarr/sdk gains language + translation helpers, and registerGuards now receives the request context (tmdbId, mediaType, seasons). The Quotas plugin which requires engines.oscarr >=0.8.2 is now installable.


New

  • Install wizard 2.0 — a 7-step state machine (Secret → Admin → Path → Services → Defaults → Sync → Done) replaces the old monolithic page. Brand panel + form split, categorized service tile grid (media-server / *arr / download-client / indexer / monitoring), modal-based per-service config, and a Done step that mirrors the admin setup-checklist.
  • Migrate from Overseerr / Jellyseerr / Seerr at install — new Fresh / Migrate path picker. The Migrate path probes the source via /api/v1/settings/* and bootstraps services, default folders, locale and quality tiers in one shot. *arr API keys and the Plex token aren't exported by Seerr — the wizard flags them as manual follow-ups.
  • Import users + requests from Overseerr / Jellyseerr / Seerr (admin) — dedicated Import tab with preview, conflict resolution (link / create / skip) and TMDB-probed importable list. Status code 4 (failed/completed) now correctly maps to approved.
  • Quality auto-mapping — new POST /admin/quality-mappings/auto endpoint scans every Radarr/Sonarr service and maps profiles to Oscarr tiers via name heuristics (HDR+UHD → 4K HDR, UHD → 4K, 1080p/720p → HD, 480p → SD). Idempotent; the install wizard calls it automatically after seeding the tiers.
  • Surface undecryptable service credentials — after restoring a backup from another instance (different OSCARR_SECRET_KEY), affected services now show an explanatory banner + per-row alert instead of leaking the enc:v1:… ciphertext into the admin form.

Plugins

  • @oscarr/sdk gains i18n helpersgetLang(), useLanguage() React hook, and a t(dict, lang, key, vars?) helper with fallback chain + interpolation. Hot-switches when the user changes language in Oscarr — no react-i18next bundle to drag in.
  • Plugin guard handlers receive request contextregisterGuards() handlers now get tmdbId, mediaType and seasons alongside the user. Additive change, existing guards keep working.
  • Plugin toggle is gated — toggling an incompatible plugin (engines range mismatch) or one that failed to import now bails early with a clear error message instead of a cryptic Prisma RecordNotFound. The admin UI also disables the toggle switch.

Fixes

  • Backend no longer restarts after install — the /setup/sync handler used to process.exit(0), relying on a supervisor to respawn. Setup routes are already 403'd by the existing requireNotInstalled preHandler once the install completes, so the exit was redundant and broke dev environments + bare-metal deployments without a supervisor.
  • Seerr import status mapping + TMDB probe — completed requests (Overseerr status 4) no longer land as pending, and re-running a preview after a partial import no longer infinite-loops on dead tmdbIds.
  • docker-compose injects OSCARR_SECRET_KEY into the container — compose only interpolates .env for YAML substitution, not container env. The bundled docker-compose.yml now adds both env_file: - .env and an explicit environment: entry so fresh upgrades pass the boot-time secret check.

Internal

  • Service connectors can declare requiredForInstall: true on their ServiceDefinition — the install wizard derives required categories from this flag instead of hardcoding the list. Adding a new required connector backend-side automatically gates the wizard with no frontend edit.

🐳 Image: ghcr.io/arediss/oscarr:0.8.2

v0.8.1

Choose a tag to compare

@Arediss Arediss released this 10 May 02:26

⚠️ BREAKING — OSCARR_SECRET_KEY is now MANDATORY

Before upgrading, generate a 32-byte hex key and add it to your environment. Without it, Oscarr will refuse to boot.

Generate one (host with Node):

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

No Node on host? Just boot the container without the key — Oscarr exits with a friendly message and a freshly-generated key you can copy-paste:

docker compose up
# … look for the "Oscarr — secret key required" block in the logs:
#   OSCARR_SECRET_KEY=<copy this line into your .env>

Then add to your compose / env file:

environment:
  - JWT_SECRET=your_random_jwt_secret
  - OSCARR_SECRET_KEY=your_64_hex_chars_key

🔐 Lose this key = stored service credentials become unrecoverable and need to be re-entered manually. Treat it like a password — back it up.

Existing plaintext credentials get flagged in the admin (floating banner, bottom-right) and re-encrypted automatically on next save.


Compose gotcha

Compose reads .env for YAML interpolation only — vars don't reach the container unless declared in environment: or loaded via env_file:. The bundled docker-compose.yml was patched post-release to do both. If you maintain your own compose file, make sure it has either:

env_file:
  - .env

…or…

environment:
  - OSCARR_SECRET_KEY=${OSCARR_SECRET_KEY}

Verify with: docker compose config | grep OSCARR_SECRET_KEY (must show the real value, not the placeholder).


Highlights

New

  • Seerr-compatible API at /api/v1/* — third-party tools (Homarr, Doplarr) can talk to Oscarr without a custom integration. Endpoints not yet implemented return a clean 501 Not Implemented.
  • Per-app API keys with revocation (Admin → Access → API Keys) — each external integration gets its own scoped credential.
  • AES-256-GCM encryption at rest for service credentials. Master key derived from OSCARR_SECRET_KEY via HKDF-SHA256.
  • Secure password reveal/copy modal — replaces the native prompt() for credential reveal in the admin.
  • TMDB trending backdrop on the login page — random pick from the top 10 trending titles.

Improved

  • qBittorrent 5.x compatibility — provider now uses API-key auth (Authorization: Bearer). Drops username/password. Pause/resume hit the new /torrents/stop and /torrents/start endpoints.
  • Searchable plugin Discover with filters (Hide installed, Nouveau pill).
  • Reusable ConfirmModal — replaces confirm()/alert() across destructive admin actions.

Removed

  • *Drop arr tag-based request sync — replaced by the upcoming Seerr import path (#192).

Fixes

  • Bump better-sqlite3 to 12.9 for Node 24+ support.
  • Slim README + extract docs/installation.md.

CI

  • Advisory React Doctor job on push + PR.

Image

ghcr.io/arediss/oscarr:0.8.1
ghcr.io/arediss/oscarr:latest

Multi-arch (linux/amd64, linux/arm64), keyless-signed (Sigstore / cosign), SPDX SBOM attached.

v0.8.0 — Plugin self-update, generic storage, indexer + download-client connector pack

Choose a tag to compare

@Arediss Arediss released this 08 May 17:38

Highlights

Plugins now self-update from inside Oscarr with a permission diff and a reload/reboot split — no more SSH dance for routine bumps. They also gain a generic isolated storage API (KV + SQLite, gated by storage:plugin), so plugin state lives next to the plugin and is wiped with it. On the integrations side, a connector pack lands: Prowlarr (indexer) plus four torrent/Usenet clients (NZBGet, SABnzbd, Transmission, Deluge) — connection-test only for now, the action layer will ship as separate plugins.

Features

  • In-app plugin update flow with permission diff. Plugins self-update from inside Oscarr without SSH — the admin sees the upcoming version, the diff of requested permissions, and chooses between a hot reload (no downtime) and a full reboot (required when manifest perms or native deps changed). Reload vs reboot is decided by the engine, not guessed by the user.
  • Generic plugin storage API (KV + SQLite). Two isolated primitives — a key/value store and a per-plugin SQLite database — exposed via PluginContext.storage and gated by the new storage:plugin permission. State is scoped to the plugin and removed with it, so the core schema doesn't leak plugin concerns.
  • Indexer + download-client connector pack (Prowlarr, NZBGet, SABnzbd, Transmission, Deluge). Five new service connectors land on the Services tab — connection testing only. Actions (queue/history/pause/etc.) will be exposed by separate plugins talking to these connectors. Each ships with a typed test() that distinguishes auth failures from network errors and surfaces protocol-specific cases like Deluge's daemon-detached state and Transmission's CSRF challenge.
  • Searchable service-type picker with provider icons + 'Untested' badge. The service-creation modal now opens a Headless UI Combobox instead of a native <select>, with a search input, provider icons rendered inline, and an amber 'Untested' pill on connectors that haven't been validated against a real instance yet. Picking an untested connector shows a one-click GitHub feedback link prefilled with the connector name — the badge is removed in the same commit that confirms the integration works.
  • Support module extracted to a standalone plugin. The legacy in-core Support module is now shipped as Oscarr-Plugin-Support, removable like any other plugin. The migration carries an export of existing tickets so admins can install the plugin and keep their data, while keeping the core lean and aligned with the plugin-first vision.

Fixes

  • SonarCloud reliability sweep — 53 bugs cleared. Three refactor tiers landed in this cycle (mechanical sweep, cosmetic batch, redundant cast removal). Pure code-health work — no behavioural change expected.
  • Log injection sanitizer hardened. CodeQL was failing to recognise the log sanitizer; rewriting it as explicit per-channel branches with separate replace() calls satisfies the static analyzer and removes the dead suppression. Closes part of the security code-scanning queue (#182).

Other

  • Faster multi-arch (amd64 + arm64) release builds. The release pipeline now produces both linux/amd64 and linux/arm64 images noticeably faster. The lockfile's platform-native deps were also restored so installs on distroless / musl images stop failing.

Full changelog: v0.7.8...v0.8.0

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.8.0
```

v0.7.8 — Account modal redesign, Jackett indexer & qBittorrent plugin contract

Choose a tag to compare

@Arediss Arediss released this 03 May 20:32

Highlights

A redesigned account modal Discord-style replaces the old avatar dropdown, ships a new account.section plugin hook, and unlocks the first official plugin built on it: qBittorrent Manager. Admins gain user-defined topbar shortcuts, a quick admin/back jump button, and a Jackett connector for indexer integrations.

Features

  • Discord-like account modal with plugin sections. The avatar dropdown is replaced by a full-screen AccountModal with a sidebar (avatar header → section list → logout) and a content pane that swaps between built-in sections (Account, Preferences) and plugin-contributed ones via the new account.section hook point. Plugins declare an icon, label and React component; built-ins and plugin entries merge in a single sorted list.
  • User-selectable avatar source. #169 — pick which connected provider (Plex, Jellyfin, Emby, …) supplies your avatar. The new AvatarEditor surfaces every provider image you're linked to and lets you swap on the fly without touching the file system.
  • Admin-defined custom topbar links. #167 — admins can publish arbitrary URL shortcuts to the home topbar (label, icon, URL, target). Useful for pinning Tautulli, Overseerr, your dashboard, or any service users should reach in one click — without writing a plugin.
  • Admin jump button + tooltip system. A discreet shield/home button now sits in every topbar (admin-gated) for one-click jumps between the user app and the admin panel — replacing the slower path through the avatar dropdown. Backed by a new shared Tooltip component with a 100ms fade (vs the browser's ~1.5s native delay), reused on the avatar cog and the notification bell.
  • Jackett indexer connector. New indexer service category with Jackett as its first member. The connection test uses the public-with-apikey Torznab caps endpoint so it works on Jackett instances locked behind an admin password (where /server/config requires a cookie session). API key passes via query (not X-Api-Key — Jackett doesn't honour that header).
  • Curated icon set expanded. DynamicIcon (used by plugin manifests for nav/admin tabs/widgets) gains 8 new icons: Coins, CreditCard, Gift, Crown, Award, Trophy, Gauge, Rocket — to cover subscription/achievements/stats plugin patterns. Unknown icons now log a one-time dev-mode console warning instead of silently falling back to Puzzle, and the available list is documented in docs/plugins.md.

Fixes

  • qBittorrent connection test no longer 403s. The qBittorrent provider used to hit /api/v2/app/version directly without first authenticating, surfacing a misleading HTTP_FORBIDDEN. It now performs the full /auth/login flow, captures the SID cookie, and reports typed errors on bad creds (AUTH_FAILED), IP ban after too many failed attempts (AUTH_BANNED) or missing session cookie (AUTH_NO_SESSION) instead of the bare HTTP code.
  • Admin-only plugins no longer reachable by URL. Any plugin shipping a frontend field was previously mountable at /p/<id> whether or not it published a nav contribution — admin-only plugins (subscription, qbittorrent-manager…) were therefore reachable by typing the URL even though their data routes were permission-gated. The /p/<id> route now refuses to mount any plugin that hasn't contributed to hookPoint='nav', falling back to plugin.not_found.

New plugin available

Oscarr-Plugin-qBittorrent v0.1.0 ships alongside this release. Discover it via Admin → Plugins → Discover once the registry update lands. Read-only torrent queue + bulk pause/resume/delete + magnet add, with cross-check against Sonarr/Radarr import history so seeds already in the library are flagged for safe cleanup.


Full changelog: v0.7.7...v0.7.8

Upgrading

docker pull ghcr.io/arediss/oscarr:0.7.8

or

docker pull ghcr.io/arediss/oscarr:latest

v0.7.7 — Customisable dashboard, plugin install metrics & live nav refresh

Choose a tag to compare

@Arediss Arediss released this 27 Apr 21:52

Highlights

The admin dashboard becomes customisable per tab and per widget, the Discover tab surfaces install counts, and the nav refreshes live when you toggle a plugin. Plus the usual sweep of fixes for stale badges, broken caches, and stuck "Copy" buttons.

Features

  • Customisable dashboard tabs and widgets. Pick an icon for each tab from a curated 56-icon set. Each widget gets a Pencil edit button in edit mode → custom title, custom icon, or just toggle "show header" to surface the widget's default title. Custom overrides survive drag/resize.
  • Live install count on the Discover tab. Each plugin card now shows the total number of GitHub release-asset downloads next to the star count. GitHub increments the counter on every install — no extra infra. Plugins that ship a source tarball (instead of a Release asset) show 0 since GitHub doesn't track those.
  • Verbose request log toggle. New opt-in toggle in Admin → Système → Instance → Debug that persists every /api/* response to AppLog with method, path, status, redirect Location, duration, IP and User-Agent. Useful for tracing OAuth round-trips or plugin proxy redirects on a live instance. Off by default; URLs and Referer scrubbed via the existing scrubSecrets pipeline.
  • Plugin tab URL sync. Admin → Plugins → Installed / Discover sub-tab now syncs to the URL via ?sub=. Refresh, bookmark or share a link and you land on the right tab.

Fixes

  • Live nav refresh on plugin toggle. Toggling a plugin used to leave its nav entries / dashboard widgets stuck until F5. usePluginUI gains a pub/sub: invalidating the cache notifies every mounted hook so contributions refetch in place. The toggle pill itself shows a spinner with "Enabling…" / "Disabling…" copy while the request is in flight.
  • Stale "update available" badge. After installing a fresh version (say v0.1.2), the badge would still claim "v0.1.1 available" until the 1h cache TTL passed — it compared with latest !== installed instead of strict semver. The check is now latest > installed (semver-aware) AND the cache invalidates on install/uninstall so the badge clears immediately.
  • Update resolver follows /releases when /latest 404s. GitHub returns 404 on /releases/latest when no release is explicitly flagged as latest (some CI workflows skip the flag, plus transient API hiccups). The resolver now falls back to /releases?per_page=30 sorted by semver desc — same logic GitHub uses internally.
  • Bust stale browser caches on version flip. Stale HTML cached for /api/* URLs (from a past misconfig) could load the SPA shell on backend routes and produce blank pages. The SPA fallback now sets Cache-Control: no-store on index.html, and /api/app/version sends Clear-Site-Data: "cache" when the client's oscarr_v cookie doesn't match the running version — Chrome/Firefox/Edge purge their HTTP cache for the site on the spot. Sessions, settings and JWT survive.
  • Logs "Copy" button works on LAN dev. navigator.clipboard requires a secure context (HTTPS or localhost). Dev over a LAN IP had no clipboard, so the button silently failed. New helper falls back to document.execCommand('copy') via a hidden textarea so the copy works on plain HTTP origins.

Schema migration

New boolean column AppSettings.verboseRequestLog (default false). Idempotent on existing rows.


Full changelog: v0.7.6...v0.7.7

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.7.7
```
or
```
docker pull ghcr.io/arediss/oscarr:latest
```

v0.7.5 — Plugin install hotfix (CSP + bind-mount perms)

Choose a tag to compare

@Arediss Arediss released this 26 Apr 00:43

Hotfix

Two prod-blocking bugs uncovered while testing the 0.7.4 plugin install flow against a live self-hosted instance.

Fixes

  • Resolve plugin install URL server-side. 0.7.4 added a frontend fetch() to api.github.com to prefer a Release asset over the GitHub-generated source tarball. The prod CSP blocks api.github.com from connect-src, so the fetch silently failed and the install fell back to the source tarball — same broken end state as 0.7.3 for plugins like kedaewyn/Leonarr that don't commit dist/ to their repo. The resolution now lives backend-side (already trusted with GitHub calls for the update check), so the fix actually applies in prod. The /plugins/install endpoint accepts { repository } from the registry path and a raw { url } for manual installs.

  • Auto-chown the plugins directory at boot. Self-hosters with a host bind-mount for /app/packages/plugins (the docker-compose default) hit EACCES when Oscarr tried to mkdir the staging dir for an install — the host directory wasn't owned by uid 1001 (the in-container oscarr user). The entrypoint now chowns + chmod 2775 (setgid) the plugins dir at boot, the same way it already handles /data. Files dropped by the host maintainer keep the right group and both sides can write.

If GITHUB_TOKEN is set on the Oscarr container's env, the install resolution path uses it — useful if your registry's source is rate-limited.


Full changelog: v0.7.4...v0.7.5

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.7.5
```
or
```
docker pull ghcr.io/arediss/oscarr:latest
```

v0.7.4 — Multi-tab dashboard + plugin install via release assets

Choose a tag to compare

@Arediss Arediss released this 25 Apr 23:43

Highlights

The admin dashboard becomes multi-tab — name them, add new ones, drag your widgets where you want them. And plugin installs finally respect prebuilt release assets, unblocking the plugins that ship a clean source repo with dist/ shipped only on the GitHub Release page.

Features

  • Multi-tab dashboard. The dashboard hosts multiple named tabs above the grid. Add a tab with the + button, double-click a tab to rename, remove the active one in edit mode (the last remaining tab is locked so you're never empty). Widgets stay unique across the whole layout.
  • Reset confirm modal. The Reset-to-default action moved out of the toolbar into a proper a11y-aware modal (Escape, focus-trap, focus-return) and only renders in edit mode where it belongs.

Fixes

  • Plugin install respects release assets. The Discover-tab installer used to hardcode tarball/HEAD — GitHub's auto-generated source archive that omits gitignored build outputs. Plugins that ship dist/ as a Release asset (the recommended pattern) would land an unbuilt tree and fail with Cannot find module .../dist/index.js. Oscarr now resolves the install URL via the GitHub Releases API: the first .tar.gz asset on the latest release wins, with a fallback to tarball/HEAD for plugins that still commit dist/ to their repo.

Docs

  • Plugin release workflow. docs/plugins.md grows a Releasing a plugin section with a copy-paste GitHub Actions workflow that builds, packs and uploads a tarball asset on every v* tag — so future plugin authors land on the asset path by default and stop polluting their git history with built code.

Schema migration

The dashboard layout schema bumps to v2 (tabs). Existing v1 layouts are auto-migrated on the next GET into a single Main tab — the row is only rewritten on the next save. No DB migration required.


Full changelog: v0.7.3...v0.7.4

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.7.4
```
or
```
docker pull ghcr.io/arediss/oscarr:latest
```

v0.7.3 — Composable admin dashboard + plugin install fix

Choose a tag to compare

@Arediss Arediss released this 25 Apr 22:33

Highlights

The admin Dashboard tab is now a composable widget grid: drag-and-drop, three built-in widgets shipped, and plugins can contribute their own via a typed hook point. Plus the plugin install path is fixed for the Docker setups where /tmp and /app live on different filesystems.

Features

  • Composable admin dashboard. A drag-and-drop widget grid replaces the static DashboardTab. Three built-ins ship out of the box: stats counters (users / pending requests / services / plugins), service health (reachability + version per configured service), and system (Oscarr version + plugin update count). The layout is persisted globally per Oscarr instance.
  • Plugin-extensible. Plugins contribute widgets via the new admin.dashboard.widget hook point. A typed Zod sub-schema validates widget props (id, title, icon, defaultSize, minSize, maxSize) at plugin load — malformed manifests are rejected before the widget can reach the dashboard.
  • WYSIWYG edit mode. Editing the dashboard no longer wraps each widget in an extra card with a redundant title. The drag handle and remove button float in the corners with a dashed outline; what you see in edit is what you get in view.

Fixes

  • Plugin install across filesystems. Plugin tarballs used to be staged under os.tmpdir() and then renamed into <pluginsDir>/<id>. In Docker setups where /tmp is a tmpfs mount and /app lives on the persistent volume, fs.rename threw EXDEV ("cross-device link not permitted") and installs failed after a successful download. The installer now stages inside the plugins dir itself (under a hidden name the loader ignores) so the final rename is atomic.

Plugin contract

A new section in docs/plugins.md documents the admin.dashboard.widget hook point — manifest example, props schema, frontend contract.


Full changelog: v0.7.2...v0.7.3

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.7.3
```
or
```
docker pull ghcr.io/arediss/oscarr:latest
```

v0.7.2 — Prisma CLI resolution fix

Choose a tag to compare

@Arediss Arediss released this 25 Apr 18:49

Hotfix

Quick follow-up to v0.7.1 — the boot-time `prisma migrate deploy` was using a hardcoded path that worked in the prod image but failed in dev, since npm workspaces hoist the prisma binary to the monorepo root in dev (no packages/backend/node_modules/.bin/prisma).

Fix

  • ensureMigrated now resolves the prisma CLI via Node's module resolution (require.resolve('prisma/package.json') + pkg.bin) instead of a hardcoded path. Works in both setups:
    • Dev (npm workspaces): finds prisma in <root>/node_modules/prisma
    • Prod image: finds prisma in packages/backend/node_modules/prisma
  • No npx dependency reintroduced — the prod image stays free of npm/yarn/corepack.

Production deploys of v0.7.1 weren't affected (the old hardcoded path matched the prod layout). This release future-proofs against any layout change.


Full changelog: v0.7.1...v0.7.2

Upgrading

```
docker pull ghcr.io/arediss/oscarr:0.7.2
```
or
```
docker pull ghcr.io/arediss/oscarr:latest
```