diff --git a/frontend/app.js b/frontend/app.js index 4cce212..bb6abc9 100755 --- a/frontend/app.js +++ b/frontend/app.js @@ -4191,9 +4191,22 @@ const Notes = (() => { const V = $('video'); const zoom = $('stgZoom'), buf = $('stgBuf'); if (zoom && V) { const m = /scale\(([\d.]+)\)/.exec(V.style.transform || ''); zoom.textContent = 'Pinch ' + (m ? Number(m[1]).toFixed(1) : '1.0') + '×'; } - if (buf && V && V.duration && V.buffered.length) { - const end = V.buffered.end(V.buffered.length - 1); - buf.textContent = end >= V.duration - 1 ? 'Fully buffered' : 'Buffered ' + Math.round((end / V.duration) * 100) + '%'; + if (buf) { + const M = Player.master || V; + if (current && current.localUrl) { + // A device copy is all here — buffering progress means nothing. + buf.textContent = 'Saved on device'; + } else if (M && M.duration && M.buffered && M.buffered.length) { + // The range around the playhead (the last range jumps to wherever + // the user last seeked), shown as how far ahead playback is covered. + const t = M.currentTime || 0; + let end = 0; + for (let i = 0; i < M.buffered.length; i++) { + if (M.buffered.start(i) <= t + 0.5 && M.buffered.end(i) >= t) { end = M.buffered.end(i); break; } + } + buf.textContent = end >= M.duration - 1 ? 'Fully buffered' + : end > t ? 'Buffered ' + Math.round((end / M.duration) * 100) + '%' : 'Buffering…'; + } } const q = $('qualitySelect'), sq = $('stgQuality'); if (sq && q && q.options.length) sq.textContent = q.options[q.selectedIndex] ? q.options[q.selectedIndex].text : 'Auto';