cache /api/search results for 3 minutes to skip repeat yt-dlp spawns
This commit is contained in:
@@ -353,11 +353,25 @@ app.get('/api/version', (c) =>
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Same query repeats a lot (users re-searching, several devices, the
|
||||||
|
// landing-page chips) and yt-dlp's own search takes several seconds — cache
|
||||||
|
// the combined (library + YouTube) result for a short TTL. Same shape as
|
||||||
|
// resolveStreams()' streamCache below, just keyed by normalized query text
|
||||||
|
// instead of videoId. Only a full success is cached, so a transient yt-dlp
|
||||||
|
// failure still gets retried on the next request.
|
||||||
|
const SEARCH_CACHE_MAX = 100;
|
||||||
|
const SEARCH_CACHE_TTL_MS = 3 * 60_000;
|
||||||
|
const searchCache = new Map(); // lowercased q -> { results, expiresAt }
|
||||||
|
|
||||||
// GET /api/search?q=<query>
|
// GET /api/search?q=<query>
|
||||||
app.get('/api/search', async (c) => {
|
app.get('/api/search', async (c) => {
|
||||||
const q = (c.req.query('q') || '').trim();
|
const q = (c.req.query('q') || '').trim();
|
||||||
if (!q) return c.json({ ok: false, error: 'empty query' }, 400);
|
if (!q) return c.json({ ok: false, error: 'empty query' }, 400);
|
||||||
|
|
||||||
|
const cacheKey = q.toLowerCase();
|
||||||
|
const cached = searchCache.get(cacheKey);
|
||||||
|
if (cached && Date.now() < cached.expiresAt) return c.json({ ok: true, results: cached.results });
|
||||||
|
|
||||||
// This server's own library first — and it still answers when YouTube
|
// This server's own library first — and it still answers when YouTube
|
||||||
// (yt-dlp) is unreachable or rate-limited.
|
// (yt-dlp) is unreachable or rate-limited.
|
||||||
let mine = [];
|
let mine = [];
|
||||||
@@ -368,7 +382,10 @@ app.get('/api/search', async (c) => {
|
|||||||
'--dump-json', '--flat-playlist',
|
'--dump-json', '--flat-playlist',
|
||||||
'--no-warnings', '--ignore-errors',
|
'--no-warnings', '--ignore-errors',
|
||||||
]);
|
]);
|
||||||
return c.json({ ok: true, results: [...mine, ...parseCards(out)] });
|
const results = [...mine, ...parseCards(out)];
|
||||||
|
if (searchCache.size >= SEARCH_CACHE_MAX) searchCache.delete(searchCache.keys().next().value);
|
||||||
|
searchCache.set(cacheKey, { results, expiresAt: Date.now() + SEARCH_CACHE_TTL_MS });
|
||||||
|
return c.json({ ok: true, results });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (mine.length) return c.json({ ok: true, results: mine, youtubeError: err.message });
|
if (mine.length) return c.json({ ok: true, results: mine, youtubeError: err.message });
|
||||||
return c.json({ ok: false, error: err.message }, 500);
|
return c.json({ ok: false, error: err.message }, 500);
|
||||||
|
|||||||
Reference in New Issue
Block a user