Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| 🎵 DJ SYSTEM - VERSÃO BÁSICA PARA CARREGAMENTO DE ÁUDIO | |
| ======================================================= | |
| Versão ultra simplificada focada APENAS no carregamento de áudio. | |
| Removidas todas as funcionalidades avançadas para eliminar complexidade. | |
| """ | |
| from fastapi import FastAPI, HTMLResponse | |
| import time | |
| app = FastAPI(title="DJ Audio Loading Test", version="1.0.0") | |
| html_content = """ | |
| <!DOCTYPE html> | |
| <html lang="pt"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>🎵 Teste de Carregamento de Áudio</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| background: #2c3e50; | |
| color: white; | |
| padding: 20px; | |
| margin: 0; | |
| } | |
| .container { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| background: #34495e; | |
| padding: 30px; | |
| border-radius: 10px; | |
| box-shadow: 0 0 20px rgba(0,0,0,0.3); | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| } | |
| .deck { | |
| background: #2c3e50; | |
| padding: 20px; | |
| margin: 20px 0; | |
| border-radius: 8px; | |
| border: 2px solid #3498db; | |
| } | |
| .deck-title { | |
| font-size: 20px; | |
| font-weight: bold; | |
| margin-bottom: 15px; | |
| color: #3498db; | |
| } | |
| .file-input { | |
| margin: 15px 0; | |
| } | |
| .file-input input[type="file"] { | |
| display: none; | |
| } | |
| .file-button { | |
| background: #e74c3c; | |
| color: white; | |
| padding: 15px 30px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| font-weight: bold; | |
| display: block; | |
| width: 100%; | |
| text-align: center; | |
| transition: background 0.3s; | |
| } | |
| .file-button:hover { | |
| background: #c0392b; | |
| } | |
| .status { | |
| margin: 10px 0; | |
| padding: 10px; | |
| border-radius: 5px; | |
| font-weight: bold; | |
| } | |
| .status.idle { | |
| background: #7f8c8d; | |
| color: white; | |
| } | |
| .status.loading { | |
| background: #f39c12; | |
| color: black; | |
| animation: pulse 1s infinite; | |
| } | |
| .status.success { | |
| background: #27ae60; | |
| color: white; | |
| } | |
| .status.error { | |
| background: #e74c3c; | |
| color: white; | |
| } | |
| @keyframes pulse { | |
| 0% { opacity: 1; } | |
| 50% { opacity: 0.7; } | |
| 100% { opacity: 1; } | |
| } | |
| .info { | |
| margin: 10px 0; | |
| padding: 10px; | |
| background: #34495e; | |
| border-radius: 5px; | |
| } | |
| .console { | |
| background: #1a1a1a; | |
| color: #00ff00; | |
| padding: 15px; | |
| border-radius: 5px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 12px; | |
| margin-top: 20px; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| .play-button { | |
| background: #27ae60; | |
| color: white; | |
| padding: 10px 20px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| margin: 5px; | |
| transition: background 0.3s; | |
| } | |
| .play-button:hover:not(:disabled) { | |
| background: #229954; | |
| } | |
| .play-button:disabled { | |
| background: #7f8c8d; | |
| cursor: not-allowed; | |
| } | |
| .test-section { | |
| background: #8e44ad; | |
| padding: 20px; | |
| border-radius: 8px; | |
| margin: 20px 0; | |
| } | |
| .test-button { | |
| background: #9b59b6; | |
| color: white; | |
| padding: 10px 15px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| margin: 5px; | |
| font-size: 12px; | |
| } | |
| .test-button:hover { | |
| background: #8e44ad; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>🎵 TESTE DE CARREGAMENTO DE ÁUDIO</h1> | |
| <p>Versão Básica - Focada apenas no carregamento de arquivos</p> | |
| </div> | |
| <div class="test-section"> | |
| <h3>🧪 TESTES DE SISTEMA</h3> | |
| <button class="test-button" onclick="testAudioContext()">Testar AudioContext</button> | |
| <button class="test-button" onclick="testFileAPI()">Testar File API</button> | |
| <button class="test-button" onclick="clearConsole()">Limpar Console</button> | |
| </div> | |
| <div class="console" id="console">🚀 Sistema inicializando...</div> | |
| <!-- Deck A --> | |
| <div class="deck"> | |
| <div class="deck-title">🔵 DECK A</div> | |
| <div class="status idle" id="status-A"> | |
| 🟢 Pronto - Clique no botão para carregar um arquivo | |
| </div> | |
| <div class="file-input"> | |
| <input type="file" id="file-A" accept="audio/*"> | |
| <label for="file-A" class="file-button"> | |
| 📁 CARREGAR ARQUIVO - DECK A | |
| </label> | |
| </div> | |
| <div class="info" id="info-A" style="display: none;"> | |
| <div><strong>Arquivo:</strong> <span id="filename-A">-</span></div> | |
| <div><strong>Duração:</strong> <span id="duration-A">-</span></div> | |
| <div><strong>Tamanho:</strong> <span id="size-A">-</span></div> | |
| <button class="play-button" id="play-A" onclick="playAudio('A')" disabled>▶️ TOCAR</button> | |
| </div> | |
| </div> | |
| <!-- Deck B --> | |
| <div class="deck"> | |
| <div class="deck-title">🟣 DECK B</div> | |
| <div class="status idle" id="status-B"> | |
| 🟢 Pronto - Clique no botão para carregar um arquivo | |
| </div> | |
| <div class="file-input"> | |
| <input type="file" id="file-B" accept="audio/*"> | |
| <label for="file-B" class="file-button"> | |
| 📁 CARREGAR ARQUIVO - DECK B | |
| </label> | |
| </div> | |
| <div class="info" id="info-B" style="display: none;"> | |
| <div><strong>Arquivo:</strong> <span id="filename-B">-</span></div> | |
| <div><strong>Duração:</strong> <span id="duration-B">-</span></div> | |
| <div><strong>Tamanho:</strong> <span id="size-B">-</span></div> | |
| <button class="play-button" id="play-B" onclick="playAudio('B')" disabled>▶️ TOCAR</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Variáveis globais | |
| let audioContext; | |
| let decks = { | |
| A: { buffer: null, source: null, isPlaying: false }, | |
| B: { buffer: null, source: null, isPlaying: false } | |
| }; | |
| // Função para adicionar logs | |
| function addLog(message) { | |
| const console = document.getElementById('console'); | |
| const timestamp = new Date().toLocaleTimeString(); | |
| console.innerHTML += `<br>[${timestamp}] ${message}`; | |
| console.scrollTop = console.scrollHeight; | |
| console.log('LOG:', message); | |
| } | |
| function clearConsole() { | |
| document.getElementById('console').innerHTML = '🚀 Console limpo - Pronto para testes'; | |
| } | |
| // Inicialização | |
| function initialize() { | |
| addLog('🚀 Iniciando sistema básico...'); | |
| // Criar AudioContext | |
| try { | |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
| addLog('✅ AudioContext criado com sucesso'); | |
| // Se AudioContext estiver suspenso, requer interação do usuário | |
| if (audioContext.state === 'suspended') { | |
| addLog('⚠️ AudioContext suspenso - aguarde interação do usuário'); | |
| } | |
| } catch (error) { | |
| addLog('❌ Erro ao criar AudioContext: ' + error.message); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Função para carregar arquivo | |
| function loadAudioFile(file, deckId) { | |
| addLog(`🎵 Iniciando carregamento do Deck ${deckId}: ${file.name}`); | |
| // Atualizar status | |
| updateStatus(deckId, 'loading', '🔄 Carregando arquivo...'); | |
| // Verificar tipo de arquivo | |
| if (!file.type.startsWith('audio/')) { | |
| addLog(`❌ Tipo de arquivo não suportado: ${file.type}`); | |
| updateStatus(deckId, 'error', '❌ Tipo de arquivo não suportado'); | |
| return; | |
| } | |
| // Verificar tamanho | |
| if (file.size > 50 * 1024 * 1024) { // 50MB | |
| addLog('❌ Arquivo muito grande (máximo 50MB)'); | |
| updateStatus(deckId, 'error', '❌ Arquivo muito grande'); | |
| return; | |
| } | |
| addLog(`📁 Arquivo válido: ${file.type}, ${Math.round(file.size/1024/1024)}MB`); | |
| // Criar FileReader | |
| const reader = new FileReader(); | |
| reader.onload = async function(event) { | |
| try { | |
| addLog(`🔄 Decodificando áudio para Deck ${deckId}...`); | |
| // Decodificar áudio | |
| const audioBuffer = await audioContext.decodeAudioData(event.target.result); | |
| addLog(`✅ Áudio decodificado com sucesso!`); | |
| addLog(`📊 Duração: ${audioBuffer.duration.toFixed(1)}s`); | |
| addLog(`🎛️ Sample Rate: ${audioBuffer.sampleRate}Hz`); | |
| // Armazenar buffer | |
| decks[deckId].buffer = audioBuffer; | |
| // Atualizar interface | |
| updateDeckInfo(deckId, file, audioBuffer); | |
| updateStatus(deckId, 'success', `✅ ${file.name} carregado com sucesso!`); | |
| // Habilitar botão play | |
| document.getElementById(`play-${deckId}`).disabled = false; | |
| addLog(`🎵 Deck ${deckId} pronto para reprodução!`); | |
| } catch (error) { | |
| addLog(`❌ Erro ao decodificar Deck ${deckId}: ${error.message}`); | |
| updateStatus(deckId, 'error', `❌ Erro ao carregar: ${error.message}`); | |
| } | |
| }; | |
| reader.onerror = function() { | |
| addLog(`❌ Erro na leitura do arquivo Deck ${deckId}`); | |
| updateStatus(deckId, 'error', '❌ Erro na leitura do arquivo'); | |
| }; | |
| // Iniciar leitura | |
| addLog(`📖 Iniciando leitura do arquivo...`); | |
| reader.readAsArrayBuffer(file); | |
| } | |
| // Função para atualizar status | |
| function updateStatus(deckId, status, message) { | |
| const statusElement = document.getElementById(`status-${deckId}`); | |
| statusElement.className = `status ${status}`; | |
| statusElement.textContent = message; | |
| } | |
| // Função para atualizar informações do deck | |
| function updateDeckInfo(deckId, file, buffer) { | |
| document.getElementById(`filename-${deckId}`).textContent = file.name; | |
| document.getElementById(`duration-${deckId}`).textContent = formatTime(buffer.duration); | |
| document.getElementById(`size-${deckId}`).textContent = formatFileSize(file.size); | |
| document.getElementById(`info-${deckId}`).style.display = 'block'; | |
| } | |
| // Função para tocar áudio | |
| function playAudio(deckId) { | |
| const deck = decks[deckId]; | |
| if (!deck.buffer) { | |
| addLog(`❌ Deck ${deckId}: Nenhum arquivo carregado`); | |
| return; | |
| } | |
| // Parar reprodução atual se estiver tocando | |
| if (deck.isPlaying) { | |
| deck.source.stop(); | |
| deck.isPlaying = false; | |
| document.getElementById(`play-${deckId}`).textContent = '▶️ TOCAR'; | |
| addLog(`⏸️ Deck ${deckId} pausado`); | |
| return; | |
| } | |
| try { | |
| // Criar nova fonte de áudio | |
| deck.source = audioContext.createBufferSource(); | |
| deck.source.buffer = deck.buffer; | |
| deck.source.connect(audioContext.destination); | |
| // Iniciar reprodução | |
| deck.source.start(0); | |
| deck.isPlaying = true; | |
| document.getElementById(`play-${deckId}`).textContent = '⏸️ PAUSAR'; | |
| addLog(`▶️ Deck ${deckId} tocando...`); | |
| // Quando terminar | |
| deck.source.onended = function() { | |
| deck.isPlaying = false; | |
| document.getElementById(`play-${deckId}`).textContent = '▶️ TOCAR'; | |
| addLog(`⏹️ Deck ${deckId} terminou`); | |
| }; | |
| } catch (error) { | |
| addLog(`❌ Erro ao tocar Deck ${deckId}: ${error.message}`); | |
| } | |
| } | |
| // Funções de teste | |
| function testAudioContext() { | |
| addLog('🧪 Testando AudioContext...'); | |
| if (audioContext) { | |
| addLog(`✅ AudioContext existe - Estado: ${audioContext.state}`); | |
| if (audioContext.state === 'suspended') { | |
| addLog('🔄 Tentando resumir AudioContext...'); | |
| audioContext.resume().then(() => { | |
| addLog('✅ AudioContext resumido com sucesso!'); | |
| }).catch(error => { | |
| addLog('❌ Erro ao resumir AudioContext: ' + error.message); | |
| }); | |
| } | |
| } else { | |
| addLog('❌ AudioContext não existe!'); | |
| } | |
| } | |
| function testFileAPI() { | |
| addLog('🧪 Testando File API...'); | |
| if (window.FileReader) { | |
| addLog('✅ FileReader suportado'); | |
| } else { | |
| addLog('❌ FileReader não suportado'); | |
| } | |
| if (window.File) { | |
| addLog('✅ File API suportado'); | |
| } else { | |
| addLog('❌ File API não suportado'); | |
| } | |
| } | |
| // Funções auxiliares | |
| function formatTime(seconds) { | |
| const mins = Math.floor(seconds / 60); | |
| const secs = Math.floor(seconds % 60); | |
| return `${mins}:${secs.toString().padStart(2, '0')}`; | |
| } | |
| function formatFileSize(bytes) { | |
| if (bytes === 0) return '0 Bytes'; | |
| const k = 1024; | |
| const sizes = ['Bytes', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
| } | |
| // Event listeners para os inputs de arquivo | |
| document.getElementById('file-A').addEventListener('change', function(event) { | |
| const file = event.target.files[0]; | |
| if (file) { | |
| addLog(`🎵 Arquivo selecionado para Deck A: ${file.name}`); | |
| loadAudioFile(file, 'A'); | |
| } | |
| }); | |
| document.getElementById('file-B').addEventListener('change', function(event) { | |
| const file = event.target.files[0]; | |
| if (file) { | |
| addLog(`🎵 Arquivo selecionado para Deck B: ${file.name}`); | |
| loadAudioFile(file, 'B'); | |
| } | |
| }); | |
| // Resumir AudioContext na primeira interação | |
| document.addEventListener('click', function() { | |
| if (audioContext && audioContext.state === 'suspended') { | |
| audioContext.resume(); | |
| addLog('🔄 AudioContext resumido por interação do usuário'); | |
| } | |
| }); | |
| // Inicializar quando a página carregar | |
| window.addEventListener('load', function() { | |
| setTimeout(() => { | |
| initialize(); | |
| }, 100); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| async def get_home(): | |
| return HTMLResponse(content=html_content) | |
| async def health_check(): | |
| return {"status": "healthy", "system": "Basic Audio Loading Test", "timestamp": time.time()} | |
| if __name__ == "__main__": | |
| import uvicorn | |
| print("🎵 Starting Basic Audio Loading Test...") | |
| print("📡 Server: http://localhost:8000") | |
| print("🎯 Focus: Simple and reliable audio file loading") | |
| uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info") |