Auto commit: 2026-02-25T20:32:07.364Z
This commit is contained in:
parent
f81d4e8569
commit
0eb723a087
148
admin.php
148
admin.php
@ -183,6 +183,37 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card p-4 border-info" style="background: rgba(13, 202, 240, 0.05);">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h5><i class="bi bi-disc-fill text-info"></i> Mi Playlist de DJ (Canciones que voy a poner)</h5>
|
||||||
|
<button class="btn btn-info btn-sm" onclick="showDjAddModal()">
|
||||||
|
<i class="bi bi-plus-lg"></i> AGREGAR CANCIÓN A MI LISTA
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-dark table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Artista</th>
|
||||||
|
<th>Canción</th>
|
||||||
|
<th>Estado</th>
|
||||||
|
<th>Acciones</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="dj-playlist-body">
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center text-secondary">Cargando mi lista...</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="card p-4">
|
<div class="card p-4">
|
||||||
@ -337,6 +368,34 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- DJ Playlist Modal -->
|
||||||
|
<div class="modal fade" id="djAddModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content bg-dark border-info">
|
||||||
|
<div class="modal-header border-secondary">
|
||||||
|
<h5 class="modal-title text-info"><i class="bi bi-disc-fill"></i> Agregar Canción a mi Playlist</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="dj-add-form">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Artista</label>
|
||||||
|
<input type="text" class="form-control bg-secondary text-white border-0" id="dj-artist" placeholder="Ej: Bad Bunny" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Canción</label>
|
||||||
|
<input type="text" class="form-control bg-secondary text-white border-0" id="dj-song" placeholder="Ej: Monaco" required>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer border-secondary">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||||
|
<button type="button" class="btn btn-info" onclick="submitDjRequest()">Añadir a mi Lista</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
|
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
|
||||||
@ -571,6 +630,7 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('id', id);
|
formData.append('id', id);
|
||||||
formData.append('action', action);
|
formData.append('action', action);
|
||||||
|
formData.append('username', 'Admin'); // Added default username for bonus logic
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('api/song_requests.php', {
|
const response = await fetch('api/song_requests.php', {
|
||||||
@ -579,6 +639,17 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
fetchRequests();
|
||||||
|
fetchDjPlaylist();
|
||||||
|
fetchStats();
|
||||||
|
} else {
|
||||||
|
alert('Error: ' + data.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('Error al procesar la solicitud');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showManualRequestModal() {
|
function showManualRequestModal() {
|
||||||
const modal = new bootstrap.Modal(document.getElementById('manualRequestModal'));
|
const modal = new bootstrap.Modal(document.getElementById('manualRequestModal'));
|
||||||
modal.show();
|
modal.show();
|
||||||
@ -619,15 +690,6 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRequests();
|
|
||||||
} else {
|
|
||||||
alert('Error: ' + data.error);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
alert('Error al procesar la solicitud');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function announceOnAir() {
|
async function announceOnAir() {
|
||||||
const title = document.getElementById('admin-track-title').innerText.trim();
|
const title = document.getElementById('admin-track-title').innerText.trim();
|
||||||
const artist = document.getElementById('admin-track-artist').innerText.trim();
|
const artist = document.getElementById('admin-track-artist').innerText.trim();
|
||||||
@ -736,17 +798,85 @@ $requests_today = $stmt->fetchColumn();
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showDjAddModal() {
|
||||||
|
const modal = new bootstrap.Modal(document.getElementById('djAddModal'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitDjRequest() {
|
||||||
|
const artist = document.getElementById('dj-artist').value;
|
||||||
|
const song = document.getElementById('dj-song').value;
|
||||||
|
|
||||||
|
if (!artist || !song) {
|
||||||
|
alert('Por favor, rellena artista y canción.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('requester', 'Lili Records DJ');
|
||||||
|
formData.append('artist', artist);
|
||||||
|
formData.append('song', song);
|
||||||
|
formData.append('source', 'admin');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('api/song_requests.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.success) {
|
||||||
|
bootstrap.Modal.getInstance(document.getElementById('djAddModal')).hide();
|
||||||
|
document.getElementById('dj-add-form').reset();
|
||||||
|
fetchDjPlaylist();
|
||||||
|
fetchRequests();
|
||||||
|
} else {
|
||||||
|
alert('Error: ' + data.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('Error al guardar la canción.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchDjPlaylist() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('api/song_requests.php?source=admin&status=pending');
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.success) {
|
||||||
|
const tbody = document.getElementById('dj-playlist-body');
|
||||||
|
if (data.requests.length === 0) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="4" class="text-center text-secondary">No tienes canciones en tu lista actual</td></tr>';
|
||||||
|
} else {
|
||||||
|
tbody.innerHTML = data.requests.map(req => `
|
||||||
|
<tr>
|
||||||
|
<td>${req.artist}</td>
|
||||||
|
<td>${req.song}</td>
|
||||||
|
<td><span class="badge bg-warning text-dark">${req.status}</span></td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-success" onclick="updateStatus(${req.id}, 'mark_played')">Sonar</button>
|
||||||
|
<button class="btn btn-sm btn-danger" onclick="updateStatus(${req.id}, 'delete')">Quitar</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching DJ playlist:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetchRequests();
|
fetchRequests();
|
||||||
fetchStats();
|
fetchStats();
|
||||||
updateNowPlaying();
|
updateNowPlaying();
|
||||||
fetchAnnouncements();
|
fetchAnnouncements();
|
||||||
fetchTopRequesters();
|
fetchTopRequesters();
|
||||||
|
fetchDjPlaylist();
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
fetchRequests();
|
fetchRequests();
|
||||||
fetchStats();
|
fetchStats();
|
||||||
updateNowPlaying();
|
updateNowPlaying();
|
||||||
fetchAnnouncements();
|
fetchAnnouncements();
|
||||||
fetchTopRequesters();
|
fetchTopRequesters();
|
||||||
|
fetchDjPlaylist();
|
||||||
}, 15000);
|
}, 15000);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -17,11 +17,24 @@ try {
|
|||||||
|
|
||||||
if ($remaining > 0) {
|
if ($remaining > 0) {
|
||||||
// Find next track for local requests
|
// Find next track for local requests
|
||||||
$stmtNext = $db->query("SELECT artist, song FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
$stmtNext = $db->query("SELECT id, artist, song FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
||||||
$nextTrack = $stmtNext->fetch();
|
$nextTrack = $stmtNext->fetch();
|
||||||
$nextInfo = null;
|
$nextInfo = null;
|
||||||
if ($nextTrack) {
|
if ($nextTrack) {
|
||||||
$nextInfo = ['artist' => $nextTrack['artist'], 'title' => $nextTrack['song']];
|
$nextInfo = ['artist' => $nextTrack['artist'], 'title' => $nextTrack['song']];
|
||||||
|
|
||||||
|
// Server-side warning logic: if 30s left and warning not sent
|
||||||
|
if ($remaining <= 35 && $remaining > 15) {
|
||||||
|
$stmtCheck = $db->prepare("SELECT warning_sent FROM song_requests WHERE id = ?");
|
||||||
|
$stmtCheck->execute([$nextTrack['id']]);
|
||||||
|
$wSent = $stmtCheck->fetchColumn();
|
||||||
|
|
||||||
|
if (!$wSent) {
|
||||||
|
$chatMsg = "⏭️ **Próxima canción:** {$nextTrack['artist']} - {$nextTrack['song']} 🎶 (en 30 seg aprox)";
|
||||||
|
$db->prepare("INSERT INTO messages (username, message, type) VALUES ('Sistema', ?, 'dj_power')")->execute([$chatMsg]);
|
||||||
|
$db->prepare("UPDATE song_requests SET warning_sent = 1 WHERE id = ?")->execute([$nextTrack['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
@ -60,11 +73,29 @@ try {
|
|||||||
|
|
||||||
if ($endAt && $duration) {
|
if ($endAt && $duration) {
|
||||||
$startedAt = date('c', strtotime($endAt) - $duration);
|
$startedAt = date('c', strtotime($endAt) - $duration);
|
||||||
|
$remainingRadio = strtotime($endAt) - time();
|
||||||
|
|
||||||
|
// If RadioKing song has ~30s left and there's a local pending request
|
||||||
|
if ($remainingRadio <= 35 && $remainingRadio > 15) {
|
||||||
|
$stmtNext = $db->query("SELECT id, artist, song FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
||||||
|
$localNext = $stmtNext->fetch();
|
||||||
|
if ($localNext) {
|
||||||
|
$stmtCheck = $db->prepare("SELECT warning_sent FROM song_requests WHERE id = ?");
|
||||||
|
$stmtCheck->execute([$localNext['id']]);
|
||||||
|
$wSent = $stmtCheck->fetchColumn();
|
||||||
|
|
||||||
|
if (!$wSent) {
|
||||||
|
$chatMsg = "⏭️ **Próxima canción:** {$localNext['artist']} - {$localNext['song']} 🎶 (en 30 seg aprox)";
|
||||||
|
$db->prepare("INSERT INTO messages (username, message, type) VALUES ('Sistema', ?, 'dj_power')")->execute([$chatMsg]);
|
||||||
|
$db->prepare("UPDATE song_requests SET warning_sent = 1 WHERE id = ?")->execute([$localNext['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For RadioKing source, check if there's a pending local request (it will be next)
|
// For RadioKing source, check if there's a pending local request (it will be next)
|
||||||
$nextInfo = $data['next_track'] ?? null;
|
$nextInfo = $data['next_track'] ?? null;
|
||||||
$stmtNext = $db->query("SELECT artist, song FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
$stmtNext = $db->query("SELECT id, artist, song FROM song_requests WHERE status = 'pending' ORDER BY is_priority DESC, created_at ASC LIMIT 1");
|
||||||
$localNext = $stmtNext->fetch();
|
$localNext = $stmtNext->fetch();
|
||||||
if ($localNext) {
|
if ($localNext) {
|
||||||
$nextInfo = ['artist' => $localNext['artist'], 'title' => $localNext['song']];
|
$nextInfo = ['artist' => $localNext['artist'], 'title' => $localNext['song']];
|
||||||
|
|||||||
@ -224,15 +224,27 @@ if ($method === 'GET') {
|
|||||||
$db->query("UPDATE song_requests SET status = 'played' WHERE status = 'pending' AND created_at < (NOW() - INTERVAL 2 HOUR)");
|
$db->query("UPDATE song_requests SET status = 'played' WHERE status = 'pending' AND created_at < (NOW() - INTERVAL 2 HOUR)");
|
||||||
|
|
||||||
$status = $_GET['status'] ?? 'pending';
|
$status = $_GET['status'] ?? 'pending';
|
||||||
|
$source = $_GET['source'] ?? null;
|
||||||
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
|
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
|
||||||
|
|
||||||
if ($status === 'all') {
|
$query = "SELECT * FROM song_requests WHERE 1=1";
|
||||||
$stmt = $db->query("SELECT * FROM song_requests ORDER BY is_priority DESC, created_at DESC LIMIT $limit");
|
$params = [];
|
||||||
} else {
|
|
||||||
$stmt = $db->prepare("SELECT * FROM song_requests WHERE status = ? ORDER BY is_priority DESC, created_at DESC LIMIT $limit");
|
if ($status !== 'all') {
|
||||||
$stmt->execute([$status]);
|
$query .= " AND status = ?";
|
||||||
|
$params[] = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($source) {
|
||||||
|
$query .= " AND source = ?";
|
||||||
|
$params[] = $source;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= " ORDER BY is_priority DESC, created_at DESC LIMIT $limit";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($query);
|
||||||
|
$stmt->execute($params);
|
||||||
|
|
||||||
$requests = $stmt->fetchAll();
|
$requests = $stmt->fetchAll();
|
||||||
echo json_encode(['success' => true, 'requests' => $requests]);
|
echo json_encode(['success' => true, 'requests' => $requests]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|||||||
26
index.php
26
index.php
@ -4444,7 +4444,6 @@ $twitter_link = "https://twitter.com/";
|
|||||||
|
|
||||||
// Fetch Now Playing Metadata
|
// Fetch Now Playing Metadata
|
||||||
let progressInterval = null;
|
let progressInterval = null;
|
||||||
let nextSongNoticeSent = false;
|
|
||||||
let currentTrackId = '';
|
let currentTrackId = '';
|
||||||
|
|
||||||
async function updateMetadata() {
|
async function updateMetadata() {
|
||||||
@ -4462,7 +4461,6 @@ $twitter_link = "https://twitter.com/";
|
|||||||
const requester = data.requester || '';
|
const requester = data.requester || '';
|
||||||
|
|
||||||
if (trackTitle.textContent !== title) {
|
if (trackTitle.textContent !== title) {
|
||||||
nextSongNoticeSent = false;
|
|
||||||
currentTrackId = fullDisplay;
|
currentTrackId = fullDisplay;
|
||||||
// If it's a local request, show special label
|
// If it's a local request, show special label
|
||||||
const label = document.querySelector('.track-label');
|
const label = document.querySelector('.track-label');
|
||||||
@ -4625,30 +4623,6 @@ $twitter_link = "https://twitter.com/";
|
|||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const elapsed = now - start;
|
const elapsed = now - start;
|
||||||
|
|
||||||
// Check if we should send next song notice (approx 30s before end)
|
|
||||||
const remainingSec = Math.floor((end - now) / 1000);
|
|
||||||
if (remainingSec <= 30 && remainingSec > 25 && !nextSongNoticeSent && data.next_track) {
|
|
||||||
nextSongNoticeSent = true;
|
|
||||||
let nextLabel = "";
|
|
||||||
if (typeof data.next_track === 'object') {
|
|
||||||
const nextArtist = data.next_track.artist || 'Artista';
|
|
||||||
const nextTitle = data.next_track.title || 'Título';
|
|
||||||
nextLabel = `${nextArtist} - ${nextTitle}`;
|
|
||||||
} else {
|
|
||||||
nextLabel = data.next_track;
|
|
||||||
}
|
|
||||||
const nextMsg = `⏭️ **Próxima canción:** ${nextLabel} 🎶`;
|
|
||||||
fetch('api/chat.php', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
username: 'Sistema',
|
|
||||||
message: nextMsg,
|
|
||||||
type: 'dj_power'
|
|
||||||
})
|
|
||||||
}).catch(err => console.error('Error sending next track notice:', err));
|
|
||||||
}
|
|
||||||
|
|
||||||
let percent = (elapsed / duration) * 100;
|
let percent = (elapsed / duration) * 100;
|
||||||
if (percent > 100) percent = 100;
|
if (percent > 100) percent = 100;
|
||||||
if (percent < 0) percent = 0;
|
if (percent < 0) percent = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user