Skip to content

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 24 Jul 02:20
· 114 commits to main since this release

A reliability release: no download can appear stuck as "downloading" forever
anymore, and imports now survive crashes, power loss, and restarts.

Fixed

  • Every permanently-stuck "downloading" state is gone. The three ways a grab
    could wedge forever are each fixed or surfaced honestly:
    • A torrent removed from the download client out-of-band is now reconciled:
      after a 5-minute grace period the grab fails and the episode reverts to
      wanted (this closes the known limitation from 0.1.0).
    • A deferred batch/season-pack grab now shows a distinct deferred status
      instead of "downloading" forever. It stays honest — the bytes are on disk
      and seeding — and manually grabbing a single-episode release replaces the
      deferred grab cleanly.
    • An import that keeps failing (a qBittorrent path-mapping gap, library
      permissions, disk full) now surfaces as stuck, with the actual error
      shown on the grab, instead of retrying silently with the reason visible
      only in the logs.
  • Folder-wrapped downloads now import. A single-episode torrent that
    delivers a directory payload is resolved to its one episode file at
    completion time; import_deferred is reserved for payloads that genuinely
    can't be disambiguated (real batches).
  • Imports are crash-safe. Durability and shutdown ordering across the whole
    import path:
    • Copy-mode imports fsync the file before renaming it into the library —
      previously a power loss could land the rename before the data, leaving a
      truncated episode that was treated as already-imported forever.
    • Hardlink-mode imports fsync the linked inode (and directory entry) before
      the grab settles, closing the same window.
    • Truncated files left in the library by past crashes are detected and
      reclaimed for re-import instead of being invisible.
    • Graceful shutdown now waits for the importer: the store can no longer close
      mid-import, in-flight multi-GB copies abort promptly within the shutdown
      budget, and a completed Place always gets its have/status writes.
  • API failures in the web UI render as error states with retry, not as
    misleading empty states ("No titles found" after a rate-limited AniList
    search). Abandoned searches are now aborted instead of left running, and an
    untrimmed search cache key no longer causes duplicate AniList queries.
  • Expired sessions are swept on a daily ticker, not only at startup, so
    long-lived instances no longer accumulate expired session rows.

Security

  • Rate-limited the change-password endpoint (POST /api/v1/auth/password).
    It verifies the current password but was not throttled, so repeated wrong
    guesses were unmetered. This matters most under TRANSPONDARR_AUTH_REQUIRED=local,
    where any loopback/private-network client is admitted without a credential: the
    endpoint was an unauthenticated password-guessing oracle for anyone on the LAN.
    In the default enabled mode a valid session was already required, so there it
    is re-authentication hygiene. Unmetered argon2id verification was also a cheap
    CPU/memory exhaustion lever. Login and change-password now share a single
    per-client bucket (5 attempts per 15 minutes) rather than getting one each,
    since both verify the same admin password.