Re-encode cached videos to HEVC when it saves at least 15 percent and serve them only to devices that can decode HEVC

This commit is contained in:
Jonathan Sykes
2026-09-13 21:09:15 +08:00
parent 91dab289c3
commit 8b0060d42a
7 changed files with 159 additions and 55 deletions

View File

@@ -68,6 +68,19 @@ function saveDataToStorage(jsonStr) {
} catch { /* ignore parse errors */ }
}
// Can this device decode the server's HEVC copies? The compression lane
// re-encodes cached videos to HEVC (8-bit, hvc1) when that is much smaller;
// the server hands those out only to clients that send hevc=1. canPlayType
// is the browser's own claim; if a copy still fails to play here, the device
// is remembered (NO_HEVC_KEY) and stops asking — it gets H.264 as before.
const NO_HEVC_KEY = 'ytpNoHevc';
function hevcCapable() {
try { if (localStorage.getItem(NO_HEVC_KEY) === '1') return false; } catch { /* storage blocked */ }
try {
return document.createElement('video').canPlayType('video/mp4; codecs="hvc1.1.6.L93.B0"') !== '';
} catch { return false; }
}
// OPFS bridge wrappers — return the same shape as the Tauri cache_* commands
// so the rest of app.js works without changes.
@@ -82,6 +95,7 @@ async function opfsDownload(videoId, { mux = false } = {}) {
// (used by "Save before playing"); default saves keep the progressive
// stream exactly as before.
if (mux) params.set('mux', '1');
if (hevcCapable()) params.set('hevc', '1');
const qs = params.toString();
const url = `/api/download/${encodeURIComponent(videoId)}${qs ? '?' + qs : ''}`;
@@ -199,7 +213,7 @@ const API = {
// nocache=1 skips the server's cached copy and resolves fresh YouTube
// streams (used when the cached copy won't play on this device).
getStreams: (videoId, { nocache = false } = {}) => WEB
? webFetch(`/api/streams?v=${encodeURIComponent(videoId)}${nocache ? '&nocache=1' : ''}`)
? webFetch(`/api/streams?v=${encodeURIComponent(videoId)}${nocache ? '&nocache=1' : ''}${!nocache && hevcCapable() ? '&hevc=1' : ''}`)
: call('yt.streams', 'yt_streams', { videoId }),
loadData: () => WEB
? Promise.resolve(loadDataFromStorage())
@@ -1581,6 +1595,11 @@ const Player = {
// device, so the ⚠ Broken button is how a user flags a bad server copy.
if (current && current.serverCached) {
const meta = current.meta;
// An HEVC copy that won't play means canPlayType over-promised on this
// device: stop asking for HEVC here (the server re-checks its copy).
if ((current.qualities || []).some((q) => q.codec === 'hevc')) {
try { localStorage.setItem(NO_HEVC_KEY, '1'); } catch { /* storage blocked */ }
}
current.serverCached = false;
toast('Server copy failed — streaming from YouTube. Tap ⚠ Broken to re-download it.', { duration: 5000 });
this.loadVideo(meta, { preferStream: true, nocache: true, resume: this._resumeOnLoad, reveal: this._revealOnLoad });