Extend video catalog source metadata

This commit is contained in:
Jonathan Sykes
2026-10-14 01:22:32 +08:00
parent f465cc86d0
commit 593ecaecd9
7 changed files with 136 additions and 17 deletions

View File

@@ -2,7 +2,7 @@
// repeat query — from any device, or after a restart — never waits on YouTube.
// Capped by row count (default 250,000 queries) AND bytes (default 2 GiB), LRU.
import { db } from './db.js';
import { ingest, withLocalThumbnails, trimCatalog } from './video-catalog.js';
import { ingest, withLocalThumbnails, trimCatalog, foldSearchText } from './video-catalog.js';
export const MAX_ROWS = Number(process.env.SEARCH_CACHE_MAX_ROWS) || 250_000;
export const MAX_BYTES = Number(process.env.SEARCH_CACHE_MAX_BYTES) || 2 * 1024 ** 3;
@@ -70,15 +70,28 @@ export async function rememberVideos(cards) {
// Cards whose title/channel contain EVERY word of the query, most-seen first.
export async function searchVideos(q, limit = 60) {
const words = String(q).toLowerCase().split(/\s+/).filter(Boolean).slice(0, 8);
const folded = foldSearchText(q).trim();
const words = folded.split(/\s+/).filter(Boolean).slice(0, 8);
if (!words.length) return [];
const like = (w) => '%' + w.replace(/[\\%_]/g, '\\$&') + '%';
const r = await db.execute({
sql: `SELECT card FROM video_meta WHERE ${words.map(() => "hay LIKE ? ESCAPE '\\'").join(' AND ')}
sql: `SELECT card,seen FROM video_meta WHERE ${words.map(() => "hay LIKE ? ESCAPE '\\'").join(' AND ')}
ORDER BY seen DESC, updated_at DESC LIMIT ?`,
args: [...words.map(like), limit],
args: [...words.map(like), Math.max(limit * 10, 200)],
});
return withLocalThumbnails(r.rows.map((x) => { try { return JSON.parse(x.card); } catch { return null; } }).filter(Boolean));
const titleHasAll = title => words.every(word => foldSearchText(title).includes(word));
const phrase = folded;
const ranked = r.rows.map(row => {
try {
const card = JSON.parse(row.card);
const title = foldSearchText(card.title);
const channel = foldSearchText(card.channel);
const score = (title === phrase || title.includes(phrase) ? 4 : 0) +
(titleHasAll(card.title) ? 2 : 0) + (words.some(word => channel.includes(word)) ? 1 : 0);
return { card: { ...card, url: card.url || `https://www.youtube.com/watch?v=${card.id}` }, score, seen: Number(row.seen) || 0 };
} catch { return null; }
}).filter(Boolean).sort((a, b) => b.score - a.score || b.seen - a.seen).slice(0, limit).map(x => x.card);
return withLocalThumbnails(ranked);
}
export async function trimVideos(max = MAX_VIDEOS) {