Update authentication system, database models, and UI components
This commit is contained in:
@ -1,81 +1,57 @@
|
||||
import { showToast } from "./toast.js";
|
||||
import { globalAudioManager } from './global-audio-manager.js';
|
||||
import { SharedAudioPlayer } from './shared-audio-player.js';
|
||||
|
||||
// Module-level state for the personal player
|
||||
let audio = null;
|
||||
function getPersonalStreamUrl(uid) {
|
||||
return `/audio/${encodeURIComponent(uid)}/stream.opus`;
|
||||
}
|
||||
|
||||
function updatePlayPauseButton(button, isPlaying) {
|
||||
if (button) button.textContent = isPlaying ? '⏸️' : '▶️';
|
||||
// Optionally, update other UI elements here
|
||||
}
|
||||
|
||||
const personalPlayer = new SharedAudioPlayer({
|
||||
playerType: 'personal',
|
||||
getStreamUrl: getPersonalStreamUrl,
|
||||
onUpdateButton: updatePlayPauseButton
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds or creates the audio element for the personal stream.
|
||||
* @returns {HTMLAudioElement | null}
|
||||
*/
|
||||
function getOrCreateAudioElement() {
|
||||
if (audio) {
|
||||
return audio;
|
||||
}
|
||||
|
||||
audio = document.createElement('audio');
|
||||
audio.id = 'me-audio';
|
||||
audio.preload = 'metadata';
|
||||
audio.crossOrigin = 'use-credentials';
|
||||
document.body.appendChild(audio);
|
||||
|
||||
// --- Setup Event Listeners (only once) ---
|
||||
audio.addEventListener('error', (e) => {
|
||||
console.error('Personal Player: Audio Element Error', e);
|
||||
const error = audio.error;
|
||||
let errorMessage = 'An unknown audio error occurred.';
|
||||
if (error) {
|
||||
switch (error.code) {
|
||||
case error.MEDIA_ERR_ABORTED:
|
||||
errorMessage = 'Audio playback was aborted.';
|
||||
break;
|
||||
case error.MEDIA_ERR_NETWORK:
|
||||
errorMessage = 'A network error caused the audio to fail.';
|
||||
break;
|
||||
case error.MEDIA_ERR_DECODE:
|
||||
errorMessage = 'The audio could not be decoded.';
|
||||
break;
|
||||
case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
||||
errorMessage = 'The audio format is not supported by your browser.';
|
||||
break;
|
||||
default:
|
||||
errorMessage = `An unexpected error occurred (Code: ${error.code}).`;
|
||||
break;
|
||||
function cleanupPersonalAudio() {
|
||||
if (audioElement) {
|
||||
try {
|
||||
if (audioElement._eventHandlers) {
|
||||
const { onPlay, onPause, onEnded, onError } = audioElement._eventHandlers;
|
||||
if (onPlay) audioElement.removeEventListener('play', onPlay);
|
||||
if (onPause) audioElement.removeEventListener('pause', onPause);
|
||||
if (onEnded) audioElement.removeEventListener('ended', onEnded);
|
||||
if (onError) audioElement.removeEventListener('error', onError);
|
||||
}
|
||||
audioElement.pause();
|
||||
audioElement.removeAttribute('src');
|
||||
audioElement.load();
|
||||
if (audioElement._eventHandlers) delete audioElement._eventHandlers;
|
||||
// Remove from DOM
|
||||
if (audioElement.parentNode) audioElement.parentNode.removeChild(audioElement);
|
||||
} catch (e) {
|
||||
console.warn('[personal-player.js] Error cleaning up audio element:', e);
|
||||
}
|
||||
showToast(errorMessage, 'error');
|
||||
});
|
||||
|
||||
audio.addEventListener('play', () => updatePlayPauseButton(true));
|
||||
audio.addEventListener('pause', () => updatePlayPauseButton(false));
|
||||
audio.addEventListener('ended', () => updatePlayPauseButton(false));
|
||||
|
||||
// The canplaythrough listener is removed as it violates autoplay policies.
|
||||
// The user will perform a second click to play the media after it's loaded.
|
||||
|
||||
return audio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the play/pause button icon based on audio state.
|
||||
* @param {boolean} isPlaying - Whether the audio is currently playing.
|
||||
*/
|
||||
function updatePlayPauseButton(isPlaying) {
|
||||
const playPauseBtn = document.querySelector('#me-page .play-pause-btn');
|
||||
if (playPauseBtn) {
|
||||
playPauseBtn.textContent = isPlaying ? '⏸️' : '▶️';
|
||||
audioElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the user's personal audio stream into the player.
|
||||
* @param {string} uid - The user's unique ID.
|
||||
*/
|
||||
export async function loadProfileStream(uid) {
|
||||
const audioElement = getOrCreateAudioElement();
|
||||
const audioSrc = `/audio/${uid}/stream.opus?t=${Date.now()}`;
|
||||
console.log(`[personal-player.js] Setting personal audio source to: ${audioSrc}`);
|
||||
audioElement.src = audioSrc;
|
||||
|
||||
|
||||
// Use the shared player for loading and playing the personal stream
|
||||
export function loadProfileStream(uid, playPauseBtn) {
|
||||
if (!uid) {
|
||||
showToast('No UID provided for profile stream', 'error');
|
||||
return;
|
||||
}
|
||||
personalPlayer.play(uid, playPauseBtn);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,50 +67,19 @@ export function initPersonalPlayer() {
|
||||
if (!playPauseBtn) return;
|
||||
|
||||
e.stopPropagation();
|
||||
const audio = getOrCreateAudioElement();
|
||||
if (!audio) return;
|
||||
|
||||
try {
|
||||
if (audio.paused) {
|
||||
if (!audio.src || audio.src.endsWith('/#')) {
|
||||
showToast('No audio file available. Please upload one first.', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Attempting to play...');
|
||||
globalAudioManager.startPlayback('personal', localStorage.getItem('uid') || 'personal');
|
||||
|
||||
const playPromise = audio.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
console.error(`Initial play() failed: ${error.name}. This is expected on first load.`);
|
||||
// If play fails, it's because the content isn't loaded.
|
||||
// The recovery is to call load(). The user will need to click play again.
|
||||
console.log('Calling load() to fetch media...');
|
||||
audio.load();
|
||||
showToast('Stream is loading. Please click play again in a moment.', 'info');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log('Attempting to pause...');
|
||||
audio.pause();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('A synchronous error occurred in handlePlayPause:', err);
|
||||
showToast('An unexpected error occurred with the audio player.', 'error');
|
||||
const uid = localStorage.getItem('uid');
|
||||
if (!uid) {
|
||||
showToast('Please log in to play audio.', 'error');
|
||||
return;
|
||||
}
|
||||
// Toggle play/pause
|
||||
if (personalPlayer.audioElement && !personalPlayer.audioElement.paused && !personalPlayer.audioElement.ended) {
|
||||
personalPlayer.pause();
|
||||
} else {
|
||||
loadProfileStream(uid, playPauseBtn);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for stop requests from the global manager
|
||||
globalAudioManager.addListener('personal', () => {
|
||||
console.log('[personal-player.js] Received stop request from global audio manager.');
|
||||
const audio = getOrCreateAudioElement();
|
||||
if (audio && !audio.paused) {
|
||||
console.log('[personal-player.js] Pausing personal audio player.');
|
||||
audio.pause();
|
||||
}
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
getOrCreateAudioElement();
|
||||
// Make loadProfileStream globally accessible for upload.js
|
||||
window.loadProfileStream = loadProfileStream;
|
||||
}
|
||||
|
Reference in New Issue
Block a user