New controller/retry.js wraps async calls with infinite retries, capped
at 30s with jitter. Applied to: TPB search, TMDB, Emby, Ollama chat,
Transmission RPC, and the status/status interval calls inherit it via
a Proxy around the Transmission client.
Also handles ollama package returning pre-parsed JSON objects.
Signed-off-by: William Mantly <wmantly@gmail.com>
When a complete-season pack cannot be found for a missing/partial season,
fillMissing now searches each missing SxxExx individually and queues the
best episode torrent per gap. Also exposes episode-level detail in the
/fill response and season plan.
Signed-off-by: William Mantly <wmantly@gmail.com>
Replaces hand-rolled fetch to /api/chat with the ollama@0.6.3 package.
The package supplies proper Accept/Content-Type/User-Agent headers and
auto-handles the Ollama protocol, fixing the CDN 403s Node's bare fetch
gets against ollama.com during filing.
Both organize and search LLM ranking now route through controller/ollama.js.
Signed-off-by: William Mantly <wmantly@gmail.com>
Node's default fetch sends a bare User-Agent that Google's CDN
fronting ollama.com rejects with 403. curl worked because it
sends curl/. Fixes organize (and search LLM ranking).
Signed-off-by: William Mantly <wmantly@gmail.com>
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>
TPB search is fuzzy: querying "Toy Story 5" returns Toy Story 4/3/… plus the
only real 2026 copies, which are CAM/Telesync. The LLM rejected them all, then
fallbackReleases picked the most-seeded (Toy Story 4), ignoring title/year.
Two deterministic guards:
- prefilter now drops low-quality source tags (CAM/TS/TELESYNC/SCR/…) via a
token match, so neither the LLM nor the fallback can surface them.
- findReleases requires the confirmed TMDB year in a movie's release name, so a
fuzzy match can't cross to a different film. If nothing survives, return no
options and tell the user it may be unreleased / only CAMs exist.
Verified: "Toy Story 5" now returns 0 options (was Toy Story 4); Night of the
Living Dead (1990) still recommends its 1080p x265 pack.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New controller/library.js queries Emby by TMDB provider id (resilient: an
unreachable Emby degrades to "unknown" so search still works).
Movies — quality-aware dedup:
- findReleases checks movieInLibrary(tmdbId) and flags each option alreadyOwned
when its resolution is <= what you already own, so only genuine upgrades are
offered; the release picker greys owned qualities and shows a library banner.
TV — library-driven "fill the gaps":
- GET /__api/search/seasons compares Emby's episode inventory against TMDB's
per-season episode counts to mark each season complete/partial/missing.
- POST /__api/search/fill picks the best complete-season pack (LLM) for every
missing/incomplete season and queues them. Front-end routes TV titles to a
season plan + "Fill all gaps" instead of the movie release list.
Adds tmdb.tmdbSeasons; shared tmdb module import in search.js.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Security & correctness hardening:
- Gate /__api/token/auth behind auth and self-scope every handler to the
caller (was fully unauthenticated — account-takeover hole).
- Escape LDAP filter values (injection) and reject empty-password binds.
- Enforce per-torrent ownership so private torrents aren't exposed via IDOR.
- Assorted cleanup: fix 'use static' typos, drop dead Torrent.migrate + the
getTorrentData noUpdate flag, Buffer.alloc, __dirname-relative reads,
res.statusCode in the error handler, const-scope pubsub.
Login-gated proxy + anti-indexing:
- Block all proxying for logged-out users via an auth-token cookie the front
end mirrors from its token; serve a local login page instead of hitting TPB.
- robots.txt disallow-all + X-Robots-Tag noindex.
Torrent category:
- Store a normalized category (TV/Movie/Music/Adult/App/Game/Other) mapped
from the TPB category id; captured at add time (migration).
Smart Search (movies/TV):
- New /__api/search: TMDB title confirm -> scrape piratebay.party HTML ->
Ollama ranks releases against quality prefs (x265/1080p/~1.5GB/subs,
prefer uncut) returning a recommended pick, optional warned 4K, and other
editions. Front-end Smart Search box + dialog feeding the existing add flow.
Post-download organization -> Emby (public Movie/TV only):
- Completion watcher files finished torrents: Ollama parses the release name,
TMDB canonicalizes title/year, files main video (+subs) into the library
with edition/quality-aware names (movies + TV SxxExx), stops seeding, and
triggers an Emby library scan. Low-confidence matches are flagged, not
mis-filed; correctable via "Fix match". Adds organizedAt/metadata columns.
Shared helpers: controller/tmdb.js, controller/ollama.js. Config blocks for
tmdb/ollama/search/emby/library/organize (secrets stay in gitignored secrets.js).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>