Autosave: 20260217-201214
This commit is contained in:
parent
e433d2380a
commit
4b069537af
29
api/get_shoutouts.php
Normal file
29
api/get_shoutouts.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
|
||||||
|
$user_name = $_GET['user_name'] ?? '';
|
||||||
|
|
||||||
|
if (empty($user_name)) {
|
||||||
|
echo json_encode(['success' => false, 'error' => 'User name is required.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the latest unseen shoutout for this user
|
||||||
|
$stmt = db()->prepare("SELECT id, message, dj_name FROM dj_shoutouts WHERE target_fan_name = ? AND is_seen = 0 ORDER BY created_at DESC LIMIT 1");
|
||||||
|
$stmt->execute([$user_name]);
|
||||||
|
$shoutout = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($shoutout) {
|
||||||
|
// Mark as seen immediately so it doesn't pop up again
|
||||||
|
$update = db()->prepare("UPDATE dj_shoutouts SET is_seen = 1 WHERE id = ?");
|
||||||
|
$update->execute([$shoutout['id']]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'shoutout' => $shoutout]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => true, 'shoutout' => null]);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
22
api/send_shoutout.php
Normal file
22
api/send_shoutout.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$target = $data['target_name'] ?? '';
|
||||||
|
$message = $data['message'] ?? '';
|
||||||
|
$dj_name = $data['dj_name'] ?? 'Lili';
|
||||||
|
|
||||||
|
if (empty($target) || empty($message)) {
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Target and message are required.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = db()->prepare("INSERT INTO dj_shoutouts (target_fan_name, message, dj_name) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$target, $message, $dj_name]);
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
14
db/migrations/20260217_dj_shoutout.sql
Normal file
14
db/migrations/20260217_dj_shoutout.sql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- Migration: Create dj_shoutouts table
|
||||||
|
-- Description: Stores personalized mentions from the DJ to fans.
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS dj_shoutouts (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
target_fan_name VARCHAR(255) NOT NULL,
|
||||||
|
message TEXT NOT NULL,
|
||||||
|
dj_name VARCHAR(255) DEFAULT 'Lili',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
is_seen TINYINT(1) DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index for faster polling by target name
|
||||||
|
CREATE INDEX idx_target_unseen ON dj_shoutouts(target_fan_name, is_seen);
|
||||||
168
index.php
168
index.php
@ -1406,6 +1406,86 @@ $twitter_link = "https://twitter.com/";
|
|||||||
box-shadow: 0 4px 12px rgba(236, 72, 153, 0.3);
|
box-shadow: 0 4px 12px rgba(236, 72, 153, 0.3);
|
||||||
animation: pulse 2s infinite;
|
animation: pulse 2s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shoutout Modal Styles */
|
||||||
|
.shoutout-modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 5000;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0,0,0,0.85);
|
||||||
|
backdrop-filter: blur(15px);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
}
|
||||||
|
.shoutout-modal.show {
|
||||||
|
display: flex;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.shoutout-card {
|
||||||
|
background: linear-gradient(145deg, rgba(30, 30, 30, 0.9), rgba(10, 10, 10, 0.95));
|
||||||
|
border: 2px solid var(--primary-color);
|
||||||
|
padding: 3rem;
|
||||||
|
border-radius: 40px;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
position: relative;
|
||||||
|
transform: scale(0.5) translateY(100px);
|
||||||
|
transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
box-shadow: 0 0 50px rgba(56, 189, 248, 0.6);
|
||||||
|
}
|
||||||
|
.shoutout-modal.show .shoutout-card {
|
||||||
|
transform: scale(1) translateY(0);
|
||||||
|
}
|
||||||
|
.shoutout-icon {
|
||||||
|
font-size: 5rem;
|
||||||
|
color: #facc15;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
filter: drop-shadow(0 0 20px rgba(250, 204, 21, 0.6));
|
||||||
|
animation: bounce 2s infinite;
|
||||||
|
}
|
||||||
|
.shoutout-title {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
background: linear-gradient(to right, #fff, var(--primary-color));
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
.shoutout-msg {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.shoutout-dj {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
}
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-20px); }
|
||||||
|
}
|
||||||
|
.shoutout-confetti {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -1462,7 +1542,7 @@ $twitter_link = "https://twitter.com/";
|
|||||||
</div>
|
</div>
|
||||||
<div class="track-info">
|
<div class="track-info">
|
||||||
<div id="dj-host-container" style="display: flex; align-items: center; gap: 8px;">
|
<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 class="dj-badge" onclick="adminOpenShoutout()" style="cursor: pointer;" title="DJ Panel (Admin)"><i class="bi bi-mic-fill"></i> <span id="current-dj-name">LILI</span></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="track-label">ESTÁS ESCUCHANDO:</span>
|
<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-title" class="track-title" onclick="copyTrackTitle()" title="Toca para copiar">Cargando stream...</div>
|
||||||
@ -1904,6 +1984,20 @@ $twitter_link = "https://twitter.com/";
|
|||||||
<!-- Celebration Overlay -->
|
<!-- Celebration Overlay -->
|
||||||
<div id="celebration-overlay"></div>
|
<div id="celebration-overlay"></div>
|
||||||
|
|
||||||
|
<!-- Shoutout Modal -->
|
||||||
|
<div id="shoutout-modal" class="shoutout-modal" onclick="this.classList.remove('show'); setTimeout(() => this.style.display = 'none', 500)">
|
||||||
|
<div class="shoutout-card" onclick="event.stopPropagation()">
|
||||||
|
<div class="shoutout-icon"><i class="bi bi-megaphone-fill"></i></div>
|
||||||
|
<div class="shoutout-title">¡Mención Especial!</div>
|
||||||
|
<div id="shoutout-target" style="font-size: 1.5rem; color: #facc15; font-weight: 800; margin-bottom: 1rem;"></div>
|
||||||
|
<div id="shoutout-message" class="shoutout-msg"></div>
|
||||||
|
<div class="shoutout-dj">— Con cariño, <span id="shoutout-dj-name">Lili</span> —</div>
|
||||||
|
<button onclick="document.getElementById('shoutout-modal').classList.remove('show'); setTimeout(() => document.getElementById('shoutout-modal').style.display = 'none', 500)" style="margin-top: 2rem; background: var(--primary-color); border: none; color: black; padding: 10px 30px; border-radius: 20px; font-weight: 800; cursor: pointer; transition: all 0.3s;">
|
||||||
|
¡GRACIAS!
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<audio id="radio-audio" src="https://listen.radioking.com/radio/828046/stream/897251" preload="auto" crossorigin="anonymous"></audio>
|
<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>
|
<audio id="welcome-sound" src="https://assets.mixkit.co/active_storage/sfx/2013/2013-preview.mp3" preload="auto"></audio>
|
||||||
|
|
||||||
@ -3385,9 +3479,81 @@ $twitter_link = "https://twitter.com/";
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize polling
|
// Initialize polling
|
||||||
|
// --- DJ Shoutout Functionality ---
|
||||||
|
async function adminOpenShoutout() {
|
||||||
|
const target = prompt("¿A quién quieres mandarle un saludo?");
|
||||||
|
if (!target) return;
|
||||||
|
const message = prompt(`¿Qué mensaje quieres decirle a ${target}?`, "¡Gracias por estar en sintonía con Lili Records!");
|
||||||
|
if (!message) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('api/send_shoutout.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ target_name: target, message: message })
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.success) {
|
||||||
|
alert("¡Mención enviada con éxito!");
|
||||||
|
} else {
|
||||||
|
alert("Error: " + data.error);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error sending shoutout:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pollShoutouts() {
|
||||||
|
const userName = document.getElementById('user-name').value.trim();
|
||||||
|
if (!userName) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`api/get_shoutouts.php?user_name=${encodeURIComponent(userName)}`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success && data.shoutout) {
|
||||||
|
showShoutoutModal(data.shoutout);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error polling shoutouts:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showShoutoutModal(shoutout) {
|
||||||
|
const modal = document.getElementById('shoutout-modal');
|
||||||
|
const targetEl = document.getElementById('shoutout-target');
|
||||||
|
const msgEl = document.getElementById('shoutout-message');
|
||||||
|
const djEl = document.getElementById('shoutout-dj-name');
|
||||||
|
const userName = document.getElementById('user-name').value.trim();
|
||||||
|
|
||||||
|
targetEl.innerText = `¡Para ${userName}!`;
|
||||||
|
msgEl.innerText = shoutout.message;
|
||||||
|
djEl.innerText = shoutout.dj_name;
|
||||||
|
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
setTimeout(() => modal.classList.add('show'), 10);
|
||||||
|
|
||||||
|
// Audio cue if possible
|
||||||
|
try {
|
||||||
|
const audio = new Audio('https://www.soundjay.com/buttons/sounds/button-3.mp3');
|
||||||
|
audio.volume = 0.5;
|
||||||
|
audio.play();
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(pollShoutouts, 5000);
|
||||||
setInterval(pollCelebrations, 5000);
|
setInterval(pollCelebrations, 5000);
|
||||||
pollCelebrations();
|
pollCelebrations();
|
||||||
|
// --- End DJ Shoutout Functionality ---
|
||||||
|
|
||||||
|
audio.addEventListener('error', function(e) {
|
||||||
|
console.error('Audio error:', e);
|
||||||
|
trackTitle.textContent = "Error de conexión. Reintentando...";
|
||||||
|
setTimeout(() => {
|
||||||
|
audio.load();
|
||||||
|
if (!audio.paused) audio.play();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user