![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/.cursor-server/data/User/History/-1ab10e94/ |
<?php
// New Enhanced Global Music Player - Based on test_enhanced_player.php
// Clean, modern SoundCloud-style bottom player
// Prevent multiple includes
if (defined('GLOBAL_PLAYER_INCLUDED')) {
return;
}
define('GLOBAL_PLAYER_INCLUDED', true);
?>
<!-- Enhanced Global Music Player -->
<div id="enhancedGlobalPlayer" class="global-bottom-player">
<!-- Track Info Section -->
<div class="player-track-info">
<div class="track-details">
<div class="track-title clickable" id="playerTrackTitle" title="Click to view track details">Loading playlists...</div>
<div class="track-artist clickable" id="playerTrackArtist" title="Click to view artist profile">Discovering great music for you</div>
</div>
</div>
<!-- Playlist Selector -->
<div class="playlist-selector" id="playlistSelector">
<select id="playlistDropdown" class="playlist-dropdown" onchange="switchPlaylist(this.value)">
<option value="vip">π΅ VIP Samples</option>
<option value="featured">β Featured</option>
<option value="community">π Community</option>
</select>
<button class="player-btn shuffle-btn" id="playerShuffleBtn" title="Shuffle Playlist" onclick="window.enhancedGlobalPlayer.playRandomTrack()">
<i class="fas fa-random"></i>
</button>
</div>
<!-- Main Player Controls -->
<div class="player-main-controls">
<button class="player-btn previous-btn" id="playerPrevBtn" title="Previous">
<i class="fas fa-step-backward"></i>
</button>
<button class="player-btn play-pause-btn" id="playerPlayBtn" title="Play">
<i class="fas fa-play" id="playerPlayIcon"></i>
</button>
<button class="player-btn next-btn" id="playerNextBtn" title="Next">
<i class="fas fa-step-forward"></i>
</button>
</div>
<!-- Progress Section with Interactive Waveform -->
<div class="player-progress-section">
<span class="time-current" id="playerTimeDisplay">0:00</span>
<div class="progress-container" id="playerProgressContainer">
<!-- Traditional Progress Bar (fallback) -->
<div class="progress-bar-background"></div>
<div class="progress-bar" id="playerProgressBar"></div>
<!-- Interactive Waveform representing the actual song -->
<div class="waveform-progress-container" id="waveformProgressContainer">
<div class="waveform-progress-bars" id="waveformProgressBars">
<!-- Waveform bars representing actual song amplitude -->
</div>
<div class="waveform-progress-line" id="waveformProgressLine"></div>
</div>
<div class="progress-handle" id="playerProgressHandle"></div>
</div>
<span class="time-duration" id="playerDurationDisplay">0:00</span>
</div>
<!-- Advanced Controls -->
<div class="player-advanced-controls">
<div class="volume-control-wrapper">
<button class="player-btn volume-btn" id="playerVolumeBtn" title="Click to mute/unmute">
<i class="fas fa-volume-up" id="playerVolumeIcon"></i>
</button>
<div class="volume-slider-container" id="volumeSliderContainer">
<input type="range" class="volume-slider" id="playerVolumeSlider" min="0" max="100" value="50" orient="horizontal">
<div class="volume-display" id="volumeDisplay">50%</div>
</div>
</div>
<button class="player-btn speed-btn" id="playerSpeedBtn" title="Speed: 1x">
<span class="speed-text">1x</span>
</button>
<button class="player-btn auto-play-btn" id="playerAutoPlayBtn" title="Auto-play: On">
<i class="fas fa-infinity" id="playerAutoPlayIcon"></i>
</button>
<button class="player-btn minimize-btn" id="playerMinimizeBtn" title="Minimize">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<!-- Waveform Visualizer -->
<div class="waveform-container" id="playerWaveformContainer">
<div class="waveform-bars" id="playerWaveformBars">
<!-- Animated waveform bars will be generated dynamically -->
</div>
</div>
<!-- Hidden Audio Element -->
<audio id="globalAudioElement" preload="none"></audio>
</div>
<style>
/* Enhanced CSS Variables from test_enhanced_player.php */
:root {
--primary: #667eea;
--primary-dark: #5a67d8;
--primary-light: #7c3aed;
--secondary: #764ba2;
--secondary-dark: #6b46c1;
--secondary-light: #8b5cf6;
--accent: #4facfe;
--accent-dark: #3b82f6;
--accent-light: #60a5fa;
--gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-secondary: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
--gradient-accent: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
--gradient-divine: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--bg-primary: #0a0a0a;
--bg-secondary: #1a1a1a;
--bg-tertiary: #2d2d2d;
--bg-quaternary: #3a3a3a;
--bg-card: rgba(26, 26, 26, 0.9);
--bg-overlay: rgba(0, 0, 0, 0.8);
--bg-glass: rgba(255, 255, 255, 0.05);
--text-primary: #ffffff;
--text-secondary: #a0aec0;
--text-muted: #718096;
--text-light: #4a5568;
--text-accent: #4facfe;
--border-light: rgba(255, 255, 255, 0.1);
--border-medium: rgba(255, 255, 255, 0.2);
--border-accent: rgba(102, 126, 234, 0.3);
--shadow-light: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
--shadow-medium: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
--shadow-heavy: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
--shadow-glow: 0 0 20px rgba(102, 126, 234, 0.3);
}
/* Enhanced SoundCloud-Style Global Player */
.global-bottom-player {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(135deg, rgba(26, 26, 26, 0.98) 0%, rgba(45, 45, 45, 0.98) 100%);
backdrop-filter: blur(20px);
border-top: 2px solid var(--border-accent);
padding: 8px 16px;
display: flex;
align-items: center;
gap: 16px;
z-index: 10000;
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.6), 0 -2px 8px rgba(102, 126, 234, 0.2);
height: 60px;
min-height: 60px;
max-height: 60px;
transition: all 0.4s ease;
overflow: hidden;
}
/* Mobile Responsive Design */
@media (max-width: 768px) {
.global-bottom-player {
height: auto;
min-height: 80px;
max-height: 120px;
padding: 12px 16px;
flex-wrap: wrap;
gap: 12px;
}
.global-bottom-player.playing {
height: auto;
min-height: 80px;
max-height: 120px;
}
.global-bottom-player.minimized {
height: 50px;
min-height: 50px;
max-height: 50px;
padding: 8px 12px;
}
/* Mobile Track Info */
.player-track-info {
min-width: 0;
flex: 1;
order: 1;
width: 100%;
margin-bottom: 8px;
}
.track-details {
min-width: 0;
width: 100%;
}
.track-title {
font-size: 13px;
line-height: 1.1;
}
.track-artist {
font-size: 11px;
line-height: 1.1;
}
/* Mobile Controls Layout */
.player-main-controls {
order: 2;
gap: 12px;
justify-content: center;
width: 100%;
margin-bottom: 8px;
}
.player-btn {
width: 32px;
height: 32px;
}
.play-pause-btn {
width: 40px;
height: 40px;
}
/* Mobile Progress Section */
.player-progress-section {
order: 3;
max-width: 100%;
margin: 0;
gap: 10px;
width: 100%;
}
.time-current,
.time-duration {
font-size: 11px;
min-width: 25px;
}
/* Mobile Advanced Controls */
.player-advanced-controls {
order: 4;
display: flex;
align-items: center;
gap: 8px;
justify-content: center;
width: 100%;
flex-wrap: wrap;
}
.volume-slider-container {
width: 80px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
}
.volume-slider {
width: 100%;
height: 4px;
-webkit-appearance: none;
appearance: none;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
outline: none;
cursor: pointer;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: var(--gradient-divine);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
.volume-slider::-moz-range-thumb {
width: 16px;
height: 16px;
background: var(--gradient-divine);
border-radius: 50%;
cursor: pointer;
border: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
.volume-display {
font-size: 10px;
color: var(--text-secondary);
text-align: center;
min-width: 40px;
padding: 2px 6px;
background: rgba(0, 0, 0, 0.3);
border-radius: 4px;
font-weight: 500;
}
/* Mobile Playlist Selector */
.playlist-selector {
order: 5;
margin: 0;
width: 100%;
text-align: center;
}
.playlist-dropdown {
font-size: 11px;
padding: 4px 8px;
background: var(--bg-glass);
border: 1px solid var(--border-light);
border-radius: 4px;
color: var(--text-primary);
cursor: pointer;
}
.shuffle-btn {
background: var(--bg-glass);
border: 1px solid var(--border-light);
color: var(--text-secondary);
transition: all 0.3s ease;
}
.shuffle-btn:hover {
background: var(--primary);
color: white;
border-color: var(--primary);
}
/* Enhanced Volume Controls */
.volume-btn {
transition: all 0.3s ease;
position: relative;
}
.volume-btn:hover {
background: var(--primary);
color: white;
border-color: var(--primary);
transform: scale(1.1);
}
.volume-btn.muted {
background: rgba(245, 101, 101, 0.2);
border-color: #f56565;
color: #f56565;
}
.volume-btn.muted:hover {
background: rgba(245, 101, 101, 0.3);
border-color: #f56565;
color: white;
}
/* Mobile Waveform */
.waveform-container {
order: 6;
width: 100%;
height: 20px;
margin-top: 8px;
}
/* Hide some elements on very small screens */
@media (max-width: 480px) {
.player-advanced-controls {
gap: 6px;
}
.player-btn {
width: 28px;
height: 28px;
}
.play-pause-btn {
width: 36px;
height: 36px;
}
.track-title {
font-size: 12px;
}
.track-artist {
font-size: 10px;
}
}
/* Landscape orientation adjustments */
@media (max-width: 768px) and (orientation: landscape) {
.global-bottom-player {
height: auto;
min-height: 60px;
max-height: 80px;
flex-wrap: nowrap;
}
.player-track-info {
order: 1;
width: auto;
margin-bottom: 0;
}
.player-main-controls {
order: 2;
width: auto;
margin-bottom: 0;
}
.player-progress-section {
order: 3;
width: auto;
flex: 1;
}
.player-advanced-controls {
order: 4;
width: auto;
}
.playlist-selector {
order: 5;
width: auto;
}
}
}
.global-bottom-player::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 100%;
background: linear-gradient(90deg,
transparent 0%,
rgba(102, 126, 234, 0.05) 25%,
rgba(118, 75, 162, 0.05) 75%,
transparent 100%);
pointer-events: none;
animation: ambientGlow 8s ease-in-out infinite;
}
@keyframes ambientGlow {
0%, 100% { opacity: 0.3; transform: translateX(-100%); }
50% { opacity: 0.7; transform: translateX(100%); }
}
.global-bottom-player.playing {
display: flex !important;
animation: slideUp 0.5s cubic-bezier(0.4, 0, 0.2, 1);
background: linear-gradient(135deg, rgba(26, 26, 26, 0.98) 0%, rgba(45, 45, 45, 0.98) 50%, rgba(102, 126, 234, 0.15) 100%);
box-shadow: 0 -8px 40px rgba(102, 126, 234, 0.4), 0 -4px 20px rgba(118, 75, 162, 0.3);
border-top-color: rgba(102, 126, 234, 0.6);
}
/* Ensure player is always visible */
.global-bottom-player {
display: flex !important;
}
.global-bottom-player.minimized {
height: 40px;
min-height: 40px;
max-height: 40px;
padding: 6px 12px;
}
@keyframes slideUp {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* Enhanced Track Info */
.player-track-info {
display: flex !important;
align-items: center;
gap: 8px;
flex-shrink: 0;
position: relative;
min-width: 250px;
visibility: visible !important;
opacity: 1 !important;
}
.track-details {
min-width: 200px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.track-title {
color: var(--text-primary);
font-weight: 700;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 2px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
line-height: 1.2;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.track-artist {
color: var(--text-secondary);
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 500;
line-height: 1.2;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
/* Clickable track title and artist styles */
.track-title.clickable,
.track-artist.clickable {
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.track-title.clickable:hover,
.track-artist.clickable:hover {
color: var(--primary);
text-shadow: 0 0 8px rgba(102, 126, 234, 0.5);
transform: translateY(-1px);
}
.track-title.clickable::after {
content: "π";
position: absolute;
right: -20px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
}
.track-title.clickable:hover::after {
opacity: 1;
}
.track-artist.clickable::after {
content: "π€";
position: absolute;
right: -20px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
}
.track-artist.clickable:hover::after {
opacity: 1;
}
.track-title-link {
color: inherit;
text-decoration: none;
transition: all 0.3s ease;
cursor: pointer;
display: block;
width: 100%;
}
.track-title-link:hover {
color: var(--primary);
text-decoration: underline;
text-shadow: 0 0 8px rgba(102, 126, 234, 0.5);
}
.track-artist-link {
color: inherit;
text-decoration: none;
transition: all 0.3s ease;
cursor: pointer;
display: block;
width: 100%;
}
.track-artist-link:hover {
color: var(--primary);
text-decoration: underline;
text-shadow: 0 0 8px rgba(102, 126, 234, 0.5);
}
/* Playlist Selector */
.playlist-selector {
margin-left: 8px;
}
.playlist-dropdown {
background: transparent;
border: none;
color: var(--text-secondary);
padding: 0;
font-size: 10px;
cursor: pointer;
outline: none;
transition: all 0.2s ease;
}
.playlist-dropdown:hover {
color: var(--text-primary);
}
.playlist-dropdown:focus {
color: var(--text-primary);
}
.playlist-dropdown option {
background: var(--bg-secondary);
color: var(--text-primary);
}
/* Main Controls */
.player-main-controls {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.player-btn {
background: var(--bg-glass);
border: 1px solid var(--border-light);
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s ease;
backdrop-filter: blur(10px);
}
.player-btn:hover {
background: var(--border-medium);
border-color: var(--border-medium);
transform: scale(1.05);
box-shadow: var(--shadow-glow);
}
.play-pause-btn {
width: 30px;
height: 30px;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border: none;
box-shadow: var(--shadow-light);
}
.play-pause-btn:hover {
transform: scale(1.1);
box-shadow: var(--shadow-glow);
}
.auto-play-btn {
position: relative;
}
.auto-play-btn.active {
background: var(--gradient-divine);
border-color: var(--primary);
box-shadow: var(--shadow-glow);
}
.auto-play-btn.active:hover {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(102, 126, 234, 0.6);
}
/* Progress Section */
.player-progress-section {
flex: 1;
display: flex;
align-items: center;
gap: 15px;
max-width: 600px;
margin: 0 20px;
}
.time-current,
.time-duration {
font-size: 12px;
color: var(--text-secondary);
font-weight: 500;
min-width: 30px;
text-align: center;
}
.progress-container {
flex: 1;
height: 20px;
background: transparent;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
.progress-container:hover {
transform: scaleY(1.05);
}
.progress-bar-background {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
}
.progress-bar {
position: absolute;
bottom: 0;
left: 0;
height: 4px;
background: var(--gradient-divine);
border-radius: 2px;
width: 0%;
transition: width 0.1s ease;
box-shadow: 0 0 10px rgba(102, 126, 234, 0.5);
z-index: 3;
}
/* Interactive Waveform Progress */
.waveform-progress-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 6px;
display: flex;
align-items: end;
overflow: hidden;
}
.waveform-progress-bars {
display: flex;
align-items: end;
height: 100%;
width: 100%;
gap: 1px;
}
.waveform-progress-bar {
background: rgba(255, 255, 255, 0.3);
flex: 1;
min-height: 2px;
max-height: 32px;
border-radius: 1px;
transition: all 0.2s ease;
cursor: pointer;
}
.waveform-progress-bar:hover {
background: rgba(255, 255, 255, 0.6);
transform: scaleY(1.2);
}
.waveform-progress-bar.played {
background: var(--gradient-divine);
box-shadow: 0 0 3px rgba(102, 126, 234, 0.5);
}
.waveform-progress-bar.playing {
background: var(--accent);
box-shadow: 0 0 8px rgba(79, 172, 254, 0.8);
animation: currentBarPulse 0.5s ease-in-out infinite alternate;
}
@keyframes currentBarPulse {
0% { transform: scaleY(1); opacity: 0.8; }
100% { transform: scaleY(1.3); opacity: 1; }
}
.waveform-progress-line {
position: absolute;
top: 0;
bottom: 6px;
width: 2px;
background: var(--text-primary);
box-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
border-radius: 1px;
left: 0%;
transition: left 0.1s ease;
z-index: 4;
}
.progress-handle {
position: absolute;
bottom: -4px;
width: 14px;
height: 14px;
background: var(--text-primary);
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4), 0 0 0 2px var(--primary);
left: 0%;
transform: translateX(-50%);
opacity: 0;
transition: all 0.3s ease;
z-index: 5;
}
.progress-container:hover .progress-handle {
opacity: 1;
transform: translateX(-50%) scale(1.2);
}
/* Advanced Controls */
.player-advanced-controls {
display: flex;
align-items: center;
gap: 10px;
position: relative;
z-index: 10000;
flex-shrink: 0;
}
/* Mobile-friendly touch targets */
@media (max-width: 768px) {
.player-btn {
min-width: 44px;
min-height: 44px;
touch-action: manipulation;
}
.play-pause-btn {
min-width: 48px;
min-height: 48px;
}
.volume-slider {
min-height: 44px;
touch-action: manipulation;
}
.playlist-dropdown {
min-height: 44px;
touch-action: manipulation;
}
.volume-slider-container {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
min-width: 60px;
min-height: 120px;
z-index: 10002;
}
}
.volume-btn,
.speed-btn,
.minimize-btn {
width: 24px;
height: 24px;
position: relative;
}
.volume-control-wrapper {
position: relative;
display: inline-block;
}
.volume-btn {
background: var(--bg-glass);
border: 1px solid var(--border-light);
border-radius: 50%;
transition: all 0.2s ease;
}
.volume-btn:hover {
background: var(--border-medium);
border-color: var(--border-medium);
transform: scale(1.05);
box-shadow: var(--shadow-glow);
}
.speed-btn {
border-radius: 6px;
width: 30px;
}
.speed-text {
font-size: 10px;
font-weight: 600;
}
.volume-slider-container {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%) translateY(10px);
background: var(--bg-tertiary);
border: 1px solid var(--border-light);
border-radius: 8px;
padding: 10px 8px;
backdrop-filter: blur(20px);
box-shadow: var(--shadow-heavy);
opacity: 0;
visibility: hidden;
transition: all 0.2s ease;
z-index: 10001;
min-width: 40px;
min-height: 100px;
}
.volume-slider-container.active {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(-10px);
z-index: 10001;
}
.volume-slider {
writing-mode: bt-lr; /* IE */
-webkit-appearance: slider-vertical; /* WebKit */
width: 16px;
height: 60px;
background: var(--bg-glass);
outline: none;
cursor: pointer;
border-radius: 8px;
-webkit-appearance: none;
appearance: none;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: var(--primary);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.volume-slider::-moz-range-thumb {
width: 16px;
height: 16px;
background: var(--primary);
border-radius: 50%;
cursor: pointer;
border: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
/* Responsive Design */
@media (max-width: 768px) {
.global-bottom-player {
padding: 0 15px;
gap: 15px;
height: 60px;
min-height: 60px;
max-height: 60px;
}
.player-track-info {
min-width: 150px;
max-width: 200px;
}
.player-progress-section {
max-width: 300px;
}
.track-title {
font-size: 13px;
}
.track-artist {
font-size: 11px;
}
}
@media (max-width: 480px) {
.global-bottom-player {
height: 50px;
min-height: 50px;
max-height: 50px;
padding: 0 5px;
gap: 5px;
}
.player-btn {
width: 20px;
height: 20px;
}
.play-pause-btn {
width: 25px;
height: 25px;
}
}
/* Waveform Visualizer */
.waveform-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 4px;
overflow: hidden;
opacity: 0.6;
pointer-events: none;
}
.waveform-bars {
display: flex;
align-items: end;
height: 100%;
gap: 1px;
justify-content: space-between;
}
.waveform-bar {
background: var(--gradient-divine);
flex: 1;
min-height: 1px;
max-width: 3px;
border-radius: 1px;
transition: all 0.3s ease;
animation: waveAnimation 1.5s ease-in-out infinite alternate;
}
@keyframes waveAnimation {
0% {
height: 20%;
opacity: 0.6;
filter: hue-rotate(0deg);
}
100% {
height: 100%;
opacity: 1;
filter: hue-rotate(10deg);
}
}
.waveform-bar:nth-child(even) {
animation-delay: 0.1s;
}
.waveform-bar:nth-child(3n) {
animation-delay: 0.2s;
}
.waveform-bar:nth-child(4n) {
animation-delay: 0.3s;
}
.waveform-bar:nth-child(5n) {
animation-delay: 0.4s;
}
/* Enhanced Playing State */
.global-bottom-player.playing .waveform-bar {
animation: wavePlayback 0.8s ease-in-out infinite alternate;
background: linear-gradient(45deg, var(--gradient-divine), var(--accent));
box-shadow: 0 0 5px rgba(102, 126, 234, 0.5);
}
@keyframes wavePlayback {
0% {
transform: scaleY(0.4);
opacity: 0.7;
filter: hue-rotate(0deg) brightness(1);
}
100% {
transform: scaleY(1.3);
opacity: 1;
filter: hue-rotate(20deg) brightness(1.2);
}
}
.global-bottom-player.playing .play-pause-btn {
animation: playButtonGlow 3s ease-in-out infinite alternate;
}
@keyframes playButtonGlow {
0% {
box-shadow: var(--shadow-glow), var(--shadow-medium);
filter: brightness(1);
}
100% {
box-shadow: 0 0 30px rgba(102, 126, 234, 0.8), 0 8px 30px rgba(118, 75, 162, 0.6);
filter: brightness(1.2);
}
}
</style>
<script>
// Enhanced Global Player with AJAX Navigation Support
(function() {
'use strict';
// Global player state
let currentTrack = null;
let currentPlaylist = 'vip';
let isPlaying = false;
let currentTime = 0;
let duration = 0;
let volume = 0.5;
let previousVolume = 0.5; // Store volume before muting
let isMuted = false;
let playbackRate = 1.0;
let autoPlay = true;
let isMinimized = false;
// Initialize global player
function initializeGlobalPlayer() {
console.log('π΅ Initializing Enhanced Global Player');
try {
// Set up audio element
const audio = document.getElementById('globalAudioElement');
if (!audio) {
console.error('β Global audio element not found');
return false;
}
// Set up event listeners
setupAudioEventListeners(audio);
// Set up player controls
setupPlayerControls();
// Set up playlist functionality
setupPlaylistFunctionality();
// Load initial playlist
loadPlaylist(currentPlaylist);
// Generate beautiful waveform visualizer
generateWaveform();
generateInteractiveWaveform(180);
// Mark player as ready
window.globalPlayerReady = true;
console.log('β
Enhanced Global Player initialized successfully');
return true;
} catch (error) {
console.error('β Global player initialization failed:', error);
return false;
}
}
// Set up audio event listeners
function setupAudioEventListeners(audio) {
audio.addEventListener('loadedmetadata', () => {
duration = audio.duration;
updateDurationDisplay();
updateProgressBar();
});
audio.addEventListener('timeupdate', () => {
currentTime = audio.currentTime;
updateTimeDisplay();
updateProgressBar();
updateWaveformProgress(currentTime, duration);
});
audio.addEventListener('ended', () => {
if (autoPlay) {
playNextTrack();
} else {
stopPlayback();
}
});
audio.addEventListener('error', (e) => {
console.error('β Audio error:', e);
showNotification('Audio playback error', 'error');
});
}
// Set up player controls
function setupPlayerControls() {
// Play/Pause button
const playBtn = document.getElementById('playerPlayBtn');
if (playBtn) {
playBtn.addEventListener('click', togglePlayPause);
}
// Previous/Next buttons
const prevBtn = document.getElementById('playerPrevBtn');
const nextBtn = document.getElementById('playerNextBtn');
if (prevBtn) prevBtn.addEventListener('click', playPreviousTrack);
if (nextBtn) nextBtn.addEventListener('click', playNextTrack);
// Volume control
const volumeSlider = document.getElementById('playerVolumeSlider');
if (volumeSlider) {
volumeSlider.addEventListener('input', (e) => {
volume = e.target.value / 100;
updateVolume();
});
// Mouse wheel support for volume
volumeSlider.addEventListener('wheel', (e) => {
e.preventDefault();
const delta = e.deltaY > 0 ? -0.05 : 0.05;
volume = Math.max(0, Math.min(1, volume + delta));
volumeSlider.value = volume * 100;
updateVolume();
});
// Click to seek in volume slider
volumeSlider.addEventListener('click', (e) => {
const rect = volumeSlider.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const width = rect.width;
volume = clickX / width;
volumeSlider.value = volume * 100;
updateVolume();
});
}
// Volume button (mute/unmute)
const volumeBtn = document.getElementById('playerVolumeBtn');
if (volumeBtn) {
volumeBtn.addEventListener('click', toggleMute);
}
// Progress bar
const progressContainer = document.getElementById('playerProgressContainer');
if (progressContainer) {
progressContainer.addEventListener('click', seekToPosition);
}
// Minimize button
const minimizeBtn = document.getElementById('playerMinimizeBtn');
if (minimizeBtn) {
minimizeBtn.addEventListener('click', toggleMinimize);
}
// Track title click - navigate to track page
const trackTitle = document.getElementById('playerTrackTitle');
if (trackTitle) {
console.log('π΅ Setting up track title click handler');
trackTitle.addEventListener('click', function(e) {
console.log('π΅ Track title clicked!');
e.preventDefault();
e.stopPropagation();
const title = trackTitle.textContent;
console.log('π΅ Title text:', title);
if (title && title !== 'Loading playlists...') {
console.log('π΅ Navigating to search for:', title);
window.location.href = `/search.php?q=${encodeURIComponent(title)}`;
} else {
console.log('π΅ Title is loading or empty');
}
});
} else {
console.log('π΅ Track title element not found');
}
// Track artist click - navigate to artist profile
const trackArtist = document.getElementById('playerTrackArtist');
if (trackArtist) {
console.log('π΅ Setting up track artist click handler');
trackArtist.addEventListener('click', function(e) {
console.log('π΅ Track artist clicked!');
e.preventDefault();
e.stopPropagation();
const artist = trackArtist.textContent;
console.log('π΅ Artist text:', artist);
if (artist && artist !== 'Discovering great music for you') {
console.log('π΅ Navigating to artists search for:', artist);
window.location.href = `/artists.php?search=${encodeURIComponent(artist)}`;
} else {
console.log('π΅ Artist is loading or empty');
}
});
} else {
console.log('π΅ Track artist element not found');
}
}
// Play track function - Main API for other pages
function playTrack(audioUrl, title, artist, duration = null) {
console.log('π΅ Global player playTrack called:', { audioUrl, title, artist, duration });
try {
if (!audioUrl) {
throw new Error('No audio URL provided');
}
const audio = document.getElementById('globalAudioElement');
if (!audio) {
throw new Error('Global audio element not found');
}
// Update track info
currentTrack = { audioUrl, title, artist, duration };
updateTrackDisplay(title, artist);
// Set audio source and load
audio.src = audioUrl;
audio.load();
// Generate new waveform for this track
if (duration) {
generateInteractiveWaveform(duration);
} else {
generateInteractiveWaveform(180); // Default 3 minutes
}
// Play the track
audio.play().then(() => {
isPlaying = true;
updatePlayButton();
showNotification(`Now playing: ${title}`, 'success');
}).catch(error => {
console.error('β Audio play failed:', error);
showNotification('Failed to play track', 'error');
});
} catch (error) {
console.error('β PlayTrack failed:', error);
showNotification('Playback error: ' + error.message, 'error');
}
}
// Toggle play/pause
function togglePlayPause() {
const audio = document.getElementById('globalAudioElement');
if (!audio) {
console.error('β Audio element not found');
return;
}
// Check if we have a track loaded
if (!currentTrack || !currentTrack.audioUrl) {
console.log('π΅ No track loaded, attempting to load playlist...');
// Try to load and play first track from current playlist
if (currentPlaylistData.length > 0) {
const firstTrack = currentPlaylistData[0];
playTrackFromPlaylist(firstTrack);
return;
} else {
showNotification('No tracks available to play', 'error');
return;
}
}
if (isPlaying) {
console.log('βΈοΈ Pausing playback');
audio.pause();
isPlaying = false;
} else {
console.log('βΆοΈ Starting playback');
// Ensure audio is loaded and ready
if (audio.readyState < 2) { // HAVE_CURRENT_DATA
audio.load();
}
audio.play().then(() => {
isPlaying = true;
console.log('β
Playback started successfully');
}).catch(error => {
console.error('β Playback failed:', error);
isPlaying = false;
showNotification('Playback failed: ' + error.message, 'error');
});
}
updatePlayButton();
}
// Update play button state
function updatePlayButton() {
const playIcon = document.getElementById('playerPlayIcon');
if (playIcon) {
playIcon.className = isPlaying ? 'fas fa-pause' : 'fas fa-play';
}
}
// Update track display
function updateTrackDisplay(title, artist) {
const titleElement = document.getElementById('playerTrackTitle');
const artistElement = document.getElementById('playerTrackArtist');
if (titleElement) titleElement.textContent = title || 'Unknown Track';
if (artistElement) artistElement.textContent = artist || 'Unknown Artist';
}
// Update time displays
function updateTimeDisplay() {
const timeDisplay = document.getElementById('playerTimeDisplay');
if (timeDisplay) {
timeDisplay.textContent = formatTime(currentTime);
}
}
function updateDurationDisplay() {
const durationDisplay = document.getElementById('playerDurationDisplay');
if (durationDisplay) {
durationDisplay.textContent = formatTime(duration);
}
}
// Format time in MM:SS
function formatTime(seconds) {
if (!seconds || isNaN(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
// Update progress bar
function updateProgressBar() {
const progressBar = document.getElementById('playerProgressBar');
if (progressBar && duration > 0) {
const progress = (currentTime / duration) * 100;
progressBar.style.width = progress + '%';
}
}
// Seek to position
function seekToPosition(e) {
const audio = document.getElementById('globalAudioElement');
if (!audio) return;
const rect = e.currentTarget.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const width = rect.width;
const seekTime = (clickX / width) * duration;
audio.currentTime = seekTime;
}
// Update volume
function updateVolume() {
const audio = document.getElementById('globalAudioElement');
if (audio) {
audio.volume = volume;
}
// Update volume icon
const volumeIcon = document.getElementById('playerVolumeIcon');
const volumeBtn = document.getElementById('playerVolumeBtn');
if (volumeIcon) {
if (isMuted || volume === 0) {
volumeIcon.className = 'fas fa-volume-mute';
} else if (volume < 0.3) {
volumeIcon.className = 'fas fa-volume-down';
} else if (volume < 0.7) {
volumeIcon.className = 'fas fa-volume-down';
} else {
volumeIcon.className = 'fas fa-volume-up';
}
}
// Update volume button state
if (volumeBtn) {
if (isMuted || volume === 0) {
volumeBtn.classList.add('muted');
} else {
volumeBtn.classList.remove('muted');
}
}
// Update volume display
updateVolumeDisplay();
}
// Toggle mute
function toggleMute() {
if (isMuted) {
// Unmute - restore previous volume
volume = previousVolume;
isMuted = false;
console.log('π Unmuted, volume restored to:', volume);
} else {
// Mute - store current volume and set to 0
previousVolume = volume;
volume = 0;
isMuted = true;
console.log('π Muted, previous volume was:', previousVolume);
}
// Update UI
const volumeSlider = document.getElementById('playerVolumeSlider');
if (volumeSlider) {
volumeSlider.value = volume * 100;
}
updateVolume();
updateVolumeDisplay();
}
// Update volume display
function updateVolumeDisplay() {
const volumeDisplay = document.getElementById('volumeDisplay');
if (volumeDisplay) {
if (isMuted) {
volumeDisplay.textContent = 'Muted';
} else {
volumeDisplay.textContent = Math.round(volume * 100) + '%';
}
}
}
// Update play button state
function updatePlayButton() {
const playIcon = document.getElementById('playerPlayIcon');
if (playIcon) {
playIcon.className = isPlaying ? 'fas fa-pause' : 'fas fa-play';
}
}
// Update track display
function updateTrackDisplay(title, artist) {
const titleElement = document.getElementById('playerTrackTitle');
const artistElement = document.getElementById('playerTrackArtist');
if (titleElement) titleElement.textContent = title || 'Unknown Track';
if (artistElement) artistElement.textContent = artist || 'Unknown Artist';
}
// Update time displays
function updateTimeDisplay() {
const timeDisplay = document.getElementById('playerTimeDisplay');
if (timeDisplay) {
timeDisplay.textContent = formatTime(currentTime);
}
}
function updateDurationDisplay() {
const durationDisplay = document.getElementById('playerDurationDisplay');
if (durationDisplay) {
durationDisplay.textContent = formatTime(duration);
}
}
// Format time in MM:SS
function formatTime(seconds) {
if (!seconds || isNaN(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
// Update progress bar
function updateProgressBar() {
const progressBar = document.getElementById('playerProgressBar');
if (progressBar && duration > 0) {
const progress = (currentTime / duration) * 100;
progressBar.style.width = progress + '%';
}
}
// Seek to position
function seekToPosition(e) {
const audio = document.getElementById('globalAudioElement');
if (!audio) return;
const rect = e.currentTarget.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const width = rect.width;
const seekTime = (clickX / width) * duration;
audio.currentTime = seekTime;
}
// Update volume
function updateVolume() {
const audio = document.getElementById('globalAudioElement');
if (audio) {
audio.volume = volume;
}
// Update volume icon
const volumeIcon = document.getElementById('playerVolumeIcon');
const volumeBtn = document.getElementById('playerVolumeBtn');
if (volumeIcon) {
if (isMuted || volume === 0) {
volumeIcon.className = 'fas fa-volume-mute';
} else if (volume < 0.3) {
volumeIcon.className = 'fas fa-volume-down';
} else if (volume < 0.7) {
volumeIcon.className = 'fas fa-volume-down';
} else {
volumeIcon.className = 'fas fa-volume-up';
}
}
// Update volume button state
if (volumeBtn) {
if (isMuted || volume === 0) {
volumeBtn.classList.add('muted');
} else {
volumeBtn.classList.remove('muted');
}
}
// Update volume display
updateVolumeDisplay();
}
// Toggle minimize
function toggleMinimize() {
const player = document.getElementById('enhancedGlobalPlayer');
if (player) {
isMinimized = !isMinimized;
player.classList.toggle('minimized', isMinimized);
const icon = document.getElementById('playerMinimizeBtn').querySelector('i');
if (icon) {
icon.className = isMinimized ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
}
}
}
// Playlist functionality
let currentPlaylistData = [];
let currentTrackIndex = 0;
function setupPlaylistFunctionality() {
const dropdown = document.getElementById('playlistDropdown');
if (dropdown) {
dropdown.value = currentPlaylist;
}
// Load initial playlist
loadPlaylist(currentPlaylist);
}
function switchPlaylist(playlistType) {
console.log('π΅ Switching to playlist:', playlistType);
currentPlaylist = playlistType;
currentTrackIndex = 0;
loadPlaylist(playlistType);
}
async function loadPlaylist(playlistType) {
console.log('π΅ Loading playlist:', playlistType);
try {
let apiUrl;
let playlistName;
switch (playlistType) {
case 'vip':
apiUrl = '/api/get_vip_sample_tracks.php?per_page=50';
playlistName = 'VIP Samples';
break;
case 'featured':
apiUrl = '/api/get_featured_tracks.php?per_page=50';
playlistName = 'Featured Tracks';
break;
case 'community':
apiUrl = '/api/get_community_tracks.php?per_page=50';
playlistName = 'Community Tracks';
break;
default:
apiUrl = '/api/get_vip_sample_tracks.php?per_page=50';
playlistName = 'VIP Samples';
}
const response = await fetch(apiUrl);
const data = await response.json();
if (data.success && data.tracks && data.tracks.length > 0) {
currentPlaylistData = data.tracks;
console.log(`β
Loaded ${data.tracks.length} tracks from ${playlistName}`);
// Update playlist info display
updatePlaylistInfo(playlistName, data.tracks.length);
// Auto-play first track if player is ready
if (window.globalPlayerReady && currentPlaylistData.length > 0) {
const firstTrack = currentPlaylistData[0];
updateTrackDisplay(firstTrack.title, firstTrack.artist_name);
console.log('π΅ First track loaded:', firstTrack.title);
}
} else {
console.warn('β οΈ No tracks found for playlist:', playlistType);
currentPlaylistData = [];
updatePlaylistInfo(playlistName, 0);
}
} catch (error) {
console.error('β Failed to load playlist:', error);
currentPlaylistData = [];
updatePlaylistInfo('Error', 0);
}
}
function updatePlaylistInfo(name, trackCount) {
const titleElement = document.getElementById('playerTrackTitle');
const artistElement = document.getElementById('playerTrackArtist');
if (titleElement) {
titleElement.textContent = trackCount > 0 ? `${name} (${trackCount} tracks)` : `${name} - No tracks available`;
}
if (artistElement) {
artistElement.textContent = trackCount > 0 ? 'Click play to start listening' : 'No tracks in this playlist';
}
}
function playNextTrack() {
if (currentPlaylistData.length === 0) {
console.log('π΅ No playlist loaded');
return;
}
currentTrackIndex = (currentTrackIndex + 1) % currentPlaylistData.length;
const track = currentPlaylistData[currentTrackIndex];
console.log('π΅ Playing next track:', track.title);
playTrackFromPlaylist(track);
}
function playPreviousTrack() {
if (currentPlaylistData.length === 0) {
console.log('π΅ No playlist loaded');
return;
}
currentTrackIndex = currentTrackIndex === 0 ? currentPlaylistData.length - 1 : currentTrackIndex - 1;
const track = currentPlaylistData[currentTrackIndex];
console.log('π΅ Playing previous track:', track.title);
playTrackFromPlaylist(track);
}
function playTrackFromPlaylist(track) {
if (!track || !track.audio_url) {
console.error('β Invalid track data:', track);
return;
}
try {
console.log('π΅ Playing track from playlist:', track.title, track.audio_url);
// Set current track
currentTrack = {
audioUrl: track.audio_url,
title: track.title,
artist: track.artist_name,
duration: track.duration || 120
};
// Update current track index
const trackIndex = currentPlaylistData.findIndex(t => t.audio_url === track.audio_url);
if (trackIndex !== -1) {
currentTrackIndex = trackIndex;
}
// Update track display
updateTrackDisplay(track.title, track.artist_name);
// Generate waveform for this track
const trackDuration = track.duration || 120;
generateInteractiveWaveform(trackDuration);
// Play the track directly
const audio = document.getElementById('globalAudioElement');
if (audio) {
audio.src = track.audio_url;
audio.load();
audio.play().then(() => {
isPlaying = true;
updatePlayButton();
console.log('β
Track started playing successfully');
}).catch(error => {
console.error('β Audio play failed:', error);
isPlaying = false;
updatePlayButton();
showNotification('Failed to play track: ' + error.message, 'error');
});
} else {
console.error('β Audio element not found');
}
} catch (error) {
console.error('β Failed to play track from playlist:', error);
}
}
function stopPlayback() {
const audio = document.getElementById('globalAudioElement');
if (audio) {
audio.pause();
audio.currentTime = 0;
}
isPlaying = false;
updatePlayButton();
}
// Show notification
function showNotification(message, type = 'info') {
if (typeof window.showNotification === 'function') {
window.showNotification(message, type);
} else {
console.log('π’', message);
}
}
// Public API
window.enhancedGlobalPlayer = {
playTrack: playTrack,
togglePlayPause: togglePlayPause,
playNextTrack: playNextTrack,
playPreviousTrack: playPreviousTrack,
stopPlayback: stopPlayback,
setVolume: (vol) => { volume = vol; updateVolume(); },
setPlaybackRate: (rate) => { playbackRate = rate; },
getCurrentTrack: () => currentTrack,
isPlaying: () => isPlaying,
initialize: initializeGlobalPlayer,
init: initializeGlobalPlayer, // Alias for compatibility
loadPlaylist: loadPlaylist,
getCurrentPlaylist: () => currentPlaylist,
getPlaylistTrackCount: () => currentPlaylistData.length,
playRandomTrack: () => {
if (currentPlaylistData.length > 0) {
currentTrackIndex = Math.floor(Math.random() * currentPlaylistData.length);
const track = currentPlaylistData[currentTrackIndex];
playTrackFromPlaylist(track);
}
}
};
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeGlobalPlayer);
} else {
initializeGlobalPlayer();
}
// Ensure player is visible after initialization
setTimeout(() => {
const player = document.getElementById('enhancedGlobalPlayer');
if (player) {
player.style.display = 'flex';
console.log('π΅ Global player visibility enforced');
}
// Auto-load VIP playlist after player is visible
if (window.globalPlayerReady) {
loadPlaylist('vip');
}
}, 100);
// Listen for AJAX navigation events
document.addEventListener('pageContentUpdated', () => {
console.log('π΅ Global player: Page content updated, reinitializing if needed');
if (!window.globalPlayerReady) {
initializeGlobalPlayer();
}
});
// Waveform Generation Functions
function generateWaveform() {
console.log('π Generating ambient waveform visualizer');
// Generate ambient background waveform (decorative)
const barsContainer = document.getElementById('playerWaveformBars');
if (!barsContainer) {
console.warn('β οΈ Waveform bars container not found');
return;
}
const numberOfBars = 50;
let barsHtml = '';
for (let i = 0; i < numberOfBars; i++) {
const height = Math.random() * 80 + 20; // 20% to 100%
const animationDelay = Math.random() * 2; // 0 to 2 seconds
barsHtml += `<div class="waveform-bar" style="height: ${height}%; animation-delay: ${animationDelay}s;"></div>`;
}
barsContainer.innerHTML = barsHtml;
console.log('π Ambient waveform visualizer generated');
}
function generateInteractiveWaveform(duration = 180) {
console.log('π Generating interactive waveform for duration:', duration);
const progressBarsContainer = document.getElementById('waveformProgressBars');
if (!progressBarsContainer) {
console.warn('β οΈ Waveform progress bars container not found');
return;
}
const numberOfBars = Math.min(100, Math.floor(duration / 2)); // 1 bar per 2 seconds, max 100
let barsHtml = '';
// Generate waveform data simulating audio amplitude
const waveformData = generateWaveformData(numberOfBars);
for (let i = 0; i < numberOfBars; i++) {
const height = waveformData[i];
const percentage = (i / numberOfBars) * 100;
barsHtml += `<div class="waveform-progress-bar"
style="height: ${height}%;"
data-position="${percentage}"
onclick="seekToWaveformPosition(${percentage})">
</div>`;
}
progressBarsContainer.innerHTML = barsHtml;
// Store waveform data for updates
window.currentWaveformBars = numberOfBars;
window.currentWaveformDuration = duration;
console.log('π Interactive waveform generated:', numberOfBars, 'bars for', duration, 'seconds');
}
function generateWaveformData(numberOfBars) {
const data = [];
for (let i = 0; i < numberOfBars; i++) {
// Base wave pattern
const baseHeight = Math.sin((i / numberOfBars) * Math.PI * 4) * 30 + 50;
// Add some randomness
const randomVariation = (Math.random() - 0.5) * 20;
// Ensure minimum height
const finalHeight = Math.max(10, Math.min(100, baseHeight + randomVariation));
data.push(finalHeight);
}
return data;
}
function seekToWaveformPosition(percentage) {
const audio = document.getElementById('globalAudioElement');
if (audio && duration > 0) {
const seekTime = (percentage / 100) * duration;
audio.currentTime = seekTime;
console.log('π Seeking to waveform position:', percentage + '%', '(', seekTime, 'seconds)');
}
}
function updateWaveformProgress(currentTime, duration) {
if (!window.currentWaveformBars || !duration) return;
const progressBars = document.querySelectorAll('.waveform-progress-bar');
const currentBar = Math.floor((currentTime / duration) * window.currentWaveformBars);
progressBars.forEach((bar, index) => {
if (index < currentBar) {
bar.classList.add('played');
bar.classList.remove('playing');
} else if (index === currentBar) {
bar.classList.add('playing');
bar.classList.remove('played');
} else {
bar.classList.remove('played', 'playing');
}
});
}
// Initialize waveform when player is ready
setTimeout(() => {
generateWaveform();
generateInteractiveWaveform(180); // Default 3 minutes
}, 500);
console.log('π΅ Enhanced Global Player script loaded');
})();
</script>