1826 lines
76 KiB
PHP
1826 lines
76 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/tracker.php';
|
|
track_visitor();
|
|
|
|
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Lili Records Radio - La mejor música en vivo.';
|
|
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? 'assets/pasted-20260215-164611-6d2aee42.png';
|
|
|
|
// WhatsApp info
|
|
$whatsapp_link = "https://chat.whatsapp.com/DkG96pTzAFO3hvLqmzwmTY";
|
|
$whatsapp_number = '+5359177041';
|
|
$facebook_link = "https://www.facebook.com/profile.php?id=61587890927489";
|
|
?>
|
|
<!doctype html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Lili Records Radio</title>
|
|
|
|
<!-- Meta tags SEO -->
|
|
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
<meta property="og:title" content="Lili Records Radio" />
|
|
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
|
<meta property="twitter:card" content="summary_large_image" />
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
|
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@1/index.js"></script>
|
|
|
|
<style>
|
|
:root {
|
|
--accent-color: #00c853; /* Refined Green */
|
|
--primary-color: #38bdf8; /* Vibrant Blue */
|
|
--bg-overlay: rgba(0, 0, 0, 0.15); /* Even lighter for maximum transparency */
|
|
--glass-bg: rgba(255, 255, 255, 0.03); /* Almost invisible glass */
|
|
--glass-border: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
body, html {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
font-family: 'Inter', sans-serif;
|
|
color: #ffffff;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.background {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: url('assets/images/background.jpg') center/cover no-repeat;
|
|
z-index: -1;
|
|
transition: filter 0.05s ease-out, transform 0.05s ease-out, background-image 1.5s ease-in-out;
|
|
will-change: filter, transform, background-image;
|
|
}
|
|
|
|
.background::after {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: var(--bg-overlay);
|
|
}
|
|
|
|
.app-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
min-height: 100vh;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem 1.5rem;
|
|
box-sizing: border-box;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
/* Center Section: Player */
|
|
.player-section {
|
|
width: 100%;
|
|
max-width: 680px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
z-index: 10;
|
|
}
|
|
|
|
.interaction-center {
|
|
width: 100%;
|
|
max-width: 520px;
|
|
z-index: 10;
|
|
}
|
|
|
|
.glass-card {
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(3px);
|
|
-webkit-backdrop-filter: blur(3px);
|
|
border: 2px solid transparent;
|
|
border-radius: 32px;
|
|
padding: 2.5rem;
|
|
box-shadow: 0 15px 45px rgba(0, 0, 0, 0.4),
|
|
0 0 30px var(--dynamic-glow-dim, transparent);
|
|
position: relative;
|
|
background-clip: padding-box;
|
|
overflow: hidden;
|
|
transition: border-radius 0.5s ease, background 0.5s ease, box-shadow 0.1s ease;
|
|
}
|
|
|
|
/* Animated colorful border */
|
|
.glass-card::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: 32px;
|
|
padding: 2px; /* thickness */
|
|
background: var(--card-border-bg, linear-gradient(45deg, var(--dynamic-glow, #00e676), #38bdf8, var(--dynamic-glow-dim, #facc15), #f472b6, var(--dynamic-glow, #00e676)));
|
|
background-size: 400% 400%;
|
|
-webkit-mask:
|
|
linear-gradient(#fff 0 0) content-box,
|
|
linear-gradient(#fff 0 0);
|
|
-webkit-mask-composite: xor;
|
|
mask-composite: exclude;
|
|
pointer-events: none;
|
|
animation: gradient-border 8s linear infinite;
|
|
transition: background 0.05s ease;
|
|
}
|
|
|
|
@keyframes gradient-border {
|
|
0% { background-position: 0% 50%; }
|
|
50% { background-position: 100% 50%; }
|
|
100% { background-position: 0% 50%; }
|
|
}
|
|
|
|
.brand h1 {
|
|
font-size: 2.8rem;
|
|
font-weight: 800;
|
|
margin: 0 0 0.5rem;
|
|
background: linear-gradient(to right, #fff, var(--primary-color), var(--accent-color));
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
letter-spacing: -1px;
|
|
filter: drop-shadow(0 0 10px rgba(56, 189, 248, 0.3));
|
|
}
|
|
|
|
.brand-logo {
|
|
width: 130px;
|
|
height: 130px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 4px solid var(--dynamic-glow, var(--primary-color));
|
|
box-shadow: 0 0 25px var(--dynamic-glow, rgba(56, 189, 248, 0.7)),
|
|
0 0 50px var(--dynamic-glow-dim, rgba(56, 189, 248, 0.4));
|
|
transition: transform 0.3s ease, border-color 0.1s ease, box-shadow 0.1s ease;
|
|
}
|
|
|
|
.logo-wrapper {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 2rem;
|
|
margin-bottom: 1.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.brand-logo:hover {
|
|
transform: scale(1.1) rotate(5deg);
|
|
}
|
|
|
|
.brand p {
|
|
font-size: 1rem;
|
|
opacity: 0.8;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Radio Player UI */
|
|
.radio-player {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.now-playing {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.2rem;
|
|
background: rgba(255, 255, 255, 0.02);
|
|
padding: 1.2rem;
|
|
border-radius: 20px;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
box-shadow: inset 0 0 15px rgba(0,0,0,0.2);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.track-cover-container {
|
|
width: 80px;
|
|
height: 80px;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
flex-shrink: 0;
|
|
position: relative;
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
|
border: 2px solid rgba(255,255,255,0.1);
|
|
transition: transform 0.3s ease, box-shadow 0.1s ease;
|
|
}
|
|
|
|
.track-cover-container img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transition: opacity 0.5s ease;
|
|
}
|
|
|
|
.track-cover-container i {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
font-size: 1.5rem;
|
|
color: rgba(255,255,255,0.5);
|
|
z-index: 1;
|
|
display: none;
|
|
}
|
|
|
|
.now-playing i {
|
|
font-size: 1.5rem;
|
|
color: var(--primary-color);
|
|
}
|
|
|
|
.track-info {
|
|
overflow: hidden;
|
|
flex: 1;
|
|
}
|
|
|
|
.track-title {
|
|
font-weight: 800;
|
|
font-size: 1.5rem;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
transition: color 0.05s ease, transform 0.05s ease, text-shadow 0.05s ease, opacity 0.5s ease;
|
|
color: #ffffff;
|
|
text-shadow: 0 0 15px rgba(56, 189, 248, 0.6);
|
|
display: block;
|
|
margin-top: 0.2rem;
|
|
will-change: color, transform, text-shadow;
|
|
}
|
|
|
|
.track-label {
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 2px;
|
|
color: var(--accent-color);
|
|
margin-bottom: -5px;
|
|
display: block;
|
|
}
|
|
|
|
@keyframes marquee {
|
|
0% { transform: translateX(0); }
|
|
100% { transform: translateX(-50%); }
|
|
}
|
|
|
|
.track-title.scrolling {
|
|
text-overflow: clip;
|
|
}
|
|
|
|
.track-title.scrolling span {
|
|
display: inline-block;
|
|
animation: marquee 15s linear infinite;
|
|
padding-right: 2rem;
|
|
}
|
|
|
|
.track-status {
|
|
font-size: 0.85rem;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.play-btn {
|
|
width: 72px;
|
|
height: 72px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--primary-color), #0ea5e9);
|
|
border: none;
|
|
color: #fff;
|
|
font-size: 2rem;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
box-shadow: 0 0 20px rgba(56, 189, 248, 0.4), inset 0 0 10px rgba(255,255,255,0.2);
|
|
position: relative;
|
|
}
|
|
|
|
.play-btn::after {
|
|
content: '';
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
border: 2px solid var(--primary-color);
|
|
opacity: 0;
|
|
transition: all 0.4s;
|
|
}
|
|
|
|
.play-btn:hover::after {
|
|
opacity: 1;
|
|
transform: scale(1.2);
|
|
}
|
|
|
|
.play-btn.playing {
|
|
background: linear-gradient(135deg, #ff4444, #cc0000) !important;
|
|
box-shadow: 0 0 25px rgba(255, 68, 68, 0.6);
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
@keyframes pulse-button {
|
|
0% { box-shadow: 0 0 0 0 rgba(255, 68, 68, 0.7); }
|
|
70% { box-shadow: 0 0 0 20px rgba(255, 68, 68, 0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(255, 68, 68, 0); }
|
|
}
|
|
|
|
.now-playing {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
padding: 1.2rem;
|
|
border-radius: 16px;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
box-shadow: inset 0 0 15px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.play-btn:hover {
|
|
transform: scale(1.05);
|
|
background: #0ea5e9;
|
|
}
|
|
|
|
.visualizer-container {
|
|
width: 100%;
|
|
height: 120px;
|
|
margin-bottom: 1rem;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
overflow: hidden;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
background: radial-gradient(circle at center, rgba(56, 189, 248, 0.05) 0%, transparent 70%);
|
|
position: relative;
|
|
padding: 0 10px;
|
|
}
|
|
|
|
.audio-visualizer {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.visualizer-bar {
|
|
width: 18px;
|
|
height: 5px;
|
|
border-radius: 4px 4px 0 0;
|
|
background: var(--primary-color);
|
|
transition: height 0.05s ease;
|
|
min-height: 5px;
|
|
position: relative;
|
|
}
|
|
|
|
.visualizer-peak {
|
|
position: absolute;
|
|
width: 18px;
|
|
height: 12px;
|
|
background: linear-gradient(to bottom, #fff, transparent);
|
|
border-radius: 2px;
|
|
bottom: 0;
|
|
z-index: 2;
|
|
box-shadow: 0 -2px 10px rgba(255, 255, 255, 0.8);
|
|
pointer-events: none;
|
|
transition: background 0.1s ease;
|
|
}
|
|
|
|
@keyframes strobe-peak {
|
|
0%, 100% { opacity: 1; filter: brightness(1.5) contrast(1.2); }
|
|
50% { opacity: 0.3; filter: brightness(4) contrast(2); }
|
|
}
|
|
|
|
.strobe {
|
|
animation: strobe-peak 0.08s infinite steps(2);
|
|
box-shadow: 0 0 30px #fff, 0 0 50px var(--peak-glow, #fff) !important;
|
|
}
|
|
|
|
/* Colores vibrantes para las barras */
|
|
.visualizer-bar:nth-child(5n+1) { background: linear-gradient(to top, #00e676, #69f0ae); }
|
|
.visualizer-bar:nth-child(5n+2) { background: linear-gradient(to top, #38bdf8, #7dd3fc); }
|
|
.visualizer-bar:nth-child(5n+3) { background: linear-gradient(to top, #facc15, #fde047); }
|
|
.visualizer-bar:nth-child(5n+4) { background: linear-gradient(to top, #f472b6, #fb923c); }
|
|
.visualizer-bar:nth-child(5n+5) { background: linear-gradient(to top, #818cf8, #a5b4fc); }
|
|
|
|
/* Playing Animations */
|
|
body.is-playing .glass-card {
|
|
animation: card-pulse 4s infinite ease-in-out;
|
|
border-color: rgba(56, 189, 248, 0.5);
|
|
}
|
|
|
|
.featured-img-container {
|
|
width: 100%;
|
|
max-width: 900px;
|
|
position: relative;
|
|
border-radius: 32px;
|
|
overflow: hidden;
|
|
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7);
|
|
aspect-ratio: 16 / 10;
|
|
transition: all 0.5s ease;
|
|
}
|
|
|
|
@keyframes card-pulse {
|
|
0%, 100% {
|
|
transform: translate(var(--shake-offset-x, 0), var(--shake-offset-y, 0)) scale(1);
|
|
box-shadow: 0 15px 45px rgba(0, 0, 0, 0.4), 0 0 20px var(--dynamic-glow-dim, rgba(0,0,0,0));
|
|
}
|
|
50% {
|
|
transform: translate(var(--shake-offset-x, 0), var(--shake-offset-y, 0)) scale(1.01);
|
|
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 40px var(--dynamic-glow, rgba(56, 189, 248, 0.4));
|
|
}
|
|
}
|
|
|
|
@keyframes float-img {
|
|
0%, 100% { transform: translateY(0) scale(1); }
|
|
50% { transform: translateY(-15px) scale(1.02); }
|
|
}
|
|
|
|
.volume-slider {
|
|
flex: 1;
|
|
height: 6px;
|
|
-webkit-appearance: none;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 3px;
|
|
outline: none;
|
|
}
|
|
|
|
.volume-slider::-webkit-slider-thumb {
|
|
-webkit-appearance: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
background: #fff;
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Interaction Form */
|
|
.interaction-form {
|
|
margin-top: 2rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
text-align: left;
|
|
}
|
|
|
|
.form-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.form-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.8rem;
|
|
}
|
|
|
|
.interaction-form label {
|
|
font-size: 0.85rem;
|
|
font-weight: 700;
|
|
opacity: 0.9;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.interaction-form input,
|
|
.interaction-form textarea {
|
|
width: 100%;
|
|
padding: 0.8rem;
|
|
border-radius: 12px;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
background-color: rgba(255, 255, 255, 0.05); /* Even more transparent */
|
|
color: #ffffff;
|
|
font-family: inherit;
|
|
font-size: 0.95rem;
|
|
box-sizing: border-box;
|
|
outline: none;
|
|
transition: all 0.2s;
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
|
|
.interaction-form textarea {
|
|
resize: none;
|
|
height: 80px;
|
|
}
|
|
|
|
.interaction-form input::placeholder,
|
|
.interaction-form textarea::placeholder {
|
|
color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.send-whatsapp-btn {
|
|
background-color: var(--accent-color);
|
|
color: #fff;
|
|
border: none;
|
|
padding: 0.8rem;
|
|
border-radius: 12px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
transition: transform 0.2s, background 0.2s;
|
|
}
|
|
|
|
.send-whatsapp-btn:hover {
|
|
transform: translateY(-2px);
|
|
background-color: #00c853;
|
|
}
|
|
|
|
/* Center Section: Featured Image */
|
|
.image-section {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 5;
|
|
}
|
|
|
|
.featured-img-container {
|
|
width: 100%;
|
|
max-width: 900px;
|
|
position: relative;
|
|
border-radius: 32px;
|
|
overflow: hidden;
|
|
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7);
|
|
aspect-ratio: 16 / 10;
|
|
}
|
|
|
|
.featured-img-container img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
background: rgba(0,0,0,0.2);
|
|
transition: transform 0.5s;
|
|
}
|
|
|
|
.featured-img-container:hover img {
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
/* Transfermovil QR Section */
|
|
.payment-section {
|
|
margin-top: 2rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.qr-placeholder {
|
|
width: 220px;
|
|
height: 220px;
|
|
margin: 1rem auto;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border-radius: 12px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #fff;
|
|
padding: 10px;
|
|
backdrop-filter: blur(4px);
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
animation: qr-pulse 2s infinite ease-in-out;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.qr-placeholder:hover {
|
|
animation-play-state: paused;
|
|
transform: scale(1.05);
|
|
box-shadow: 0 0 20px var(--accent-color);
|
|
background: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
@keyframes qr-pulse {
|
|
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(0, 230, 118, 0.4); }
|
|
50% { transform: scale(1.03); box-shadow: 0 0 20px 10px rgba(0, 230, 118, 0); }
|
|
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(0, 230, 118, 0); }
|
|
}
|
|
|
|
/* Modal Styles */
|
|
.qr-modal {
|
|
display: none;
|
|
position: fixed;
|
|
z-index: 2000;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0,0,0,0.6);
|
|
backdrop-filter: blur(15px);
|
|
justify-content: center;
|
|
align-items: center;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.qr-modal.show {
|
|
display: flex;
|
|
opacity: 1;
|
|
}
|
|
|
|
.qr-modal-content {
|
|
max-width: 90%;
|
|
max-height: 90%;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
backdrop-filter: blur(20px);
|
|
padding: 30px;
|
|
border-radius: 32px;
|
|
position: relative;
|
|
transform: scale(0.7);
|
|
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
overflow: hidden;
|
|
box-shadow: 0 0 50px rgba(0, 230, 118, 0.4), 0 0 100px rgba(0, 0, 0, 0.5);
|
|
animation: glow-color-change 8s infinite ease-in-out;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
@keyframes glow-color-change {
|
|
0% { box-shadow: 0 0 50px rgba(0, 230, 118, 0.4), 0 0 100px rgba(0, 0, 0, 0.5); }
|
|
33% { box-shadow: 0 0 50px rgba(56, 189, 248, 0.4), 0 0 100px rgba(0, 0, 0, 0.5); }
|
|
66% { box-shadow: 0 0 50px rgba(244, 114, 182, 0.4), 0 0 100px rgba(0, 0, 0, 0.5); }
|
|
100% { box-shadow: 0 0 50px rgba(0, 230, 118, 0.4), 0 0 100px rgba(0, 0, 0, 0.5); }
|
|
}
|
|
|
|
.qr-modal-content::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -150%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: linear-gradient(
|
|
120deg,
|
|
transparent,
|
|
rgba(255, 255, 255, 0.1),
|
|
transparent
|
|
);
|
|
transform: rotate(10deg);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.qr-modal.show .qr-modal-content::after {
|
|
animation: modal-shine 4s infinite;
|
|
}
|
|
|
|
@keyframes modal-shine {
|
|
0% { left: -150%; }
|
|
20% { left: 150%; }
|
|
100% { left: 150%; }
|
|
}
|
|
|
|
.qr-modal.show .qr-modal-content {
|
|
transform: scale(1);
|
|
}
|
|
|
|
.qr-modal-close {
|
|
position: absolute;
|
|
top: 15px;
|
|
right: 20px;
|
|
color: #ffffff;
|
|
font-size: 2.5rem;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
text-shadow: 0 0 10px rgba(0,0,0,0.5);
|
|
}
|
|
|
|
.qr-placeholder i {
|
|
font-size: 3rem;
|
|
margin-bottom: 10px;
|
|
color: #fff;
|
|
}
|
|
|
|
.qr-placeholder span {
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
/* Floating Social Buttons */
|
|
.social-float-container {
|
|
position: fixed;
|
|
bottom: 2rem;
|
|
right: 2rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
z-index: 100;
|
|
}
|
|
|
|
.social-float {
|
|
width: 60px;
|
|
height: 60px;
|
|
color: #FFF;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
font-size: 28px;
|
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
transition: all 0.05s ease-out; /* Super fast for vibration */
|
|
position: relative;
|
|
will-change: transform, background-color, box-shadow;
|
|
}
|
|
|
|
.social-float::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: 50%;
|
|
padding: 3px;
|
|
background: linear-gradient(45deg, #00e676, #38bdf8, #facc15, #f472b6, #00e676);
|
|
background-size: 400% 400%;
|
|
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
-webkit-mask-composite: xor;
|
|
mask-composite: exclude;
|
|
pointer-events: none;
|
|
animation: gradient-border 6s linear infinite;
|
|
}
|
|
|
|
.social-float:hover {
|
|
transform: scale(1.1) rotate(8deg);
|
|
color: #fff;
|
|
}
|
|
|
|
.social-float.whatsapp {
|
|
background-color: var(--accent-color);
|
|
box-shadow: 0 0 20px rgba(0, 230, 118, 0.5);
|
|
}
|
|
|
|
.social-float.youtube {
|
|
background-color: #ff0000;
|
|
box-shadow: 0 0 20px rgba(255, 0, 0, 0.5);
|
|
}
|
|
|
|
.social-float.facebook {
|
|
background-color: #1877F2;
|
|
box-shadow: 0 0 20px rgba(24, 119, 242, 0.5);
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(-5px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0% { transform: scale(1); opacity: 1; }
|
|
50% { transform: scale(1.1); opacity: 0.7; }
|
|
100% { transform: scale(1); opacity: 1; }
|
|
}
|
|
|
|
@keyframes alert-pulse {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.3); background: #facc15 !important; }
|
|
100% { transform: scale(1); }
|
|
}
|
|
.counter-alert {
|
|
animation: alert-pulse 1s infinite ease-in-out;
|
|
box-shadow: 0 0 10px #facc15;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 992px) {
|
|
.app-container {
|
|
flex-direction: column;
|
|
height: auto;
|
|
overflow-y: auto;
|
|
padding-top: 4rem;
|
|
}
|
|
.player-section, .interaction-center {
|
|
max-width: 100% !important;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.interaction-center {
|
|
grid-template-columns: 1fr !important;
|
|
}
|
|
.chat-window, .ranking-window {
|
|
height: 400px !important;
|
|
}
|
|
.image-section {
|
|
padding-left: 0;
|
|
width: 100%;
|
|
}
|
|
.featured-img-container {
|
|
aspect-ratio: 1 / 1;
|
|
}
|
|
}
|
|
@media (max-width: 600px) {
|
|
.form-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
.glass-card {
|
|
padding: 1.5rem;
|
|
}
|
|
.brand h1 {
|
|
font-size: 2rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="background"></div>
|
|
|
|
<div class="app-container">
|
|
<!-- Left Section: Player -->
|
|
<section class="player-section">
|
|
<div class="glass-card">
|
|
<header class="brand">
|
|
<div class="logo-wrapper">
|
|
<img src="./assets/pasted-20260215-163754-def41f49.png" alt="Lili Records Logo" class="brand-logo">
|
|
<img src="./assets/pasted-20260215-171328-d90df4ce.jpg" alt="Logo Secundario" class="brand-logo">
|
|
</div>
|
|
<h1>Lili Records</h1>
|
|
<p>Siente la música, vive el ritmo.</p>
|
|
</header>
|
|
|
|
<div class="radio-player">
|
|
<div class="visualizer-container">
|
|
<div id="audio-visualizer" class="audio-visualizer"></div>
|
|
</div>
|
|
<div class="now-playing">
|
|
<div class="track-cover-container">
|
|
<i id="cover-placeholder" class="bi bi-broadcast"></i>
|
|
<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">
|
|
<span class="track-label">ESTÁS ESCUCHANDO:</span>
|
|
<div id="track-title" class="track-title">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>
|
|
<div id="track-album" style="font-size: 0.8rem; opacity: 0.6; color: #fff; margin-top: 2px; display: none; font-style: italic;"></div>
|
|
<div class="track-status" style="margin-top: 5px; display: flex; align-items: center; gap: 5px; font-size: 0.75rem;">
|
|
<span style="width: 8px; height: 8px; background: #ff4444; border-radius: 50%; display: inline-block; animation: pulse 1.5s infinite;"></span>
|
|
EN VIVO
|
|
</div>
|
|
<div id="track-progress-container" style="width: 100%; height: 4px; background: rgba(255,255,255,0.1); border-radius: 2px; margin-top: 10px; display: none; overflow: hidden; box-shadow: inset 0 1px 2px rgba(0,0,0,0.2);">
|
|
<div id="track-progress-bar" style="height: 100%; background: linear-gradient(90deg, var(--primary-color), var(--accent-color)); width: 0%; transition: width 1s linear;"></div>
|
|
</div>
|
|
<a id="lyrics-link" href="#" target="_blank" style="font-size: 0.7rem; color: var(--primary-color); text-decoration: none; margin-top: 8px; display: none; align-items: center; gap: 4px; opacity: 0.8; transition: opacity 0.2s;" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.8'">
|
|
<i class="bi bi-music-note-list"></i> BUSCAR LETRA
|
|
</a>
|
|
<a id="whatsapp-share-track" href="#" target="_blank" style="font-size: 0.7rem; color: #25D366; text-decoration: none; margin-top: 8px; display: none; align-items: center; gap: 4px; opacity: 0.8; transition: opacity 0.2s;" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.8'">
|
|
<i class="bi bi-whatsapp"></i> COMPARTIR CANCIÓN
|
|
</a>
|
|
</div>
|
|
<button id="like-song-btn" onclick="likeSong()" style="background: none; border: none; color: #ff4444; font-size: 1.8rem; cursor: pointer; transition: transform 0.2s; display: flex; align-items: center; gap: 5px;">
|
|
<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>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<button id="play-pause" class="play-btn" onclick="togglePlay()">
|
|
<i id="play-icon" class="bi bi-play-fill"></i>
|
|
</button>
|
|
<i class="bi bi-volume-up"></i>
|
|
<input type="range" class="volume-slider" min="0" max="1" step="0.01" value="1" oninput="changeVolume(this.value)">
|
|
</div>
|
|
|
|
<div id="recent-tracks-container" style="margin-top: 1rem; display: none;">
|
|
<span class="track-label" style="font-size: 0.65rem; margin-bottom: 0.5rem;">CANCIONES ANTERIORES:</span>
|
|
<div id="recent-tracks-list" style="display: flex; flex-direction: column; gap: 0.5rem;"></div>
|
|
</div>
|
|
|
|
<div id="top-songs-container" style="margin-top: 1.5rem; background: rgba(255, 255, 255, 0.03); padding: 1rem; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.05);">
|
|
<span class="track-label" style="font-size: 0.65rem; margin-bottom: 0.8rem; color: #facc15;">
|
|
<i class="bi bi-trophy-fill"></i> TOP CANCIONES DE LA SEMANA
|
|
</span>
|
|
<div id="top-songs-list" style="display: flex; flex-direction: column; gap: 0.6rem;">
|
|
<div style="font-size: 0.8rem; opacity: 0.5; text-align: center;">Cargando ranking...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="interaction-form">
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="user-name">NOMBRE</label>
|
|
<input type="text" id="user-name" placeholder="Tu nombre..." oninput="this.style.borderColor='rgba(255, 255, 255, 0.2)'">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="user-phone">MOVIL</label>
|
|
<input type="tel" id="user-phone" placeholder="Tu número..." oninput="this.style.borderColor='rgba(255, 255, 255, 0.2)'" onchange="savePhone(this.value)">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="user-message">MENSAJE</label>
|
|
<textarea id="user-message" placeholder="¿Qué quieres escuchar?"></textarea>
|
|
</div>
|
|
|
|
<a href="<?= $whatsapp_link ?>" target="_blank" class="send-whatsapp-btn" style="text-decoration: none;">
|
|
<i class="bi bi-whatsapp"></i> WHATSAPP
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Espacio para Código QR -->
|
|
<div class="payment-section">
|
|
<div class="qr-placeholder" style="padding: 0; overflow: hidden; background: rgba(255,255,255,0.1);" onclick="openQRModal()">
|
|
<img src="./assets/pasted-20260216-203652-f5645ae9.jpg" alt="Código QR" style="width: 100%; height: 100%; object-fit: contain; border-radius: 12px;">
|
|
</div>
|
|
<p style="color: var(--accent-color); font-size: 0.9rem; font-weight: 600; margin-top: 0.5rem; text-transform: uppercase;">
|
|
Contribuye con tu ayuda a nuestra Web App
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if (isset($_GET['admin']) && $_GET['admin'] === '1'): ?>
|
|
<!-- Admin Real-Time Stats (Only visible with ?admin=1) -->
|
|
<div class="glass-card mt-4" style="margin-top: 2rem;">
|
|
<h3 style="font-size: 1.2rem; margin-bottom: 1rem; color: var(--accent-color);">
|
|
<i class="bi bi-shield-lock"></i> Panel Admin Real-Time
|
|
</h3>
|
|
<iframe src="admin.php?token=lili_admin_2026" style="width: 100%; height: 400px; border: none; border-radius: 12px; background: rgba(0,0,0,0.2);"></iframe>
|
|
</div>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<!-- Interaction Center: Live Chat -->
|
|
<section class="interaction-center">
|
|
<!-- Live Web Chat -->
|
|
<div class="glass-card chat-window" style="height: 500px; display: flex; flex-direction: column;">
|
|
<h3 style="font-size: 1.2rem; margin-bottom: 1rem; color: var(--primary-color);">
|
|
<i class="bi bi-chat-dots-fill"></i> CHAT EN VIVO
|
|
</h3>
|
|
<div id="chat-messages" style="flex: 1; overflow-y: auto; margin-bottom: 1rem; padding-right: 5px; display: flex; flex-direction: column; gap: 0.8rem;">
|
|
<!-- Mensajes se cargarán aquí -->
|
|
<div style="opacity: 0.5; font-size: 0.9rem; text-align: center; margin-top: 2rem;">Cargando mensajes...</div>
|
|
</div>
|
|
<div class="chat-input-area" style="display: flex; gap: 0.5rem; position: relative;">
|
|
<input type="hidden" id="chat-user">
|
|
<button onclick="toggleEmojiPicker()" style="background: rgba(255,255,255,0.1); border: none; border-radius: 8px; color: white; padding: 0 0.5rem; cursor: pointer;">
|
|
<i class="bi bi-emoji-smile"></i>
|
|
</button>
|
|
<button id="camera-btn" onclick="document.getElementById('chat-file').click()" title="Subir foto" style="background: rgba(255,255,255,0.1); border: none; border-radius: 8px; color: white; padding: 0 0.5rem; cursor: pointer; position: relative; transition: all 0.3s;">
|
|
<i class="bi bi-camera-fill"></i>
|
|
<span id="photo-counter" style="position: absolute; top: -10px; right: -5px; background: var(--primary-color); color: white; font-size: 0.6rem; padding: 1px 4px; border-radius: 10px; font-weight: bold; border: 1px solid rgba(255,255,255,0.3); display: none;">0/5</span>
|
|
</button>
|
|
<div id="photo-limit-msg" style="display: none; position: absolute; bottom: -20px; left: 0; width: 100%; text-align: center; font-size: 0.65rem; color: #ff4444; font-weight: bold; animation: fadeIn 0.3s;"></div>
|
|
<input type="file" id="chat-file" style="display: none;" accept="image/*" onchange="uploadImage(this)">
|
|
<input type="text" id="chat-msg" placeholder="Escribe un mensaje..." style="flex: 1; font-size: 0.8rem; padding: 0.5rem; border-radius: 8px; border: none; background: rgba(255,255,255,0.05); color: white;">
|
|
<button onclick="sendChatMessage()" style="background: var(--primary-color); border: none; border-radius: 8px; color: white; padding: 0 1rem; cursor: pointer;">
|
|
<i class="bi bi-send-fill"></i>
|
|
</button>
|
|
|
|
<emoji-picker id="emoji-picker" style="display: none; position: absolute; bottom: 50px; left: 0; z-index: 1000; --num-columns: 6; --category-button-size: 1.5rem; width: 300px; height: 350px;"></emoji-picker>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
</div>
|
|
|
|
<!-- Floating Social Links -->
|
|
<div class="social-float-container">
|
|
<a href="<?= $facebook_link ?>" class="social-float facebook" target="_blank" title="Facebook">
|
|
<i class="bi bi-facebook"></i>
|
|
</a>
|
|
<a href="https://www.youtube.com/@lilirecords" class="social-float youtube" target="_blank" title="YouTube">
|
|
<i class="bi bi-youtube"></i>
|
|
</a>
|
|
<a href="<?= $whatsapp_link ?>" class="social-float whatsapp" target="_blank" title="WhatsApp">
|
|
<i class="bi bi-whatsapp"></i>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- QR Modal -->
|
|
<div id="qr-modal" class="qr-modal" onclick="closeQRModal()">
|
|
<div class="qr-modal-content" onclick="event.stopPropagation()">
|
|
<span class="qr-modal-close" onclick="closeQRModal()">×</span>
|
|
<img src="./assets/pasted-20260216-203652-f5645ae9.jpg" alt="QR Ampliado" style="width: 100%; max-width: 400px; height: auto; border-radius: 12px; display: block; margin: 0 auto;">
|
|
<p style="color: #333; text-align: center; margin-top: 1rem; font-weight: 700; font-size: 1.1rem;">¡ÚNETE A NUESTRO WHATSAPP!</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
|
|
<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>
|
|
|
|
<script>
|
|
const audio = document.getElementById('radio-audio');
|
|
const playBtn = document.getElementById('play-pause');
|
|
const playIcon = document.getElementById('play-icon');
|
|
const trackTitle = document.getElementById('track-title');
|
|
const trackArtist = document.getElementById('track-artist');
|
|
const trackAlbum = document.getElementById('track-album');
|
|
const lyricsLink = document.getElementById('lyrics-link');
|
|
const trackCover = document.getElementById('track-cover');
|
|
const coverPlaceholder = document.getElementById('cover-placeholder');
|
|
const visualizerContainer = document.getElementById('audio-visualizer');
|
|
const glassCard = document.querySelector('.glass-card');
|
|
const trackLabel = document.querySelector('.track-label');
|
|
const socialIcons = document.querySelectorAll('.social-float');
|
|
|
|
let audioCtx;
|
|
let analyzer;
|
|
let source;
|
|
let animationId;
|
|
const BAR_COUNT = 16;
|
|
let visualizerBars = [];
|
|
let visualizerPeaks = [];
|
|
let barHeights = new Array(BAR_COUNT).fill(5);
|
|
let peakHeights = new Array(BAR_COUNT).fill(5);
|
|
const bg = document.querySelector('.background');
|
|
|
|
let colorOffset = 0;
|
|
function draw() {
|
|
if (audio.paused || audio.ended) {
|
|
animationId = null;
|
|
visualizerBars.forEach(bar => bar.style.height = '5px');
|
|
visualizerPeaks.forEach(peak => {
|
|
peak.style.bottom = '5%';
|
|
peak.style.background = 'linear-gradient(to bottom, #fff, transparent)';
|
|
peak.style.boxShadow = '0 -2px 10px rgba(255, 255, 255, 0.8)';
|
|
});
|
|
document.documentElement.style.setProperty('--dynamic-glow', 'rgba(56, 189, 248, 0.7)');
|
|
document.documentElement.style.setProperty('--dynamic-glow-dim', 'rgba(56, 189, 248, 0.4)');
|
|
if (bg) {
|
|
bg.style.filter = 'brightness(1)';
|
|
bg.style.transform = 'scale(1)';
|
|
}
|
|
return;
|
|
}
|
|
|
|
animationId = requestAnimationFrame(draw);
|
|
const bufferLength = analyzer.frequencyBinCount;
|
|
const dataArray = new Uint8Array(bufferLength);
|
|
analyzer.getByteFrequencyData(dataArray);
|
|
|
|
colorOffset += 1;
|
|
|
|
// Bass detection for background flicker
|
|
// We use the first 4 bins (low frequencies)
|
|
const bassAvg = (dataArray[0] + dataArray[1] + dataArray[2] + dataArray[3]) / 4;
|
|
const bassIntensity = bassAvg / 255;
|
|
|
|
// Apply flicker to background
|
|
if (bg) {
|
|
const brightness = 1 + (bassIntensity * 0.3); // Toned down
|
|
const scale = 1 + (bassIntensity * 0.02); // Toned down zoom
|
|
bg.style.filter = `brightness(${brightness})`;
|
|
bg.style.transform = `scale(${scale})`;
|
|
}
|
|
|
|
for (let i = 0; i < BAR_COUNT; i++) {
|
|
// Map frequency data to bars (skipping very low and very high)
|
|
const freqIndex = Math.floor((i / BAR_COUNT) * (dataArray.length * 0.7)) + 1;
|
|
const val = dataArray[freqIndex];
|
|
const targetHeight = (val / 255) * 100 + 5;
|
|
|
|
// Retro "slow fall" logic
|
|
if (targetHeight > barHeights[i]) {
|
|
barHeights[i] = targetHeight;
|
|
} else {
|
|
barHeights[i] -= 2;
|
|
if (barHeights[i] < 5) barHeights[i] = 5;
|
|
}
|
|
|
|
if (visualizerBars[i]) {
|
|
visualizerBars[i].style.height = `${barHeights[i]}%`;
|
|
}
|
|
|
|
// Peak logic
|
|
if (barHeights[i] > peakHeights[i]) {
|
|
peakHeights[i] = barHeights[i];
|
|
} else {
|
|
peakHeights[i] -= 1.2;
|
|
if (peakHeights[i] < 5) peakHeights[i] = 5;
|
|
}
|
|
|
|
if (visualizerPeaks[i]) {
|
|
visualizerPeaks[i].style.bottom = `${peakHeights[i]}%`;
|
|
|
|
const hue = Math.max(0, 200 - (peakHeights[i] * 1.8));
|
|
const color = `hsla(${hue}, 100%, 85%, 1)`;
|
|
const glow = `hsla(${hue}, 100%, 60%, 0.9)`;
|
|
|
|
visualizerPeaks[i].style.background = `linear-gradient(to bottom, ${color}, transparent)`;
|
|
visualizerPeaks[i].style.boxShadow = `0 -2px 12px ${glow}, 0 0 20px ${glow}`;
|
|
|
|
if (peakHeights[i] > 90) {
|
|
visualizerPeaks[i].classList.add('strobe');
|
|
visualizerPeaks[i].style.setProperty('--peak-glow', glow);
|
|
} else {
|
|
visualizerPeaks[i].classList.remove('strobe');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dynamic glow effect based on average volume
|
|
let sum = 0;
|
|
for(let i=0; i<dataArray.length; i++) sum += dataArray[i];
|
|
const average = sum / dataArray.length;
|
|
|
|
const dominantHue = (average * 2 + colorOffset) % 360;
|
|
document.documentElement.style.setProperty('--dynamic-glow', `hsla(${dominantHue}, 100%, 60%, 0.8)`);
|
|
document.documentElement.style.setProperty('--dynamic-glow-dim', `hsla(${dominantHue}, 100%, 60%, 0.3)`);
|
|
document.documentElement.style.setProperty('--card-border-bg', '');
|
|
document.documentElement.style.setProperty('--shake-offset-x', '0px');
|
|
document.documentElement.style.setProperty('--shake-offset-y', '0px');
|
|
if (glassCard) glassCard.style.transform = '';
|
|
|
|
if (trackTitle) {
|
|
trackTitle.style.color = '';
|
|
trackTitle.style.textShadow = '';
|
|
trackTitle.style.transform = '';
|
|
}
|
|
|
|
if (trackLabel) {
|
|
trackLabel.style.color = '';
|
|
trackLabel.style.textShadow = '';
|
|
}
|
|
|
|
// Reset Social Icons
|
|
socialIcons.forEach(icon => {
|
|
icon.style.backgroundColor = '';
|
|
icon.style.boxShadow = '';
|
|
icon.style.transform = '';
|
|
});
|
|
}
|
|
|
|
function initVisualizer() {
|
|
// Create bars and peaks if not already created
|
|
if (visualizerBars.length === 0) {
|
|
visualizerContainer.innerHTML = '';
|
|
for (let i = 0; i < BAR_COUNT; i++) {
|
|
const barWrapper = document.createElement('div');
|
|
barWrapper.style.position = 'relative';
|
|
barWrapper.style.height = '100%';
|
|
barWrapper.style.display = 'flex';
|
|
barWrapper.style.alignItems = 'flex-end';
|
|
barWrapper.style.width = '18px';
|
|
|
|
const bar = document.createElement('div');
|
|
bar.className = 'visualizer-bar';
|
|
|
|
const peak = document.createElement('div');
|
|
peak.className = 'visualizer-peak';
|
|
|
|
barWrapper.appendChild(bar);
|
|
barWrapper.appendChild(peak);
|
|
visualizerContainer.appendChild(barWrapper);
|
|
|
|
visualizerBars.push(bar);
|
|
visualizerPeaks.push(peak);
|
|
}
|
|
}
|
|
|
|
if (!audioCtx) {
|
|
try {
|
|
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
analyzer = audioCtx.createAnalyser();
|
|
source = audioCtx.createMediaElementSource(audio);
|
|
source.connect(analyzer);
|
|
analyzer.connect(audioCtx.destination);
|
|
analyzer.fftSize = 128;
|
|
} catch (e) {
|
|
console.error("AudioContext error:", e);
|
|
}
|
|
}
|
|
|
|
if (audioCtx && audioCtx.state === 'suspended') {
|
|
audioCtx.resume();
|
|
}
|
|
|
|
if (!animationId && !audio.paused) {
|
|
draw();
|
|
}
|
|
}
|
|
|
|
audio.addEventListener('play', () => {
|
|
initVisualizer();
|
|
});
|
|
|
|
function togglePlay() {
|
|
if (audio.paused) {
|
|
audio.play().then(() => {
|
|
initVisualizer();
|
|
}).catch(err => {
|
|
console.error("Error playing audio:", err);
|
|
});
|
|
playIcon.classList.remove('bi-play-fill');
|
|
playIcon.classList.add('bi-pause-fill');
|
|
playBtn.classList.add('playing');
|
|
document.body.classList.add('is-playing');
|
|
} else {
|
|
audio.pause();
|
|
playIcon.classList.remove('bi-pause-fill');
|
|
playIcon.classList.add('bi-play-fill');
|
|
playBtn.classList.remove('playing');
|
|
document.body.classList.remove('is-playing');
|
|
}
|
|
}
|
|
|
|
function changeVolume(val) {
|
|
audio.volume = val;
|
|
}
|
|
|
|
function savePhone(phone) {
|
|
const phoneInput = document.getElementById('user-phone');
|
|
const phoneRegex = /^\+?[0-9]{7,15}$/;
|
|
const cleanPhone = phone.replace(/\s/g, '');
|
|
|
|
if (cleanPhone && !phoneRegex.test(cleanPhone)) {
|
|
phoneInput.style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
phoneInput.style.borderColor = 'rgba(255, 255, 255, 0.2)';
|
|
|
|
const formData = new FormData();
|
|
formData.append('phone', cleanPhone);
|
|
fetch('api/save_phone.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
}
|
|
|
|
function sendToWhatsApp() {
|
|
const name = document.getElementById('user-name').value.trim();
|
|
const phone = document.getElementById('user-phone').value.trim();
|
|
const message = document.getElementById('user-message').value.trim();
|
|
const phoneRegex = /^\+?[0-9]{7,15}$/;
|
|
|
|
if (name.length < 3) {
|
|
alert('Por favor, ingresa un nombre válido (mínimo 3 caracteres).');
|
|
document.getElementById('user-name').style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
if (!phone) {
|
|
alert('Por favor, ingresa tu número de móvil para continuar.');
|
|
document.getElementById('user-phone').style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
if (!phoneRegex.test(phone.replace(/\s/g, ''))) {
|
|
alert('Por favor, ingresa un número de móvil válido (ej: +5359177041).');
|
|
document.getElementById('user-phone').style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
const now = new Date();
|
|
const dateTime = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();
|
|
const refId = Math.floor(1000 + Math.random() * 9000);
|
|
const currentSong = document.getElementById('track-title').innerText.replace(/\s{2,}/g, ' ').trim();
|
|
|
|
const text = `*PETICIÓN RADIO* (Ref: #${refId})\n\n` +
|
|
`*Nombre:* ${name}\n` +
|
|
`*Móvil:* ${phone}\n` +
|
|
`*Fecha:* ${dateTime}\n` +
|
|
`*Sonando ahora:* ${currentSong}\n\n` +
|
|
`*Mensaje:* ${message || 'Sin mensaje específico'}`;
|
|
|
|
const url = `https://wa.me/<?= str_replace('+', '', $whatsapp_number) ?>?text=${encodeURIComponent(text)}`;
|
|
window.open(url, '_blank');
|
|
}
|
|
|
|
// --- Chat Functionality ---
|
|
const chatMessages = document.getElementById('chat-messages');
|
|
const chatUser = document.getElementById('chat-user');
|
|
const chatMsg = document.getElementById('chat-msg');
|
|
const emojiPicker = document.getElementById('emoji-picker');
|
|
let lastMessageCount = 0;
|
|
|
|
function toggleEmojiPicker() {
|
|
emojiPicker.style.display = emojiPicker.style.display === 'none' ? 'block' : 'none';
|
|
}
|
|
|
|
emojiPicker.addEventListener('emoji-click', event => {
|
|
chatMsg.value += event.detail.unicode;
|
|
emojiPicker.style.display = 'none';
|
|
chatMsg.focus();
|
|
});
|
|
|
|
// Close emoji picker when clicking outside
|
|
document.addEventListener('click', (e) => {
|
|
if (!emojiPicker.contains(e.target) && !e.target.closest('button[onclick="toggleEmojiPicker()"]')) {
|
|
emojiPicker.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
async function uploadImage(input) {
|
|
if (!input.files || !input.files[0]) return;
|
|
|
|
const file = input.files[0];
|
|
const formData = new FormData();
|
|
formData.append('image', file);
|
|
|
|
try {
|
|
const response = await fetch('api/upload.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
sendChatMessage(result.url, 'image');
|
|
updatePhotoCounter();
|
|
} else {
|
|
alert(result.error || 'Error al subir la imagen');
|
|
}
|
|
} catch (error) {
|
|
console.error('Upload error:', error);
|
|
alert('Error de conexión al subir la imagen');
|
|
}
|
|
input.value = ''; // Reset input
|
|
}
|
|
|
|
async function fetchMessages() {
|
|
try {
|
|
const response = await fetch('api/chat.php');
|
|
const messages = await response.json();
|
|
|
|
const currentUserName = document.getElementById('user-name').value.trim() || 'Anónimo';
|
|
chatMessages.innerHTML = '';
|
|
messages.forEach(msg => {
|
|
const div = document.createElement('div');
|
|
const isLike = msg.message.includes('❤️');
|
|
|
|
const customColor = msg.custom_color ? `color: ${msg.custom_color} !important;` : '';
|
|
|
|
div.style.background = isLike ? 'rgba(255, 68, 68, 0.15)' : 'rgba(255,255,255,0.05)';
|
|
div.style.padding = '0.8rem';
|
|
div.style.borderRadius = '12px';
|
|
div.style.borderLeft = `4px solid ${isLike ? '#ff4444' : (msg.username === currentUserName ? 'var(--primary-color)' : 'rgba(255,255,255,0.2)')}`;
|
|
|
|
let content = '';
|
|
if (msg.type === 'image') {
|
|
content = `<img src="${msg.message}" style="max-width: 100%; border-radius: 8px; margin-top: 5px; cursor: pointer;" onclick="window.open('${msg.message}', '_blank')">`;
|
|
} else {
|
|
content = `<div style="font-size: 0.85rem; line-height: 1.4; ${isLike ? 'font-weight: 600;' : ''}">${msg.message}</div>`;
|
|
}
|
|
|
|
div.innerHTML = `
|
|
<div style="font-size: 0.7rem; font-weight: bold; ${customColor || (isLike ? 'color: #ff4444' : 'var(--primary-color)')}; margin-bottom: 2px;">
|
|
${msg.username}
|
|
</div>
|
|
${content}
|
|
<div style="font-size: 0.6rem; opacity: 0.4; margin-top: 4px; text-align: right;">${new Date(msg.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</div>
|
|
`;
|
|
chatMessages.appendChild(div);
|
|
});
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
lastMessageCount = messages.length;
|
|
} catch (error) {
|
|
console.error('Chat error:', error);
|
|
}
|
|
}
|
|
|
|
async function sendChatMessage(msgContent = null, type = 'text') {
|
|
const userNameInput = document.getElementById('user-name');
|
|
const userPhoneInput = document.getElementById('user-phone');
|
|
const user = userNameInput.value.trim();
|
|
const phone = userPhoneInput.value.trim();
|
|
const message = msgContent || chatMsg.value.trim();
|
|
const phoneRegex = /^\+?[0-9]{7,15}$/;
|
|
|
|
if (user.length < 3) {
|
|
alert('Por favor, ingresa un nombre válido arriba (mínimo 3 caracteres).');
|
|
userNameInput.style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
if (!phone) {
|
|
alert('Por favor, regístrate con tu móvil arriba para poder chatear.');
|
|
userPhoneInput.style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
if (!phoneRegex.test(phone.replace(/\s/g, ''))) {
|
|
alert('Por favor, ingresa un número de móvil válido arriba.');
|
|
userPhoneInput.style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
if (!message) return;
|
|
|
|
try {
|
|
const response = await fetch('api/chat.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username: user, message: message, type: type })
|
|
});
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
if (!msgContent) chatMsg.value = '';
|
|
fetchMessages();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error sending message:', error);
|
|
}
|
|
}
|
|
|
|
chatMsg.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') sendChatMessage();
|
|
});
|
|
|
|
async function updatePhotoCounter() {
|
|
try {
|
|
const response = await fetch('api/photo_status.php');
|
|
const data = await response.json();
|
|
const counter = document.getElementById('photo-counter');
|
|
const cameraBtn = document.getElementById('camera-btn');
|
|
const fileInput = document.getElementById('chat-file');
|
|
const limitMsg = document.getElementById('photo-limit-msg');
|
|
|
|
if (data && typeof data.count !== 'undefined') {
|
|
counter.innerText = `${data.count}/${data.limit}`;
|
|
counter.style.display = 'block';
|
|
|
|
// Alerta cuando solo queda 1 foto (4 de 5)
|
|
if (data.count === data.limit - 1) {
|
|
counter.classList.add('counter-alert');
|
|
} else {
|
|
counter.classList.remove('counter-alert');
|
|
}
|
|
|
|
if (data.count >= data.limit) {
|
|
counter.style.background = '#ff4444';
|
|
// Bloquear visualmente el botón
|
|
cameraBtn.style.opacity = '0.4';
|
|
cameraBtn.style.filter = 'grayscale(1)';
|
|
cameraBtn.style.pointerEvents = 'none';
|
|
cameraBtn.title = 'Límite de fotos alcanzado';
|
|
fileInput.disabled = true;
|
|
|
|
// Mostrar tiempo restante
|
|
if (data.reset_in_seconds > 0) {
|
|
const hours = Math.floor(data.reset_in_seconds / 3600);
|
|
const minutes = Math.floor((data.reset_in_seconds % 3600) / 60);
|
|
const timeStr = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
limitMsg.innerText = `Disponible en ${timeStr}`;
|
|
limitMsg.style.display = 'block';
|
|
}
|
|
} else {
|
|
counter.style.background = 'var(--primary-color)';
|
|
// Restaurar el botón
|
|
cameraBtn.style.opacity = '1';
|
|
cameraBtn.style.filter = 'none';
|
|
cameraBtn.style.pointerEvents = 'auto';
|
|
cameraBtn.title = 'Subir foto';
|
|
fileInput.disabled = false;
|
|
limitMsg.style.display = 'none';
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating photo counter:', error);
|
|
}
|
|
}
|
|
|
|
// Initial fetch and poll
|
|
fetchMessages();
|
|
updatePhotoCounter();
|
|
setInterval(fetchMessages, 3000);
|
|
setInterval(updatePhotoCounter, 30000); // Check limit status every 30s
|
|
// --- End Chat Functionality ---
|
|
|
|
function openQRModal() {
|
|
const modal = document.getElementById('qr-modal');
|
|
modal.style.display = 'flex';
|
|
setTimeout(() => {
|
|
modal.classList.add('show');
|
|
}, 10);
|
|
}
|
|
|
|
function closeQRModal() {
|
|
const modal = document.getElementById('qr-modal');
|
|
modal.classList.remove('show');
|
|
setTimeout(() => {
|
|
modal.style.display = 'none';
|
|
}, 300);
|
|
}
|
|
|
|
// Close modal on Esc key
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') closeQRModal();
|
|
});
|
|
|
|
async function likeSong() {
|
|
const nameInput = document.getElementById('user-name');
|
|
const name = nameInput.value.trim();
|
|
const song = document.getElementById('track-title').innerText.replace(/\s{2,}/g, ' ').trim();
|
|
|
|
if (name.length < 3) {
|
|
alert('Por favor, ingresa tu nombre arriba para dar Like.');
|
|
nameInput.style.borderColor = '#ff4444';
|
|
return;
|
|
}
|
|
|
|
const btn = document.getElementById('like-song-btn');
|
|
const icon = btn.querySelector('i');
|
|
|
|
icon.classList.remove('bi-heart');
|
|
icon.classList.add('bi-heart-fill');
|
|
btn.style.transform = 'scale(1.3)';
|
|
|
|
try {
|
|
const response = await fetch('api/like_song.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username: name, song_title: song })
|
|
});
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
// Confetti explosion!
|
|
confetti({
|
|
particleCount: 100,
|
|
spread: 70,
|
|
origin: { y: 0.6 },
|
|
colors: ['#ff4444', '#00e676', '#38bdf8', '#facc15']
|
|
});
|
|
|
|
document.getElementById('like-count').innerText = result.likes_count;
|
|
setTimeout(() => {
|
|
btn.style.transform = 'scale(1)';
|
|
}, 200);
|
|
fetchMessages();
|
|
fetchTopFans(); // Update ranking
|
|
}
|
|
} catch (error) {
|
|
console.error('Error liking song:', error);
|
|
}
|
|
}
|
|
|
|
let recentTracks = JSON.parse(localStorage.getItem('recentTracks') || '[]');
|
|
|
|
function renderRecentTracks() {
|
|
const container = document.getElementById('recent-tracks-container');
|
|
const list = document.getElementById('recent-tracks-list');
|
|
if (!list || recentTracks.length === 0) {
|
|
if (container) container.style.display = 'none';
|
|
return;
|
|
}
|
|
if (container) container.style.display = 'block';
|
|
list.innerHTML = '';
|
|
recentTracks.forEach(track => {
|
|
const item = document.createElement('div');
|
|
item.style.display = 'flex';
|
|
item.style.alignItems = 'center';
|
|
item.style.gap = '10px';
|
|
item.style.background = 'rgba(255,255,255,0.03)';
|
|
item.style.padding = '5px 10px';
|
|
item.style.borderRadius = '8px';
|
|
item.style.fontSize = '0.75rem';
|
|
item.style.border = '1px solid rgba(255,255,255,0.05)';
|
|
|
|
const likesCount = track.likes || '0';
|
|
|
|
item.innerHTML = `
|
|
<img src="${track.cover}" style="width: 30px; height: 30px; border-radius: 4px; object-fit: cover;">
|
|
<div style="flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; opacity: 0.7;">
|
|
${track.title}
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 3px; color: #ff4444; font-weight: bold; opacity: 0.9;">
|
|
<i class="bi bi-heart-fill" style="font-size: 0.65rem;"></i>
|
|
<span>${likesCount}</span>
|
|
</div>
|
|
`;
|
|
list.appendChild(item);
|
|
});
|
|
}
|
|
|
|
// Initial render
|
|
renderRecentTracks();
|
|
|
|
async function fetchTopSongs() {
|
|
try {
|
|
const response = await fetch('api/top-songs.php');
|
|
const result = await response.json();
|
|
if (result.success && result.data) {
|
|
const list = document.getElementById('top-songs-list');
|
|
if (result.data.length === 0) {
|
|
list.innerHTML = '<div style="font-size: 0.8rem; opacity: 0.5; text-align: center;">Aún no hay votos esta semana.</div>';
|
|
return;
|
|
}
|
|
list.innerHTML = result.data.map((song, index) => `
|
|
<div style="display: flex; align-items: center; justify-content: space-between; background: rgba(255,255,255,0.05); padding: 0.6rem 0.8rem; border-radius: 10px; border: 1px solid rgba(255,255,255,0.05); transition: transform 0.2s; cursor: default;" onmouseover="this.style.transform='translateX(5px)'" onmouseout="this.style.transform='translateX(0)'">
|
|
<div style="display: flex; align-items: center; gap: 10px; overflow: hidden;">
|
|
<span style="font-weight: 800; color: #facc15; font-size: 0.9rem; min-width: 20px;">#${index + 1}</span>
|
|
<span style="font-size: 0.85rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${song.song_title}</span>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px; color: #ff4444; font-weight: bold; font-size: 0.8rem;">
|
|
<i class="bi bi-heart-fill"></i>
|
|
<span>${song.likes_count}</span>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching top songs:', error);
|
|
}
|
|
}
|
|
|
|
// Fetch Now Playing Metadata from RadioKing
|
|
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 || 'Lili Records';
|
|
const album = data.album || '';
|
|
const coverUrl = data.cover || './assets/pasted-20260215-163754-def41f49.png';
|
|
|
|
const fullDisplay = title.includes(artist) ? title : `${artist} - ${title}`;
|
|
|
|
if (trackTitle.textContent !== title || (trackArtist && trackArtist.textContent !== artist)) {
|
|
// Clear existing progress interval
|
|
if (progressInterval) clearInterval(progressInterval);
|
|
|
|
// Add previous song to history before changing
|
|
if (trackTitle.textContent !== "Cargando stream..." && trackTitle.textContent !== "Lili Records Radio - En Vivo") {
|
|
const prevTrack = {
|
|
title: trackTitle.textContent + (trackArtist ? ' - ' + trackArtist.textContent : ''),
|
|
cover: trackCover.src,
|
|
likes: document.getElementById('like-count').innerText || '0'
|
|
};
|
|
if (recentTracks.length === 0 || recentTracks[0].title !== prevTrack.title) {
|
|
recentTracks.unshift(prevTrack);
|
|
if (recentTracks.length > 5) recentTracks.pop();
|
|
localStorage.setItem('recentTracks', JSON.stringify(recentTracks));
|
|
renderRecentTracks();
|
|
}
|
|
}
|
|
|
|
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');
|
|
likeIcon.classList.add('bi-heart');
|
|
}
|
|
const likeCount = document.getElementById('like-count');
|
|
if (likeCount) likeCount.innerText = '';
|
|
|
|
trackTitle.classList.remove('scrolling');
|
|
setTimeout(async () => {
|
|
trackTitle.textContent = title;
|
|
if (trackArtist) trackArtist.textContent = artist;
|
|
|
|
if (trackAlbum) {
|
|
if (album) {
|
|
trackAlbum.textContent = album;
|
|
trackAlbum.style.display = 'block';
|
|
trackAlbum.style.opacity = '0.6';
|
|
} else {
|
|
trackAlbum.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
if (lyricsLink) {
|
|
lyricsLink.href = `https://www.google.com/search?q=${encodeURIComponent(fullDisplay + " letra lyrics")}`;
|
|
lyricsLink.style.display = 'flex';
|
|
}
|
|
|
|
const whatsappShareBtn = document.getElementById('whatsapp-share-track');
|
|
if (whatsappShareBtn) {
|
|
const shareText = `¡Estoy escuchando "${title}" de ${artist} en Lili Records Radio! 🎶📻\n\nEscúchala aquí: ${window.location.href}`;
|
|
whatsappShareBtn.href = `https://wa.me/?text=${encodeURIComponent(shareText)}`;
|
|
whatsappShareBtn.style.display = 'flex';
|
|
}
|
|
|
|
trackTitle.style.opacity = '1';
|
|
if (trackArtist) trackArtist.style.opacity = '0.8';
|
|
|
|
if (trackCover) {
|
|
trackCover.src = coverUrl;
|
|
trackCover.style.display = 'block';
|
|
if (coverPlaceholder) coverPlaceholder.style.display = 'none';
|
|
trackCover.style.opacity = '1';
|
|
|
|
// Dynamic Color Extraction
|
|
trackCover.onload = function() {
|
|
try {
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
canvas.width = 1;
|
|
canvas.height = 1;
|
|
ctx.drawImage(trackCover, 0, 0, 1, 1);
|
|
const rgb = ctx.getImageData(0, 0, 1, 1).data;
|
|
if (rgb[0] + rgb[1] + rgb[2] > 30) {
|
|
const color = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
|
|
document.documentElement.style.setProperty('--primary-color', color);
|
|
document.documentElement.style.setProperty('--dynamic-glow', `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, 0.7)`);
|
|
}
|
|
} catch(e) {}
|
|
};
|
|
}
|
|
|
|
// Dynamic Background Update
|
|
fetch(`api/pexels.php?query=${encodeURIComponent(artist + " " + title + " music background")}`)
|
|
.then(res => res.json())
|
|
.then(pData => {
|
|
if (pData.success && pData.url && bg) {
|
|
bg.style.backgroundImage = `url('${pData.url}')`;
|
|
}
|
|
}).catch(() => {});
|
|
|
|
// Progress Bar Logic
|
|
const progContainer = document.getElementById('track-progress-container');
|
|
const progBar = document.getElementById('track-progress-bar');
|
|
|
|
if (data.started_at && data.end_at && progContainer && progBar) {
|
|
progContainer.style.display = 'block';
|
|
const start = new Date(data.started_at).getTime();
|
|
const end = new Date(data.end_at).getTime();
|
|
const duration = end - start;
|
|
|
|
function updateProgressBar() {
|
|
const now = new Date().getTime();
|
|
const elapsed = now - start;
|
|
let percent = (elapsed / duration) * 100;
|
|
if (percent > 100) percent = 100;
|
|
if (percent < 0) percent = 0;
|
|
progBar.style.width = percent + '%';
|
|
if (percent >= 100) clearInterval(progressInterval);
|
|
}
|
|
|
|
updateProgressBar();
|
|
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();
|
|
if (lData.likes_count > 0 && likeCount) {
|
|
likeCount.innerText = lData.likes_count;
|
|
}
|
|
} catch (e) {}
|
|
|
|
// Check if scrolling is needed
|
|
if (trackTitle.scrollWidth > trackTitle.clientWidth) {
|
|
trackTitle.classList.add('scrolling');
|
|
trackTitle.innerHTML = `<span>${title} ${title} </span>`;
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
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' }
|
|
]
|
|
});
|
|
}
|
|
} else {
|
|
trackTitle.textContent = "Lili Records Radio - En Vivo";
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching metadata:', error);
|
|
if (trackTitle.textContent === "Cargando stream...") {
|
|
trackTitle.textContent = "Lili Records Radio - En Vivo";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update every 30 seconds
|
|
updateMetadata();
|
|
fetchTopSongs();
|
|
setInterval(() => {
|
|
updateMetadata();
|
|
fetchTopSongs();
|
|
}, 30000);
|
|
|
|
// Handle possible audio interruptions
|
|
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>
|
|
</body>
|
|
</html>
|