Update authentication system, database models, and UI components
This commit is contained in:
162
static/shared-audio-player.js
Normal file
162
static/shared-audio-player.js
Normal file
@ -0,0 +1,162 @@
|
||||
// shared-audio-player.js
|
||||
// Unified audio player logic for both streams and personal player
|
||||
|
||||
import { globalAudioManager } from './global-audio-manager.js';
|
||||
|
||||
export class SharedAudioPlayer {
|
||||
constructor({ playerType, getStreamUrl, onUpdateButton }) {
|
||||
this.playerType = playerType; // 'streams' or 'personal'
|
||||
this.getStreamUrl = getStreamUrl; // function(uid) => url
|
||||
this.onUpdateButton = onUpdateButton; // function(button, isPlaying)
|
||||
this.audioElement = null;
|
||||
this.currentUid = null;
|
||||
this.isPlaying = false;
|
||||
this.currentButton = null;
|
||||
this._eventHandlers = {};
|
||||
|
||||
// Register stop listener
|
||||
globalAudioManager.addListener(playerType, () => {
|
||||
this.stop();
|
||||
});
|
||||
}
|
||||
|
||||
pause() {
|
||||
if (this.audioElement && !this.audioElement.paused && !this.audioElement.ended) {
|
||||
this.audioElement.pause();
|
||||
this.isPlaying = false;
|
||||
if (this.onUpdateButton && this.currentButton) {
|
||||
this.onUpdateButton(this.currentButton, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async play(uid, button) {
|
||||
const ctx = `[SharedAudioPlayer][${this.playerType}]${uid ? `[${uid}]` : ''}`;
|
||||
const isSameUid = this.currentUid === uid;
|
||||
const isActive = this.audioElement && !this.audioElement.paused && !this.audioElement.ended;
|
||||
|
||||
// Guard: If already playing the requested UID and not paused/ended, do nothing
|
||||
if (isSameUid && isActive) {
|
||||
if (this.onUpdateButton) this.onUpdateButton(button || this.currentButton, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If same UID but paused, resume
|
||||
if (isSameUid && this.audioElement && this.audioElement.paused && !this.audioElement.ended) {
|
||||
try {
|
||||
await this.audioElement.play();
|
||||
this.isPlaying = true;
|
||||
if (this.onUpdateButton) this.onUpdateButton(button || this.currentButton, true);
|
||||
globalAudioManager.startPlayback(this.playerType, uid);
|
||||
} catch (err) {
|
||||
this.isPlaying = false;
|
||||
if (this.onUpdateButton) this.onUpdateButton(button || this.currentButton, false);
|
||||
console.error(`${ctx} play() resume failed:`, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, stop current and start new
|
||||
if (!isSameUid && this.audioElement) {
|
||||
} else {
|
||||
}
|
||||
this.stop();
|
||||
this.currentUid = uid;
|
||||
this.currentButton = button;
|
||||
const url = this.getStreamUrl(uid);
|
||||
this.audioElement = new Audio(url);
|
||||
this.audioElement.preload = 'auto';
|
||||
this.audioElement.crossOrigin = 'anonymous';
|
||||
this.audioElement.style.display = 'none';
|
||||
document.body.appendChild(this.audioElement);
|
||||
this._attachEventHandlers();
|
||||
try {
|
||||
await this.audioElement.play();
|
||||
this.isPlaying = true;
|
||||
if (this.onUpdateButton) this.onUpdateButton(button, true);
|
||||
globalAudioManager.startPlayback(this.playerType, uid);
|
||||
} catch (err) {
|
||||
this.isPlaying = false;
|
||||
if (this.onUpdateButton) this.onUpdateButton(button, false);
|
||||
console.error(`${ctx} play() failed:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.audioElement) {
|
||||
this._removeEventHandlers();
|
||||
try {
|
||||
this.audioElement.pause();
|
||||
this.audioElement.removeAttribute('src');
|
||||
this.audioElement.load();
|
||||
if (this.audioElement.parentNode) {
|
||||
this.audioElement.parentNode.removeChild(this.audioElement);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[shared-audio-player] Error cleaning up audio element:', e);
|
||||
}
|
||||
this.audioElement = null;
|
||||
}
|
||||
this.isPlaying = false;
|
||||
this.currentUid = null;
|
||||
if (this.currentButton && this.onUpdateButton) {
|
||||
this.onUpdateButton(this.currentButton, false);
|
||||
}
|
||||
this.currentButton = null;
|
||||
}
|
||||
|
||||
_attachEventHandlers() {
|
||||
if (!this.audioElement) return;
|
||||
const ctx = `[SharedAudioPlayer][${this.playerType}]${this.currentUid ? `[${this.currentUid}]` : ''}`;
|
||||
const logEvent = (event) => {
|
||||
// Debug logging disabled
|
||||
};
|
||||
// Core handlers
|
||||
const onPlay = (e) => {
|
||||
logEvent(e);
|
||||
this.isPlaying = true;
|
||||
if (this.currentButton && this.onUpdateButton) this.onUpdateButton(this.currentButton, true);
|
||||
};
|
||||
const onPause = (e) => {
|
||||
logEvent(e);
|
||||
// console.trace(`${ctx} Audio pause stack trace:`);
|
||||
this.isPlaying = false;
|
||||
if (this.currentButton && this.onUpdateButton) this.onUpdateButton(this.currentButton, false);
|
||||
};
|
||||
const onEnded = (e) => {
|
||||
logEvent(e);
|
||||
this.isPlaying = false;
|
||||
if (this.currentButton && this.onUpdateButton) this.onUpdateButton(this.currentButton, false);
|
||||
};
|
||||
const onError = (e) => {
|
||||
logEvent(e);
|
||||
this.isPlaying = false;
|
||||
if (this.currentButton && this.onUpdateButton) this.onUpdateButton(this.currentButton, false);
|
||||
console.error(`${ctx} Audio error:`, e);
|
||||
};
|
||||
// Attach handlers
|
||||
this.audioElement.addEventListener('play', onPlay);
|
||||
this.audioElement.addEventListener('pause', onPause);
|
||||
this.audioElement.addEventListener('ended', onEnded);
|
||||
this.audioElement.addEventListener('error', onError);
|
||||
// Attach debug logging for all relevant events
|
||||
const debugEvents = [
|
||||
'abort','canplay','canplaythrough','durationchange','emptied','encrypted','loadeddata','loadedmetadata',
|
||||
'loadstart','playing','progress','ratechange','seeked','seeking','stalled','suspend','timeupdate','volumechange','waiting'
|
||||
];
|
||||
debugEvents.forEach(evt => {
|
||||
this.audioElement.addEventListener(evt, logEvent);
|
||||
}); // Logging now disabled
|
||||
this._eventHandlers = { onPlay, onPause, onEnded, onError, debugEvents, logEvent };
|
||||
}
|
||||
|
||||
_removeEventHandlers() {
|
||||
if (!this.audioElement || !this._eventHandlers) return;
|
||||
const { onPlay, onPause, onEnded, onError } = this._eventHandlers;
|
||||
if (onPlay) this.audioElement.removeEventListener('play', onPlay);
|
||||
if (onPause) this.audioElement.removeEventListener('pause', onPause);
|
||||
if (onEnded) this.audioElement.removeEventListener('ended', onEnded);
|
||||
if (onError) this.audioElement.removeEventListener('error', onError);
|
||||
this._eventHandlers = {};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user