diff --git a/frontend/src/pages/observation.tsx b/frontend/src/pages/observation.tsx index e468292..b53c28e 100644 --- a/frontend/src/pages/observation.tsx +++ b/frontend/src/pages/observation.tsx @@ -25,6 +25,8 @@ import { mdiDancePole, mdiEye, mdiEyeOff, + mdiUpload, + mdiCheckCircle, } from '@mdi/js'; import BaseIcon from '../components/BaseIcon'; import { useAppDispatch } from '../stores/hooks'; @@ -114,6 +116,7 @@ const ObservationPage = () => { const canvasRef = useRef(null); const crowdAudioRef = useRef(null); const karaokeAudioRef = useRef(null); + const fileInputRef = useRef(null); const audioCtxRef = useRef(null); const audioDestRef = useRef(null); @@ -148,6 +151,9 @@ const ObservationPage = () => { const [mediaRecorder, setMediaRecorder] = useState(null); const [videoUrl, setVideoUrl] = useState(null); + const [customAudioMap, setCustomAudioMap] = useState>({}); + const [songToUpload, setSongToUpload] = useState(null); + const imageCache = useRef>(new Map()); // Persistent karaoke audio setup @@ -296,7 +302,8 @@ const ObservationPage = () => { setShowPlaylist(false); audio.pause(); - audio.src = song.url; + // Use custom audio if available, otherwise use default URL + audio.src = customAudioMap[song.id] || song.url; audio.load(); try { @@ -320,6 +327,38 @@ const ObservationPage = () => { } }; + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file && songToUpload) { + const url = URL.createObjectURL(file); + setCustomAudioMap(prev => { + // Revoke previous custom audio for this song if it exists + if (prev[songToUpload.id]) { + URL.revokeObjectURL(prev[songToUpload.id]); + } + return { ...prev, [songToUpload.id]: url }; + }); + setSongToUpload(null); + // If we're currently playing this song, update the source immediately + if (currentSong?.id === songToUpload.id && karaokeAudioRef.current) { + const wasPaused = karaokeAudioRef.current.paused; + karaokeAudioRef.current.src = url; + karaokeAudioRef.current.load(); + if (!wasPaused) { + karaokeAudioRef.current.play().catch(err => console.error("Playback update error:", err)); + } + } + } + // Reset file input value to allow selecting the same file again if needed + if (fileInputRef.current) fileInputRef.current.value = ""; + }; + + const triggerUpload = (e: React.MouseEvent, song: any) => { + e.stopPropagation(); + setSongToUpload(song); + fileInputRef.current?.click(); + }; + useEffect(() => { let animationFrame: number; const canvas = canvasRef.current; @@ -417,6 +456,9 @@ const ObservationPage = () => {
KARAOKE GLOBAL 10K+ | AO VIVO + {/* Hidden File Input for Custom Audio */} + +
{!isCameraActive && (
@@ -466,8 +508,9 @@ const ObservationPage = () => {
- + {currentSong.title} - {currentSong.artist} + {customAudioMap[currentSong.id] && LOCAL}
{currentLyrics || "VAI COMEÇAR..."} @@ -551,7 +594,7 @@ const ObservationPage = () => {

Estúdio 10.000+

-

Seu palco, sua música, seu mundo

+

Configure seus playbacks e brilhe

@@ -574,19 +617,27 @@ const ObservationPage = () => {
{filteredSongs.length > 0 ? filteredSongs.map(song => ( - +
+ +
- +
)) : (
@@ -595,17 +646,20 @@ const ObservationPage = () => {
)} -
+
{ + setSongToUpload({ id: 'new-custom', title: 'Upload Personalizado', artist: 'Arquivo Local', genre: 'Personalizado' }); + fileInputRef.current?.click(); + }}> -

Explorar Nuvem de 10.000 Hits

-

Novos playbacks adicionados diariamente

+

Carregar Áudio Personalizado

+

Substitua playbacks por seus próprios arquivos MP3/WAV

- Qualidade de Áudio - ULTRA-HD 320KBPS + Configuração de Playback + LOCAL & CLOUD SYNC ATIVO