Auto commit: 2026-02-17T19:00:15.988Z
This commit is contained in:
parent
52fa755b06
commit
09b1594a66
@ -5,9 +5,26 @@ header('Content-Type: application/json');
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT username, total_likes, custom_color FROM user_likes ORDER BY total_likes DESC LIMIT 5");
|
||||
// Get top fans from the fans table
|
||||
$stmt = $pdo->query("SELECT name as username, points as total_likes, photo, is_fan_of_month FROM fans ORDER BY points DESC LIMIT 5");
|
||||
$fans = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Add badge logic
|
||||
foreach ($fans as &$fan) {
|
||||
$fan['badges'] = [];
|
||||
if ($fan['is_fan_of_month']) {
|
||||
$fan['badges'][] = ['icon' => 'bi-star-fill', 'color' => '#facc15', 'label' => 'Fan del Mes'];
|
||||
}
|
||||
if ($fan['total_likes'] >= 1000) {
|
||||
$fan['badges'][] = ['icon' => 'bi-gem', 'color' => '#38bdf8', 'label' => 'Diamante'];
|
||||
} elseif ($fan['total_likes'] >= 500) {
|
||||
$fan['badges'][] = ['icon' => 'bi-shield-check', 'color' => '#00c853', 'label' => 'Veterano'];
|
||||
}
|
||||
|
||||
// Custom color fallback
|
||||
$fan['custom_color'] = $fan['is_fan_of_month'] ? '#facc15' : '#38bdf8';
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true, 'fans' => $fans]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
|
||||
@ -45,6 +45,21 @@ if ($method === 'POST') {
|
||||
try {
|
||||
$stmt = $db->prepare("INSERT INTO song_requests (artist, song, requester) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$artist, $song, $requester]);
|
||||
|
||||
// Award points for song request
|
||||
if ($requester !== 'Anónimo') {
|
||||
$fanStmt = $db->prepare("SELECT id, points FROM fans WHERE name = ?");
|
||||
$fanStmt->execute([$requester]);
|
||||
$fan = $fanStmt->fetch();
|
||||
|
||||
if ($fan) {
|
||||
$newPoints = $fan['points'] + 25; // More points for a request
|
||||
$db->prepare("UPDATE fans SET points = ? WHERE id = ?")->execute([$newPoints, $fan['id']]);
|
||||
} else {
|
||||
$db->prepare("INSERT INTO fans (name, points) VALUES (?, ?)")->execute([$requester, 25]);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
|
||||
151
index.php
151
index.php
@ -1194,6 +1194,59 @@ $twitter_link = "https://twitter.com/";
|
||||
opacity: 0.6;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* Leaderboard Styles */
|
||||
.leaderboard-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
.leaderboard-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding: 0.8rem;
|
||||
border-radius: 16px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.leaderboard-item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
transform: translateX(5px);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.leaderboard-rank {
|
||||
font-weight: 800;
|
||||
font-size: 1.1rem;
|
||||
width: 25px;
|
||||
text-align: center;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.leaderboard-avatar {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--glass-border);
|
||||
object-fit: cover;
|
||||
}
|
||||
.leaderboard-info {
|
||||
flex: 1;
|
||||
}
|
||||
.leaderboard-name {
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.leaderboard-points {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.badge-icon {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -1513,6 +1566,22 @@ $twitter_link = "https://twitter.com/";
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fan Leaderboard Widget -->
|
||||
<div class="glass-card mt-4" style="margin-top: 1.5rem;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
||||
<h3 style="font-size: 1.2rem; margin: 0; color: var(--primary-color);">
|
||||
<i class="bi bi-trophy-fill"></i> TOP FANS
|
||||
</h3>
|
||||
<a href="ranking.php" style="font-size: 0.75rem; color: var(--accent-color); text-decoration: none; font-weight: 700;">VER TODO <i class="bi bi-arrow-right"></i></a>
|
||||
</div>
|
||||
<div id="leaderboard-list" class="leaderboard-list">
|
||||
<div style="opacity: 0.5; font-size: 0.85rem; text-align: center; padding: 1rem;">Cargando ranking...</div>
|
||||
</div>
|
||||
<div style="margin-top: 1rem; font-size: 0.65rem; opacity: 0.5; text-align: center; font-style: italic;">
|
||||
Suma puntos participando en el chat y pidiendo canciones.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
@ -2493,11 +2562,35 @@ $twitter_link = "https://twitter.com/";
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch Now Playing Metadata from RadioKing
|
||||
let progressInterval = null;
|
||||
|
||||
async function updateMetadata() {
|
||||
// ... (keeping existing logic)
|
||||
async function fetchLeaderboard() {
|
||||
const container = document.getElementById('leaderboard-list');
|
||||
try {
|
||||
const response = await fetch('api/get_top_fans.php');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
if (data.fans.length === 0) {
|
||||
container.innerHTML = '<div style="opacity: 0.5; font-size: 0.85rem; text-align: center; padding: 1rem;">No hay fans destacados aún.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = data.fans.map((fan, index) => `
|
||||
<div class="leaderboard-item">
|
||||
<div class="leaderboard-rank">${index + 1}</div>
|
||||
<img src="${fan.photo || 'assets/pasted-20260215-163754-def41f49.png'}" alt="${fan.username}" class="leaderboard-avatar">
|
||||
<div class="leaderboard-info">
|
||||
<div class="leaderboard-name">
|
||||
${fan.username}
|
||||
${fan.badges.map(b => `<i class="bi ${b.icon}" style="color: ${b.color};" title="${b.label}"></i>`).join('')}
|
||||
</div>
|
||||
<div class="leaderboard-points">${parseInt(fan.total_likes).toLocaleString()} puntos</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
} catch (error) {
|
||||
container.innerHTML = '<div style="opacity: 0.5; font-size: 0.85rem; text-align: center; padding: 1rem; color: #ff4444;">Error al cargar el ranking.</div>';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchGallery() {
|
||||
@ -2546,18 +2639,27 @@ $twitter_link = "https://twitter.com/";
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
// Initial fetch
|
||||
fetchGallery();
|
||||
setInterval(fetchGallery, 60000); // Update every minute
|
||||
// Fetch Now Playing Metadata
|
||||
let progressInterval = null;
|
||||
|
||||
}
|
||||
async function updateMetadata() {
|
||||
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) {
|
||||
const title = data.title;
|
||||
const artist = data.artist;
|
||||
const album = data.album || '';
|
||||
const coverUrl = data.cover || './assets/pasted-20260215-163754-def41f49.png';
|
||||
const fullDisplay = `${artist} - ${title}`;
|
||||
|
||||
if (trackTitle.textContent !== title) {
|
||||
trackTitle.style.opacity = '0';
|
||||
if (trackArtist) trackArtist.style.opacity = '0';
|
||||
if (trackAlbum) trackAlbum.style.opacity = '0';
|
||||
if (trackCover) trackCover.style.opacity = '0';
|
||||
|
||||
// Reset Like Button
|
||||
const likeIcon = document.querySelector('#like-song-btn i');
|
||||
if (likeIcon) {
|
||||
likeIcon.classList.remove('bi-heart-fill');
|
||||
@ -2633,14 +2735,12 @@ $twitter_link = "https://twitter.com/";
|
||||
if (coverPlaceholder) coverPlaceholder.style.display = 'none';
|
||||
trackCover.style.opacity = '1';
|
||||
|
||||
// Record History in Database
|
||||
fetch('api/record_history.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ title: title, artist: artist, cover: coverUrl })
|
||||
}).catch(err => console.error("Error recording history:", err));
|
||||
|
||||
// Dynamic Color Extraction
|
||||
trackCover.onload = function() {
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
@ -2652,13 +2752,11 @@ $twitter_link = "https://twitter.com/";
|
||||
if (rgb[0] + rgb[1] + rgb[2] > 30) {
|
||||
const color = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
|
||||
document.documentElement.style.setProperty('--primary-color', color);
|
||||
// Dynamic glow removed for stability
|
||||
}
|
||||
} catch(e) {}
|
||||
};
|
||||
}
|
||||
|
||||
// Dynamic Background Update
|
||||
fetch(`api/pexels.php?query=${encodeURIComponent(artist + " " + title + " music background")}`)
|
||||
.then(res => res.json())
|
||||
.then(pData => {
|
||||
@ -2667,7 +2765,6 @@ $twitter_link = "https://twitter.com/";
|
||||
}
|
||||
}).catch(() => {});
|
||||
|
||||
// Progress Bar Logic
|
||||
const progContainer = document.getElementById('track-progress-container');
|
||||
const progBar = document.getElementById('track-progress-bar');
|
||||
|
||||
@ -2688,12 +2785,12 @@ $twitter_link = "https://twitter.com/";
|
||||
}
|
||||
|
||||
updateProgressBar();
|
||||
if (progressInterval) clearInterval(progressInterval);
|
||||
progressInterval = setInterval(updateProgressBar, 1000);
|
||||
} else if (progContainer) {
|
||||
progContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// Fetch likes for this song
|
||||
try {
|
||||
const lResp = await fetch(`api/get_likes.php?song_title=${encodeURIComponent(fullDisplay)}`);
|
||||
const lData = await lResp.json();
|
||||
@ -2702,13 +2799,11 @@ $twitter_link = "https://twitter.com/";
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Check if scrolling is needed
|
||||
if (trackTitle.scrollWidth > trackTitle.clientWidth) {
|
||||
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');
|
||||
@ -2722,16 +2817,12 @@ $twitter_link = "https://twitter.com/";
|
||||
|
||||
document.title = `▶ ${fullDisplay} | Lili Records Radio`;
|
||||
|
||||
// Media Session API for System Controls
|
||||
if ('mediaSession' in navigator) {
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: title,
|
||||
artist: artist,
|
||||
album: 'Lili Records Radio',
|
||||
artwork: [
|
||||
{ src: data.cover || './assets/pasted-20260215-163754-def41f49.png', sizes: '512x512', type: 'image/png' },
|
||||
{ src: data.cover || './assets/pasted-20260215-163754-def41f49.png', sizes: '256x256', type: 'image/png' }
|
||||
]
|
||||
artwork: [{ src: coverUrl, sizes: '512x512', type: 'image/png' }]
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -2745,13 +2836,17 @@ $twitter_link = "https://twitter.com/";
|
||||
}
|
||||
}
|
||||
|
||||
// Update every 30 seconds
|
||||
// Initial fetch
|
||||
updateMetadata();
|
||||
fetchTopSongs();
|
||||
setInterval(() => {
|
||||
updateMetadata();
|
||||
fetchTopSongs();
|
||||
}, 30000);
|
||||
fetchGallery();
|
||||
fetchLeaderboard();
|
||||
|
||||
// Update cycles
|
||||
setInterval(updateMetadata, 30000);
|
||||
setInterval(fetchTopSongs, 60000);
|
||||
setInterval(fetchGallery, 60000);
|
||||
setInterval(fetchLeaderboard, 60000);
|
||||
|
||||
// Theme Toggle Functionality
|
||||
function toggleTheme() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user