Remember announced items so re-created ones aren't new (1.5.0) #11

Merged
joeyr merged 1 commit from feat/remember-announced into main 2026-10-05 21:03:19 -05:00
Owner

The newsletter now remembers what it has announced. "New" used to mean only "created in Jellyfin during the period", and Jellyfin re-creates an item on every Radarr/Sonarr rename or upgrade, so old films came back by the hundred (716 in the last preview).

  • internal/announced (new): ANNOUNCED_ITEMS.json beside config.yml. Movies are keyed by TMDB ID (title and year without one), so each film is announced once and a 4K copy isn't new. Episodes are keyed by series plus SxxEyy. FilterSeries drops announced episodes, then empty seasons and series, and clears the "whole new season/show" flags when it removed any. The file is written through a rename.
  • newsletter.go: newItems filters the window's candidates; a send (partial included) records what went out; a dry run never writes. PrepareAnnounced, called from main at startup, records the whole library when there is no file, so the baseline is taken at deploy time.
  • jellyfin: GetMoviesAddedAfter / GetSeriesAddedAfter split out of the existing queries (the zero time returns everything).
  • Tests: keys, filtering (a re-created film, a 4K copy in the same run, a partly announced season, a new season, a genuinely new show), save/load, and an end-to-end flow with a fake Jellyfin and real dry-run output. That flow test fails without the filter (4 movies instead of 1).
  • Live check: an 18 s baseline of 826 movies and 12,055 episodes (316 KB), then nothing new where 1.4.1 found 716; a dry run left the file unchanged.
  • VERSION 1.5.0, CHANGELOG, CLAUDE.md (the planned-work list is now empty).

🤖 Generated with Claude Code

The newsletter now remembers what it has announced. "New" used to mean only "created in Jellyfin during the period", and Jellyfin re-creates an item on every Radarr/Sonarr rename or upgrade, so old films came back by the hundred (716 in the last preview). - `internal/announced` (new): `ANNOUNCED_ITEMS.json` beside `config.yml`. Movies are keyed by TMDB ID (title and year without one), so each film is announced once and a 4K copy isn't new. Episodes are keyed by series plus `SxxEyy`. `FilterSeries` drops announced episodes, then empty seasons and series, and clears the "whole new season/show" flags when it removed any. The file is written through a rename. - `newsletter.go`: `newItems` filters the window's candidates; a send (partial included) records what went out; a dry run never writes. `PrepareAnnounced`, called from `main` at startup, records the whole library when there is no file, so the baseline is taken at deploy time. - `jellyfin`: `GetMoviesAddedAfter` / `GetSeriesAddedAfter` split out of the existing queries (the zero time returns everything). - Tests: keys, filtering (a re-created film, a 4K copy in the same run, a partly announced season, a new season, a genuinely new show), save/load, and an end-to-end flow with a fake Jellyfin and real dry-run output. That flow test fails without the filter (4 movies instead of 1). - Live check: an 18 s baseline of 826 movies and 12,055 episodes (316 KB), then nothing new where 1.4.1 found 716; a dry run left the file unchanged. - VERSION 1.5.0, CHANGELOG, CLAUDE.md (the planned-work list is now empty). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Remember announced items so re-created ones aren't new (1.5.0)
All checks were successful
CI / gate (pull_request) Successful in 1m3s
CI / lint (pull_request) Successful in 57s
CI / image (pull_request) Has been skipped
c5092d8388
"New" meant only "DateCreated in the period". Jellyfin re-creates an
item whenever Radarr or Sonarr renames or upgrades it, so old films came
back as new by the hundred: 716 movies in the 2026-10-05 preview.

internal/announced keeps ANNOUNCED_ITEMS.json beside config.yml, keyed
by what an item is rather than by Jellyfin IDs: movies by TMDB ID (title
and year without one), so each film is announced once and a 4K copy
isn't new; episodes by series key plus SxxEyy (an unnumbered episode adds
its name). FilterSeries drops announced episodes and then empty seasons
and series, and clears IsSeasonNew/IsSeriesNew when it removed any, so a
show with one genuinely new episode reads "Season 2, Episode 10" rather
than as a whole new show. The file is written through a rename.

newItems filters the window's candidates; runOnce records what it sent,
a partial send included, and a dry run reads the file but never writes
it. With no file, PrepareAnnounced (called by main at startup) records
the whole library, via the new GetMoviesAddedAfter and
GetSeriesAddedAfter with the zero time, so the baseline is taken at
deploy time. A run that still finds no file takes it then and announces
nothing.

Checked against the real server: the baseline took 18 s for 826 movies
and 12,055 episodes (316 KB), the run after it found nothing new where
1.4.1 found 716, and a dry run left the file unchanged. The flow test
fails without the filter with 4 movies instead of 1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
joeyr merged commit 96d45c9c92 into main 2026-10-05 21:03:19 -05:00
joeyr deleted branch feat/remember-announced 2026-10-05 21:03:19 -05:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
joeyr/jellyfin-newsletter!11
No description provided.