Skip to content

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 01 Aug 18:06
· 73 commits to main since this release

Monitoring and scheduled search: the release where the monitored flag starts
doing real work. Add a series, touch nothing, and episodes arrive β€” searched on
a broadcast-aware cadence, graded against your quality profile, grabbed,
imported, and remembered when they fail. Automation ships off by default;
enable it under Settings β†’ Automation.

Added

  • Scheduled search sweep. A wanted-search job periodically searches
    monitored series with outstanding wanted items once their episodes have aired
    (an unknown air date counts as searchable β€” absence is normal, not an error),
    runs the same match-and-score path as manual search, and grabs only a fully
    eligible release: matched, clear of excludes, over the profile floor. No
    eligible candidate means grab nothing β€” "nothing yet" is a correct outcome.
    Empty passes back off exponentially from an hour toward a day, clamped so a
    weekly show is still searched at broadcast however many empty passes came
    before; a new episode airing resets the clock, and integration edits in
    Settings apply on the next pass without a restart.
  • Recent-feed polling. The sweep costs one indexer query per series, so its
    interval must be long; the Torznab recent feed inverts that β€” one request
    returns the newest releases across the endpoint, matched against everything
    wanted at once. The feed is the hot path, polled on a short interval, and the
    sweep becomes the safety net. A new release for a wanted, aired episode is
    grabbed on the next poll, not the next sweep. An indexer without a feed
    degrades to sweep-only as a supported configuration, and a quiet poll costs
    one request.
  • A pinned group can now mean "wait for," not just "win when present." The
    sweep holds another group's release for a delay window measured from the
    episode's broadcast, so the pinned group's slower release gets its chance
    before automation settles. Global default plus a per-series override; a
    manual grab is never held.
  • Automation controls. A global auto-search toggle and the default pin
    delay, persisted and editable live in Settings β†’ Automation β€” flipping the
    switch takes effect at the next tick, off or on, without a restart. Off
    until you enable it, deliberately: an install that has never configured an
    indexer must not start grabbing on its own. A monitored series page says so
    when automation is globally off, since monitored now means "will be grabbed
    automatically," not just "appears on the calendar."
  • Failure memory: a release that fails is not chosen again. The sweep's
    determinism made its own bug β€” a failed download reverted its item to wanted,
    the next pass re-derived the same ranking, and the same release won forever.
    Failed releases are now blocklisted per series with an escalating expiry
    (24 hours, then 7 days, then permanent): repeat failure of the same release
    is the only signal separating a dead release from a bad day, so first
    failures stay recoverable while a proven-dead release converges to permanent.
    Identity is info hash and normalized title, because Torznab feeds often
    omit the hash. Automation degrades to the next-best eligible release;
    blocked releases appear in the series History tab with the reason, an
    unblock, and bulk clear actions β€” and a manual grab is never refused and
    never leaves a block behind.
  • An environmental-fault breaker guards the failure memory itself. A full
    disk or a client reaping torrents fails a different release every pass β€”
    the escalation ladder never triggers, and the candidate pool drains into the
    blocklist one entry at a time. Failures across distinct items library-wide
    now trip a breaker that suppresses recording (never grabbing) until the
    window passes; Settings says so in words, and clearing the library blocklist
    also closes the breaker so a fixed fault doesn't wait out its window.
    Refused adds are remembered too, when the client can attribute the failure
    to the release itself β€” an unreachable client blocklists nothing.
  • Background jobs status in Settings. Each runner job's last run, duration,
    and last error (styled as one), refreshed live β€” "did automation actually
    run, and did it fail?" no longer requires reading server logs.
  • Season packs are matched honestly, and automation declines them. Packs
    previously surfaced as unmatched with a reason; they now match their items
    and are declined by automation with an explicit ineligible reason instead β€”
    the importer can only defer a multi-episode payload, and unattended grabbing
    must not volunteer for a state it cannot finish. A manual grab of a pack
    still succeeds, landing in the deferred flow as before. Per-file batch
    import is tracked for a later release.

Fixed

  • Search terms with unicode punctuation found nothing. AniList titles carry
    typography that never appears in release names (Γ—, β˜†, ・), so a
    HUNTERΓ—HUNTER-class title searched verbatim died before matching ever ran β€”
    and unattended search would have inherited the silence. Queries are now
    sanitized (Γ— β†’ x, separators to spaces), zero results fall back to the
    English then native title variants, and matching transliterates instead of
    deleting, so the romaji variant matches real releases on its own.
  • Dual-titled scene releases misparsed the alternate title as the release
    group.
    The trailing (Romaji Title, Multi-Audio, Multi-Subs) parenthetical
    became the group, so group ranking, blocking, and pinning silently never
    applied to a whole common release family. An implausible group is now
    distrusted and the real scene group recovered from the codec-dash pattern.
    The same family's no-episode-title variant also lost its source and codec to
    a misfiled tag run; both now survive.
  • Saving any Settings section no longer blanks the Authentication card. The
    section writers returned a settings body without the auth block and the UI
    cached it whole; all writers now share one complete response.

Internal

  • Search, decide, and grab moved into one core package (internal/core/ acquire), shared by the manual routes, the sweep, and the feed poll β€” one
    matcher, one eligibility path, three entry points. Recording a grab is now a
    single transaction per release, so a multi-episode grab can no longer be
    half-recorded by a mid-write failure.
  • Per-series search cadence lives in the store (last searched, backoff,
    next due) with an epoch guard so a reset landing mid-sweep β€” a series
    growing, or being re-monitored β€” beats the sweep's stale write.
  • The recent-feed capability is a type assertion, not a wider interface,
    per the repo's optional-capability rule: an indexer that lacks it is a
    supported configuration, and decorators forward it only when the inner
    source really has one.