Tags

Tags give the ability to mark specific points in history as being important
  • v1.9.2

    protected
    v1.9.2 — hygiene sweep + iPhone PWA safe-area (correcting v1.9.1, which was tagged on a stale local main and shipped the v1.9.0 tree; per policy the bad tag stays, this tag points at the intended hygiene merge, deliberately excluding the Stage 2 merge pending the Aug 5 data checkpoint)
  • v1.9.1

    protected
    v1.9.1 — hygiene sweep + iPhone PWA safe-area hardening
    
    Safe-area insets for viewport-fit=cover, defensive overflow containers,
    [WEB LOG] double-print removed, mark.log rotation, Seerr (type,title)
    keying + pagination hardening, SSL_BYPASS across all HTTP sessions,
    Plex shared-user timeout, dead-code sweep.
  • v1.9.0

    protected
    v1.9.0 — web auth (C5) and Stage 1: the DB is the web layer's single source of truth
    
    Session auth on every route and the log websocket, fail-closed without
    FERRET_WEB_PASSWORD. Dashboard renders the real deletion queue from
    cleanup.db with live countdowns, the deletion audit trail, incomplete-scan
    banner, and honest labels for matched-this-scan vs in-queue. Kills the
    in-memory cleanup_results dual state, unifies CLEANUP_DB_PATH resolution,
    adds busy_timeout, exclusion match feedback, stall re-alerting, and
    versioned static assets with cache headers.
  • v1.8.0

    protected
    v1.8.0 — Phase 0 deletion-safety fixes
    
    Ships the pre-Aug-18 items from the 2026-08-03 audit: degraded-scan guard
    for all three server types plus a scan-size drop check (C1), warning sends
    confirmed before marking sent with full chunked title lists (C2/H7), year
    in the flag key with an in-place migration (C3), resurrected flags start
    fresh countdowns (H2), pre-delete exclusion re-check (H3), fail-safe
    dry-run parsing (H4), provider-id contradiction veto and stall routing for
    year mismatches (H8/C4), empty-mount refusal (M3), and a per-cycle
    effective-config log line with per-key sources (H1).
  • v1.7.0

    protected
    v1.7.0 — settle deletions no *arr owns
    
    Deletions for items absent from Radarr/Sonarr no longer retry forever.
    Presence is probed with three states (present/absent/unknown); disk
    checking is opt-in via CLEANUP_MEDIA_PATH_MAP, so an unconfigured
    deployment never concludes a file is gone.
  • v1.6.1

    protected
    v1.6.1 — the stuck-deletion alert stops repeating
    
    The alert shipped in v1.2.0 re-sent every cleanup cycle — hourly, indefinitely —
    and reported rows the scan no longer flags. 19 identical messages about one
    movie whose underlying metadata had already been corrected.
    
    Now fires once per item, and only for items the current scan actually flagged.
  • v1.6.0

    protected
    v1.6.0 — episode identity includes season/episode number
    
    Also the version prod gets pinned to, so that `dockerUpdateAll` stops shipping
    every main merge straight to production. The container was running :latest, which
    CI rebuilds on every merge, which made the tag gate meaningless for Ferret.
  • v1.5.0

    protected
    v1.5.0 — deletions resolve by provider id, not by title
    
    The stuck "Falling" deletion was not Ferret being confused about a movie Radarr
    lacks — Radarr had it. Jellyfin had "Fallen (2006)" (tmdb 50126) catalogued under
    the title "Falling", so the Radarr lookup found nothing. And Radarr holds two
    films called "Fallen", so even the correct title would have been ambiguous.
    
    The resolver now tries tmdb, then imdb, then tvdb before falling back to
    title+year. Those ids were already collected for cross-server identity matching
    in v1.1.0; they just never reached the deletion path.
  • v1.4.0

    protected
    v1.4.0 — sync stops un-marking watched episodes
    
      - The Jellyfin/Emby episode write path could reset a FINISHED episode to
        unwatched with a resume position, because the Series/Episodes queries lack
        the isPlayed=false filter the movie path has. Sync is additive; it never
        un-marks.
      - Series folders stopped matching across servers: path_suffix's two-component
        rule is right for episode files but a series folder's parent IS the library
        root, which is what differs between servers. Every show whose libraries are
        named differently synced no episodes at all.
      - Watch state was merged into the local picture before the write was known to
        have succeeded, so a failed write made the next server pair skip those items
        as "already synced".
    
    First test coverage for functions.py series handling, jellyfin_emby.py writes
    and main.py ordering — the files carrying all three.
  • v1.3.0

    protected
    v1.3.0 — the deletion guard now measures what it was supposed to
    
    Two more paths where the engine concluded "never watched" from data it never
    had, both data loss:
    
      - The guard compared collected data against CONNECTED servers, not configured
        ones. generate_server_connections returns the survivors of a connection
        failure, so an unreachable Plex produced "1/1 returned data — complete" and
        everything watched only on Plex became deletable.
      - Partial failures inside a server (a dropped shared user, a library that
        would not open) hid watch history while the scan still counted as complete.
    
    Cleanup thresholds are also validated now. CLEANUP_DELETE_AFTER_DAYS=0 meant
    flag and delete in the same scan; MAX_AGE=0 flagged the entire library. Both
    were accepted from the settings API while SLEEP_DURATION beside them was
    bounds-checked.
  • v1.2.0

    protected
    v1.2.0 — a stuck deletion stops being invisible
    
    An item that cannot be resolved to a single Radarr/Sonarr entry is refused,
    correctly, but was then refused again every hour forever with no counter, no
    alert and no dashboard surface. One movie sat eight days past its deletion date
    looking perfectly healthy.
    
    Failures are now counted per item with their reason, and escalate after three
    consecutive misses. The audit trail is written per deletion rather than batched,
    so a crash mid-batch can no longer leave media deleted with no record of it.
  • v1.1.0

    protected
    v1.1.0 — the cleanup engine stops deleting media people have watched
    
    Six independent paths could answer "nobody watched this" when somebody had, and
    each ended in an irreversible file delete.
    
      - Cross-server identity: the merge keyed on the raw title string, so Plex's
        "Star Wars: The Mandalorian and Grogu" and Jellyfin's "The Mandalorian and
        Grogu" were two records — one holding every watch, one holding none. Now
        matched on tmdb/imdb/tvdb ids, which Jellyfin was already fetching and
        discarding.
      - Watched-with-no-play-date counted as never watched.
      - A missing Overseerr request date skipped the grace period entirely.
      - A lone *arr title match was accepted without comparing years, so the wrong
        film could be deleted.
      - "Requested & Unwatched Shows" could never fire ("tv" vs "show").
      - Exclusions checked only one server's spelling, a config seed silently
        destroyed user-added protections, and legacy wildcards were dead rules.
    
    CLEANUP_EXCLUDE_CONTINUING was also a no-op for Plex shows: plexapi reports no
    status, so the engine now treats it as unknown and declines to delete a series
    it cannot confirm has ended.
  • v0.1.0

    protected
    v0.1.0 — first release on GitLab CI/CD (lint+lockfile+audit+build+scan+deploy)