Auto commit: 2026-02-17T19:34:31.288Z
This commit is contained in:
parent
9a708e280e
commit
e433d2380a
23
api/get_latest_tips.php
Normal file
23
api/get_latest_tips.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../db/config.php";
|
||||
header("Content-Type: application/json");
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
// Fetch tips from the last 15 seconds to trigger celebrations
|
||||
$stmt = $pdo->prepare("SELECT * FROM dj_tips WHERE created_at > (NOW() - INTERVAL 15 SECOND) ORDER BY created_at DESC LIMIT 5");
|
||||
$stmt->execute();
|
||||
$tips = $stmt->fetchAll();
|
||||
|
||||
// Also get current DJ
|
||||
$stmt = $pdo->query("SELECT setting_value FROM settings WHERE setting_key = 'current_dj'");
|
||||
$dj = $stmt->fetchColumn() ?: "Lili";
|
||||
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"tips" => $tips,
|
||||
"current_dj" => $dj
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(["success" => false, "error" => $e->getMessage()]);
|
||||
}
|
||||
51
api/send_tip.php
Normal file
51
api/send_tip.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../db/config.php";
|
||||
header("Content-Type: application/json");
|
||||
|
||||
$pdo = db();
|
||||
$username = $_POST["username"] ?? "";
|
||||
$amount = intval($_POST["amount"] ?? 100);
|
||||
|
||||
if (!$username) {
|
||||
echo json_encode(["success" => false, "error" => "Inicia sesión para enviar flores"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Get current DJ
|
||||
$stmt = $pdo->query("SELECT setting_value FROM settings WHERE setting_key = 'current_dj'");
|
||||
$dj = $stmt->fetchColumn() ?: "Lili";
|
||||
|
||||
// Check user points
|
||||
$stmt = $pdo->prepare("SELECT points FROM fans WHERE name = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user || $user["points"] < $amount) {
|
||||
echo json_encode(["success" => false, "error" => "No tienes suficientes puntos ($amount requeridos)"]);
|
||||
$pdo->rollBack();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Deduct points
|
||||
$stmt = $pdo->prepare("UPDATE fans SET points = points - ? WHERE name = ?");
|
||||
$stmt->execute([$amount, $username]);
|
||||
|
||||
// Log tip
|
||||
$stmt = $pdo->prepare("INSERT INTO dj_tips (sender_name, dj_name, amount) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$username, $dj, $amount]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"message" => "¡Has enviado flores a $dj!",
|
||||
"dj" => $dj
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(["success" => false, "error" => $e->getMessage()]);
|
||||
}
|
||||
11
db/migrations/20260217_dj_flores.sql
Normal file
11
db/migrations/20260217_dj_flores.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- Migration: DJ Flores and Current DJ settings
|
||||
INSERT INTO settings (setting_key, setting_value) VALUES ('current_dj', 'Lili') ON DUPLICATE KEY UPDATE setting_value = setting_value;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dj_tips (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
sender_name VARCHAR(255) NOT NULL,
|
||||
dj_name VARCHAR(255) NOT NULL,
|
||||
amount INT NOT NULL,
|
||||
message VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
190
index.php
190
index.php
@ -1360,39 +1360,53 @@ $twitter_link = "https://twitter.com/";
|
||||
font-size: 1rem;
|
||||
color: white;
|
||||
}
|
||||
.shop-item-desc {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.shop-item-price {
|
||||
font-weight: 800;
|
||||
color: #facc15;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.pinned-message-container {
|
||||
background: linear-gradient(90deg, rgba(56, 189, 248, 0.2), rgba(0, 200, 83, 0.2));
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 12px;
|
||||
padding: 0.8rem;
|
||||
margin-bottom: 1rem;
|
||||
display: none;
|
||||
animation: fadeIn 0.5s ease;
|
||||
position: relative;
|
||||
}
|
||||
.pinned-label {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 800;
|
||||
color: var(--primary-color);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
.shop-item-desc {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Celebration & Flowers */
|
||||
#celebration-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flower-particle {
|
||||
position: absolute;
|
||||
font-size: 2rem;
|
||||
user-select: none;
|
||||
animation: fall-and-sway var(--duration) linear forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes fall-and-sway {
|
||||
0% { transform: translateY(-10vh) translateX(0) rotate(0deg); opacity: 0; }
|
||||
10% { opacity: 1; }
|
||||
90% { opacity: 1; }
|
||||
100% { transform: translateY(110vh) translateX(var(--sway)) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
|
||||
.dj-badge {
|
||||
background: linear-gradient(135deg, #f472b6, #db2777);
|
||||
color: white;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 800;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin-bottom: 8px;
|
||||
box-shadow: 0 4px 12px rgba(236, 72, 153, 0.3);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="background"></div>
|
||||
@ -1447,6 +1461,9 @@ $twitter_link = "https://twitter.com/";
|
||||
<img id="track-cover" src="./assets/pasted-20260215-163754-def41f49.png" alt="Cover" crossorigin="anonymous" onerror="this.style.display='none'; document.getElementById('cover-placeholder').style.display='block';">
|
||||
</div>
|
||||
<div class="track-info">
|
||||
<div id="dj-host-container" style="display: flex; align-items: center; gap: 8px;">
|
||||
<div class="dj-badge"><i class="bi bi-mic-fill"></i> <span id="current-dj-name">LILI</span></div>
|
||||
</div>
|
||||
<span class="track-label">ESTÁS ESCUCHANDO:</span>
|
||||
<div id="track-title" class="track-title" onclick="copyTrackTitle()" title="Toca para copiar">Cargando stream...</div>
|
||||
<div id="track-artist" class="track-artist" style="font-size: 0.95rem; font-weight: 600; opacity: 0.8; color: var(--primary-color); text-transform: uppercase; letter-spacing: 1px; margin-top: 2px;">Lili Records Radio</div>
|
||||
@ -1480,6 +1497,10 @@ $twitter_link = "https://twitter.com/";
|
||||
<i class="bi bi-heart"></i>
|
||||
<span id="like-count" style="font-size: 0.9rem; color: white; opacity: 0.8; font-weight: bold;"></span>
|
||||
</button>
|
||||
<button id="send-flowers-btn" onclick="sendFlowersToDJ()" style="background: none; border: none; color: #f472b6; font-size: 1.8rem; cursor: pointer; transition: transform 0.2s; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-left: 10px;" title="Regalar flores al DJ">
|
||||
<i class="bi bi-flower1"></i>
|
||||
<span style="font-size: 0.6rem; color: white; opacity: 0.8; font-weight: bold; margin-top: -5px;">FLORES</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
@ -1880,6 +1901,9 @@ $twitter_link = "https://twitter.com/";
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
|
||||
<!-- Celebration Overlay -->
|
||||
<div id="celebration-overlay"></div>
|
||||
|
||||
<audio id="radio-audio" src="https://listen.radioking.com/radio/828046/stream/897251" preload="auto" crossorigin="anonymous"></audio>
|
||||
<audio id="welcome-sound" src="https://assets.mixkit.co/active_storage/sfx/2013/2013-preview.mp3" preload="auto"></audio>
|
||||
|
||||
@ -3264,6 +3288,106 @@ $twitter_link = "https://twitter.com/";
|
||||
setInterval(fetchActivePerks, 10000);
|
||||
fetchActivePerks();
|
||||
// --- End Radio Shop Functionality ---
|
||||
|
||||
// --- DJ Flores Functionality ---
|
||||
let lastCelebrationId = 0;
|
||||
const shownTips = new Set();
|
||||
|
||||
async function sendFlowersToDJ() {
|
||||
const userName = document.getElementById('user-name').value.trim();
|
||||
if (!userName) {
|
||||
alert('Por favor, ingresa tu nombre arriba para regalar flores.');
|
||||
document.getElementById('user-name').focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`¿Quieres enviarle un ramo de flores al DJ por 100 puntos?`)) return;
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('username', userName);
|
||||
formData.append('amount', 100);
|
||||
|
||||
const response = await fetch('api/send_tip.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert(data.message);
|
||||
launchFlowerCelebration(); // Local trigger
|
||||
fetchLeaderboard(); // Update points
|
||||
} else {
|
||||
alert(data.error);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error sending flowers:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function pollCelebrations() {
|
||||
try {
|
||||
const response = await fetch('api/get_latest_tips.php');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Update DJ Name
|
||||
if (data.current_dj) {
|
||||
document.getElementById('current-dj-name').innerText = data.current_dj.toUpperCase();
|
||||
}
|
||||
|
||||
// Check for new tips
|
||||
data.tips.forEach(tip => {
|
||||
if (!shownTips.has(tip.id)) {
|
||||
shownTips.add(tip.id);
|
||||
launchFlowerCelebration();
|
||||
console.log(`Celebration for tip from ${tip.sender_name}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup set to keep it small
|
||||
if (shownTips.size > 50) {
|
||||
const it = shownTips.values();
|
||||
shownTips.delete(it.next().value);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error polling celebrations:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function launchFlowerCelebration() {
|
||||
const container = document.getElementById('celebration-overlay');
|
||||
const emojis = ['🌸', '🌹', '🌺', '🌻', '🌼', '🌷', '✨', '💖'];
|
||||
const count = 30;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
setTimeout(() => {
|
||||
const flower = document.createElement('div');
|
||||
flower.className = 'flower-particle';
|
||||
flower.innerText = emojis[Math.floor(Math.random() * emojis.length)];
|
||||
|
||||
const left = Math.random() * 100;
|
||||
const sway = (Math.random() - 0.5) * 200;
|
||||
const duration = 3 + Math.random() * 4;
|
||||
|
||||
flower.style.left = `${left}%`;
|
||||
flower.style.setProperty('--sway', `${sway}px`);
|
||||
flower.style.setProperty('--duration', `${duration}s`);
|
||||
flower.style.fontSize = `${1.5 + Math.random() * 2}rem`;
|
||||
|
||||
container.appendChild(flower);
|
||||
|
||||
setTimeout(() => flower.remove(), duration * 1000);
|
||||
}, i * 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize polling
|
||||
setInterval(pollCelebrations, 5000);
|
||||
pollCelebrations();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user