github theantipopau/slimarr v2.0.0.0
Slimarr - v2.0.0.0

5 hours ago

Slimarr 2.0.0.0 Release Notes

Release date: 2026-09-03
Theme: Discovery & Recommendations, full backend audit, GitHub-reported fixes

Standalone release summary: docs/UPGRADE_NOTES_2.0.0.md

A full backend/frontend audit against the actual implementation (not README
claims), a competitive gap analysis against mature *arr platforms, two
confirmed correctness fixes, and a new deterministic Discovery &
Recommendations
feature.

  • New: Discovery & Recommendations. Slimarr can now suggest titles
    related to what you already own - missing collection entries, sequels/
    prequels, and related titles - scored deterministically with a
    transparent, human-readable reason for every suggestion. Off by default
    (recommendations.enabled: false). See docs/RECOMMENDATION_ARCHITECTURE.md.
  • New: region-specific streaming availability. Looked up per-title via
    TMDB's own /watch/providers endpoint only - no streaming service is
    scraped or asked for credentials, and availability is timestamped and
    treated as stale after 24 hours rather than shown as current indefinitely.
  • New: explicit hand-off to Radarr/Sonarr from Discovery. Sending a
    recommendation to Radarr or Sonarr requires you to confirm the root
    folder and quality profile; it's a separate, explicit action, never an
    automatic one, and duplicate-checked against the live instance first.
    Seerr hand-off is intentionally not implemented this release - see
    docs/RECOMMENDATION_INTEGRATIONS.md for the capability-detection
    rationale.
  • New: optional, provider-neutral AI reranking abstraction (disabled by
    default, no provider shipped enabled). It can only rerank a candidate
    list Slimarr already sourced or produce short explanations - it cannot
    invent titles or availability, cannot see your Plex token, file paths, or
    more watch history than explicitly opted in, and cannot trigger a
    download. Every AI-returned ID is re-validated against TMDB before
    display.
  • Fixed: auto_cleanup_old_orphans() deleted its tracking row before
    confirming the underlying file removal actually succeeded, so a failed
    cleanup could silently lose track of an orphaned download. It now checks
    the removal outcome first and only clears the row on confirmed success.
  • Fixed: SABnzbd connection-test and job-purge error paths could log an
    API key embedded in a request URL inside an exception message. Errors are
    now redacted before logging, matching the existing redaction behavior
    used elsewhere in the codebase.
  • Fixed: a storage path containing an embedded .. segment (e.g.
    /mnt/local/../nas/movies) could evade NAS-prefix classification,
    skipping budget/throttle/cooldown protection entirely. Paths are now
    collapsed before classification.
  • Fixed: on a case-sensitive filesystem (Linux/most Docker/NAS-via-NFS),
    path classification lowercased unconditionally, which could cause a false
    NAS match or a false miss depending on how nas_path_prefixes was cased.
    Case is now only folded on Windows.
  • Fixed: if a cross-device NAS copy's final source-file cleanup failed
    after the copy itself had already succeeded, the whole move was reported
    as failed even though the target had a complete, correct copy - leaving
    a duplicate and a misleading status. It's now reported as completed with
    an explicit warning instead.
  • Fixed: the image-proxy endpoint could leak a raw exception (including
    local filesystem paths) to any client on a cache-fetch failure; it's now
    logged server-side only.
  • Fixed: a job's event timeline had no upper bound, so a job retried
    many times returned an ever-growing array from GET /jobs/{id}. Capped
    to the most recent 200 events.
  • TMDB, Radarr, and Sonarr's original API methods now reuse the app's
    pooled HTTP client instead of opening a new connection per call (Radarr/
    Sonarr only when the instance's own TLS-verification setting agrees with
    the shared client's, so a self-signed-cert setup is never silently
    affected).
  • Two low-severity silent-failure spots (/metrics DB query, diagnostics
    bundle NAS summary) now leave a debug-level trace instead of swallowing
    the exception entirely.
  • New: send a recommendation straight to Radarr/Sonarr from Discovery.
    A hand-off modal fetches the target instance's root folders and quality
    profiles live, lets you pick monitored/search-now, and calls the
    existing (previously unreachable from the UI) send-to-radarr/sonarr
    endpoints - closing the biggest functional gap in the initial Discovery
    ship, where this control was a non-interactive placeholder.
  • New: pagination and a streaming-provider filter on the Discovery page.
    The list endpoint always supported page/per_page and a provider_id
    filter, but the page fetched one fixed batch of 60 with no way to reach
    anything past it, and the provider filter had no UI at all. A "Load more"
    control and a provider dropdown (backed by a new
    GET /recommendations/providers) close both gaps.
  • Discovery UI polish: an "Open on TMDB" link and TMDB-attributed
    availability chips on every card, a "Copy TMDB ID" action, and a full
    Discovery & Recommendations configuration section in Settings.
  • Fixed (GitHub issue #1): the NAS write-budget reservation charged a
    same-directory rename (backup_existing_target's metadata-only,
    zero-byte os.rename()) at full file size, since it only checked whether
    the target classified as NAS/network rather than whether source and
    target were on the same device. On the reporter's production instance
    this exhausted a 300GB/day budget on phantom writes alone, then blocked
    genuine replacements and discarded already-downloaded releases. Now
    skipped whenever _same_storage_device() is true.
  • Fixed: a NAS failure cooldown was purely in-process, so a restart
    right after a failure silently dropped it and let the next replacement
    hit the same failing share immediately. Now restored from
    StoragePathHealth on startup.
  • Fixed: the duplicate-cleanup recycle path mkdir'd onto its
    destination without preflighting it first; a misconfigured or
    unreachable recycling-bin share is now checked before use, falling back
    to skip-and-retry-next-scan instead of a permanent delete.
  • Fixed (GitHub issue #2): GHCR images weren't publishing for latest
    or any tagged version - CI's lint and test jobs were failing outright
    (a missing pytest.ini plus 88 ruff findings), so the jobs that actually
    push to GHCR never ran. Also fixed a latent race in the multi-arch Docker
    build where the per-platform matrix job pushed directly to the same tags
    as the manifest-merge job, letting linux/amd64 and linux/arm64 builds
    overwrite each other under latest.
  • Fixed: a cross-device directory move onto a NAS/network target fell
    through to a plain, unthrottled shutil.move() with no rate limit and no
    budget accounting - the one path that bypassed every NAS safety control
    this module exists to provide. Nothing in this release triggers it
    (movies are single-file), so it now refuses loudly instead of moving the
    bytes unsafely; a same-device directory move is unaffected.
  • Fixed: marking a recommendation as already-owned could be silently
    reverted by the next refresh if the correlation check still couldn't see
    it as owned (physical media, an unscanned library) - that state is now
    protected the same way dismiss/hide/watchlist already were.
  • Fixed: genres_include/genres_exclude filtering was permanently
    dead code - sourced candidates always got an empty genre tuple, since
    TMDB's collection/recommendations/similar payloads only carry numeric
    genre IDs, never names, and nothing resolved them against TMDB's genre
    list. Now resolved via a genre map fetched once per refresh.
  • Fixed: a recommendation that dropped below minimum_score on a later
    refresh was left frozen at its old score forever instead of expiring.
  • Fixed: GET /recommendations's provider_id filter ran in Python
    after pagination and after total was computed from an unfiltered count,
    so a page could come back empty (or split matches across pages) while
    total still reported the unfiltered figure. Filtering now happens at
    the SQL level before pagination.
  • Fixed: the same endpoint's Plex-ownership check ran two SELECT count(*) queries per returned row; replaced with one batched lookup.
  • Fixed: a transient Windows file lock (e.g. Plex or an AV scanner
    briefly holding a just-created file) during post-replacement cleanup
    could permanently orphan the old file, since that cleanup step runs
    once and nothing else ever retries it. Given the same retry the
    move-into-place step already had.
  • Full audit findings: docs/BACKEND_AND_RECOMMENDATIONS_AUDIT.md.
    Competitive analysis: docs/ARR_PLATFORM_GAP_ANALYSIS.md.

Upgrading

No existing config key or database column changes meaning or shape - see
docs/UPGRADE_NOTES_2.0.0.md for the full standalone upgrade note. The new
recommendations: config block defaults to enabled: false, so nothing
changes on upgrade until you turn it on in Settings.

Windows installer

Download SlimarrSetup-2.0.0.0.exe below and run it - per-user install, no
admin rights required.

Don't miss a new slimarr release

NewReleases is sending notifications on new releases.