Prewarm upcoming queue streams

This commit is contained in:
Jonathan Sykes
2026-10-07 16:30:15 +08:00
parent fcd98b6a4d
commit d65b9e032a
3 changed files with 15 additions and 2 deletions

View File

@@ -623,8 +623,9 @@ const API = {
// Pre-resolve streams for videos the user is likely to play next (server
// /api/streams/warm). Each id is warmed at most once per 20 min per tab.
const warmedAt = new Map();
const knownServerCachedIds = new Set();
function warmStreams(ids) {
if (!WEB || navigator.onLine === false) return;
if (!WEB || navigator.onLine === false || navigator.connection?.saveData) return;
const now = Date.now();
for (const id of ids) {
if (!id || !/^[A-Za-z0-9_-]{11}$/.test(id) || cachedIds.has(id)) continue;
@@ -634,6 +635,14 @@ function warmStreams(ids) {
}
}
function warmNextQueue() {
if (!window.PrewarmNext || queueIndex < 0) return;
warmStreams(window.PrewarmNext.candidates(queue, queueIndex, data.settings, 2, {
offline: cachedIds,
serverCached: knownServerCachedIds,
}));
}
// Resolve a native file path to a URL the WebView can load (Tauri asset
// protocol). Returns null on shells without it.
function toAssetUrl(path) {
@@ -2332,6 +2341,7 @@ const Player = {
if (seq !== this._loadSeq) return; // a newer load took over meanwhile
if (!res || !res.ok) throw new Error(res?.error || 'Could not load streams');
current = res.data;
if (current.serverCached && current.meta?.id) knownServerCachedIds.add(current.meta.id);
// Merge richer metadata we may already have from the list card.
current.meta = { ...videoObj, ...current.meta };
@@ -3014,7 +3024,7 @@ function wirePlayerEvents() {
perfMeasure('ytp:tap-to-play', 'ytp:tap');
try { performance.clearMarks('ytp:tap'); } catch { /* ignore */ }
}
if (Array.isArray(queue) && queueIndex >= 0) warmStreams(queue.slice(queueIndex + 1, queueIndex + 3).map((x) => x && x.id));
warmNextQueue();
showSpinner(false);
Player.clearBufferGrace();
if (Player.secondary && !el.paused && Player.secondary.paused) {
@@ -8043,6 +8053,7 @@ function playFromList(list, index, source = '', { playFull = false } = {}) {
unshuffledQueue = null;
// Play-in-full keeps the list order — a service set plays as arranged.
if (data.settings.shuffle && !playFull) applyShuffle();
warmNextQueue();
Player.loadVideo(queue[queueIndex]);
renderUpNext();
}

View File

@@ -693,6 +693,7 @@
<script src="piano.js"></script>
<script src="setlist-import.js"></script>
<script src="car-mode.js"></script>
<script src="prewarm-next.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@@ -124,6 +124,7 @@ const SHELL = [
'/piano.js',
'/setlist-import.js',
'/car-mode.js',
'/prewarm-next.js',
'/car-mode.css',
'/lower-third.css',
'/settings-sections.css',