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

This commit is contained in:
Dmitry 2026-01-24 20:47:38 +03:00
parent 71e4926395
commit 44f56e0554
2 changed files with 50 additions and 7 deletions

View file

@ -386,7 +386,26 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
const handlePlayPause = () => {
if (!audioRef.current) {
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
audio.onended = () => {
@ -394,9 +413,18 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
audioRef.current = null
}
audio.onerror = (e) => {
audio.onerror = (e: Event | string) => {
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)
audioRef.current = null
}
@ -407,7 +435,10 @@ function VoiceItem({ voice, onRemove, disabled }: VoiceItemProps) {
audio.play().catch((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)
audioRef.current = null
})

View file

@ -173,9 +173,18 @@ export function AudioUpload({
audioRef.current = null
}
audio.onerror = (e) => {
audio.onerror = (e: Event | string) => {
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)
audioRef.current = null
}
@ -186,7 +195,10 @@ export function AudioUpload({
audio.play().catch((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)
audioRef.current = null
})