230 Commits

Author SHA1 Message Date
Tom Wheeler
67b813988e perf(letterboxd): reduce Playwright usage and parallelise TMDB resolution
searches TMDB API first, if no exact match found then grabs TMDB ID from individual page with
playwright
2026-03-17 21:00:33 +13:00
Tom Wheeler
199841f3ae fix(placeholders): placeholder filters blocking creation when grab missing items was not enabled
fix #509
2026-03-17 19:43:59 +13:00
Tom Wheeler
c2f11799cf fix(imdb-letterboxd): use Playwright clients in random list and title validation for IMDb/Letterboxd
fix #475
2026-03-17 19:35:50 +13:00
Tom Wheeler
78842cd050 fix(tmdb-collections): respect language setting for TMDB franchise collections
fix #487
2026-03-03 23:51:32 +13:00
Sean Bingham
4a4e1d85c1
fix(cleanup): prevent auto-franchise collections from being deleted when custom sync is enabled (#470)
Updated 'CollectionCleanupService' so deletion checks look at all Agregarr labels on a collection, instead of only the first one.
2026-02-23 09:58:22 +13:00
Sean Bingham
069e58c174
fix(coming-soon): makes hideIndividualItems work for Coming Soon collections (#469)
* - Updated `hideIndividualItems` description in settings to clarify support for both Coming Soon and TMDB auto_franchise collections.
- Improved `ComingSoonCollectionSync` to filter items based on media type and apply collection exclusions.
- Added logic to set collection mode when `hideIndividualItems` is enabled, ensuring individual items are hidden in the library tab.
- Adjusted UI components to reflect changes in collection mode options for TMDB and Coming Soon collections.

* fix(comingsoon): guard missingItems before quick-sync storage
2026-02-20 13:25:41 +13:00
bitr8
77c5a91139
fix(Placeholders): Scan all placeholder-enabled libraries, not just the first (#467)
.find() only returned the first TV/movie library with placeholders
enabled, silently skipping any additional libraries. Replace with
.filter() + Set to discover and process placeholders across all
libraries.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-20 13:24:37 +13:00
bitr8
63b8851a1a
fix(Placeholders): Separate placeholder filters independent of auto-request filters (#456)
* feat: separate placeholder filters independent of auto-request filters

Add placeholderMinimumYear, placeholderMinimumImdbRating,
placeholderMinimumRottenTomatoesRating,
placeholderMinimumRottenTomatoesAudienceRating, and
placeholderFilterSettings to CollectionConfig and
MultiSourceCollectionConfig.

buildPlaceholderFilterConfig() helper swaps placeholder values into
standard filter fields so MissingItemFilterService works unchanged.
Updated BaseCollectionSync and MultiSourceOrchestrator call sites.

Collapsible "Placeholder Filters" section in collection edit form
reuses FilterWithMode/KeywordFilterWithMode. Auto-expands when
editing configs with existing values.

Fixed pre-existing gap: keywords missing from
MultiSourceCollectionConfig.filterSettings type.

---------

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
Co-authored-by: Tom Wheeler <thomas.wheeler.tcw@gmail.com>
2026-02-20 13:22:44 +13:00
bitr8
e0470bcb0a
fix: pass rating filters and seasonGrabOrder to multi-source collections (#459)
Multi-source config assembly was missing minimumImdbRating,
minimumRottenTomatoesRating, minimumRottenTomatoesAudienceRating,
and seasonGrabOrder. Items below the rating threshold were not
being filtered for multi-source collections.

re #440

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-13 08:50:21 +13:00
bitr8
87087cbb6c
fix: re-apply placeholder markers during global discovery (#453)
Movie placeholder labels were only re-applied by Coming Soon collections,
so movies in other collection types (Letterboxd, IMDB, Trakt, etc.) could
permanently leak into filtered hubs if the initial label application failed.

TV placeholder title fixes returned false on timeout but the result was
never checked, giving no visibility into failures.

- Re-apply trailer-placeholder label for all movie placeholders during
  global discovery pass
- Log warnings when episode title or movie label application fails
- Track failure counts in discovery summary logs

Relates to #414

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-13 08:40:35 +13:00
bitr8
a6e3e017bd
fix(collections): use correct Plex API endpoint for collection title updates (#444)
Collections require the /library/sections/{id}/all?type=18 endpoint for
metadata updates, not /library/metadata/{ratingKey}. This fixes dynamic
cycle titles (DYNAMIC_CYCLE_TITLE) not updating in Plex after first sync.

- Add libraryKey parameter to updateCollectionTitle()
- Use correct Plex API endpoint for collection metadata updates
- Lock title field to prevent Plex overwriting
- Propagate errors instead of swallowing them

Fixes #432

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-13 08:37:58 +13:00
bitr8
ecda35507c
fix(filtered-hub): use episode air date for TV recently released (#450)
originallyAvailableAt on type=2 (shows) returns the show's premiere
date, not the latest episode's air date. A show like The Rookie
(premiered 2018) wouldn't appear even with new episodes airing.

Changed to episode.originallyAvailableAt:desc which sorts shows by
their most recent episode's air date.

Fixes #442

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-08 21:30:05 +13:00
bitr8
bf569aea54
fix: use searchPerson API for person spotlight TMDB disambiguation (#452)
searchMulti returns all media types without known_for_department,
causing wrong person selection when names collide (e.g., actor
"Ingmar Bergman" chosen over the director). Switch to searchPerson
and rank results by department match, profile image, then popularity.

Relates to #443

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-08 21:29:44 +13:00
bitr8
968d4246f5
fix(letterboxd): resolve letterboxd items via film page TMDB links (#454)
Letterboxd film pages embed exact TMDB links (data-track-action="TMDb"),
but the current resolution relies entirely on fuzzy title+year search.
Short or common titles like "Columbus", "Flow", and "Moonlight" frequently
resolve to wrong results because the scoring gives near-identical scores
to partial title matches and off-by-one year differences.

This adds film page scraping as the primary resolution method, with the
existing TMDB search as fallback.

- Scrape individual film pages for TMDB ID before attempting title search
- Batch scraping with concurrency limit (5 concurrent, 200ms delay)
- Containment scoring now scales by title length ratio instead of flat 0.9
- Year scoring: exact match 0.3, +/-1 year 0.2 (was 0.3 for both)

Fixes #448

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-02-08 21:03:00 +13:00
Ryan Brothers
3668ec2931
feat(collections): Add custom TMDB Collection Builder (#416)
Collections can now be created using the TMDB Discover Movie/TV endpoint, allowing for complex filters to create custom collections. Includes custom builder with dropdowns and search fields.
---------

Co-authored-by: Tom Wheeler <thomas.wheeler.tcw@gmail.com>
2026-02-02 16:18:20 +13:00
Tom Wheeler
5745991f46 feat(missing-items): tMDB Keyword added to allow for more advanced filtering
such as christmas, seasonal movies

fix #256
2026-02-02 01:42:25 +13:00
Tom Wheeler
a02e5475f0 feat(coming-soon): coming soon collections can now be filtered by Radarr/Sonarr server and tags
fix #406, fix #411
2026-01-30 21:27:52 +13:00
Tom Wheeler
84db0e23c2 feat(collections): items that fall off collections now have a label 'agregarr-stale' added
includes check after each collection is processed to handle items existing in multiple collections

fix #384
2026-01-29 19:29:20 +13:00
Tom Wheeler
627eb99fae fix(radarr-sonarr): show auto-generated tag in collection config 2026-01-29 18:54:40 +13:00
Tom Wheeler
a87ab2557d feat(radarr-sonarr): add option to tag existing media
previously only missing items could have tags added, a new option in radarr/sonarr settings allows
the addition of tags to existing media, using the existing tags used in missing items. also extracts
and refactors tagging functions to remove duplication.

fix #248
2026-01-29 17:27:26 +13:00
Tom Wheeler
afd53297c0 chore(tvdb): add tvdb id extraction for future implementation. also extract some shared functions 2026-01-29 15:09:46 +13:00
Tom Wheeler
b510fdc9f2 fix(multi-source): fixes collection title not updating when changed
fix #425
2026-01-29 11:14:43 +13:00
Tom Wheeler
9b0d319102 feat(tautulli): add 'Most Watched' collection by Play Count or Watch Duration
fix #426
2026-01-29 10:52:34 +13:00
Tom Wheeler
eb22483553 fix(cleanup): prevent auto franchise collections from being deleted during full sync
when custom sync was enabled. repliactes same method used for overseerr individual requests, which
are also identified by label since it is a 'one config multiple collections' type
2026-01-29 10:16:31 +13:00
Tom Wheeler
9016bd98f3 fix(letterboxd): improve TMDB matching with year-aware search and scoring
fix #236
2026-01-29 08:33:40 +13:00
bitr8
db4c17a1ba
fix(letterboxd): extract title from data-item-name instead of img alt (#405)
The previous regex extracted from `<img alt="...">` which contains
"Poster for [Title]" instead of the clean title.

- Use `data-item-name` attribute which has the actual title
- Strip year suffix since year is extracted separately from
  `data-item-full-display-name`

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-23 00:41:13 +13:00
bitr8
56432fd273
fix(placeholders): skip date filtering for non-Coming-Soon collections with includeAllReleasedItems (#387)
The date window filtering in enrichWithTMDBReleaseDates() was removing items
before includeAllReleasedItems could preserve them. Now passing skipDateFilter
param to bypass filtering when includeAllReleasedItems is true for non-Coming-Soon
collections.

- Added skipDateFilter param to enrichWithTMDBReleaseDates()
- Skip movie/TV date window filtering when skipDateFilter is true
- Fail-open on TMDB fetch errors when skipDateFilter is true
- PlaceholderCreation passes skipDateFilter based on config

Fixes #336

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-22 14:46:50 +13:00
bitr8
be758cbf65
fix(collections): don't double-estimate digital release dates (#349)
Radarr sometimes sets releaseDate to an estimated digital release.
The code was adding another 90 days on top. Now checks if releaseDate
is already 30+ days after inCinemas before adding the estimate.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-22 14:39:59 +13:00
Tom Wheeler
bff75b8111 fix(letterboxd): add cloudflare solver for leterboxd
recent changes from letterbox require cloudflare cookie. uses playwright, similar to the imdb
implementation

fix #402
2026-01-22 14:15:50 +13:00
Tom Wheeler
9087e84a9f fix(sonarr): add all sonarr mointoring options to main settings and collection config
update styles, load server defaults for new collections

fix #397
2026-01-21 07:47:23 +13:00
Tom Wheeler
cdb87f5eb9 fix(metadata): fix incorrect release date for old releases with single modern digital release date
fix #374
2026-01-19 19:06:09 +13:00
Tom Wheeler
8b1d1c67a5 feat(trakt): add Trakt watchlist support (via OAuth)
fix #377
2026-01-17 16:50:19 +13:00
Tom Wheeler
0783c0692f fix(placeholders): add includeAllReleasedItems to sync and settings 2026-01-15 17:19:45 +13:00
Tom Wheeler
e621b7554f fix(overseerr): disable notifications for overseerr users
fix #240
2026-01-15 04:31:26 +13:00
Tom Wheeler
91f7484904 fix(letterboxd): fix mixed lists in letterboxd
re #236
2026-01-15 04:31:24 +13:00
Tom Wheeler
9600cb245b fix(overseerr): fix plexClient and libraryCache not being passed to sync
fix #363
2026-01-15 02:17:09 +13:00
Tom Wheeler
76db41b2ac fix(random-lists): fixes letterboxd and imdb random lists
not matching due to requirement to meet maxItems, which is passed as 9999 when intially matching
random lists

fix #324
2026-01-15 01:02:01 +13:00
Tom Wheeler
f124211bda fix(placeholders): improve date filtering UX/logic for general lists
add "Include all released items" toggle, fix orphaned cleanup to use fixed 7-day grace period, fix
placeholder quick sync deleting tv items, other minor changes

re #336, re #268, re #253, re #307
2026-01-14 23:24:56 +13:00
Tom Wheeler
193833ce85 fix(trakt): add support for new app.trakt.tv urls 2026-01-14 23:09:47 +13:00
Tom Wheeler
030c928844 fix(mdblist): fix mdblist for multi-source collections
fix #299
2026-01-14 11:39:06 +13:00
bitr8
01f94d5c1f
feat(imdb): add Top 250 English Movies collection type (#358)
Adds support for IMDb's Top 250 English-language movies list as a new
collection source. The list is available at /chart/top-english-movies/.

- Added TOP_250_ENGLISH_MOVIES enum value and URL mapping
- Added 'top_250_english' subtype to collection sources
- Added UI options in CollectionTypeSection and MultiSourceConfigSection
- Added title presets for the new collection type
- Auto-sets mediaType to 'movie' when selecting this subtype

Closes agregarr/agregarr#330

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-14 10:19:36 +13:00
bitr8
287befaa50
fix(plex): handle 404 gracefully when deleting hub items (#356)
Hub items that no longer exist in Plex should not cause errors during
cleanup operations. This matches the behavior of other delete methods
that also ignore 404 responses.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-14 10:16:50 +13:00
bitr8
bcda04dc64
fix(scheduler): startNow immediate sync and deadlock bugs (#348)
Bug 1: startNow doesn't trigger immediate sync
- When startNow=true, firstSyncAt was set to current time
- calculateNextRunFromFirstSync() returned firstSyncAt + interval (12h later)
- No immediate sync was triggered
- Fix: If firstSyncAt is within 60s of now, queue immediate sync

Bug 2: Deadlock when scheduled sync overlaps full sync
- Scheduled sync acquired API lock in queueCollectionSync()
- Queued sync to process "after main sync completes"
- But main sync was waiting for the same API lock
- Fix: Move API lock acquisition from queue time to execution time
  in processLibraryQueue(), after fullSyncRunning check

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-14 10:16:02 +13:00
Tom Wheeler
e8b40272e1 fix(missing-item-filter): change from include to exclude when ratings return null/undefined 2026-01-12 11:33:06 +13:00
Tom Wheeler
b02e767e9a fix(item-ordering): fix original plex order overriding source order
re #225
2026-01-12 10:20:41 +13:00
bitr8
7c6ff6b030
fix(security): harden API clients and file operations (#300)
- overseerr.ts: Redact credentials in error logs (whitelist headers,
  sanitize URL query params, try/catch stringify with pre-truncation)
- externalapi.ts: Add catch handler to rolling cache background refresh
- animeIds.ts: Add 30s timeout and 50MB size limit with streaming
- MultiSourceOrchestrator.ts: Validate sources array before cycle_lists
- LocalPosterFolderService.ts: Validate poster downloads (size, status, type)
- placeholderManager.ts: Prevent path traversal with realpath validation

Reviewed by Codex - addresses credential leakage, unhandled rejections,
resource exhaustion, division by zero, and directory traversal vectors.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-11 22:22:38 +13:00
bitr8
452a2be4a9
fix(placeholders): trigger Plex scan and empty trash after cleanup (#332)
When placeholders are cleaned up because real content arrived, Plex
wasn't notified and ghost entries remained in the library. This adds:

- New emptyTrash() method to PlexAPI
- Fire-and-forget scan + empty trash after placeholder cleanup
- New autoEmptyTrash setting (default: true) with UI toggle
- Setting in Plex settings page with "advanced" badge

The scan runs in the background so it doesn't block the sync process.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-11 22:20:25 +13:00
bitr8
5150bc790d
fix: multi-source label regex for collection matching (#345)
parseConfigIdFromLabel() regex didn't handle source names containing
hyphens or underscores (multi-source, filtered_hub). This caused
DYNAMIC_CYCLE_TITLE collections to create new Plex collections on each
cycle instead of updating the existing one.

Updated regex to allow hyphens/underscores in source names while
ensuring configId capture starts at the first digit.

Co-authored-by: bitr8 <bitr8@users.noreply.github.com>
2026-01-11 22:16:57 +13:00
Tom Wheeler
d9c6e2f7f8 fix(imdb): add watchlist support
fix #343
2026-01-11 22:13:34 +13:00
Tom Wheeler
459b9e339e fix(imdb): add AWS WAF challenge solver, fixing all IMDb lists
adds headless chromium to solve challenge. recent changes to IMDb require this, all lists return
zero items otherwise.
2026-01-11 18:01:01 +13:00