Fix progress bar seek pausing playback + add persistent mini-player
- video-player: add userSeeking flag so mid-seek pause events are suppressed; force-resume on 'seeked' if video was playing before seek; guard player click handler against progCont clicks; e.preventDefault() on touchend to stop synthetic click toggling play - audio-player: apply identical seek fixes (same four changes) - app layout: add floating mini-player that saves video state to sessionStorage when bottom nav is tapped while a video is playing, then restores playback on the next page via a floating overlay Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
615e7efd7c
commit
d1441b213a
3 files changed
+264
-13
No files matched your search
@@ -709,13 +709,15 @@ const loopRow = document.getElementById('ytpLoopRow');
|
||||
const loopVal = document.getElementById('ytpLoopVal');
|
||||
|
||||
// ── State ─────────────────────────────────────────────
|
||||
let hideTimer = null;
|
||||
let isDragging = false;
|
||||
let isTheater = false;
|
||||
let isFullscreen = false;
|
||||
let currentSpeed = 1;
|
||||
let lastTap = 0;
|
||||
let tapTimer = null;
|
||||
let hideTimer = null;
|
||||
let isDragging = false;
|
||||
let isTheater = false;
|
||||
let isFullscreen = false;
|
||||
let currentSpeed = 1;
|
||||
let lastTap = 0;
|
||||
let tapTimer = null;
|
||||
let userSeeking = false; // true from seekTo() until 'seeked' fires
|
||||
let wasPlayingBeforeSeek = false; // remember play state so we can resume after seek
|
||||
|
||||
// ── HLS source ────────────────────────────────────────
|
||||
const HLS_URL = @json($hlsUrl);
|
||||
@@ -904,6 +906,7 @@ playBtn.addEventListener('click', e => { e.stopPropagation(); togglePlay(); show
|
||||
let clickTimer = null;
|
||||
player.addEventListener('click', e => {
|
||||
if (e.target === settingsBtn || settingsPanel.contains(e.target)) return;
|
||||
if (progCont.contains(e.target)) return;
|
||||
clearTimeout(clickTimer);
|
||||
clickTimer = setTimeout(() => { togglePlay(); }, 200);
|
||||
});
|
||||
@@ -954,6 +957,8 @@ volRange.addEventListener('click', e => e.stopPropagation());
|
||||
// ── Progress bar scrubbing ────────────────────────────
|
||||
function seekTo(pct) {
|
||||
if (!video.duration) return;
|
||||
if (!userSeeking) wasPlayingBeforeSeek = !video.paused;
|
||||
userSeeking = true;
|
||||
video.currentTime = pct * video.duration;
|
||||
updateProgress();
|
||||
}
|
||||
@@ -1000,7 +1005,7 @@ progCont.addEventListener('touchstart', e => {
|
||||
progCont.addEventListener('touchmove', e => {
|
||||
if (isDragging) seekTo(touchProgressPct(e));
|
||||
}, { passive: true });
|
||||
progCont.addEventListener('touchend', () => { isDragging = false; progBar.classList.remove('dragging'); });
|
||||
progCont.addEventListener('touchend', e => { e.preventDefault(); isDragging = false; progBar.classList.remove('dragging'); });
|
||||
|
||||
// ── Settings panel ────────────────────────────────────
|
||||
settingsBtn.addEventListener('click', e => {
|
||||
@@ -1143,7 +1148,19 @@ if (pipBtn) {
|
||||
|
||||
// ── Video events ──────────────────────────────────────
|
||||
video.addEventListener('play', () => { updatePlayIcon(); resetHideTimer(); largePlay.classList.remove('visible'); requestWakeLock(); });
|
||||
video.addEventListener('pause', () => { updatePlayIcon(); showControls(); largePlay.classList.add('visible'); clearTimeout(hideTimer); releaseWakeLock(); });
|
||||
video.addEventListener('pause', () => {
|
||||
if (userSeeking) return; // suppress mid-seek pause events
|
||||
updatePlayIcon(); showControls(); largePlay.classList.add('visible'); clearTimeout(hideTimer); releaseWakeLock();
|
||||
});
|
||||
video.addEventListener('seeked', () => {
|
||||
userSeeking = false;
|
||||
if (wasPlayingBeforeSeek) {
|
||||
// Resume if the browser/HLS.js paused the video during seeking
|
||||
if (video.paused) video.play().catch(() => {});
|
||||
largePlay.classList.remove('visible');
|
||||
resetHideTimer();
|
||||
}
|
||||
});
|
||||
video.addEventListener('timeupdate', updateProgress);
|
||||
video.addEventListener('progress', updateProgress);
|
||||
video.addEventListener('durationchange', () => { timeDur.textContent = fmt(video.duration); });
|
||||
@@ -1242,10 +1259,25 @@ function init() {
|
||||
}
|
||||
}, { once: true });
|
||||
|
||||
// If user returned from mini-player, seek to the saved timestamp
|
||||
const miniRaw = sessionStorage.getItem('ytpMiniState');
|
||||
let miniSeekTime = 0;
|
||||
if (miniRaw) {
|
||||
try {
|
||||
const ms = JSON.parse(miniRaw);
|
||||
if (ms && ms.time > 0) miniSeekTime = ms.time;
|
||||
} catch(e) {}
|
||||
sessionStorage.removeItem('ytpMiniState');
|
||||
}
|
||||
|
||||
// canplay fires for ALL source types (HLS.js, MP4, Safari native HLS)
|
||||
// once the browser has enough data to start — most reliable autoplay trigger
|
||||
video.addEventListener('canplay', function autoStart() {
|
||||
video.removeEventListener('canplay', autoStart);
|
||||
if (miniSeekTime > 0) {
|
||||
video.currentTime = miniSeekTime;
|
||||
miniSeekTime = 0;
|
||||
}
|
||||
video.play().catch(() => {});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user