Auto commit: 2026-02-25T19:30:52.555Z
This commit is contained in:
parent
6b0e285541
commit
2e5c1af7eb
36
api/automation.php
Normal file
36
api/automation.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
// 1. Check if there is an active "played" song within its duration (e.g. 5 minutes)
|
||||||
|
$stmt = $db->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()]);
|
||||||
|
}
|
||||||
53
api/current_song.php
Normal file
53
api/current_song.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
// Check for a "manual override" song that was recently marked as played
|
||||||
|
// We look for a song marked as 'played' in the last 4 minutes (typical song duration)
|
||||||
|
$stmt = $db->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()]);
|
||||||
|
}
|
||||||
@ -70,8 +70,54 @@ if ($method === 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source) VALUES (?, ?, ?, ?)");
|
// Auto-DJ: Check if we should "execute" this song immediately
|
||||||
$stmt->execute([$artist, $song, $requester, $source]);
|
// 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
|
// Award points for song request
|
||||||
if ($requester !== 'Anónimo') {
|
if ($requester !== 'Anónimo') {
|
||||||
|
|||||||
50
index.php
50
index.php
@ -3588,11 +3588,23 @@ $twitter_link = "https://twitter.com/";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial fetch and poll
|
async function checkAutomation() {
|
||||||
fetchMessages();
|
try {
|
||||||
updatePhotoCounter();
|
const response = await fetch('api/automation.php');
|
||||||
setInterval(fetchMessages, 3000);
|
const data = await response.json();
|
||||||
setInterval(updatePhotoCounter, 30000); // Check limit status every 30s
|
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 ---
|
// --- End Chat Functionality ---
|
||||||
|
|
||||||
// --- Song Request Functionality ---
|
// --- Song Request Functionality ---
|
||||||
@ -4435,7 +4447,7 @@ $twitter_link = "https://twitter.com/";
|
|||||||
|
|
||||||
async function updateMetadata() {
|
async function updateMetadata() {
|
||||||
try {
|
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();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data && data.title) {
|
if (data && data.title) {
|
||||||
@ -4444,8 +4456,34 @@ $twitter_link = "https://twitter.com/";
|
|||||||
const album = data.album || '';
|
const album = data.album || '';
|
||||||
const coverUrl = data.cover || './assets/pasted-20260215-163754-def41f49.png';
|
const coverUrl = data.cover || './assets/pasted-20260215-163754-def41f49.png';
|
||||||
const fullDisplay = `${artist} - ${title}`;
|
const fullDisplay = `${artist} - ${title}`;
|
||||||
|
const source = data.source || 'radioking';
|
||||||
|
const requester = data.requester || '';
|
||||||
|
|
||||||
if (trackTitle.textContent !== title) {
|
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 <span style="color: #facc15;">${requester.toUpperCase()}</span>:`;
|
||||||
|
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 = '<i class="bi bi-youtube"></i> VER VIDEO';
|
||||||
|
label.appendChild(youtubeBtn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label.innerText = 'ESTÁS ESCUCHANDO:';
|
||||||
|
label.style.animation = 'none';
|
||||||
|
}
|
||||||
trackTitle.style.opacity = '0';
|
trackTitle.style.opacity = '0';
|
||||||
if (trackArtist) trackArtist.style.opacity = '0';
|
if (trackArtist) trackArtist.style.opacity = '0';
|
||||||
if (trackAlbum) trackAlbum.style.opacity = '0';
|
if (trackAlbum) trackAlbum.style.opacity = '0';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user