diff --git a/api/automation.php b/api/automation.php new file mode 100644 index 0000000..03c388b --- /dev/null +++ b/api/automation.php @@ -0,0 +1,36 @@ +query("SELECT COUNT(*) FROM song_requests WHERE status = 'played' AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)"); + $hasActive = $stmt->fetchColumn(); + + if ($hasActive == 0) { + // 2. No active song? Let's take the oldest pending request and "execute" it + $stmt = $db->query("SELECT * FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1"); + $next = $stmt->fetch(); + + if ($next) { + $stmt = $db->prepare("UPDATE song_requests SET status = 'played' WHERE id = ?"); + $stmt->execute([$next['id']]); + + // Log automation + $db->prepare("INSERT INTO automation_logs (message) VALUES (?)")->execute(["Auto-DJ ejecutó: {$next['artist']} - {$next['song']}"]); + + // Announce in chat + $chatMsg = "🤖 [AUTO-DJ] Es el turno de: **{$next['artist']} - {$next['song']}** (Pedido por: **{$next['requester']}**) 🎧🔥"; + $db->prepare("INSERT INTO messages (username, message, type) VALUES ('Sistema', ?, 'dj_power')")->execute([$chatMsg]); + + echo json_encode(['success' => true, 'action' => 'executed', 'song' => $next['song']]); + exit; + } + } + + echo json_encode(['success' => true, 'action' => 'none']); +} catch (Exception $e) { + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/api/current_song.php b/api/current_song.php new file mode 100644 index 0000000..533c30d --- /dev/null +++ b/api/current_song.php @@ -0,0 +1,53 @@ +query("SELECT artist, song, requester, youtube_url FROM song_requests WHERE status = 'played' AND created_at > DATE_SUB(NOW(), INTERVAL 4 MINUTE) ORDER BY created_at DESC LIMIT 1"); + $override = $stmt->fetch(); + + if ($override) { + echo json_encode([ + 'success' => true, + 'source' => 'local_request', + 'artist' => $override['artist'], + 'title' => $override['song'], + 'requester' => $override['requester'], + 'youtube_url' => $override['youtube_url'], + 'cover' => './assets/pasted-20260215-163754-def41f49.png' + ]); + exit; + } + + // Fallback: Proxy RadioKing metadata + $radioKingUrl = 'https://www.radioking.com/widgets/api/v1/radio/828046/track/current'; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $radioKingUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $resp = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200 && $resp) { + $data = json_decode($resp, true); + echo json_encode([ + 'success' => true, + 'source' => 'radioking', + 'artist' => $data['artist'] ?? 'Lili Records', + 'title' => $data['title'] ?? 'La mejor música', + 'cover' => $data['cover'] ?? './assets/pasted-20260215-163754-def41f49.png', + 'duration' => $data['duration'] ?? 0, + 'end_at' => $data['end_at'] ?? null, + 'next_track' => $data['next_track'] ?? null + ]); + } else { + echo json_encode(['success' => false, 'error' => 'Failed to fetch RadioKing metadata']); + } +} catch (Exception $e) { + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/api/song_requests.php b/api/song_requests.php index 3b4165c..82b3126 100644 --- a/api/song_requests.php +++ b/api/song_requests.php @@ -70,8 +70,54 @@ if ($method === 'POST') { } try { - $stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source) VALUES (?, ?, ?, ?)"); - $stmt->execute([$artist, $song, $requester, $source]); + // Auto-DJ: Check if we should "execute" this song immediately + // If there's no song marked as 'played' in the last 5 minutes, we execute this one automatically + $checkStmt = $db->query("SELECT COUNT(*) FROM song_requests WHERE status = 'played' AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)"); + $activePlayed = $checkStmt->fetchColumn(); + + $initialStatus = 'pending'; + $wasAutoExecuted = false; + + if ($activePlayed == 0) { + $initialStatus = 'played'; + $wasAutoExecuted = true; + } + + $stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$artist, $song, $requester, $source, $initialStatus]); + + if ($wasAutoExecuted) { + // Try to find a YouTube link for the song using AI + $youtubeUrl = null; + try { + require_once __DIR__ . '/../ai/LocalAIApi.php'; + $aiResp = LocalAIApi::createResponse([ + 'input' => [ + ['role' => 'system', 'content' => 'Eres un asistente de radio. Tu tarea es encontrar el ID de YouTube oficial para una canción. Responde ÚNICAMENTE con el ID del video (ej: dQw4w9WgXcQ). Si no estás seguro, responde "None".'], + ['role' => 'user', 'content' => "Encuentra el ID de YouTube para: $artist - $song"] + ] + ]); + if (!empty($aiResp['success'])) { + $id = trim(LocalAIApi::extractText($aiResp)); + if ($id !== 'None' && strlen($id) > 5 && strlen($id) < 15) { + $youtubeUrl = "https://www.youtube.com/watch?v=$id"; + } + } + } catch (Exception $e) { + error_log("AI YouTube search failed: " . $e->getMessage()); + } + + $stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status, youtube_url) VALUES (?, ?, ?, ?, ?, ?)"); + $stmt->execute([$artist, $song, $requester, $source, $initialStatus, $youtubeUrl]); + + // Announce auto-execution + $chatMsg = "🚀 [AUTO-DJ] ¡Petición de **$requester** ejecutada automáticamente! 🎶 Sonando: **$artist - $song**" . ($youtubeUrl ? " (con video)" : ""); + $db->prepare("INSERT INTO messages (username, message, type) VALUES ('Sistema', ?, 'dj_power')")->execute([$chatMsg]); + } else { + $stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$artist, $song, $requester, $source, $initialStatus]); + } + // Award points for song request if ($requester !== 'Anónimo') { diff --git a/index.php b/index.php index d1bc600..c467b46 100644 --- a/index.php +++ b/index.php @@ -3588,11 +3588,23 @@ $twitter_link = "https://twitter.com/"; } } - // Initial fetch and poll - fetchMessages(); - updatePhotoCounter(); - setInterval(fetchMessages, 3000); - setInterval(updatePhotoCounter, 30000); // Check limit status every 30s + async function checkAutomation() { + try { + const response = await fetch('api/automation.php'); + const data = await response.json(); + if (data.success && data.action === 'executed') { + // Force metadata update if something was executed + updateMetadata(); + if (typeof fetchSongRequests === 'function') fetchSongRequests(); + } + } catch (error) { + console.error('Automation error:', error); + } + } + + // Run automation check every 15 seconds + setInterval(checkAutomation, 15000); + setTimeout(checkAutomation, 2000); // Initial check // --- End Chat Functionality --- // --- Song Request Functionality --- @@ -4435,7 +4447,7 @@ $twitter_link = "https://twitter.com/"; async function updateMetadata() { try { - const response = await fetch('https://www.radioking.com/widgets/api/v1/radio/828046/track/current'); + const response = await fetch('api/current_song.php'); const data = await response.json(); if (data && data.title) { @@ -4444,8 +4456,34 @@ $twitter_link = "https://twitter.com/"; const album = data.album || ''; const coverUrl = data.cover || './assets/pasted-20260215-163754-def41f49.png'; const fullDisplay = `${artist} - ${title}`; + const source = data.source || 'radioking'; + const requester = data.requester || ''; if (trackTitle.textContent !== title) { + // If it's a local request, show special label + const label = document.querySelector('.track-label'); + if (source === 'local_request') { + label.innerHTML = `PETICIÓN DE ${requester.toUpperCase()}:`; + label.style.animation = 'pulse 1s infinite'; + if (data.youtube_url) { + const youtubeBtn = document.createElement('a'); + youtubeBtn.href = data.youtube_url; + youtubeBtn.target = '_blank'; + youtubeBtn.style.background = '#ff0000'; + youtubeBtn.style.color = '#fff'; + youtubeBtn.style.padding = '4px 10px'; + youtubeBtn.style.borderRadius = '12px'; + youtubeBtn.style.fontSize = '0.65rem'; + youtubeBtn.style.fontWeight = '800'; + youtubeBtn.style.textDecoration = 'none'; + youtubeBtn.style.marginLeft = '10px'; + youtubeBtn.innerHTML = ' VER VIDEO'; + label.appendChild(youtubeBtn); + } + } else { + label.innerText = 'ESTÁS ESCUCHANDO:'; + label.style.animation = 'none'; + } trackTitle.style.opacity = '0'; if (trackArtist) trackArtist.style.opacity = '0'; if (trackAlbum) trackAlbum.style.opacity = '0';