fix: Scrub lag fix and Volume control for Audiobooks
This commit is contained in:
1 parent
4b07203082
commit
7744ae85db
4 files changed
+37
-9
No files matched your search
+9
-2
@@ -429,7 +429,7 @@
|
||||
</button>
|
||||
<div class="volume-wrap">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--text3)"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>
|
||||
<input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="80" oninput="setVolume(this.value)">
|
||||
<input type="range" class="volume-slider volume-slider-sync" id="volume-slider" min="0" max="100" value="50" oninput="setVolume(this.value)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -712,6 +712,13 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Volume -->
|
||||
<div class="abs-volume-row">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--text3);flex-shrink:0"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/></svg>
|
||||
<input type="range" class="abs-vol-slider volume-slider-sync" min="0" max="100" value="50" oninput="setVolume(this.value)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--text3);flex-shrink:0"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>
|
||||
</div>
|
||||
|
||||
<!-- Chapter list -->
|
||||
<div id="abs-chapter-list" class="abs-chapter-list"></div>
|
||||
</div>
|
||||
@@ -872,7 +879,7 @@
|
||||
</button>
|
||||
<div class="np-vol">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:rgba(255,255,255,.45)"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/></svg>
|
||||
<input type="range" class="np-vol-slider" id="np-vol-slider" min="0" max="100" value="80" oninput="setVolume(this.value);document.getElementById('volume-slider').value=this.value">
|
||||
<input type="range" class="np-vol-slider volume-slider-sync" id="np-vol-slider" min="0" max="100" value="50" oninput="setVolume(this.value)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:rgba(255,255,255,.45)"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>
|
||||
</div>
|
||||
<button class="np-icon-btn" id="np-radio-btn" onclick="toggleRadioMode()" title="Radio-Modus: endloser Shuffle">
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ window.addEventListener('load', () => {
|
||||
}
|
||||
});
|
||||
|
||||
S.audio.volume = 0.65;
|
||||
S.audio.volume = 0.5;
|
||||
|
||||
// Re-register MediaSession handlers when returning from background/screen-off/flip
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
|
||||
+23
-6
@@ -213,8 +213,16 @@ export function updateProgress() {
|
||||
|
||||
export function seekTo(e) {
|
||||
const bar = document.getElementById('progress-bar');
|
||||
if (!bar || !S.audio.duration) return;
|
||||
const rect = bar.getBoundingClientRect();
|
||||
S.audio.currentTime = ((e.clientX - rect.left) / rect.width) * S.audio.duration;
|
||||
const pos = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
||||
const fill = document.getElementById('progress-fill');
|
||||
if (fill) { fill.style.transition = 'none'; fill.style.width = (pos * 100) + '%'; }
|
||||
S.audio.currentTime = pos * S.audio.duration;
|
||||
S._scrubbing = true;
|
||||
const done = () => { S._scrubbing = false; requestAnimationFrame(() => { if (fill) fill.style.transition = ''; }); };
|
||||
S.audio.addEventListener('seeked', done, { once: true });
|
||||
setTimeout(done, 1500);
|
||||
}
|
||||
|
||||
export function initProgressScrub() {
|
||||
@@ -236,14 +244,15 @@ function _initBarScrub(bar, fill, onMove) {
|
||||
function startScrub(pos) { S._scrubbing=true; fill.style.transition='none'; fill.style.width=(pos*100)+'%'; onMove(pos); }
|
||||
function moveScrub(pos) { fill.style.width=(pos*100)+'%'; onMove(pos); }
|
||||
function endScrub(pos) {
|
||||
fill.style.transition='';
|
||||
fill.style.width = (pos * 100) + '%'; // pin visual position before re-enabling transition
|
||||
if(S.audio.duration) {
|
||||
S.audio.currentTime = pos * S.audio.duration;
|
||||
// Keep _scrubbing=true until seek completes so timeupdate can't snap bar back
|
||||
S.audio.addEventListener('seeked', () => { S._scrubbing = false; }, { once: true });
|
||||
setTimeout(() => { S._scrubbing = false; }, 1500); // fallback if seeked never fires
|
||||
const done = () => { S._scrubbing = false; requestAnimationFrame(() => { fill.style.transition = ''; }); };
|
||||
S.audio.addEventListener('seeked', done, { once: true });
|
||||
setTimeout(done, 1500); // fallback if seeked never fires
|
||||
} else {
|
||||
S._scrubbing = false;
|
||||
fill.style.transition = '';
|
||||
}
|
||||
}
|
||||
bar.addEventListener('touchstart', e => { startScrub(getPos(e.touches[0].clientX)); e.stopPropagation(); }, {passive:true});
|
||||
@@ -258,7 +267,15 @@ function _initBarScrub(bar, fill, onMove) {
|
||||
});
|
||||
}
|
||||
|
||||
export function setVolume(v) { S.audio.volume = v/100; S.previewAudio.volume = v/100; }
|
||||
export function setVolume(v) {
|
||||
const vol = v / 100;
|
||||
S.audio.volume = vol;
|
||||
S.previewAudio.volume = vol;
|
||||
const absAudio = document.getElementById('abs-audio');
|
||||
if (absAudio) absAudio.volume = vol;
|
||||
// sync all volume sliders
|
||||
document.querySelectorAll('.volume-slider-sync').forEach(el => { el.value = v; });
|
||||
}
|
||||
|
||||
// ─── MEDIA SESSION ───
|
||||
export function updateMediaSession(s) {
|
||||
|
||||
@@ -965,4 +965,8 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
|
||||
.abs-mini-open{background:none;border:none;color:var(--text2);cursor:pointer;padding:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
||||
.abs-mini-open:hover{color:var(--text)}
|
||||
.abs-hbtn.active{color:var(--accent)}
|
||||
.abs-volume-row{display:flex;align-items:center;gap:10px;padding:0 24px 14px}
|
||||
.abs-vol-slider{flex:1;-webkit-appearance:none;appearance:none;height:3px;border-radius:2px;background:var(--surface2);outline:none;cursor:pointer}
|
||||
.abs-vol-slider::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--accent);cursor:pointer}
|
||||
.abs-vol-slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--accent);cursor:pointer;border:none}
|
||||
@media(max-width:768px){.abs-mini-bar{bottom:80px;height:var(--player-h)}}
|
||||
Reference in new issue
Block a user