stream bug

This commit is contained in:
Broque Thomas 2025-08-23 15:19:43 -07:00
parent 886c2e84c8
commit c5d9b010c9
2 changed files with 189 additions and 13 deletions

View file

@ -966,7 +966,22 @@ def stream_audio():
return jsonify({"error": "Audio file not found"}), 404
print(f"🎵 Serving audio file: {os.path.basename(file_path)}")
return send_file(file_path, as_attachment=False)
# Determine MIME type based on file extension
file_ext = os.path.splitext(file_path)[1].lower()
mime_types = {
'.mp3': 'audio/mpeg',
'.flac': 'audio/flac',
'.ogg': 'audio/ogg',
'.aac': 'audio/aac',
'.m4a': 'audio/mp4',
'.wav': 'audio/wav',
'.wma': 'audio/x-ms-wma'
}
mimetype = mime_types.get(file_ext, 'audio/mpeg') # Default to MP3
return send_file(file_path, as_attachment=False, mimetype=mimetype)
except Exception as e:
print(f"❌ Error serving audio file: {e}")

View file

@ -339,11 +339,25 @@ function clearTrack() {
// Hide loading animation
hideLoadingAnimation();
// Show no track message and collapse if expanded
// Show no track message and collapse media player
document.getElementById('no-track-message').classList.remove('hidden');
// Force collapse the media player when track is cleared
if (mediaPlayerExpanded) {
toggleMediaPlayerExpansion();
}
// Ensure media player returns to compact state
const mediaPlayer = document.getElementById('media-player');
if (mediaPlayer) {
mediaPlayer.style.minHeight = '85px';
const expandedContent = document.getElementById('media-expanded');
if (expandedContent) {
expandedContent.classList.add('hidden');
}
}
console.log('🧹 Track cleared and media player reset');
}
function setPlayingState(playing) {
@ -551,19 +565,54 @@ async function startAudioPlayback() {
console.log(`🎵 Loading audio from: ${audioUrl}`);
// Start playback
await audioPlayer.play();
// Wait a moment for the file to be fully ready
await new Promise(resolve => setTimeout(resolve, 500));
// Update UI to playing state
hideLoadingAnimation();
setPlayingState(true);
// Try to start playback with retry logic
let retryCount = 0;
const maxRetries = 3;
console.log('✅ Audio playback started successfully');
while (retryCount < maxRetries) {
try {
await audioPlayer.play();
console.log('✅ Audio playback started successfully');
// Update UI to playing state
hideLoadingAnimation();
setPlayingState(true);
return; // Success!
} catch (playError) {
retryCount++;
console.warn(`⚠️ Audio play attempt ${retryCount} failed:`, playError.message);
if (retryCount >= maxRetries) {
throw playError; // Re-throw after max retries
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
} catch (error) {
console.error('❌ Error starting audio playback:', error);
hideLoadingAnimation();
showToast(`Playback error: ${error.message}`, 'error');
// Provide user-friendly error messages
let userMessage = 'Playback failed';
if (error.message.includes('no supported source') ||
error.message.includes('Not supported') ||
error.message.includes('MEDIA_ELEMENT_ERROR')) {
userMessage = 'Audio format not supported by your browser. Try downloading instead.';
} else if (error.message.includes('network') || error.message.includes('fetch')) {
userMessage = 'Network error - please try again';
} else if (error.message.includes('decode')) {
userMessage = 'Audio file is corrupted or incompatible';
}
showToast(userMessage, 'error');
clearTrack();
}
}
@ -659,10 +708,49 @@ function onAudioEnded() {
function onAudioError(event) {
// Handle audio playback errors
console.error('❌ Audio error:', event.target.error);
const error = event.target.error;
console.error('❌ Audio error:', error);
// Don't show error toast if it's just a format/codec issue and retrying
if (error && error.code) {
console.error(`Audio error code: ${error.code}, message: ${error.message || 'Unknown error'}`);
// Only show user-facing errors for serious issues
if (error.code === 4) { // MEDIA_ELEMENT_ERROR: Media not supported
console.warn('⚠️ Media format not supported by browser, but streaming may still work');
// Don't clear track or show error - let retry logic handle it
return;
}
}
hideLoadingAnimation();
showToast('Audio playback error occurred', 'error');
clearTrack();
// Only clear track after a short delay to allow for recovery
setTimeout(() => {
if (audioPlayer && audioPlayer.error) {
let userMessage = 'Audio format not supported by your browser. Try downloading instead.';
if (error && error.code) {
switch (error.code) {
case 1: // MEDIA_ERR_ABORTED
userMessage = 'Playback was stopped';
break;
case 2: // MEDIA_ERR_NETWORK
userMessage = 'Network error - please try again';
break;
case 3: // MEDIA_ERR_DECODE
userMessage = 'Audio file is corrupted or incompatible';
break;
case 4: // MEDIA_ERR_SRC_NOT_SUPPORTED
userMessage = 'Audio format not supported by your browser. Try downloading instead.';
break;
}
}
showToast(userMessage, 'error');
clearTrack();
}
}, 2000);
}
function onAudioLoadStart() {
@ -684,6 +772,54 @@ function formatTime(seconds) {
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
// ===============================
// AUDIO FORMAT SUPPORT DETECTION
// ===============================
function getFileExtension(filename) {
if (!filename) return '';
const ext = filename.toLowerCase().match(/\.([^.]+)$/);
return ext ? ext[1] : '';
}
function isAudioFormatSupported(filename) {
const ext = getFileExtension(filename);
const supportedFormats = ['mp3', 'ogg', 'wav']; // Most reliable formats
const partialSupport = ['flac', 'aac']; // Depends on browser
const unsupported = ['m4a', 'wma', 'ape', 'aiff']; // Generally problematic
if (supportedFormats.includes(ext)) {
return true;
}
if (partialSupport.includes(ext)) {
// Test if browser can actually play this format
return canPlayAudioFormat(ext);
}
return false; // Unsupported formats
}
function canPlayAudioFormat(extension) {
const audio = document.createElement('audio');
const mimeTypes = {
'mp3': 'audio/mpeg',
'ogg': 'audio/ogg; codecs="vorbis"',
'wav': 'audio/wav',
'flac': 'audio/flac',
'aac': 'audio/aac',
'm4a': 'audio/mp4',
'wma': 'audio/x-ms-wma'
};
const mimeType = mimeTypes[extension];
if (!mimeType) return false;
const canPlay = audio.canPlayType(mimeType);
return canPlay === 'probably' || canPlay === 'maybe';
}
// ===============================
// DONATION WIDGET
// ===============================
@ -1745,6 +1881,13 @@ async function streamTrack(index) {
const result = window.currentSearchResults[index];
console.log(`🎵 Streaming track:`, result);
// Check for unsupported formats before streaming
if (result.filename && !isAudioFormatSupported(result.filename)) {
const format = getFileExtension(result.filename);
showToast(`Sorry, ${format.toUpperCase()} format is not supported in web browsers. Try downloading instead.`, 'error');
return;
}
await startStream(result);
} catch (error) {
@ -1778,7 +1921,25 @@ async function streamAlbumTrack(albumIndex, trackIndex) {
const track = album.tracks[trackIndex];
console.log(`🎵 Streaming album track:`, track);
await startStream(track);
// Ensure album tracks have required fields
const trackData = {
...track,
username: track.username || album.username,
filename: track.filename || track.path,
artist: track.artist || album.artist,
album: track.album || album.title || album.album
};
console.log(`🎵 Enhanced track data:`, trackData);
// Check for unsupported formats before streaming
if (trackData.filename && !isAudioFormatSupported(trackData.filename)) {
const format = getFileExtension(trackData.filename);
showToast(`Sorry, ${format.toUpperCase()} format is not supported in web browsers. Try downloading instead.`, 'error');
return;
}
await startStream(trackData);
} catch (error) {
console.error('Album track streaming error:', error);