35 lines
2.1 KiB
JavaScript
35 lines
2.1 KiB
JavaScript
/* Best-effort discovery for playback that never requests server streams. */
|
|
(function(root) {
|
|
'use strict';
|
|
function createReporter({ fetch: send = root.fetch?.bind(root), online = () => root.navigator?.onLine !== false, enabled = () => true } = {}) {
|
|
const seen = new Set(), deferred = new Map();
|
|
function report(meta) {
|
|
if (!enabled() || !send || !meta || !/^[A-Za-z0-9_-]{11}$/.test(meta.id) || meta.custom || meta.upload || !meta.title || meta.title === meta.id || seen.has(meta.id)) return;
|
|
// Snapshot only the known metadata, never stream URLs or local blob art.
|
|
let thumbnail;
|
|
try {
|
|
const url = new URL(meta.thumbnail);
|
|
if (url.protocol === 'https:' && /^(?:i|i\d)\.ytimg\.com$/.test(url.hostname) && !url.port && !url.username && !url.password) thumbnail = url.href;
|
|
} catch { /* server supplies canonical art */ }
|
|
const card = { id: meta.id, title: String(meta.title).slice(0,300), channel: String(meta.channel || meta.artist || meta.uploader || '').slice(0,300),
|
|
duration: Math.max(0, Math.min(86400, Number(meta.duration) || 0)), ...(thumbnail ? { thumbnail } : {}) };
|
|
if (!online()) {
|
|
deferred.set(meta.id, card);
|
|
if (deferred.size > 256) deferred.delete(deferred.keys().next().value);
|
|
return;
|
|
}
|
|
seen.add(meta.id); deferred.delete(meta.id);
|
|
// No synchronous/network failure can interrupt the player event handler.
|
|
try {
|
|
Promise.resolve(send(`/api/media/${encodeURIComponent(card.id)}/meta`, {
|
|
method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(card),
|
|
signal: root.AbortSignal?.timeout?.(10000),
|
|
})).catch(() => {});
|
|
} catch { /* best effort; a later session can report again */ }
|
|
}
|
|
return { report, flush: () => { if (online()) for (const card of [...deferred.values()]) report(card); } };
|
|
}
|
|
if (typeof module !== 'undefined') module.exports = { createReporter };
|
|
else { const reporter = createReporter(); root.ServerBackfill = reporter; root.addEventListener('online', reporter.flush); }
|
|
})(typeof window !== 'undefined' ? window : globalThis);
|