27a6656ac5
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>
59 lines
1.5 KiB
JavaScript
59 lines
1.5 KiB
JavaScript
'use strict';
|
|
|
|
const router = require('express').Router();
|
|
const search = require('>/controller/search');
|
|
const { Torrent } = require('>/models');
|
|
|
|
// Step 1: fuzzy query -> a few TMDB title candidates( with posters) to confirm.
|
|
router.get('/title', async function(req, res, next){
|
|
try{
|
|
res.json({results: await search.tmdbSearch(req.query.q)});
|
|
}catch(error){
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
// Step 2: confirmed title -> TPB search + LLM-curated release options.
|
|
router.post('/releases', async function(req, res, next){
|
|
try{
|
|
res.json(await search.findReleases(req.body.tmdbId, req.body.mediaType));
|
|
}catch(error){
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
// TV: which seasons you have vs are missing (Emby inventory vs TMDB counts).
|
|
router.get('/seasons', async function(req, res, next){
|
|
try{
|
|
res.json(await search.seasonPlan(req.query.tmdbId));
|
|
}catch(error){
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
// TV: queue the best complete-season pack for every missing/incomplete season.
|
|
router.post('/fill', async function(req, res, next){
|
|
try{
|
|
let plan = await search.fillMissing(req.body.tmdbId);
|
|
let queued = [];
|
|
for(let pick of plan.picks){
|
|
try{
|
|
await Torrent.create({
|
|
magnetLink: pick.magnetLink,
|
|
isPrivate: false,
|
|
added_by: req.user.username,
|
|
category: pick.category,
|
|
});
|
|
queued.push({ season: pick.season, name: pick.name });
|
|
}catch(error){
|
|
plan.skipped.push({ season: pick.season, reason: error.message });
|
|
}
|
|
}
|
|
res.json({ title: plan.title, year: plan.year, queued, skipped: plan.skipped });
|
|
}catch(error){
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|