fix timeline
This commit is contained in:
parent
6b8f27ad19
commit
f0346d82ad
@ -23,7 +23,6 @@ class SimpleAudioPlayer {
|
||||
this.isSeeking = false;
|
||||
this.rafId = null;
|
||||
this.abortCtrl = null;
|
||||
this._posInterval = null;
|
||||
|
||||
// Pre-compute icons once
|
||||
const fill = getComputedStyle(document.documentElement)
|
||||
@ -53,6 +52,32 @@ class SimpleAudioPlayer {
|
||||
this._initMediaSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the current position to MediaSession so lockscreen / BT UIs stay in sync.
|
||||
* Keeps values strict but avoids over-clamping that can confuse some platforms.
|
||||
*/
|
||||
_pushPositionState(force = false) {
|
||||
if (!navigator.mediaSession?.setPositionState) return;
|
||||
|
||||
const duration = this.audio.duration;
|
||||
const position = this.audio.currentTime;
|
||||
if (!Number.isFinite(duration) || duration <= 0) return;
|
||||
if (!Number.isFinite(position) || position < 0) return;
|
||||
|
||||
const playbackRate = this.audio.paused
|
||||
? 0
|
||||
: (Number.isFinite(this.audio.playbackRate) ? this.audio.playbackRate : 1);
|
||||
|
||||
try {
|
||||
if ('playbackState' in navigator.mediaSession) {
|
||||
navigator.mediaSession.playbackState = this.audio.paused ? 'paused' : 'playing';
|
||||
}
|
||||
navigator.mediaSession.setPositionState({ duration, playbackRate, position });
|
||||
} catch (err) {
|
||||
if (force) console.warn('setPositionState failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal SVG helper
|
||||
svg(pathD, fill) {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="${fill}">
|
||||
@ -71,36 +96,40 @@ class SimpleAudioPlayer {
|
||||
this.timeline.max = this.audio.duration;
|
||||
this.timeline.value = 0;
|
||||
this.timeline.style.backgroundSize = '0% 100%';
|
||||
this._pushPositionState(true);
|
||||
});
|
||||
|
||||
this.audio.addEventListener('play', () => this._updatePlayState());
|
||||
this.audio.addEventListener('pause', () => this._updatePlayState());
|
||||
this.audio.addEventListener('ended', () => this.playBtn.innerHTML = this.icons.play);
|
||||
this.audio.addEventListener('play', () => {
|
||||
this._updatePlayState();
|
||||
this._pushPositionState(true);
|
||||
});
|
||||
|
||||
this.audio.addEventListener('playing', () => this._pushPositionState(true));
|
||||
|
||||
this.audio.addEventListener('pause', () => {
|
||||
this._updatePlayState();
|
||||
this._pushPositionState(true);
|
||||
});
|
||||
|
||||
this.audio.addEventListener('ratechange', () => this._pushPositionState(true));
|
||||
this.audio.addEventListener('ended', () => {
|
||||
this.playBtn.innerHTML = this.icons.play;
|
||||
this._pushPositionState(true);
|
||||
if ('mediaSession' in navigator) navigator.mediaSession.playbackState = 'paused';
|
||||
});
|
||||
|
||||
// Native timeupdate => update timeline
|
||||
this.audio.addEventListener('timeupdate', () => this.updateTimeline());
|
||||
|
||||
// Fallback interval for throttled mobile
|
||||
this._interval = setInterval(() => {
|
||||
if (!this.audio.paused && !this.isSeeking) {
|
||||
this.updateTimeline();
|
||||
}
|
||||
}, 500);
|
||||
// Keep position in sync when page visibility changes
|
||||
document.addEventListener('visibilitychange', () => this._pushPositionState(true));
|
||||
|
||||
// Unified seek input
|
||||
this.timeline.addEventListener('input', () => {
|
||||
this.isSeeking = true;
|
||||
this.audio.currentTime = this.timeline.value;
|
||||
|
||||
// immediate Android sync
|
||||
if (navigator.mediaSession?.setPositionState && Number.isFinite(this.audio.duration)) {
|
||||
navigator.mediaSession.setPositionState({
|
||||
duration: this.audio.duration,
|
||||
playbackRate: this.audio.playbackRate,
|
||||
position: this.audio.currentTime
|
||||
});
|
||||
}
|
||||
|
||||
this._pushPositionState(true); // immediate Android sync
|
||||
this.updateTimeline();
|
||||
this.isSeeking = false;
|
||||
});
|
||||
@ -112,9 +141,7 @@ class SimpleAudioPlayer {
|
||||
|
||||
_updatePlayState() {
|
||||
this.playBtn.innerHTML = this.audio.paused ? this.icons.play : this.icons.pause;
|
||||
if ('mediaSession' in navigator) {
|
||||
navigator.mediaSession.playbackState = this.audio.paused ? 'paused' : 'playing';
|
||||
}
|
||||
this._pushPositionState(true); // lock‑screen refresh on play/pause toggle
|
||||
}
|
||||
|
||||
_formatTime(sec) {
|
||||
@ -134,13 +161,7 @@ class SimpleAudioPlayer {
|
||||
this.timeInfo.textContent =
|
||||
`${this._formatTime(this.audio.currentTime)} / ${this._formatTime(this.audio.duration)}`;
|
||||
// 4) Push to Android widget
|
||||
if (navigator.mediaSession?.setPositionState && Number.isFinite(this.audio.duration)) {
|
||||
navigator.mediaSession.setPositionState({
|
||||
duration: this.audio.duration,
|
||||
playbackRate: this.audio.playbackRate,
|
||||
position: this.audio.currentTime
|
||||
});
|
||||
}
|
||||
this._pushPositionState();
|
||||
}
|
||||
|
||||
toggleCollapse() {
|
||||
@ -267,16 +288,6 @@ class SimpleAudioPlayer {
|
||||
}
|
||||
}));
|
||||
|
||||
// Heartbeat for widget
|
||||
this._posInterval = setInterval(() => {
|
||||
if (!this.audio.paused && navigator.mediaSession?.setPositionState && Number.isFinite(this.audio.duration)) {
|
||||
navigator.mediaSession.setPositionState({
|
||||
duration: this.audio.duration,
|
||||
playbackRate: this.audio.playbackRate,
|
||||
position: this.audio.currentTime
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user