Remember unavailable movies and auto-grab them later (wishlist)

When Smart Search finds no good copy of a movie (unreleased / only CAMs), we
now record it instead of dropping it:
- New Wanted model + migration (dedup by tmdbId, status wanted|fulfilled).
- POST /__api/search/releases remembers a movie when it returns no options,
  and the UI confirms it was added to the wishlist.
- controller/wantedWatcher re-runs Smart Search for wishlisted items every 6h
  (and on boot); when a good copy appears it queues the recommended release,
  which then flows through the normal download + organize pipeline, and marks
  the item fulfilled.
- GET/DELETE /__api/search/wanted to view/remove the wishlist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 00:51:48 -04:00
parent 2046e5080b
commit b166403309
9 changed files with 152 additions and 6 deletions
+2 -2
View File
@@ -259,7 +259,7 @@ async function findReleases(tmdbId, mediaType){
}
if(!candidates.length){
return { title: meta.title, year: meta.year, options: [] };
return { title: meta.title, year: meta.year, tmdbId, mediaType, options: [] };
}
let today = new Date().toISOString().slice(0, 10);
@@ -274,7 +274,7 @@ async function findReleases(tmdbId, mediaType){
options = decorateOptions(options, candidates);
if(!options.length) options = decorateOptions(fallbackReleases(candidates), candidates);
let result = { title: meta.title, year: meta.year, options };
let result = { title: meta.title, year: meta.year, tmdbId, mediaType, options };
// Quality-aware dedup: flag options you already own at equal-or-better quality.
if(mediaType !== 'tv'){