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

@@ -257,6 +257,7 @@ export async function initDb() {
last_used_at INTEGER
);
`);
await migrateVideoMeta();
// Uploads shared from devices (PWA share target): who sent it, and whether it
// is listed in everyone's search (admin uploads) or reachable only by link.
for (const col of ['owner TEXT', 'listed INTEGER NOT NULL DEFAULT 1']) {
@@ -284,6 +285,47 @@ export async function initDb() {
}
}
const YOUTUBE_ID = /^[\w-]{11}$/;
const folded = value => String(value || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
// These columns were added after video_meta shipped. Keep startup migration
// idempotent and page the backfill so a large catalogue never becomes one
// unbounded JS allocation.
export async function migrateVideoMeta({ pageSize = 500 } = {}) {
for (const [name, type] of [['url', 'TEXT'], ['channel_id', 'TEXT'], ['channel_url', 'TEXT'], ['published', 'TEXT'], ['lang', 'TEXT']]) {
try { await db.execute(`ALTER TABLE video_meta ADD COLUMN ${name} ${type}`); } catch { /* column already exists */ }
}
await db.execute('CREATE TABLE IF NOT EXISTS catalog_schema_migrations (version INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL)');
const done = await db.execute({ sql: 'SELECT 1 FROM catalog_schema_migrations WHERE version=1' });
if (done.rows.length) return;
let cursor = '';
for (;;) {
const rows = (await db.execute({
sql: 'SELECT id,card,hay FROM video_meta WHERE id>? ORDER BY id LIMIT ?', args: [cursor, pageSize],
})).rows;
if (!rows.length) break;
const updates = [];
for (const row of rows) {
cursor = row.id;
let card = {};
try { card = JSON.parse(row.card || '{}'); } catch { /* malformed legacy card */ }
const url = YOUTUBE_ID.test(row.id) ? `https://www.youtube.com/watch?v=${row.id}` : null;
const channelId = card.channelId || card.channel_id || null;
const channelUrl = card.channelUrl || card.channel_url || null;
const published = card.published || card.publishedAt || card.upload_date || null;
const lang = card.lang || card.language || null;
card = { ...card, url, channelId: channelId || '', channelUrl: channelUrl || '' };
const hay = folded([card.title, card.channel, channelId, card.description,
...(Array.isArray(card.tags) ? card.tags : []), ...(Array.isArray(card.categories) ? card.categories : [])].filter(Boolean).join(' '));
updates.push({ sql: 'UPDATE video_meta SET card=?,url=?,channel_id=?,channel_url=?,published=?,lang=?,hay=? WHERE id=?',
args: [JSON.stringify(card), url, channelId, channelUrl, published, lang, hay || folded(row.hay), row.id] });
}
await db.batch(updates, 'write');
if (rows.length < pageSize) break;
}
await db.execute({ sql: 'INSERT OR IGNORE INTO catalog_schema_migrations(version,applied_at) VALUES(1,?)', args: [Date.now()] });
}
// ---- Shared video notes (lyrics / chapters) ---------------------------------
function noteRow(r) {