Fix 403 error when loading music files
- Fix path traversal security check by using absolute paths - Remove problematic fetch override that forced JSON headers on all API requests - Add error tracking and visual indicators for failed tracks - Correct music directory resolution for both relative and absolute paths The main issue was the security validation comparing relative paths incorrectly, causing legitimate music file requests to be rejected with 403 errors.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
:is-playing="isPlaying"
|
||||
:loading="loading"
|
||||
:loading-track="loadingTrack"
|
||||
:failed-tracks="failedTracks"
|
||||
@track-selected="handleTrackSelected"
|
||||
/>
|
||||
</MainContainer>
|
||||
@@ -76,6 +77,7 @@ const duration = ref(0)
|
||||
const volume = ref(0.7)
|
||||
const loading = ref(true)
|
||||
const loadingTrack = ref(null)
|
||||
const failedTracks = ref(new Set()) // Track failed tracks
|
||||
|
||||
// Theme (handled by ThemeToggle component now)
|
||||
const isDark = useLocalStorage('theme-dark', false)
|
||||
@@ -139,6 +141,11 @@ const playTrack = async (track, index) => {
|
||||
// Fetch and preload entire song into memory
|
||||
const encodedName = encodeURIComponent(track.name)
|
||||
const response = await fetch(`/api/music/${encodedName}`)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
const blob = await response.blob()
|
||||
const audioUrl = URL.createObjectURL(blob)
|
||||
|
||||
@@ -155,7 +162,12 @@ const playTrack = async (track, index) => {
|
||||
}, { once: true })
|
||||
} catch (error) {
|
||||
console.error('Failed to preload track:', error)
|
||||
// Fallback to streaming
|
||||
|
||||
// Mark track as failed
|
||||
failedTracks.value.add(track.name)
|
||||
loadingTrack.value = null
|
||||
|
||||
// Try fallback to streaming
|
||||
const encodedName = encodeURIComponent(track.name)
|
||||
audioPlayer.value.src = `/api/music/${encodedName}`
|
||||
audioPlayer.value.load()
|
||||
@@ -270,8 +282,19 @@ const onLoadedMetadata = () => {
|
||||
const onAudioError = (error) => {
|
||||
console.error('Audio error:', error)
|
||||
console.error('Failed to load:', currentTrack.value?.name)
|
||||
|
||||
// Mark track as failed
|
||||
if (currentTrack.value) {
|
||||
failedTracks.value.add(currentTrack.value.name)
|
||||
}
|
||||
|
||||
// Clear loading state
|
||||
loadingTrack.value = null
|
||||
|
||||
// Try next track if current fails
|
||||
nextTrack()
|
||||
setTimeout(() => {
|
||||
nextTrack()
|
||||
}, 1000) // Small delay before trying next track
|
||||
}
|
||||
|
||||
const onTimeUpdate = () => {
|
||||
@@ -291,7 +314,7 @@ const onCanPlay = () => {
|
||||
|
||||
// Watchers
|
||||
watch(isDark, (newValue) => {
|
||||
if (process.client) {
|
||||
if (import.meta.client) {
|
||||
document.documentElement.setAttribute('data-theme', newValue ? 'dark' : 'light')
|
||||
}
|
||||
}, { immediate: true })
|
||||
@@ -313,7 +336,7 @@ const cleanupAudio = () => {
|
||||
|
||||
// Handle mobile browser UI bars
|
||||
const handleViewportChange = () => {
|
||||
if (!process.client) return
|
||||
if (!import.meta.client) return
|
||||
|
||||
const vh = window.innerHeight
|
||||
const dvh = window.visualViewport ? window.visualViewport.height : vh
|
||||
@@ -336,7 +359,7 @@ const handleViewportChange = () => {
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
loadTracks()
|
||||
if (process.client) {
|
||||
if (import.meta.client) {
|
||||
document.documentElement.setAttribute('data-theme', isDark.value ? 'dark' : 'light')
|
||||
|
||||
// Handle mobile browser UI changes
|
||||
@@ -354,7 +377,7 @@ onMounted(() => {
|
||||
|
||||
onUnmounted(() => {
|
||||
cleanupAudio()
|
||||
if (process.client) {
|
||||
if (import.meta.client) {
|
||||
window.removeEventListener('beforeunload', cleanupAudio)
|
||||
window.removeEventListener('pagehide', cleanupAudio)
|
||||
window.removeEventListener('resize', handleViewportChange)
|
||||
|
||||
Reference in New Issue
Block a user