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:
@@ -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 });
|
||||
|
||||
Reference in New Issue
Block a user