admin
Some checks are pending
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
71e4926395
commit
44f56e0554
2 changed files with 50 additions and 7 deletions
|
|
@ -386,7 +386,26 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
|
||||||
const handlePlayPause = () => {
|
const handlePlayPause = () => {
|
||||||
if (!audioRef.current) {
|
if (!audioRef.current) {
|
||||||
try {
|
try {
|
||||||
const audio = new Audio(`data:audio/mpeg;base64,${voice.voiceUrl}`)
|
// voiceUrl can be either:
|
||||||
|
// 1. Presigned URL (http/https) - new format
|
||||||
|
// 2. Base64 data URL (data:audio/...) - legacy format
|
||||||
|
// 3. UUID - if presigned URL generation failed (shouldn't happen, but handle gracefully)
|
||||||
|
let audioUrl = voice.voiceUrl
|
||||||
|
|
||||||
|
// If it's a UUID (not a URL and not base64), we can't play it directly
|
||||||
|
// This shouldn't happen as backend should return presigned URL, but handle it
|
||||||
|
if (!audioUrl.startsWith('http://') && !audioUrl.startsWith('https://') && !audioUrl.startsWith('data:')) {
|
||||||
|
// Check if it looks like a UUID
|
||||||
|
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
||||||
|
if (uuidPattern.test(audioUrl)) {
|
||||||
|
toast.error('Audio URL is not available. Please refresh the page.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Otherwise, assume it's legacy base64 without data: prefix
|
||||||
|
audioUrl = `data:audio/mpeg;base64,${audioUrl}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const audio = new Audio(audioUrl)
|
||||||
audioRef.current = audio
|
audioRef.current = audio
|
||||||
|
|
||||||
audio.onended = () => {
|
audio.onended = () => {
|
||||||
|
|
@ -394,9 +413,18 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
}
|
}
|
||||||
|
|
||||||
audio.onerror = (e) => {
|
audio.onerror = (e: Event | string) => {
|
||||||
console.error('Audio playback error:', e)
|
console.error('Audio playback error:', e)
|
||||||
toast.error('Failed to play audio. The file may be corrupted or in an unsupported format.')
|
let errorMessage = 'Failed to play audio. The file may be corrupted, in an unsupported format, or the URL may have expired.'
|
||||||
|
|
||||||
|
if (e instanceof Event) {
|
||||||
|
const audioElement = e.target as HTMLAudioElement | null
|
||||||
|
if (audioElement?.error) {
|
||||||
|
errorMessage = `Failed to load audio: ${audioElement.error.message || 'Unknown error'}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.error(errorMessage)
|
||||||
setIsPlaying(false)
|
setIsPlaying(false)
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
}
|
}
|
||||||
|
|
@ -407,7 +435,10 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
|
||||||
|
|
||||||
audio.play().catch((error) => {
|
audio.play().catch((error) => {
|
||||||
console.error('Audio play error:', error)
|
console.error('Audio play error:', error)
|
||||||
toast.error('Failed to play audio. Please check your browser audio settings.')
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Failed to play audio'
|
||||||
|
toast.error(`Failed to play audio: ${errorMessage}. Please check your browser audio settings.`)
|
||||||
setIsPlaying(false)
|
setIsPlaying(false)
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -173,9 +173,18 @@ export function AudioUpload({
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
}
|
}
|
||||||
|
|
||||||
audio.onerror = (e) => {
|
audio.onerror = (e: Event | string) => {
|
||||||
console.error('Audio playback error:', e)
|
console.error('Audio playback error:', e)
|
||||||
alert('Failed to play audio. The file may be corrupted or in an unsupported format.')
|
let errorMessage = 'Failed to play audio. The file may be corrupted, in an unsupported format, or the URL may have expired.'
|
||||||
|
|
||||||
|
if (e instanceof Event) {
|
||||||
|
const audioElement = e.target as HTMLAudioElement | null
|
||||||
|
if (audioElement?.error) {
|
||||||
|
errorMessage = `Failed to load audio: ${audioElement.error.message || 'Unknown error'}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(errorMessage)
|
||||||
setIsPlaying(false)
|
setIsPlaying(false)
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +195,10 @@ export function AudioUpload({
|
||||||
|
|
||||||
audio.play().catch((error) => {
|
audio.play().catch((error) => {
|
||||||
console.error('Audio play error:', error)
|
console.error('Audio play error:', error)
|
||||||
alert('Failed to play audio. Please check your browser audio settings.')
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Failed to play audio'
|
||||||
|
alert(`Failed to play audio: ${errorMessage}. Please check your browser audio settings.`)
|
||||||
setIsPlaying(false)
|
setIsPlaying(false)
|
||||||
audioRef.current = null
|
audioRef.current = null
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue