Playlist files: export with metadata and YouTube links (all or one playlist), import v1/v2 with duplicate handling, and ask the server to download the imported videos

This commit is contained in:
Jonathan Sykes
2026-10-15 22:19:04 +08:00
parent 450dc80488
commit cda8b068c7
3 changed files with 104 additions and 17 deletions

View File

@@ -1657,6 +1657,28 @@ registerMediaMetaRoutes(app, { db: notesDb, catalog: videoCatalog, media });
// POST /api/media/:id/redownload — the client's "Broken" button. Idempotent:
// a job already queued/running for this id is just reported back.
// POST /api/media/prefetch { ids: [...] } — queue server copies of many videos
// (e.g. an imported playlist) at background priority. Already-ready ids are
// reported, not refetched; the usual duration/disk limits still apply.
const prefetchHits = new Map(); // ip → timestamps
app.post('/api/media/prefetch', async (c) => {
let body; try { body = await c.req.json(); } catch { return c.json({ ok: false, error: 'invalid JSON' }, 400); }
const ip = clientIpOf(c.req.raw, null) || 'local';
const t = Date.now(), recent = (prefetchHits.get(ip) || []).filter((x) => t - x < 10 * 60_000);
if (recent.length >= 10) return c.json({ ok: false, error: 'too many download requests — try again in a few minutes' }, 429);
recent.push(t); prefetchHits.set(ip, recent); if (prefetchHits.size > 5000) prefetchHits.clear();
const ids = [...new Set((Array.isArray(body?.ids) ? body.ids : []).map(String).filter((id) => media.isMediaId(id) && !id.startsWith('upl_')))].slice(0, 500);
if (!ids.length) return c.json({ ok: false, error: 'no YouTube video ids in the request' }, 400);
let ready = 0, queued = 0;
for (const id of ids) {
if (await media.getReady(id).catch(() => null)) { ready++; continue; }
queued++;
media.ensureCached(id, { priority: LOW, auto: true }).catch(() => {});
}
serverCopies.at = 0; // the On server badges refresh on the next search
return c.json({ ok: true, requested: ids.length, ready, queued });
});
app.post('/api/media/:id/redownload', async (c) => {
try {
return c.json({ ok: true, ...(await media.redownload(c.req.param('id'))) });