Queue bounded stream prewarm requests

This commit is contained in:
Jonathan Sykes
2026-10-07 03:13:30 +08:00
parent b4c776dcfe
commit b77938ab4a
4 changed files with 82 additions and 7 deletions

View File

@@ -67,6 +67,7 @@ import { ingest as collectVideoMetadata, syncListening, linkListening, startThum
import { registerCatalogRoutes } from './recommendations.js';
import QRCode from 'qrcode';
import { createYtdlpPool } from './ytdlp-pool.js';
import { createWarmQueue } from './warm-queue.js';
import { dirname, join as pathJoin } from 'node:path';
// A media proxy must not die because one client's stream hit an edge case
@@ -728,15 +729,20 @@ function pickFormat(formats, { formatId, wantAudio, wantHeight }) {
// GET /api/streams/warm?v=<id> — fire-and-forget: resolve streams into
// streamCache so the real /api/streams a moment later is instant. Bounded
// so a scrolling user can't queue dozens of yt-dlp processes.
const WARM_MAX = 2;
let warmActive = 0;
const streamWarmQueue = createWarmQueue({
concurrency: 2,
maxQueued: 8,
run: async (id) => {
try { if (await media.getReady(id)) return; } catch { /* fall through */ }
await resolveStreams(id);
},
});
app.get('/api/streams/warm', async (c) => {
const id = (c.req.query('v') || '').trim();
if (!/^[A-Za-z0-9_-]{11}$/.test(id)) return c.body(null, 204);
if (warmActive >= WARM_MAX) return c.body(null, 204);
try { if (await media.getReady(id)) return c.body(null, 204); } catch { /* fall through */ }
warmActive++;
resolveStreams(id).catch(() => {}).finally(() => { warmActive--; });
// Best effort: bounded queue preserves a small burst (e.g. the first three
// search cards) while limiting background extractor work.
streamWarmQueue.enqueue(id);
return c.body(null, 204);
});