Auto commit: 2026-02-25T20:04:50.502Z
This commit is contained in:
parent
2e5c1af7eb
commit
ca1b853970
@ -5,18 +5,82 @@ require_once __DIR__ . '/../db/config.php';
|
|||||||
try {
|
try {
|
||||||
$db = db();
|
$db = db();
|
||||||
|
|
||||||
// 1. Check if there is an active "played" song within its duration (e.g. 5 minutes)
|
// 1. Check if there is an active local "played" song and if it's still playing
|
||||||
$stmt = $db->query("SELECT COUNT(*) FROM song_requests WHERE status = 'played' AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)");
|
$stmt = $db->query("SELECT *, UNIX_TIMESTAMP(created_at) as started_at FROM song_requests WHERE status = 'played' ORDER BY created_at DESC LIMIT 1");
|
||||||
$hasActive = $stmt->fetchColumn();
|
$lastPlayed = $stmt->fetch();
|
||||||
|
|
||||||
if ($hasActive == 0) {
|
$isLocalActive = false;
|
||||||
// 2. No active song? Let's take the oldest pending request and "execute" it
|
if ($lastPlayed) {
|
||||||
|
$duration = (int)($lastPlayed['duration'] ?? 240);
|
||||||
|
$endTime = $lastPlayed['started_at'] + $duration;
|
||||||
|
if (time() < $endTime) {
|
||||||
|
$isLocalActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. If no local song is active, check if RadioKing is playing something we should wait for
|
||||||
|
$shouldWait = $isLocalActive;
|
||||||
|
|
||||||
|
if (!$isLocalActive) {
|
||||||
|
// Optional: Check RadioKing current track end_at
|
||||||
|
try {
|
||||||
|
$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, 3);
|
||||||
|
$resp = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($resp) {
|
||||||
|
$data = json_decode($resp, true);
|
||||||
|
if (isset($data['end_at'])) {
|
||||||
|
$endAt = strtotime($data['end_at']);
|
||||||
|
// If the RadioKing song ends in more than 5 seconds, we wait
|
||||||
|
if ($endAt > (time() + 5)) {
|
||||||
|
$shouldWait = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Ignore RadioKing errors and proceed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$shouldWait) {
|
||||||
|
// 3. 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");
|
$stmt = $db->query("SELECT * FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
||||||
$next = $stmt->fetch();
|
$next = $stmt->fetch();
|
||||||
|
|
||||||
if ($next) {
|
if ($next) {
|
||||||
$stmt = $db->prepare("UPDATE song_requests SET status = 'played' WHERE id = ?");
|
// Find YouTube info before playing if missing
|
||||||
$stmt->execute([$next['id']]);
|
$youtubeUrl = $next['youtube_url'];
|
||||||
|
$duration = $next['duration'] ?? 240;
|
||||||
|
|
||||||
|
if (!$youtubeUrl) {
|
||||||
|
try {
|
||||||
|
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
||||||
|
$artist = $next['artist'];
|
||||||
|
$song = $next['song'];
|
||||||
|
$aiResp = LocalAIApi::createResponse([
|
||||||
|
'input' => [
|
||||||
|
['role' => 'system', 'content' => 'Eres un asistente de radio. Tu tarea es encontrar el ID de YouTube oficial y la duración aproximada en segundos para una canción. Responde ÚNICAMENTE con un JSON: {"id": "...", "duration": ...}. Si no estás seguro, usa id null y duration 240.'],
|
||||||
|
['role' => 'user', 'content' => "Encuentra el ID de YouTube y duración para: $artist - $song"]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (!empty($aiResp['success'])) {
|
||||||
|
$jsonText = LocalAIApi::extractText($aiResp);
|
||||||
|
$data = json_decode($jsonText, true);
|
||||||
|
if ($data && isset($data['id']) && $data['id'] !== null) {
|
||||||
|
$youtubeUrl = "https://www.youtube.com/watch?v={$data['id']}";
|
||||||
|
$duration = (int)($data['duration'] ?? 240);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $db->prepare("UPDATE song_requests SET status = 'played', youtube_url = ?, duration = ?, created_at = NOW() WHERE id = ?");
|
||||||
|
$stmt->execute([$youtubeUrl, $duration, $next['id']]);
|
||||||
|
|
||||||
// Log automation
|
// Log automation
|
||||||
$db->prepare("INSERT INTO automation_logs (message) VALUES (?)")->execute(["Auto-DJ ejecutó: {$next['artist']} - {$next['song']}"]);
|
$db->prepare("INSERT INTO automation_logs (message) VALUES (?)")->execute(["Auto-DJ ejecutó: {$next['artist']} - {$next['song']}"]);
|
||||||
|
|||||||
@ -5,12 +5,17 @@ require_once __DIR__ . '/../db/config.php';
|
|||||||
try {
|
try {
|
||||||
$db = db();
|
$db = db();
|
||||||
|
|
||||||
// Check for a "manual override" song that was recently marked as played
|
// Check for a local "played" song that is currently within its duration
|
||||||
// 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, duration, UNIX_TIMESTAMP(created_at) as started_at FROM song_requests WHERE status = 'played' ORDER BY created_at DESC LIMIT 1");
|
||||||
$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();
|
$override = $stmt->fetch();
|
||||||
|
|
||||||
if ($override) {
|
if ($override) {
|
||||||
|
$duration = (int)($override['duration'] ?? 240);
|
||||||
|
$startedAt = $override['started_at'];
|
||||||
|
$endAt = $startedAt + $duration;
|
||||||
|
$remaining = $endAt - time();
|
||||||
|
|
||||||
|
if ($remaining > 0) {
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'source' => 'local_request',
|
'source' => 'local_request',
|
||||||
@ -18,10 +23,15 @@ try {
|
|||||||
'title' => $override['song'],
|
'title' => $override['song'],
|
||||||
'requester' => $override['requester'],
|
'requester' => $override['requester'],
|
||||||
'youtube_url' => $override['youtube_url'],
|
'youtube_url' => $override['youtube_url'],
|
||||||
|
'duration' => $duration,
|
||||||
|
'started_at' => date('c', $startedAt),
|
||||||
|
'end_at' => date('c', $endAt),
|
||||||
|
'remaining' => $remaining,
|
||||||
'cover' => './assets/pasted-20260215-163754-def41f49.png'
|
'cover' => './assets/pasted-20260215-163754-def41f49.png'
|
||||||
]);
|
]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fallback: Proxy RadioKing metadata
|
// Fallback: Proxy RadioKing metadata
|
||||||
$radioKingUrl = 'https://www.radioking.com/widgets/api/v1/radio/828046/track/current';
|
$radioKingUrl = 'https://www.radioking.com/widgets/api/v1/radio/828046/track/current';
|
||||||
@ -35,19 +45,27 @@ try {
|
|||||||
|
|
||||||
if ($httpCode === 200 && $resp) {
|
if ($httpCode === 200 && $resp) {
|
||||||
$data = json_decode($resp, true);
|
$data = json_decode($resp, true);
|
||||||
|
$duration = $data['duration'] ?? 0;
|
||||||
|
$endAt = $data['end_at'] ?? null;
|
||||||
|
$startedAt = null;
|
||||||
|
|
||||||
|
if ($endAt && $duration) {
|
||||||
|
$startedAt = date('c', strtotime($endAt) - $duration);
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'source' => 'radioking',
|
'source' => 'radioking',
|
||||||
'artist' => $data['artist'] ?? 'Lili Records',
|
'artist' => $data['artist'] ?? 'Lili Records',
|
||||||
'title' => $data['title'] ?? 'La mejor música',
|
'title' => $data['title'] ?? 'La mejor música',
|
||||||
'cover' => $data['cover'] ?? './assets/pasted-20260215-163754-def41f49.png',
|
'cover' => $data['cover'] ?? './assets/pasted-20260215-163754-def41f49.png',
|
||||||
'duration' => $data['duration'] ?? 0,
|
'duration' => $duration,
|
||||||
'end_at' => $data['end_at'] ?? null,
|
'started_at' => $startedAt,
|
||||||
|
'end_at' => $endAt,
|
||||||
'next_track' => $data['next_track'] ?? null
|
'next_track' => $data['next_track'] ?? null
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
echo json_encode(['success' => false, 'error' => 'Failed to fetch RadioKing metadata']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,39 +83,42 @@ if ($method === 'POST') {
|
|||||||
$wasAutoExecuted = true;
|
$wasAutoExecuted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status) VALUES (?, ?, ?, ?, ?)");
|
$stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status, duration) VALUES (?, ?, ?, ?, ?, ?)");
|
||||||
$stmt->execute([$artist, $song, $requester, $source, $initialStatus]);
|
$stmt->execute([$artist, $song, $requester, $source, $initialStatus, 240]);
|
||||||
|
$requestId = $db->lastInsertId();
|
||||||
|
|
||||||
if ($wasAutoExecuted) {
|
if ($wasAutoExecuted) {
|
||||||
// Try to find a YouTube link for the song using AI
|
// Try to find a YouTube link and duration for the song using AI
|
||||||
$youtubeUrl = null;
|
$youtubeUrl = null;
|
||||||
|
$duration = 240;
|
||||||
try {
|
try {
|
||||||
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
||||||
$aiResp = LocalAIApi::createResponse([
|
$aiResp = LocalAIApi::createResponse([
|
||||||
'input' => [
|
'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' => 'system', 'content' => 'Eres un asistente de radio. Tu tarea es encontrar el ID de YouTube oficial y la duración aproximada en segundos para una canción. Responde ÚNICAMENTE con un JSON: {"id": "...", "duration": ...}. Si no estás seguro, usa id null y duration 240.'],
|
||||||
['role' => 'user', 'content' => "Encuentra el ID de YouTube para: $artist - $song"]
|
['role' => 'user', 'content' => "Encuentra el ID de YouTube y duración para: $artist - $song"]
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
if (!empty($aiResp['success'])) {
|
if (!empty($aiResp['success'])) {
|
||||||
$id = trim(LocalAIApi::extractText($aiResp));
|
$jsonText = LocalAIApi::extractText($aiResp);
|
||||||
if ($id !== 'None' && strlen($id) > 5 && strlen($id) < 15) {
|
$data = json_decode($jsonText, true);
|
||||||
$youtubeUrl = "https://www.youtube.com/watch?v=$id";
|
if ($data && isset($data['id']) && $data['id'] !== null) {
|
||||||
|
$youtubeUrl = "https://www.youtube.com/watch?v={$data['id']}";
|
||||||
|
$duration = (int)($data['duration'] ?? 240);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("AI YouTube search failed: " . $e->getMessage());
|
error_log("AI YouTube search failed: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester, source, status, youtube_url) VALUES (?, ?, ?, ?, ?, ?)");
|
if ($youtubeUrl || $duration != 240) {
|
||||||
$stmt->execute([$artist, $song, $requester, $source, $initialStatus, $youtubeUrl]);
|
$stmt = $db->prepare("UPDATE song_requests SET youtube_url = ?, duration = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$youtubeUrl, $duration, $requestId]);
|
||||||
|
}
|
||||||
|
|
||||||
// Announce auto-execution
|
// Announce auto-execution
|
||||||
$chatMsg = "🚀 [AUTO-DJ] ¡Petición de **$requester** ejecutada automáticamente! 🎶 Sonando: **$artist - $song**" . ($youtubeUrl ? " (con video)" : "");
|
$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]);
|
$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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
index.php
13
index.php
@ -4624,7 +4624,17 @@ $twitter_link = "https://twitter.com/";
|
|||||||
if (percent > 100) percent = 100;
|
if (percent > 100) percent = 100;
|
||||||
if (percent < 0) percent = 0;
|
if (percent < 0) percent = 0;
|
||||||
progBar.style.width = percent + '%';
|
progBar.style.width = percent + '%';
|
||||||
if (percent >= 100) clearInterval(progressInterval);
|
if (percent >= 100) {
|
||||||
|
clearInterval(progressInterval);
|
||||||
|
// Play transition sound
|
||||||
|
transitionAudio.volume = 0.5;
|
||||||
|
transitionAudio.play().catch(e => console.log('Transition sound blocked:', e));
|
||||||
|
|
||||||
|
// Trigger automation check and metadata refresh immediately
|
||||||
|
fetch('api/automation.php').finally(() => {
|
||||||
|
setTimeout(updateMetadata, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgressBar();
|
updateProgressBar();
|
||||||
@ -4691,6 +4701,7 @@ $twitter_link = "https://twitter.com/";
|
|||||||
|
|
||||||
const ticTacAudio = new Audio('https://assets.mixkit.co/active_storage/sfx/560/560-preview.mp3');
|
const ticTacAudio = new Audio('https://assets.mixkit.co/active_storage/sfx/560/560-preview.mp3');
|
||||||
const applauseAudio = new Audio('https://assets.mixkit.co/active_storage/sfx/467/467-preview.mp3'); // Crowd Cheer
|
const applauseAudio = new Audio('https://assets.mixkit.co/active_storage/sfx/467/467-preview.mp3'); // Crowd Cheer
|
||||||
|
const transitionAudio = new Audio('https://assets.mixkit.co/active_storage/sfx/2013/2013-preview.mp3'); // Ding
|
||||||
|
|
||||||
function testTicTac() {
|
function testTicTac() {
|
||||||
const btn = document.getElementById('test-tictac-btn');
|
const btn = document.getElementById('test-tictac-btn');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user