Auto commit: 2026-02-17T18:45:07.833Z
This commit is contained in:
parent
55ebbe45e6
commit
cc5bd4931c
98
admin.php
98
admin.php
@ -48,6 +48,30 @@ $locations = $stmt->fetchAll();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Now Playing Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card p-3 border-success" style="background: rgba(0, 230, 118, 0.05);">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="position-relative me-3">
|
||||
<img id="admin-track-cover" src="./assets/pasted-20260215-163754-def41f49.png" style="width: 60px; height: 60px; border-radius: 10px; object-fit: cover; border: 2px solid #00e676;">
|
||||
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-light rounded-circle" style="width: 12px; height: 12px;"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-success fw-bold x-small" style="font-size: 0.7rem; letter-spacing: 1px;">SONANDO AHORA:</span>
|
||||
<h4 id="admin-track-title" class="mb-0">Lili Records Radio</h4>
|
||||
<p id="admin-track-artist" class="text-secondary mb-0">En vivo desde el estudio</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<span id="admin-track-timer" class="badge bg-dark border border-secondary">00:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card p-4 text-center">
|
||||
@ -159,20 +183,47 @@ $locations = $stmt->fetchAll();
|
||||
</div>
|
||||
|
||||
<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>
|
||||
const map = L.map('map').setView([20, 0], 2);
|
||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
}).addTo(map);
|
||||
|
||||
const locations = <?= json_encode($locations) ?>;
|
||||
locations.forEach(loc => {
|
||||
if (loc.lat && loc.lon) {
|
||||
L.marker([loc.lat, loc.lon])
|
||||
.addTo(map)
|
||||
.bindPopup(`<b>${loc.country}</b><br>${loc.count} usuario(s)`);
|
||||
let heatmapLayer;
|
||||
let markersGroup = L.layerGroup().addTo(map);
|
||||
|
||||
function updateMap(locations) {
|
||||
markersGroup.clearLayers();
|
||||
const heatData = [];
|
||||
|
||||
locations.forEach(loc => {
|
||||
if (loc.lat && loc.lon) {
|
||||
// Add marker
|
||||
L.marker([loc.lat, loc.lon])
|
||||
.addTo(markersGroup)
|
||||
.bindPopup(`<b>${loc.country}</b><br>${loc.count} usuario(s)`);
|
||||
|
||||
// Add to heatmap data (lat, lon, intensity)
|
||||
// We use the count as intensity, but capped/scaled for better visualization
|
||||
heatData.push([loc.lat, loc.lon, Math.min(loc.count * 0.5, 1)]);
|
||||
}
|
||||
});
|
||||
|
||||
if (heatmapLayer) {
|
||||
map.removeLayer(heatmapLayer);
|
||||
}
|
||||
});
|
||||
|
||||
heatmapLayer = L.heatLayer(heatData, {
|
||||
radius: 25,
|
||||
blur: 15,
|
||||
maxZoom: 10,
|
||||
gradient: {0.4: 'blue', 0.6: 'cyan', 0.7: 'lime', 0.8: 'yellow', 1: 'red'}
|
||||
}).addTo(map);
|
||||
}
|
||||
|
||||
// Initial map data
|
||||
updateMap(<?= json_encode($locations) ?>);
|
||||
|
||||
let volumeChart;
|
||||
function initChart() {
|
||||
@ -292,6 +343,10 @@ $locations = $stmt->fetchAll();
|
||||
volumeChart.data.datasets[0].data = hourlyData;
|
||||
volumeChart.update();
|
||||
}
|
||||
|
||||
if (data.locations) {
|
||||
updateMap(data.locations);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching stats:', error);
|
||||
@ -321,11 +376,40 @@ $locations = $stmt->fetchAll();
|
||||
}
|
||||
}
|
||||
|
||||
async function updateNowPlaying() {
|
||||
try {
|
||||
const response = await fetch('https://www.radioking.com/widgets/api/v1/radio/828046/track/current');
|
||||
const data = await response.json();
|
||||
if (data && data.title) {
|
||||
document.getElementById('admin-track-title').textContent = data.title;
|
||||
document.getElementById('admin-track-artist').textContent = data.artist || 'Lili Records';
|
||||
if (data.cover) {
|
||||
document.getElementById('admin-track-cover').src = data.cover;
|
||||
}
|
||||
|
||||
if (data.started_at && data.end_at) {
|
||||
const start = new Date(data.started_at).getTime();
|
||||
const end = new Date(data.end_at).getTime();
|
||||
const duration = end - start;
|
||||
const now = new Date().getTime();
|
||||
const elapsed = Math.max(0, now - start);
|
||||
const m = Math.floor(elapsed / 60000);
|
||||
const s = Math.floor((elapsed % 60000) / 1000);
|
||||
document.getElementById('admin-track-timer').textContent = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching now playing:', error);
|
||||
}
|
||||
}
|
||||
|
||||
fetchRequests();
|
||||
fetchStats();
|
||||
updateNowPlaying();
|
||||
setInterval(() => {
|
||||
fetchRequests();
|
||||
fetchStats();
|
||||
updateNowPlaying();
|
||||
}, 15000);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -69,11 +69,16 @@ if ($method === 'GET') {
|
||||
$stmt = $db->query("SELECT HOUR(created_at) as hour, COUNT(*) as count FROM song_requests WHERE created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR) GROUP BY hour ORDER BY hour ASC");
|
||||
$volume_stats = $stmt->fetchAll();
|
||||
|
||||
// Visitor locations (last 10 minutes)
|
||||
$stmt = $db->query("SELECT country, country_code, lat, lon, COUNT(*) as count FROM visitor_logs WHERE last_activity > DATE_SUB(NOW(), INTERVAL 10 MINUTE) GROUP BY country_code");
|
||||
$locations = $stmt->fetchAll();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'top_artists' => $top_artists,
|
||||
'top_songs' => $top_songs,
|
||||
'volume_stats' => $volume_stats
|
||||
'volume_stats' => $volume_stats,
|
||||
'locations' => $locations
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
|
||||
26
index.php
26
index.php
@ -1024,6 +1024,22 @@ $facebook_link = "https://www.facebook.com/profile.php?id=61587890927489";
|
||||
<body>
|
||||
<div class="background"></div>
|
||||
|
||||
<!-- Sticky Top Marquee -->
|
||||
<div id="sticky-now-playing" style="position: fixed; top: 0; left: 0; width: 100%; background: rgba(15, 23, 42, 0.85); backdrop-filter: blur(10px); z-index: 1000; padding: 10px 0; border-bottom: 1px solid rgba(56, 189, 248, 0.3); display: none; animation: slideDown 0.5s ease;">
|
||||
<div style="max-width: 1200px; margin: 0 auto; display: flex; align-items: center; justify-content: center; gap: 15px; padding: 0 20px;">
|
||||
<div style="width: 40px; height: 40px; border-radius: 8px; overflow: hidden; flex-shrink: 0; border: 1px solid var(--primary-color);">
|
||||
<img id="sticky-track-cover" src="./assets/pasted-20260215-163754-def41f49.png" style="width: 100%; height: 100%; object-fit: cover;">
|
||||
</div>
|
||||
<div style="overflow: hidden; white-space: nowrap; flex: 1; text-align: center;">
|
||||
<span style="color: var(--primary-color); font-weight: 800; font-size: 0.75rem; text-transform: uppercase; margin-right: 10px;">SONANDO:</span>
|
||||
<span id="sticky-track-info" style="font-weight: 700; font-size: 0.9rem; color: #fff;">Lili Records Radio</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
@keyframes slideDown { from { transform: translateY(-100%); } to { transform: translateY(0); } }
|
||||
</style>
|
||||
|
||||
<div class="app-container">
|
||||
<!-- Left Section: Player -->
|
||||
<section class="player-section">
|
||||
@ -2394,6 +2410,16 @@ $facebook_link = "https://www.facebook.com/profile.php?id=61587890927489";
|
||||
trackTitle.classList.add('scrolling');
|
||||
trackTitle.innerHTML = `<span>${title} ${title} </span>`;
|
||||
}
|
||||
|
||||
// Update Sticky Bar
|
||||
const stickyBar = document.getElementById('sticky-now-playing');
|
||||
const stickyCover = document.getElementById('sticky-track-cover');
|
||||
const stickyInfo = document.getElementById('sticky-track-info');
|
||||
if (stickyBar && stickyCover && stickyInfo) {
|
||||
stickyCover.src = coverUrl;
|
||||
stickyInfo.textContent = `${artist} - ${title}`;
|
||||
stickyBar.style.display = 'block';
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user