![]() 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/domains/soundstudiopro.com/public_html/ |
<?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>
</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">
<button class="player-btn volume-btn" id="playerVolumeBtn" title="Volume">
<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">
</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: none;
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;
}
.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;
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);
}
.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;
}
.volume-btn,
.speed-btn,
.minimize-btn {
width: 24px;
height: 24px;
position: relative;
}
.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 Music Player JavaScript
(function() {
'use strict';
// Player state
let currentTrack = null;
let isPlaying = false;
let currentTime = 0;
let duration = 0;
let volume = 0.5;
let playbackSpeed = 1;
let isMinimized = false;
// Playlist management
let currentPlaylist = [];
let currentPlaylistType = 'vip'; // Default to VIP samples
let currentTrackIndex = 0;
// Auto-play state
let autoPlayEnabled = true; // Default to enabled
// Toggle auto-play
function toggleAutoPlay() {
autoPlayEnabled = !autoPlayEnabled;
const autoPlayBtn = document.getElementById('playerAutoPlayBtn');
const autoPlayIcon = document.getElementById('playerAutoPlayIcon');
if (autoPlayBtn && autoPlayIcon) {
if (autoPlayEnabled) {
autoPlayBtn.title = 'Auto-play: On';
autoPlayIcon.className = 'fas fa-infinity';
autoPlayBtn.classList.add('active');
} else {
autoPlayBtn.title = 'Auto-play: Off';
autoPlayIcon.className = 'fas fa-times';
autoPlayBtn.classList.remove('active');
}
}
console.log('🎵 Auto-play toggled:', autoPlayEnabled);
}
// DOM elements
let playerElement = null;
let audioElement = null;
let trackTitle = null;
let trackArtist = null;
let playIcon = null;
let progressBar = null;
let progressHandle = null;
let timeDisplay = null;
let durationDisplay = null;
let volumeSlider = null;
let volumeIcon = null;
let speedBtn = null;
let volumeSliderContainer = null;
// Generate interactive waveform representing song structure
function generateWaveform() {
// Generate ambient background waveform (decorative)
const barsContainer = document.getElementById('playerWaveformBars');
if (barsContainer) {
barsContainer.innerHTML = '';
const numberOfBars = 60;
let barsHtml = '';
for (let i = 0; i < numberOfBars; i++) {
const height = Math.random() * 80 + 20;
const animationDelay = Math.random() * 2;
barsHtml += `<div class="waveform-bar" style="height: ${height}%; animation-delay: ${animationDelay}s;"></div>`;
}
barsContainer.innerHTML = barsHtml;
}
console.log('🌊 Ambient waveform visualizer generated');
}
// Generate interactive waveform for current track
function generateInteractiveWaveform(duration = 180) {
const progressBarsContainer = document.getElementById('waveformProgressBars');
if (!progressBarsContainer) return;
// Clear existing bars
progressBarsContainer.innerHTML = '';
// Calculate number of bars based on song duration (1 bar per 3 seconds, min 50, max 200)
const barsPerSecond = 1/3;
const numberOfBars = Math.max(50, Math.min(200, Math.floor(duration * barsPerSecond)));
// Generate waveform data simulating audio amplitude
const waveformData = generateWaveformData(numberOfBars);
let barsHtml = '';
for (let i = 0; i < numberOfBars; i++) {
const height = waveformData[i];
const percentage = (i / numberOfBars) * 100;
barsHtml += `<div class="waveform-progress-bar"
data-index="${i}"
data-time="${(duration * i / numberOfBars).toFixed(2)}"
style="height: ${height}%;"
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');
}
// Generate realistic waveform data
function generateWaveformData(numberOfBars) {
const data = [];
for (let i = 0; i < numberOfBars; i++) {
const position = i / numberOfBars;
// Create realistic audio amplitude pattern
let amplitude = 0;
// Base wave pattern
amplitude += Math.sin(position * Math.PI * 8) * 0.3;
// Add some randomness for realism
amplitude += (Math.random() - 0.5) * 0.4;
// Add crescendos and diminuendos
amplitude += Math.sin(position * Math.PI * 2) * 0.2;
// Normalize to 20-100% range
amplitude = Math.max(0.2, Math.min(1, (amplitude + 1) / 2));
const height = amplitude * 80 + 20; // 20% to 100%
data.push(height);
}
return data;
}
// Update waveform progress as song plays
function updateWaveformProgress(currentTime, duration) {
const progressBars = document.querySelectorAll('.waveform-progress-bar');
const progressLine = document.getElementById('waveformProgressLine');
const progressHandle = document.getElementById('playerProgressHandle');
if (!progressBars.length || !duration) return;
const progress = currentTime / duration;
const progressPercentage = progress * 100;
// Update progress line position
if (progressLine) {
progressLine.style.left = `${progressPercentage}%`;
}
// Update progress handle position
if (progressHandle) {
progressHandle.style.left = `${progressPercentage}%`;
}
// Update waveform bar states
progressBars.forEach((bar, index) => {
const barProgress = (index / progressBars.length);
bar.classList.remove('played', 'playing');
if (barProgress < progress) {
bar.classList.add('played');
} else if (Math.abs(barProgress - progress) < (1 / progressBars.length)) {
bar.classList.add('playing');
}
});
}
// Seek to waveform position when clicked
function seekToWaveformPosition(percentage) {
if (!audioElement || !audioElement.duration) return;
const seekTime = (percentage / 100) * audioElement.duration;
audioElement.currentTime = seekTime;
console.log('🎯 Seeked to', percentage.toFixed(1) + '%', 'of track (' + formatTime(seekTime) + ')');
}
// Initialize player when DOM is ready
// Clear cached track state to prevent stale data issues
function clearCachedTrackState() {
console.log('🎵 Clearing cached track state');
currentTrack = null;
currentPlaylist = [];
currentTrackIndex = 0;
currentPlaylistType = 'vip';
isPlaying = false;
currentTime = 0;
duration = 0;
// Clear any stored track references
if (typeof localStorage !== 'undefined') {
localStorage.removeItem('globalPlayerCurrentTrack');
localStorage.removeItem('globalPlayerCurrentIndex');
localStorage.removeItem('globalPlayerPlaylistType');
}
}
function initializePlayer() {
console.log('🎵 Initializing Enhanced Global Player');
// Clear any cached track state to prevent stale data issues
clearCachedTrackState();
// Get DOM elements
playerElement = document.getElementById('enhancedGlobalPlayer');
audioElement = document.getElementById('globalAudioElement');
trackTitle = document.getElementById('playerTrackTitle');
trackArtist = document.getElementById('playerTrackArtist');
playIcon = document.getElementById('playerPlayIcon');
progressBar = document.getElementById('playerProgressBar');
progressHandle = document.getElementById('playerProgressHandle');
timeDisplay = document.getElementById('playerTimeDisplay');
durationDisplay = document.getElementById('playerDurationDisplay');
volumeSlider = document.getElementById('playerVolumeSlider');
volumeIcon = document.getElementById('playerVolumeIcon');
speedBtn = document.getElementById('playerSpeedBtn');
volumeSliderContainer = document.getElementById('volumeSliderContainer');
if (!playerElement || !audioElement) {
console.error('🎵 Global player elements not found');
return;
}
setupEventListeners();
setupAudioEvents();
generateWaveform();
// Set initial volume
audioElement.volume = volume;
volumeSlider.value = volume * 100;
// Initialize auto-play button state
const autoPlayBtn = document.getElementById('playerAutoPlayBtn');
if (autoPlayBtn) {
autoPlayBtn.classList.toggle('active', autoPlayEnabled);
}
console.log('🎵 Enhanced Global Player initialized');
// Load default playlist on homepage (without auto-play)
if (window.location.pathname === '/' || window.location.pathname === '/index.php') {
console.log('🎵 Homepage detected - loading VIP samples (no auto-play)');
setTimeout(() => {
loadPlaylist('vip', false); // false = don't auto-play
}, 1000); // Small delay to ensure everything is ready
}
}
// Setup event listeners
function setupEventListeners() {
// Play/Pause button
document.getElementById('playerPlayBtn').addEventListener('click', togglePlayPause);
// Previous/Next buttons
document.getElementById('playerPrevBtn').addEventListener('click', playPrevious);
document.getElementById('playerNextBtn').addEventListener('click', playNext);
// Progress bar
document.getElementById('playerProgressContainer').addEventListener('click', seekToPosition);
// Volume controls
document.getElementById('playerVolumeBtn').addEventListener('click', toggleVolumeSlider);
volumeSlider.addEventListener('input', updateVolume);
// Speed button
speedBtn.addEventListener('click', cyclePlaybackSpeed);
// Auto-play button
document.getElementById('playerAutoPlayBtn').addEventListener('click', toggleAutoPlay);
// Minimize button
document.getElementById('playerMinimizeBtn').addEventListener('click', toggleMinimize);
// Track title click handler
document.getElementById('playerTrackTitle').addEventListener('click', handleTrackTitleClick);
// Track artist click handler
document.getElementById('playerTrackArtist').addEventListener('click', handleTrackArtistClick);
// Close volume slider when clicking outside
document.addEventListener('click', function(e) {
if (!e.target.closest('.player-advanced-controls')) {
volumeSliderContainer.classList.remove('active');
}
});
}
// Setup audio element events
function setupAudioEvents() {
audioElement.addEventListener('timeupdate', updateProgress);
audioElement.addEventListener('loadedmetadata', updateDuration);
audioElement.addEventListener('ended', onTrackEnded);
audioElement.addEventListener('error', onAudioError);
audioElement.addEventListener('canplay', onCanPlay);
}
// Playlist management functions
async function loadPlaylist(type, autoPlay = false) {
console.log('🎵 Loading playlist:', type, 'autoPlay:', autoPlay);
try {
let url;
switch(type) {
case 'vip':
url = '/api/get_vip_sample_tracks.php?per_page=50&_t=' + Date.now();
break;
case 'featured':
url = '/api/get_featured_tracks.php?per_page=20&_t=' + Date.now();
break;
case 'community':
url = '/api/get_community_tracks.php?per_page=50&_t=' + Date.now();
break;
default:
url = '/api/get_vip_sample_tracks.php?per_page=50&_t=' + Date.now();
}
const response = await fetch(url);
const data = await response.json();
if (data.success && data.tracks) {
console.log('🎵 Playlist data received:', {
type: type,
trackCount: data.tracks.length,
tracks: data.tracks.map(t => ({ id: t.id, title: t.title, artist: t.artist_name }))
});
currentPlaylist = data.tracks;
currentPlaylistType = type;
currentTrackIndex = 0;
updatePlayerDisplay(data.playlist_info);
// Only auto-play if explicitly requested
if (autoPlay && currentPlaylist.length > 0) {
const firstTrack = currentPlaylist[0];
playTrack(firstTrack.audio_url, firstTrack.title, firstTrack.artist_name, firstTrack.id, firstTrack.user_id);
console.log('🎵 Auto-playing first track from', type, 'playlist');
} else if (currentPlaylist.length > 0) {
console.log('🎵 Playlist loaded - ready for user interaction');
}
console.log('🎵 Loaded', currentPlaylist.length, 'tracks from', type, 'playlist');
} else {
console.error('🎵 Failed to load playlist:', data.error);
fallbackToSampleTrack();
}
} catch (error) {
console.error('🎵 Playlist loading error:', error);
fallbackToSampleTrack();
}
}
function updatePlayerDisplay(playlistInfo) {
const trackTitleLink = document.getElementById('playerTrackTitleLink');
const trackArtistLink = document.getElementById('playerTrackArtistLink');
// Show actual track info when playing, or playlist info when not playing
if (currentTrack && currentTrack.title) {
// Show the actual track title and artist
if (trackTitleLink) {
trackTitleLink.textContent = currentTrack.title;
trackTitleLink.href = '#';
trackTitleLink.style.cursor = 'default';
} else {
trackTitle.textContent = currentTrack.title;
}
if (trackArtistLink) {
trackArtistLink.textContent = currentTrack.artist;
trackArtistLink.href = '#';
trackArtistLink.style.cursor = 'default';
} else {
trackArtist.textContent = currentTrack.artist;
}
} else if (currentPlaylist.length > 0) {
// Show playlist info when no track is currently playing
if (trackTitleLink) {
trackTitleLink.textContent = playlistInfo.name;
trackTitleLink.href = '#';
trackTitleLink.style.cursor = 'default';
} else {
trackTitle.textContent = playlistInfo.name;
}
if (trackArtistLink) {
trackArtistLink.textContent = `${currentPlaylist.length} tracks • ${playlistInfo.description}`;
trackArtistLink.href = '#';
trackArtistLink.style.cursor = 'default';
} else {
trackArtist.textContent = `${currentPlaylist.length} tracks • ${playlistInfo.description}`;
}
} else {
if (trackTitleLink) {
trackTitleLink.textContent = 'No tracks available';
trackTitleLink.href = '#';
trackTitleLink.style.cursor = 'default';
} else {
trackTitle.textContent = 'No tracks available';
}
if (trackArtistLink) {
trackArtistLink.textContent = 'Try switching to a different playlist';
trackArtistLink.href = '#';
trackArtistLink.style.cursor = 'default';
} else {
trackArtist.textContent = 'Try switching to a different playlist';
}
}
}
function fallbackToSampleTrack() {
trackTitle.textContent = 'No tracks available';
trackArtist.textContent = 'Try switching to a different playlist';
currentPlaylist = [{
audio_url: 'https://www.soundjay.com/misc/sounds/bell-ringing-05.wav',
title: 'No tracks available',
artist_name: 'SoundStudioPro'
}];
}
// Global function for playlist switching
window.switchPlaylist = function(type) {
console.log('🎵 Switching to playlist:', type);
// Clear cached state before loading new playlist
clearCachedTrackState();
loadPlaylist(type);
};
// Force refresh current playlist (for debugging track ownership issues)
window.refreshCurrentPlaylist = function() {
console.log('🎵 Force refreshing current playlist:', currentPlaylistType);
clearCachedTrackState();
loadPlaylist(currentPlaylistType);
};
// Force clear all caches and reload playlist
window.forceRefreshPlaylist = function() {
console.log('🎵 Force clearing all caches and reloading playlist');
clearCachedTrackState();
// Clear browser cache for API requests
if ('caches' in window) {
caches.keys().then(function(names) {
for (let name of names) {
caches.delete(name);
}
});
}
// Force reload with cache busting
setTimeout(() => {
loadPlaylist(currentPlaylistType);
}, 100);
};
// Public API - Play track
function playTrack(audioUrl, title, artist, trackId = null, artistId = null) {
console.log('🎵 Global Player playTrack called:', { audioUrl, title, artist, trackId });
// Validate inputs
if (!audioUrl || audioUrl === 'NULL' || audioUrl === 'null') {
console.error('🎵 Invalid audio URL:', audioUrl);
return false;
}
// Check if this is the same track that's already playing
if (currentTrack && currentTrack.audioUrl === audioUrl && isPlaying) {
console.log('🎵 Same track already playing, ignoring duplicate request');
return true;
}
// Check if this is the same track that's paused - just resume it
if (currentTrack && currentTrack.audioUrl === audioUrl && audioElement.src === audioUrl && !isPlaying) {
console.log('🎵 Resuming paused track instead of reloading');
audioElement.play().then(() => {
isPlaying = true;
updatePlayButton();
console.log('🎵 Resumed playback successfully');
}).catch(error => {
console.error('🎵 Resume failed, will reload track:', error);
// Continue with normal track loading below
});
return true;
}
// Find track index in current playlist if it exists
if (currentPlaylist.length > 0) {
const trackIndex = currentPlaylist.findIndex(track =>
track.audio_url === audioUrl ||
(track.title === title && track.artist_name === artist)
);
if (trackIndex !== -1) {
currentTrackIndex = trackIndex;
console.log('🎵 Found track in playlist at index:', currentTrackIndex, 'of', currentPlaylist.length);
} else {
console.warn('🎵 Track not found in current playlist:', { title, artist, audioUrl });
console.log('🎵 Current playlist tracks:', currentPlaylist.map(t => ({ title: t.title, artist: t.artist_name, audio: t.audio_url })));
// If track not found, try to load VIP playlist first
if (currentPlaylist.length === 0 || currentPlaylistType !== 'vip') {
console.log('🎵 Loading VIP playlist to find track...');
loadPlaylist('vip', false).then(() => {
// Retry finding the track after playlist is loaded
const retryIndex = currentPlaylist.findIndex(track =>
track.audio_url === audioUrl ||
(track.title === title && track.artist_name === artist)
);
if (retryIndex !== -1) {
currentTrackIndex = retryIndex;
console.log('🎵 Found track in loaded playlist at index:', currentTrackIndex);
}
});
}
}
} else {
console.log('🎵 No playlist loaded, loading VIP playlist...');
loadPlaylist('vip', false);
}
// Sanitize and validate track info
const sanitizedTitle = (title || 'Unknown Track').trim();
const sanitizedArtist = (artist || 'Unknown Artist').trim();
console.log('🎵 Sanitized track info:', {
originalTitle: title,
sanitizedTitle,
originalArtist: artist,
sanitizedArtist
});
// Update track info
currentTrack = {
audioUrl,
title: sanitizedTitle,
artist: sanitizedArtist,
trackId: trackId,
artistId: artistId
};
// Update UI with proper escaping
if (trackTitle) {
trackTitle.textContent = sanitizedTitle;
console.log('🎵 Updated track title element with:', sanitizedTitle);
} else {
console.error('🎵 trackTitle element not found!');
}
if (trackArtist) {
trackArtist.textContent = sanitizedArtist;
console.log('🎵 Updated track artist element with:', sanitizedArtist);
} else {
console.error('🎵 trackArtist element not found!');
}
// Double-check the elements are actually updated
const titleCheck = document.getElementById('playerTrackTitle');
const artistCheck = document.getElementById('playerTrackArtist');
if (titleCheck) {
console.log('🎵 Title element content after update:', titleCheck.textContent);
}
if (artistCheck) {
console.log('🎵 Artist element content after update:', artistCheck.textContent);
}
// Always stop current audio before loading new track
console.log('🎵 Current audio state - paused:', audioElement.paused, 'src:', audioElement.src);
// Force stop any current playback
audioElement.pause();
audioElement.currentTime = 0;
isPlaying = false;
updatePlayButton();
console.log('🎵 Forced stop of current audio');
// Clear any pending event listeners to prevent conflicts
audioElement.removeEventListener('canplay', arguments.callee);
audioElement.removeEventListener('loadeddata', arguments.callee);
// Load new audio immediately
console.log('🎵 Loading new audio source:', audioUrl);
audioElement.src = audioUrl;
audioElement.load();
// Show player
showPlayer();
// Use a more robust approach to play when ready
let playAttempted = false;
function attemptPlay() {
if (playAttempted) return;
playAttempted = true;
console.log('🎵 Attempting to play new track');
audioElement.play().then(() => {
isPlaying = true;
updatePlayButton();
console.log('🎵 New track playback started successfully');
}).catch(error => {
console.error('🎵 New track playback failed:', error);
playAttempted = false; // Allow retry
onAudioError(error);
});
}
// Try multiple events to ensure playback starts
audioElement.addEventListener('canplay', function onCanPlay() {
audioElement.removeEventListener('canplay', onCanPlay);
console.log('🎵 Audio can play - starting playback');
attemptPlay();
});
audioElement.addEventListener('loadeddata', function onLoadedData() {
audioElement.removeEventListener('loadeddata', onLoadedData);
console.log('🎵 Audio data loaded - ready to play');
if (!playAttempted) {
setTimeout(attemptPlay, 100); // Small delay to ensure readiness
}
});
// Fallback timeout in case events don't fire
setTimeout(() => {
if (!playAttempted && audioElement.readyState >= 2) {
console.log('🎵 Fallback: attempting play after timeout');
attemptPlay();
}
}, 1000);
return true;
}
// Show player
function showPlayer() {
if (playerElement) {
playerElement.classList.add('playing');
console.log('🎵 Player shown');
}
}
// Hide player
function hidePlayer() {
if (playerElement) {
playerElement.classList.remove('playing');
console.log('🎵 Player hidden');
}
}
// Toggle play/pause
function togglePlayPause() {
console.log('🎵 Toggle play/pause called', {
hasAudioSrc: !!audioElement.src,
isPlaying: isPlaying,
playlistLength: currentPlaylist.length,
currentTrackIndex: currentTrackIndex
});
// If no audio source is set, try to load the first track from playlist
if (!audioElement.src) {
if (currentPlaylist.length > 0) {
const firstTrack = currentPlaylist[0];
console.log('🎵 No track loaded, playing first track from playlist:', firstTrack.title);
playTrack(firstTrack.audio_url, firstTrack.title, firstTrack.artist_name);
return;
} else {
console.log('🎵 No playlist loaded, loading VIP samples');
loadPlaylist('vip', true); // true = auto-play
return;
}
}
if (isPlaying) {
console.log('🎵 Pausing playback');
audioElement.pause();
isPlaying = false;
} else {
console.log('🎵 Starting playback');
audioElement.play().then(() => {
isPlaying = true;
console.log('🎵 Playback started successfully');
}).catch(error => {
console.error('🎵 Play failed:', error);
onAudioError(error);
});
}
updatePlayButton();
}
// Update play button icon
function updatePlayButton() {
if (playIcon) {
playIcon.className = isPlaying ? 'fas fa-pause' : 'fas fa-play';
}
}
// Seek to position
function seekToPosition(e) {
if (!audioElement.src || !duration) return;
const rect = e.currentTarget.getBoundingClientRect();
const percent = (e.clientX - rect.left) / rect.width;
const newTime = percent * duration;
audioElement.currentTime = newTime;
}
// Update progress
function updateProgress() {
if (!audioElement.src) return;
currentTime = audioElement.currentTime;
const percent = (currentTime / duration) * 100;
if (progressBar) {
progressBar.style.width = `${percent}%`;
}
if (timeDisplay) {
timeDisplay.textContent = formatTime(currentTime);
}
// Update interactive waveform progress
updateWaveformProgress(currentTime, duration);
}
// Update duration
function updateDuration() {
duration = audioElement.duration;
if (durationDisplay) {
durationDisplay.textContent = formatTime(duration);
}
// Generate interactive waveform based on actual song duration
if (duration > 0) {
generateInteractiveWaveform(duration);
}
}
// Format time
function formatTime(seconds) {
if (isNaN(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
// Volume controls
function toggleVolumeSlider() {
volumeSliderContainer.classList.toggle('active');
}
function updateVolume() {
volume = volumeSlider.value / 100;
audioElement.volume = volume;
// Update volume icon
if (volume === 0) {
volumeIcon.className = 'fas fa-volume-mute';
} else if (volume < 0.5) {
volumeIcon.className = 'fas fa-volume-down';
} else {
volumeIcon.className = 'fas fa-volume-up';
}
}
// Playback speed
function cyclePlaybackSpeed() {
const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2];
const currentIndex = speeds.indexOf(playbackSpeed);
playbackSpeed = speeds[(currentIndex + 1) % speeds.length];
audioElement.playbackRate = playbackSpeed;
speedBtn.querySelector('.speed-text').textContent = `${playbackSpeed}x`;
speedBtn.title = `Speed: ${playbackSpeed}x`;
}
// Minimize/restore
function toggleMinimize() {
isMinimized = !isMinimized;
playerElement.classList.toggle('minimized', isMinimized);
const icon = document.getElementById('playerMinimizeBtn').querySelector('i');
icon.className = isMinimized ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
}
// Playlist navigation functions
function playPrevious() {
if (currentPlaylist.length === 0) {
console.log('🎵 No playlist loaded');
return;
}
currentTrackIndex = (currentTrackIndex - 1 + currentPlaylist.length) % currentPlaylist.length;
const track = currentPlaylist[currentTrackIndex];
playTrack(track.audio_url, track.title, track.artist_name, track.id, track.user_id);
console.log('🎵 Playing previous track:', track.title);
}
function playNext() {
if (currentPlaylist.length === 0) {
console.log('🎵 No playlist loaded');
return;
}
currentTrackIndex = (currentTrackIndex + 1) % currentPlaylist.length;
const track = currentPlaylist[currentTrackIndex];
playTrack(track.audio_url, track.title, track.artist_name, track.id, track.user_id);
console.log('🎵 Playing next track:', track.title);
}
// Event handlers
function onTrackEnded() {
isPlaying = false;
updatePlayButton();
console.log('🎵 Track ended');
// Auto-play next track if enabled and we have a playlist
if (autoPlayEnabled && currentPlaylist.length > 0) {
console.log('🎵 Auto-playing next track...');
playNext();
} else if (!autoPlayEnabled) {
console.log('🎵 Auto-play disabled, not playing next track');
} else {
console.log('🎵 No playlist loaded, not auto-playing');
}
}
function onAudioError(error) {
console.error('🎵 Audio error:', error);
isPlaying = false;
updatePlayButton();
// If it's a 404 or network error, the track might have changed ownership
if (error.message && (error.message.includes('404') || error.message.includes('Failed to fetch'))) {
console.warn('🎵 Track not found - may have changed ownership, refreshing playlist...');
// Force refresh the playlist after a short delay
setTimeout(() => {
refreshCurrentPlaylist();
}, 1000);
}
}
function onCanPlay() {
console.log('🎵 Audio ready to play');
}
// Expose global API
window.enhancedGlobalPlayer = {
playTrack: playTrack,
showPlayer: showPlayer,
hidePlayer: hidePlayer,
togglePlayPause: togglePlayPause,
loadPlaylist: loadPlaylist,
init: initializePlayer
};
// Signal that global player is ready - now that enhancedGlobalPlayer is created
window.globalPlayerReady = true;
console.log('🎵 Enhanced Global Player fully initialized and ready');
// Global function to enable play buttons when player is ready
window.enablePlayButtons = function() {
console.log('🎵 Enabling play buttons - global player is ready');
// This function can be called by other pages to enable their play buttons
document.querySelectorAll('.preview-btn.play-track-btn, .action-btn.play-btn').forEach(btn => {
btn.classList.add('ready');
btn.disabled = false;
// Remove loading state if present
const icon = btn.querySelector('i');
if (icon && icon.className.includes('fa-spinner')) {
icon.className = 'fas fa-play';
}
});
};
// Global function to wait for player to be ready
window.waitForGlobalPlayer = function(callback, maxAttempts = 20) {
if (window.globalPlayerReady && window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
callback();
return;
}
if (maxAttempts > 0) {
setTimeout(() => waitForGlobalPlayer(callback, maxAttempts - 1), 250);
} else {
console.error('🎵 Global player not available after maximum attempts');
}
};
// Track title click handler
function handleTrackTitleClick() {
console.log('🎵 Track title clicked');
// Use the current track index to get the actual playing track
if (currentPlaylist && currentPlaylist.length > 0 && currentTrackIndex >= 0 && currentTrackIndex < currentPlaylist.length) {
const currentTrack = currentPlaylist[currentTrackIndex];
if (currentTrack && currentTrack.id) {
// Navigate to track page using the current track's ID
console.log('🎵 Navigating to track page:', currentTrack.id, 'for track:', currentTrack.title);
window.open(`/track.php?id=${currentTrack.id}`, '_blank');
return;
}
}
// Fallback: get title from display and search
const trackTitle = document.getElementById('playerTrackTitle');
if (trackTitle) {
const title = trackTitle.textContent;
console.log('🎵 No track ID found, searching for tracks with title:', title);
window.open(`/search.php?q=${encodeURIComponent(title)}`, '_blank');
}
}
// Track artist click handler
function handleTrackArtistClick() {
console.log('🎵 Track artist clicked');
const trackArtist = document.getElementById('playerTrackArtist');
if (!trackArtist) {
console.log('🎵 Track artist element not found');
return;
}
const artist = trackArtist.textContent;
console.log('🎵 Track artist clicked:', { artist });
// Search for the artist in the current playlist to get user ID
if (currentPlaylist && currentPlaylist.length > 0) {
const currentTrack = currentPlaylist.find(track =>
track.artist_name === artist
);
if (currentTrack && currentTrack.user_id) {
// Navigate to artist profile page
console.log('🎵 Navigating to artist profile:', currentTrack.user_id);
window.open(`/artist_profile.php?id=${currentTrack.user_id}`, '_blank');
return;
}
}
// Fallback: search for artists with this name
console.log('🎵 No specific artist found, searching for similar artists');
window.open(`/artists.php?search=${encodeURIComponent(artist)}`, '_blank');
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializePlayer);
} else {
initializePlayer();
}
// Signal that global player is ready - moved to after initialization
// window.globalPlayerReady = true; // REMOVED - will be set after initialization
console.log('🎵 Enhanced Global Player script loaded');
})();
</script>