![]() 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/private_html/ |
<?php
session_start();
// Handle AJAX requests
$is_ajax = isset($_GET['ajax']) && $_GET['ajax'] == '1';
if ($is_ajax) {
echo '<div class="container" id="pageContainer">';
} else {
include 'includes/header.php';
}
// JavaScript functions for global player (must be defined before HTML content)
?>
<script>
// Global player initialization check
function waitForGlobalPlayer(callback, maxAttempts = 20) {
// Check for global player ready signal
if (window.globalPlayerReady && window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
callback();
return;
}
if (maxAttempts > 0) {
setTimeout(() => waitForGlobalPlayer(callback, maxAttempts - 1), 250);
} else {
if (typeof window.showNotification === 'function') {
window.showNotification('Audio player not available. Please refresh the page.', 'error');
}
}
}
// Enable play buttons when global player is ready
function enablePlayButtons() {
// Enable all 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';
}
});
// Show ready notification
if (typeof window.showNotification === 'function') {
window.showNotification('๐ต Audio player ready!', 'success');
}
}
// Use global player for track playback
function playTrack(trackId, audioUrl, title, artist) {
// Validate audio URL
if (!audioUrl || audioUrl === 'null' || audioUrl === 'undefined' || audioUrl === '') {
showNotification('Invalid audio URL', 'error');
return;
}
// Check if global player is available
if (!window.enhancedGlobalPlayer || typeof window.enhancedGlobalPlayer.playTrack !== 'function') {
showNotification('Audio player not ready. Please refresh the page.', 'error');
return;
}
try {
// Call the global player's playTrack function
const success = window.enhancedGlobalPlayer.playTrack(audioUrl, title, artist);
if (success) {
// Update UI - Mark this track as currently playing
document.querySelectorAll('.music-card').forEach(card => {
card.classList.remove('currently-playing', 'playing');
});
// Reset all play buttons
document.querySelectorAll('.preview-btn.play-track-btn').forEach(btn => {
btn.classList.remove('playing');
const icon = btn.querySelector('i');
if (icon) {
icon.className = 'fas fa-play';
}
});
const currentCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (currentCard) {
currentCard.classList.add('currently-playing', 'playing');
// Update the play button
const currentButton = currentCard.querySelector('.preview-btn.play-track-btn');
if (currentButton) {
currentButton.classList.add('playing');
const icon = currentButton.querySelector('i');
if (icon) icon.className = 'fas fa-pause';
}
}
// Record play analytics if function exists
if (typeof window.recordTrackPlay === 'function') {
window.recordTrackPlay(trackId);
}
// Show notification
showNotification('๐ต Now playing: ' + title, 'success');
} else {
showNotification('Failed to start playback. Please try again.', 'error');
}
} catch (error) {
showNotification('Playback error: ' + error.message, 'error');
}
}
// Record Track Play
function recordTrackPlay(trackId) {
fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=play&track_id=${trackId}`
})
.catch(error => console.error('Play tracking error:', error));
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Check if global player is already ready
if (window.globalPlayerReady && window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
enablePlayButtons();
return;
}
// Wait for global player to be ready, then enable play buttons
waitForGlobalPlayer(() => {
enablePlayButtons();
});
});
</script>
<?php
require_once 'config/database.php';
$pdo = getDBConnection();
// Get artist ID from URL
$artist_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$artist_id) {
header('Location: /artists.php');
exit;
}
// Get artist data with comprehensive stats
$stmt = $pdo->prepare("
SELECT
u.id,
u.name as username,
u.email,
u.plan,
u.credits,
u.created_at as joined_date,
up.profile_image,
up.bio,
up.location,
up.website,
up.social_links,
up.genres,
up.music_style,
up.artist_highlights,
up.influences,
up.equipment,
up.achievements,
up.featured_tracks,
up.artist_statement,
COUNT(mt.id) as total_tracks,
COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) as completed_tracks,
COUNT(CASE WHEN mt.status = 'processing' THEN 1 END) as processing_tracks,
COUNT(CASE WHEN mt.status = 'failed' THEN 1 END) as failed_tracks,
MAX(mt.created_at) as last_activity,
COALESCE(SUM(CASE WHEN mt.status = 'complete' THEN mt.duration ELSE 0 END), 0) as total_duration,
COALESCE((SELECT COUNT(*) FROM track_plays WHERE track_id IN (SELECT id FROM music_tracks WHERE user_id = u.id)), 0) as total_plays,
COALESCE((SELECT COUNT(*) FROM track_likes WHERE track_id IN (SELECT id FROM music_tracks WHERE user_id = u.id)), 0) as total_likes,
(SELECT COUNT(*) FROM user_follows WHERE following_id = u.id) as followers_count,
(SELECT COUNT(*) FROM user_follows WHERE follower_id = u.id) as following_count,
CASE
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 20 THEN '๐ต Pro Creator'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 10 THEN 'โญ Rising Star'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 5 THEN '๐ฅ Active Artist'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 1 THEN '๐ผ New Artist'
ELSE '๐ค Member'
END as badge
FROM users u
LEFT JOIN user_profiles up ON u.id = up.user_id
LEFT JOIN music_tracks mt ON u.id = mt.user_id
WHERE u.id = ?
GROUP BY u.id, u.name, u.email, u.plan, u.credits, u.created_at, up.profile_image, up.bio, up.location, up.website, up.social_links, up.genres, up.music_style, up.artist_highlights, up.influences, up.equipment, up.achievements, up.featured_tracks, up.artist_statement
");
$stmt->execute([$artist_id]);
$artist = $stmt->fetch();
if (!$artist) {
header('Location: /artists.php');
exit;
}
// Get artist's tracks (show all tracks, not just completed ones)
$stmt = $pdo->prepare("
SELECT
mt.*,
u.name as artist_name,
(SELECT COUNT(*) FROM track_likes WHERE track_id = mt.id) as like_count,
(SELECT COUNT(*) FROM track_comments WHERE track_id = mt.id) as comment_count,
(SELECT COUNT(*) FROM track_plays WHERE track_id = mt.id) as play_count
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
WHERE mt.user_id = ? AND mt.status = 'complete' AND mt.is_public = 1
ORDER BY mt.created_at DESC
LIMIT 20
");
$stmt->execute([$artist_id]);
$tracks = $stmt->fetchAll();
// Get similar artists
$stmt = $pdo->prepare("
SELECT
u.id,
u.name as username,
u.profile_image,
COUNT(mt.id) as track_count,
(SELECT COUNT(*) FROM user_follows WHERE following_id = u.id) as followers_count
FROM users u
LEFT JOIN music_tracks mt ON u.id = mt.user_id
WHERE u.id != ? AND mt.status = 'complete'
GROUP BY u.id, u.name, u.profile_image
ORDER BY followers_count DESC
LIMIT 6
");
$stmt->execute([$artist_id]);
$similar_artists = $stmt->fetchAll();
// Check if current user is following this artist
$is_following = false;
if (isset($_SESSION['user_id'])) {
$stmt = $pdo->prepare("SELECT COUNT(*) FROM user_follows WHERE follower_id = ? AND following_id = ?");
$stmt->execute([$_SESSION['user_id'], $artist_id]);
$is_following = $stmt->fetchColumn() > 0;
}
// Check if current user is friends with this artist
$is_friend = false;
if (isset($_SESSION['user_id'])) {
$stmt = $pdo->prepare("SELECT COUNT(*) FROM user_friends WHERE (user_id = ? AND friend_id = ?) OR (user_id = ? AND friend_id = ?)");
$stmt->execute([$_SESSION['user_id'], $artist_id, $artist_id, $_SESSION['user_id']]);
$is_friend = $stmt->fetchColumn() > 0;
}
// Set page variables
$page_title = $artist['username'] . ' - Artist Profile - SoundStudioPro';
$page_description = 'Discover ' . $artist['username'] . '\'s music, tracks, and latest releases on SoundStudioPro.';
$current_page = 'artist_profile';
?>
<style>
/* ULTIMATE ARTIST PROFILE STYLES - INSPIRED BY ALL PLATFORMS */
/* Hero Section - EPIC Design */
.artist-hero {
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0a0a0a 100%);
position: relative;
overflow: hidden;
padding: 4rem 0 6rem;
margin-bottom: 0;
}
.artist-hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(102,126,234,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
opacity: 0.3;
}
.hero-content {
max-width: 120rem;
margin: 0 auto;
position: relative;
z-index: 2;
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 4rem;
align-items: center;
}
/* Artist Profile Section */
.artist-profile {
text-align: center;
}
.artist-avatar {
width: 200px;
height: 200px;
border-radius: 50%;
margin: 0 auto 2rem;
position: relative;
overflow: hidden;
border: 4px solid rgba(102, 126, 234, 0.3);
box-shadow: 0 20px 60px rgba(102, 126, 234, 0.4);
animation: avatarGlow 3s ease-in-out infinite;
}
@keyframes avatarGlow {
0%, 100% { box-shadow: 0 20px 60px rgba(102, 126, 234, 0.4); }
50% { box-shadow: 0 20px 60px rgba(102, 126, 234, 0.8); }
}
.artist-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.artist-avatar .default-avatar {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 4rem;
color: white;
font-weight: bold;
}
.artist-name {
font-size: 3.5rem;
font-weight: 900;
color: white;
margin-bottom: 1rem;
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.artist-badge {
display: inline-block;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
color: #667eea;
padding: 0.8rem 1.6rem;
border-radius: 50px;
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 2rem;
border: 1px solid rgba(102, 126, 234, 0.3);
}
.artist-location {
color: #a0aec0;
font-size: 1.4rem;
margin-bottom: 2rem;
}
/* Stats Section - INSPIRED BY LAST.FM & DEEZER */
.artist-stats {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
padding: 3rem;
text-align: center;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-bottom: 3rem;
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 3rem;
font-weight: 900;
color: white;
margin-bottom: 0.5rem;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.stat-label {
color: #a0aec0;
font-size: 1.2rem;
font-weight: 500;
}
/* Action Buttons - INSPIRED BY ALL PLATFORMS */
.artist-actions {
display: flex;
gap: 1.5rem;
justify-content: center;
margin-bottom: 3rem;
}
.btn-primary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
.btn-follow {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
border: none;
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
}
.btn-follow:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(72, 187, 120, 0.4);
}
.btn-follow.following {
background: linear-gradient(135deg, #e53e3e, #c53030);
}
.btn-friend {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
}
.btn-friend:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}
.btn-friend.friend {
background: linear-gradient(135deg, #38b2ac, #319795);
}
.btn-message {
background: linear-gradient(135deg, #ed8936, #dd6b20);
color: white;
border: none;
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
}
.btn-message:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(237, 137, 54, 0.4);
}
/* Message Modal Styles */
.message-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
backdrop-filter: blur(10px);
}
.message-modal-content {
background: linear-gradient(135deg, #1a1a1a, #0a0a0a);
border-radius: 20px;
width: 90%;
max-width: 500px;
max-height: 80vh;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
}
.message-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.message-modal-header h3 {
color: white;
margin: 0;
font-size: 1.8rem;
}
.message-modal-title-link {
color: white;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
transition: all 0.3s ease;
cursor: pointer;
padding: 0.25rem 0.5rem;
border-radius: 6px;
}
.message-modal-title-link:hover {
color: #667eea;
background: rgba(102, 126, 234, 0.1);
transform: translateX(2px);
}
.close-modal {
background: none;
border: none;
color: #a0aec0;
font-size: 2rem;
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
}
.close-modal:hover {
background: rgba(255, 255, 255, 0.1);
color: white;
}
.message-modal-body {
flex: 1;
display: flex;
flex-direction: column;
padding: 2rem;
}
.message-history {
flex: 1;
max-height: 300px;
overflow-y: auto;
margin-bottom: 2rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.message {
margin-bottom: 1rem;
display: flex;
}
.message.own-message {
justify-content: flex-end;
}
.message.other-message {
justify-content: flex-start;
}
.message-content {
max-width: 70%;
padding: 1rem 1.5rem;
border-radius: 18px;
position: relative;
}
.own-message .message-content {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-bottom-right-radius: 4px;
}
.other-message .message-content {
background: rgba(255, 255, 255, 0.1);
color: white;
border-bottom-left-radius: 4px;
}
.message-text {
margin-bottom: 0.5rem;
line-height: 1.4;
}
.message-time {
font-size: 0.8rem;
opacity: 0.7;
}
.message-input-container {
display: flex;
gap: 1rem;
align-items: flex-end;
}
#messageInput {
flex: 1;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem;
color: white;
font-size: 1.4rem;
resize: none;
min-height: 50px;
max-height: 100px;
}
#messageInput:focus {
outline: none;
border-color: rgba(102, 126, 234, 0.5);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.send-message-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
white-space: nowrap;
}
.send-message-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}
.send-message-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.loading-messages,
.no-messages,
.error-messages {
text-align: center;
color: #a0aec0;
padding: 2rem;
font-size: 1.4rem;
}
.error-messages {
color: #e53e3e;
}
/* Social Links */
.social-links {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 2rem;
}
.social-link {
width: 50px;
height: 50px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.8rem;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.social-link:hover {
background: rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
/* Main Content Area */
.main-content {
background: #0a0a0a;
min-height: 100vh;
padding: 4rem 0;
position: relative;
z-index: 1;
}
.content-container {
max-width: 120rem;
margin: 0 auto;
display: grid;
grid-template-columns: 2fr 1fr;
gap: 4rem;
position: relative;
z-index: 2;
}
/* Music Marketplace - Modern Design */
.music-marketplace {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
backdrop-filter: blur(20px);
border-radius: 24px;
padding: 3rem;
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
position: relative;
z-index: 3;
}
.marketplace-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
padding-bottom: 2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.header-content h2.marketplace-title {
font-size: 2.8rem;
font-weight: 800;
color: white;
margin: 0 0 0.5rem 0;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.marketplace-subtitle {
font-size: 1.4rem;
color: #a0aec0;
margin: 0;
font-weight: 400;
}
.header-actions {
display: flex;
gap: 1rem;
}
.filter-btn,
.sort-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem 1.5rem;
color: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.3rem;
font-weight: 500;
}
.filter-btn:hover,
.sort-btn:hover {
background: rgba(102, 126, 234, 0.3);
border-color: rgba(102, 126, 234, 0.5);
transform: translateY(-2px);
}
/* Filter Bar */
.filter-bar {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 2rem;
margin-bottom: 3rem;
border: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
gap: 2rem;
align-items: center;
}
.filter-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.filter-group label {
font-size: 1.2rem;
color: #a0aec0;
font-weight: 500;
}
.filter-select {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 0.8rem 1rem;
color: white;
font-size: 1.3rem;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-select:hover {
border-color: rgba(102, 126, 234, 0.5);
}
.filter-select option {
background: #1a1a1a;
color: white;
}
/* Music Grid */
.music-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
}
.music-card {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
border-radius: 20px;
padding: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.music-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #667eea, #764ba2, #667eea);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.music-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.2);
}
.music-card:hover::before {
transform: scaleX(1);
}
.card-header {
display: flex;
gap: 1.5rem;
margin-bottom: 2rem;
}
.music-artwork {
position: relative;
flex-shrink: 0;
}
.artwork-placeholder {
width: 80px;
height: 80px;
border-radius: 16px;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 2.4rem;
color: white;
font-weight: 700;
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.sale-badge {
position: absolute;
top: -8px;
right: -8px;
background: linear-gradient(135deg, #e53e3e, #c53030);
color: white;
padding: 0.4rem 0.8rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 700;
box-shadow: 0 4px 15px rgba(229, 62, 62, 0.4);
}
.music-info {
flex: 1;
}
.music-title {
font-size: 1.8rem;
font-weight: 700;
color: white;
margin: 0 0 1rem 0;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.music-meta {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.genre-tag,
.mood-tag {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
padding: 0.4rem 0.8rem;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
border: 1px solid rgba(102, 126, 234, 0.3);
}
.mood-tag {
background: rgba(72, 187, 120, 0.2);
color: #48bb78;
border-color: rgba(72, 187, 120, 0.3);
}
.music-details {
display: flex;
gap: 1.5rem;
color: #a0aec0;
font-size: 1.2rem;
}
.music-details span {
display: flex;
align-items: center;
gap: 0.5rem;
}
.card-body {
margin-bottom: 2rem;
}
.preview-section {
margin-bottom: 2rem;
}
.waveform-preview {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 1rem;
margin-bottom: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.waveform-canvas {
width: 100%;
height: 40px;
border-radius: 8px;
}
.preview-controls {
display: flex;
justify-content: space-between;
align-items: center;
}
.preview-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 12px;
padding: 0.8rem 1.5rem;
font-size: 1.2rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.preview-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.preview-duration {
color: #a0aec0;
font-size: 1.2rem;
font-weight: 500;
}
.pricing-section {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.price-info {
display: flex;
align-items: center;
gap: 1rem;
}
.original-price {
color: #a0aec0;
font-size: 1.4rem;
text-decoration: line-through;
font-weight: 500;
}
.current-price {
font-size: 2.4rem;
font-weight: 800;
color: #48bb78;
text-shadow: 0 2px 10px rgba(72, 187, 120, 0.3);
}
.purchase-actions {
display: flex;
gap: 1rem;
}
.buy-btn {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
border: none;
border-radius: 12px;
padding: 1rem 2rem;
font-size: 1.3rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.buy-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(72, 187, 120, 0.4);
}
.wishlist-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem;
color: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.wishlist-btn:hover {
background: rgba(229, 62, 62, 0.2);
border-color: rgba(229, 62, 62, 0.5);
transform: scale(1.05);
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 1.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.track-stats {
display: flex;
gap: 1.5rem;
}
.stat-item {
display: flex;
align-items: center;
gap: 0.5rem;
color: #a0aec0;
font-size: 1.2rem;
font-weight: 500;
}
.stat-item i {
color: #667eea;
font-size: 1rem;
}
.license-info {
display: flex;
align-items: center;
}
.license-badge {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
padding: 0.4rem 0.8rem;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
border: 1px solid rgba(102, 126, 234, 0.3);
}
/* Empty Store */
.empty-store {
text-align: center;
padding: 4rem 2rem;
color: #a0aec0;
}
.empty-store .empty-icon {
font-size: 6rem;
margin-bottom: 2rem;
opacity: 0.5;
}
.empty-store h3 {
font-size: 2.4rem;
color: white;
margin: 0 0 1rem 0;
}
.empty-store p {
font-size: 1.4rem;
margin: 0 0 2rem 0;
}
/* Load More Section */
.load-more-section {
text-align: center;
padding-top: 2rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.load-more-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 16px;
padding: 1.2rem 3rem;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 1rem;
}
.load-more-btn:hover {
transform: translateY(-2px);
box-shadow: 0 12px 40px rgba(102, 126, 234, 0.4);
}
/* Legacy Tracks Section Styles (keeping for compatibility) */
.tracks-section {
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 3rem;
border: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
z-index: 3;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
}
.section-title {
font-size: 2.4rem;
font-weight: 700;
color: white;
margin: 0;
}
.track-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.track-item {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 2rem;
display: flex;
align-items: center;
gap: 2rem;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.track-item:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(10px);
border-color: rgba(102, 126, 234, 0.3);
}
.track-artwork {
width: 80px;
height: 80px;
border-radius: 10px;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: white;
font-weight: bold;
flex-shrink: 0;
}
.track-info {
flex: 1;
}
.track-title {
font-size: 1.6rem;
font-weight: 600;
color: white;
margin-bottom: 0.5rem;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.track-meta {
color: #a0aec0;
font-size: 1.2rem;
margin-bottom: 0.5rem;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.track-stats {
display: flex;
gap: 2rem;
color: #718096;
font-size: 1.1rem;
}
.track-actions {
display: flex;
gap: 1rem;
}
.track-btn {
width: 40px;
height: 40px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.track-btn.play-btn {
background: linear-gradient(135deg, #667eea, #764ba2) !important;
border: 2px solid #667eea !important;
font-size: 1.2rem !important;
font-weight: bold !important;
}
.track-btn:hover {
background: rgba(102, 126, 234, 0.3);
transform: scale(1.1);
}
/* Enhanced Sidebar - Modern Design */
.enhanced-sidebar {
display: flex;
flex-direction: column;
gap: 2.5rem;
}
/* Ensure enhanced sidebar works with existing grid layout */
.sidebar.enhanced-sidebar {
align-self: start;
}
.enhanced-sidebar-section {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
backdrop-filter: blur(20px);
border-radius: 24px;
padding: 2.5rem;
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.enhanced-sidebar-section:hover {
transform: translateY(-2px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.2);
}
/* Modern Section Headers */
.section-header-modern {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2.5rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.header-content {
display: flex;
align-items: center;
gap: 1.2rem;
}
.header-icon {
font-size: 2.4rem;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.section-title-modern {
font-size: 2rem;
font-weight: 700;
color: white;
margin: 0;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.section-subtitle {
font-size: 1.3rem;
color: #a0aec0;
margin: 0;
font-weight: 400;
}
.header-action {
display: flex;
gap: 0.8rem;
}
.refresh-btn,
.stats-toggle {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 0.8rem;
color: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
}
.refresh-btn:hover,
.stats-toggle:hover {
background: rgba(102, 126, 234, 0.3);
border-color: rgba(102, 126, 234, 0.5);
transform: scale(1.05);
}
/* Legacy Sidebar Styles (keeping for compatibility) */
.sidebar {
display: flex;
flex-direction: column;
gap: 3rem;
}
.sidebar-section {
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 2.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.sidebar-title {
font-size: 1.8rem;
font-weight: 600;
color: white;
margin-bottom: 2rem;
display: flex;
align-items: center;
gap: 1rem;
}
/* Artist Highlights - INSPIRED BY BEATPORT */
.highlights-list {
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.highlight-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.highlight-item:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(5px);
}
.highlight-item i {
color: #fbbf24;
font-size: 1.2rem;
}
.highlight-item span {
color: #e2e8f0;
font-size: 1.3rem;
font-weight: 500;
}
/* Achievements - INSPIRED BY DJ MAG */
.achievements-list {
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.achievement-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.achievement-item:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(5px);
}
.achievement-item i {
color: #f59e0b;
font-size: 1.2rem;
}
.achievement-item span {
color: #e2e8f0;
font-size: 1.3rem;
font-weight: 500;
}
/* Influences & Equipment - INSPIRED BY LAST.FM */
.influences-content,
.equipment-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
background: rgba(255, 255, 255, 0.03);
padding: 1.5rem;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
/* Artist Statement - INSPIRED BY BANDCAMP */
.statement-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.7;
font-style: italic;
background: rgba(102, 126, 234, 0.1);
padding: 2rem;
border-radius: 15px;
border-left: 4px solid #667eea;
position: relative;
}
.statement-content::before {
content: '"';
font-size: 4rem;
color: #667eea;
position: absolute;
top: -1rem;
left: 1rem;
opacity: 0.3;
}
/* Enhanced Similar Artists - Modern Design */
.artists-grid {
display: grid;
gap: 1.5rem;
}
.artist-card-modern {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
border-radius: 20px;
padding: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
cursor: pointer;
position: relative;
overflow: hidden;
}
.artist-card-modern::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, #667eea, #764ba2, #667eea);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.artist-card-modern:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
border-color: rgba(255, 255, 255, 0.2);
}
.artist-card-modern:hover::before {
transform: scaleX(1);
}
.artist-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.artist-avatar-modern {
position: relative;
}
.avatar-placeholder {
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
color: white;
font-weight: 700;
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
}
.artist-status {
position: relative;
}
.status-dot {
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.2);
}
.status-dot.online {
background: #48bb78;
box-shadow: 0 0 10px rgba(72, 187, 120, 0.5);
}
.status-dot.offline {
background: #a0aec0;
}
.artist-card-body {
margin-bottom: 1.5rem;
}
.artist-name-modern {
font-size: 1.6rem;
font-weight: 700;
color: white;
margin: 0 0 1rem 0;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.artist-meta {
display: flex;
gap: 1.5rem;
}
.meta-item {
display: flex;
align-items: center;
gap: 0.5rem;
color: #a0aec0;
font-size: 1.2rem;
font-weight: 500;
}
.meta-item i {
color: #667eea;
font-size: 1rem;
}
.artist-card-footer {
display: flex;
justify-content: flex-end;
}
.follow-btn-mini {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
border: none;
border-radius: 12px;
padding: 0.8rem 1.5rem;
font-size: 1.2rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.follow-btn-mini:hover {
transform: scale(1.05);
box-shadow: 0 4px 20px rgba(72, 187, 120, 0.4);
}
.follow-btn-mini.following {
background: linear-gradient(135deg, #e53e3e, #c53030);
}
.empty-state {
text-align: center;
padding: 3rem 2rem;
color: #a0aec0;
}
.empty-icon {
font-size: 4rem;
margin-bottom: 1rem;
opacity: 0.5;
}
.empty-state h4 {
font-size: 1.8rem;
color: white;
margin: 0 0 0.5rem 0;
}
.empty-state p {
font-size: 1.3rem;
margin: 0;
}
/* Enhanced Stats Grid */
.stats-grid-modern {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
margin-bottom: 2.5rem;
}
.stat-card {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
border-radius: 16px;
padding: 1.8rem;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, #667eea, #764ba2);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
border-color: rgba(255, 255, 255, 0.2);
}
.stat-card:hover::before {
transform: scaleX(1);
}
.stat-icon {
width: 50px;
height: 50px;
border-radius: 12px;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
}
.stat-icon i {
color: white;
font-size: 1.8rem;
}
.stat-content {
margin-bottom: 1rem;
}
.stat-number {
font-size: 2.4rem;
font-weight: 800;
color: white;
margin-bottom: 0.3rem;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.stat-label {
font-size: 1.2rem;
color: #a0aec0;
font-weight: 500;
}
.stat-trend {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 1.1rem;
font-weight: 600;
padding: 0.4rem 0.8rem;
border-radius: 8px;
width: fit-content;
}
.stat-trend.positive {
background: rgba(72, 187, 120, 0.2);
color: #48bb78;
border: 1px solid rgba(72, 187, 120, 0.3);
}
.stat-trend.negative {
background: rgba(245, 101, 101, 0.2);
color: #f56565;
border: 1px solid rgba(245, 101, 101, 0.3);
}
.stat-trend.neutral {
background: rgba(160, 174, 192, 0.2);
color: #a0aec0;
border: 1px solid rgba(160, 174, 192, 0.3);
}
/* Stats Summary */
.stats-summary {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.summary-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.summary-item:last-child {
margin-bottom: 0;
}
.summary-label {
font-size: 1.3rem;
color: #a0aec0;
font-weight: 500;
}
.rating-display {
display: flex;
align-items: center;
gap: 0.8rem;
}
.stars {
display: flex;
gap: 0.2rem;
}
.stars i {
color: #fbbf24;
font-size: 1.2rem;
}
.rating-text {
font-size: 1.2rem;
color: white;
font-weight: 600;
}
.engagement-bar {
position: relative;
width: 80px;
height: 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
overflow: hidden;
}
.engagement-fill {
height: 100%;
background: linear-gradient(90deg, #48bb78, #38a169);
border-radius: 4px;
transition: width 0.3s ease;
}
.engagement-text {
position: absolute;
right: -30px;
top: 50%;
transform: translateY(-50%);
font-size: 1.1rem;
color: white;
font-weight: 600;
}
/* Legacy Similar Artists Styles (keeping for compatibility) */
.similar-artists {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.similar-artist {
display: flex;
align-items: center;
gap: 1.5rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.similar-artist:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(5px);
}
.similar-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
color: white;
font-weight: bold;
flex-shrink: 0;
}
.similar-info {
flex: 1;
}
.similar-name {
font-size: 1.4rem;
font-weight: 600;
color: white;
margin-bottom: 0.3rem;
}
.similar-stats {
color: #a0aec0;
font-size: 1.1rem;
}
/* Bio Section - INSPIRED BY LAST.FM */
.bio-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
margin-bottom: 2rem;
}
.bio-more {
color: #667eea;
cursor: pointer;
font-weight: 600;
}
/* NEW: Top Artist Information Section - Feng Shui Design */
.artist-info-top {
background: linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 50%, #0f0f0f 100%);
padding: 4rem 0;
position: relative;
overflow: hidden;
}
.artist-info-top::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(102,126,234,0.05)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
opacity: 0.3;
}
.info-container {
max-width: 120rem;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2.5rem;
position: relative;
z-index: 2;
}
.info-card {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 20px;
padding: 2.5rem;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
}
.info-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #667eea, #764ba2, #667eea);
background-size: 200% 100%;
animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.info-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.3);
}
.info-title {
font-size: 2rem;
font-weight: 700;
color: white;
margin-bottom: 2rem;
display: flex;
align-items: center;
gap: 1rem;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
/* Specific card styles for visual hierarchy */
.highlights-card {
background: linear-gradient(135deg, rgba(251, 191, 36, 0.1), rgba(245, 158, 11, 0.1));
border-color: rgba(251, 191, 36, 0.3);
}
.highlights-card:hover {
border-color: rgba(251, 191, 36, 0.5);
box-shadow: 0 20px 40px rgba(251, 191, 36, 0.2);
}
.about-card {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
border-color: rgba(102, 126, 234, 0.3);
}
.about-card:hover {
border-color: rgba(102, 126, 234, 0.5);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.2);
}
.influences-card {
background: linear-gradient(135deg, rgba(72, 187, 120, 0.1), rgba(56, 161, 105, 0.1));
border-color: rgba(72, 187, 120, 0.3);
}
.influences-card:hover {
border-color: rgba(72, 187, 120, 0.5);
box-shadow: 0 20px 40px rgba(72, 187, 120, 0.2);
}
.equipment-card {
background: linear-gradient(135deg, rgba(237, 137, 54, 0.1), rgba(221, 107, 32, 0.1));
border-color: rgba(237, 137, 54, 0.3);
}
.equipment-card:hover {
border-color: rgba(237, 137, 54, 0.5);
box-shadow: 0 20px 40px rgba(237, 137, 54, 0.2);
}
.achievements-card {
background: linear-gradient(135deg, rgba(245, 158, 11, 0.1), rgba(217, 119, 6, 0.1));
border-color: rgba(245, 158, 11, 0.3);
}
.achievements-card:hover {
border-color: rgba(245, 158, 11, 0.5);
box-shadow: 0 20px 40px rgba(245, 158, 11, 0.2);
}
.statement-card {
background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(147, 51, 234, 0.1));
border-color: rgba(168, 85, 247, 0.3);
}
.statement-card:hover {
border-color: rgba(168, 85, 247, 0.5);
box-shadow: 0 20px 40px rgba(168, 85, 247, 0.2);
}
/* Enhanced content styles for the top section */
.artist-info-top .highlights-list {
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.artist-info-top .highlight-item {
display: flex;
align-items: center;
gap: 1.2rem;
padding: 1.2rem;
background: rgba(255, 255, 255, 0.08);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.artist-info-top .highlight-item:hover {
background: rgba(255, 255, 255, 0.12);
transform: translateX(8px);
}
.artist-info-top .highlight-item i {
color: #fbbf24;
font-size: 1.4rem;
flex-shrink: 0;
}
.artist-info-top .highlight-item span {
color: #e2e8f0;
font-size: 1.4rem;
font-weight: 500;
line-height: 1.4;
}
.artist-info-top .achievements-list {
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.artist-info-top .achievement-item {
display: flex;
align-items: center;
gap: 1.2rem;
padding: 1.2rem;
background: rgba(255, 255, 255, 0.08);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.artist-info-top .achievement-item:hover {
background: rgba(255, 255, 255, 0.12);
transform: translateX(8px);
}
.artist-info-top .achievement-item i {
color: #f59e0b;
font-size: 1.4rem;
flex-shrink: 0;
}
.artist-info-top .achievement-item span {
color: #e2e8f0;
font-size: 1.4rem;
font-weight: 500;
line-height: 1.4;
}
.artist-info-top .influences-content,
.artist-info-top .equipment-content {
color: #e2e8f0;
font-size: 1.5rem;
line-height: 1.7;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.artist-info-top .statement-content {
color: #e2e8f0;
font-size: 1.5rem;
line-height: 1.7;
font-style: italic;
padding: 2rem;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.15), rgba(118, 75, 162, 0.15));
border-radius: 15px;
border: 1px solid rgba(102, 126, 234, 0.2);
text-align: center;
position: relative;
}
.artist-info-top .statement-content::before {
content: '"';
font-size: 4rem;
color: #667eea;
position: absolute;
top: -1rem;
left: 1rem;
opacity: 0.3;
}
.artist-info-top .bio-content {
color: #e2e8f0;
font-size: 1.5rem;
line-height: 1.7;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.artist-info-top .bio-more {
color: #667eea;
cursor: pointer;
font-weight: 600;
text-decoration: underline;
transition: color 0.3s ease;
}
.artist-info-top .bio-more:hover {
color: #5a67d8;
}
/* Placeholder styles for empty content */
.placeholder-text {
color: #a0aec0;
font-style: italic;
font-size: 1.3rem;
line-height: 1.6;
text-align: center;
padding: 1rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 10px;
border: 1px dashed rgba(255, 255, 255, 0.2);
}
.highlight-item.placeholder,
.achievement-item.placeholder {
opacity: 0.7;
background: rgba(255, 255, 255, 0.03);
border: 1px dashed rgba(255, 255, 255, 0.2);
}
.highlight-item.placeholder i,
.achievement-item.placeholder i {
opacity: 0.5;
}
.highlight-item.placeholder span,
.achievement-item.placeholder span {
color: #a0aec0;
font-style: italic;
}
/* Ensure proper spacing and visibility */
.artist-info-top {
margin-bottom: 2rem;
}
.info-container {
padding: 0 2rem;
}
/* Fix for potential CSS conflicts */
.artist-info-top .info-card {
margin-bottom: 0;
display: block;
visibility: visible;
opacity: 1;
}
/* Ensure proper z-index and positioning */
.artist-info-top {
position: relative;
z-index: 10;
}
.info-container {
position: relative;
z-index: 11;
}
/* Responsive Design */
@media (max-width: 1024px) {
.hero-content {
grid-template-columns: 1fr;
gap: 3rem;
}
.content-container {
grid-template-columns: 1fr;
gap: 3rem;
}
.info-container {
grid-template-columns: 1fr;
gap: 2rem;
padding: 0 2rem;
}
}
@media (max-width: 768px) {
.artist-name {
font-size: 2.8rem;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.artist-actions {
flex-direction: column;
align-items: center;
}
.track-item {
flex-direction: column;
text-align: center;
gap: 1.5rem;
}
.info-container {
padding: 0 1rem;
}
.info-card {
padding: 2rem;
}
.info-title {
font-size: 1.8rem;
}
}
@media (max-width: 768px) {
.artist-name {
font-size: 2.8rem;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.artist-actions {
flex-direction: column;
align-items: center;
}
.track-item {
flex-direction: column;
text-align: center;
gap: 1.5rem;
}
}
/* Track Player - SOUNDCLOUD STYLE */
.track-player {
margin: 1.5rem 0;
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.player-controls {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 1rem;
}
.play-btn {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
border: none;
color: white;
font-size: 1.8rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.play-btn:hover {
transform: scale(1.1);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
.play-btn.playing {
background: linear-gradient(135deg, #e53e3e, #c53030);
}
.player-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.track-time {
display: flex;
justify-content: space-between;
color: #a0aec0;
font-size: 1.2rem;
font-weight: 500;
}
.progress-bar {
position: relative;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
cursor: pointer;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 3px;
width: 0%;
transition: width 0.1s ease;
position: relative;
}
.progress-handle {
position: absolute;
top: 50%;
left: 0%;
width: 12px;
height: 12px;
background: white;
border-radius: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
opacity: 0;
transition: opacity 0.3s ease;
}
.progress-bar:hover .progress-handle {
opacity: 1;
}
.volume-control {
display: flex;
align-items: center;
gap: 0.8rem;
color: #a0aec0;
}
.volume-icon {
font-size: 1.4rem;
cursor: pointer;
}
.volume-slider {
width: 80px;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
outline: none;
cursor: pointer;
}
.volume-slider::-webkit-slider-thumb {
appearance: none;
width: 12px;
height: 12px;
background: white;
border-radius: 50%;
cursor: pointer;
}
.waveform-container {
height: 60px;
background: rgba(0, 0, 0, 0.2);
border-radius: 8px;
overflow: hidden;
position: relative;
}
.waveform {
width: 100%;
height: 100%;
cursor: pointer;
}
/* Enhanced Track Item */
.track-item {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 2rem;
display: flex;
align-items: flex-start;
gap: 2rem;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
}
.track-item:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(10px);
border-color: rgba(102, 126, 234, 0.3);
}
.track-item.playing {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.5);
box-shadow: 0 0 30px rgba(102, 126, 234, 0.2);
}
.track-item.playing::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 0 2px 2px 0;
}
.track-btn.liked {
background: rgba(229, 62, 62, 0.3);
border-color: rgba(229, 62, 62, 0.5);
color: #e53e3e;
}
.track-btn.liked:hover {
background: rgba(229, 62, 62, 0.4);
transform: scale(1.1);
}
/* Track Status Styles */
.track-item.processing {
opacity: 0.8;
border-color: rgba(255, 193, 7, 0.3);
}
.track-item.failed {
opacity: 0.7;
border-color: rgba(220, 53, 69, 0.3);
}
.track-item.complete {
border-color: rgba(40, 167, 69, 0.3);
}
.status-badge {
position: absolute;
top: -5px;
right: -5px;
background: rgba(0, 0, 0, 0.8);
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
border: 2px solid rgba(255, 255, 255, 0.2);
}
.track-artwork {
position: relative;
}
.status-text {
color: #a0aec0;
font-size: 0.9em;
}
.track-status-message {
margin: 1rem 0;
padding: 1rem;
border-radius: 10px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.processing-message {
display: flex;
align-items: center;
gap: 0.5rem;
color: #ffc107;
}
.processing-message .spinner {
animation: spin 2s linear infinite;
}
.failed-message {
color: #dc3545;
}
.unknown-status {
color: #6c757d;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes waveformPulse {
0% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.4);
transform: scale(1);
}
50% {
box-shadow: 0 0 0 10px rgba(102, 126, 234, 0.1);
transform: scale(1.02);
}
100% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.4);
transform: scale(1);
}
}
/* Profile editing styles */
.edit-field {
width: 100%;
max-width: 400px;
margin: 0.5rem auto;
color: var(--text-primary);
font-family: inherit;
}
.edit-field:focus {
outline: none;
border-color: var(--primary-gradient);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
.artist-bio {
margin-top: 1rem;
text-align: center;
max-width: 500px;
margin-left: auto;
margin-right: auto;
}
.artist-bio p {
font-size: 1.4rem;
color: #e2e8f0;
line-height: 1.6;
margin: 0;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.btn-success {
background: linear-gradient(135deg, #28a745, #20c997);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin: 0 0.5rem;
}
.btn-success:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-medium);
}
.btn-success:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
/* Comments Modal */
.comments-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 10000;
backdrop-filter: blur(10px);
}
.comments-modal-content {
background: var(--bg-card);
border-radius: 20px;
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
border: 1px solid var(--border-light);
}
.comments-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem;
border-bottom: 1px solid var(--border-light);
}
.comments-modal-header h3 {
color: white;
font-size: 2rem;
margin: 0;
}
.close-modal {
background: none;
border: none;
color: #a0aec0;
font-size: 2rem;
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.close-modal:hover {
color: white;
background: rgba(255, 255, 255, 0.1);
}
.comments-list {
max-height: 400px;
overflow-y: auto;
padding: 2rem;
}
.comment-item {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
padding-bottom: 2rem;
border-bottom: 1px solid var(--border-light);
}
.comment-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.comment-avatar {
flex-shrink: 0;
}
.comment-avatar .default-avatar {
width: 40px;
height: 40px;
font-size: 1.6rem;
}
.comment-avatar img {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
.comment-content {
flex: 1;
}
.comment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.comment-author {
color: white;
font-weight: 600;
font-size: 1.4rem;
}
.comment-date {
color: #a0aec0;
font-size: 1.2rem;
}
.comment-text {
color: #e2e8f0;
line-height: 1.6;
font-size: 1.4rem;
}
.comment-form {
padding: 2rem;
border-top: 1px solid var(--border-light);
background: rgba(255, 255, 255, 0.02);
}
.comment-form textarea {
width: 100%;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 1rem;
color: white;
font-size: 1.4rem;
resize: vertical;
margin-bottom: 1rem;
}
.comment-form textarea:focus {
outline: none;
border-color: var(--primary-gradient);
}
.loading-comments, .no-comments {
text-align: center;
color: #a0aec0;
font-size: 1.4rem;
padding: 2rem;
}
/* Notifications */
.notification {
position: fixed;
top: 100px;
right: 20px;
background: var(--bg-card);
color: white;
padding: 1.5rem 2rem;
border-radius: 12px;
box-shadow: var(--shadow-medium);
border: 2px solid var(--border-medium);
z-index: 10001;
transform: translateX(100%);
transition: transform 0.3s ease;
max-width: 300px;
}
.notification.show {
transform: translateX(0);
}
.notification-content {
display: flex;
align-items: center;
gap: 1rem;
}
.notification-success {
border-color: #28a745;
}
.notification-error {
border-color: #dc3545;
}
.notification-info {
border-color: #17a2b8;
}
/* Avatar upload styles */
.artist-avatar {
position: relative;
cursor: pointer;
}
.avatar-upload-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.artist-avatar:hover .avatar-upload-overlay {
opacity: 1;
}
.upload-label {
color: white;
text-align: center;
cursor: pointer;
font-size: 1.2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.upload-label i {
font-size: 2rem;
}
.upload-label span {
font-size: 1rem;
font-weight: 500;
}
.avatar-upload-overlay.active {
opacity: 1;
}
/* Genre Tags - INSPIRED BY BEATPORT & SPOTIFY */
.genre-tags {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
justify-content: center;
margin: 1.5rem 0;
}
.genre-tag {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
color: #667eea;
padding: 0.6rem 1.2rem;
border-radius: 20px;
font-size: 1.2rem;
font-weight: 600;
border: 1px solid rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
cursor: pointer;
}
.genre-tag:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.4), rgba(118, 75, 162, 0.4));
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.genre-input-container {
margin: 1.5rem 0;
text-align: center;
}
.genre-suggestions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
justify-content: center;
margin-top: 1rem;
}
.suggestion {
background: rgba(255, 255, 255, 0.1);
color: #a0aec0;
padding: 0.4rem 0.8rem;
border-radius: 15px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.suggestion:hover {
background: rgba(102, 126, 234, 0.3);
color: white;
transform: scale(1.05);
}
/* Music Style - INSPIRED BY LAST.FM */
.music-style {
margin: 1.5rem 0;
text-align: center;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.music-style:hover {
background: rgba(255, 255, 255, 0.08);
transform: translateY(-2px);
}
.style-label {
font-size: 1.2rem;
font-weight: 600;
color: #667eea;
margin-bottom: 0.8rem;
}
.style-text {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
font-style: italic;
}
}
.style-label {
font-size: 1.2rem;
color: #667eea;
font-weight: 600;
margin-bottom: 0.5rem;
}
.style-text {
font-size: 1.4rem;
color: #e2e8f0;
font-style: italic;
line-height: 1.4;
}
/* Enhanced Sidebar Sections */
.highlights-list, .achievements-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.highlight-item, .achievement-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.highlight-item:hover, .achievement-item:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateX(5px);
}
.highlight-item i {
color: #fbbf24;
font-size: 1.2rem;
}
.achievement-item i {
color: #f59e0b;
font-size: 1.2rem;
}
.highlight-item span, .achievement-item span {
color: #e2e8f0;
font-size: 1.3rem;
line-height: 1.4;
}
.influences-content, .equipment-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.statement-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
font-style: italic;
padding: 1.5rem;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
border-radius: 12px;
border: 1px solid rgba(102, 126, 234, 0.2);
text-align: center;
}
/* Enhanced Bio Section */
.bio-content {
color: #e2e8f0;
font-size: 1.4rem;
line-height: 1.6;
margin-bottom: 2rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.bio-more {
color: #667eea;
cursor: pointer;
font-weight: 600;
text-decoration: underline;
}
.bio-more:hover {
color: #5a67d8;
}
</style>
<div class="artist-hero">
<div class="hero-content">
<!-- Artist Profile -->
<div class="artist-profile">
<div class="artist-avatar" id="artistAvatarContainer">
<?php if ($artist['profile_image']): ?>
<img src="<?= htmlspecialchars($artist['profile_image']) ?>" alt="<?= htmlspecialchars(ucwords(strtolower($artist['username']))) ?>" id="artistAvatarImage">
<?php else: ?>
<div class="default-avatar" id="artistAvatarDefault"><?= substr(htmlspecialchars(ucwords(strtolower($artist['username']))), 0, 1) ?></div>
<?php endif; ?>
<?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $artist['id']): ?>
<div class="avatar-upload-overlay" id="avatarUploadOverlay" style="display: none;">
<label for="profileImageUpload" class="upload-label">
<i class="fas fa-camera"></i>
<span>Change Photo</span>
</label>
<input type="file" id="profileImageUpload" accept="image/*" style="display: none;">
</div>
<?php endif; ?>
</div>
<h1 class="artist-name" id="artistNameDisplay"><?= htmlspecialchars(ucwords(strtolower($artist['username']))) ?></h1>
<input type="text" class="form-input edit-field" id="artistNameEdit" value="<?= htmlspecialchars($artist['username']) ?>" style="display: none; font-size: 2.4rem; font-weight: 700; text-align: center; background: transparent; border: 2px solid var(--primary-gradient); border-radius: 8px; padding: 0.5rem;">
<div class="artist-badge"><?= htmlspecialchars($artist['badge']) ?></div>
<div class="artist-location" id="locationDisplay">
<?php if ($artist['location']): ?>
๐ <?= htmlspecialchars($artist['location']) ?>
<?php endif; ?>
</div>
<input type="text" class="form-input edit-field" id="locationEdit" value="<?= htmlspecialchars($artist['location'] ?? '') ?>" placeholder="Enter your location" style="display: none; text-align: center; background: transparent; border: 2px solid var(--primary-gradient); border-radius: 8px; padding: 0.5rem;">
<!-- Genre Tags -->
<?php
$genres = json_decode($artist['genres'] ?? '[]', true);
if (!empty($genres)):
?>
<div class="genre-tags" id="genreDisplay">
<?php foreach ($genres as $genre): ?>
<span class="genre-tag"><?= htmlspecialchars($genre) ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="genre-input-container" id="genreEdit" style="display: none;">
<input type="text" class="form-input edit-field" id="genreInput" placeholder="Add genres (comma separated)" value="<?= htmlspecialchars(implode(', ', $genres ?? [])) ?>" style="text-align: center;">
<div class="genre-suggestions">
<span class="suggestion" onclick="addGenre('House')">House</span>
<span class="suggestion" onclick="addGenre('Techno')">Techno</span>
<span class="suggestion" onclick="addGenre('Trance')">Trance</span>
<span class="suggestion" onclick="addGenre('Dubstep')">Dubstep</span>
<span class="suggestion" onclick="addGenre('Drum & Bass')">Drum & Bass</span>
<span class="suggestion" onclick="addGenre('Ambient')">Ambient</span>
<span class="suggestion" onclick="addGenre('Chillout')">Chillout</span>
<span class="suggestion" onclick="addGenre('Progressive')">Progressive</span>
</div>
</div>
<!-- Music Style -->
<?php if ($artist['music_style']): ?>
<div class="music-style" id="styleDisplay">
<div class="style-label">๐ต Style:</div>
<div class="style-text"><?= htmlspecialchars($artist['music_style']) ?></div>
</div>
<?php endif; ?>
<textarea class="form-input edit-field" id="styleEdit" rows="2" placeholder="Describe your unique music style..." style="display: none; text-align: center; background: transparent; border: 2px solid var(--primary-gradient); border-radius: 8px; padding: 0.5rem; resize: vertical;"><?= htmlspecialchars($artist['music_style'] ?? '') ?></textarea>
<div class="artist-bio" id="bioDisplay">
<?php if ($artist['bio']): ?>
<p><?= htmlspecialchars($artist['bio']) ?></p>
<?php endif; ?>
</div>
<textarea class="form-input edit-field" id="bioEdit" rows="3" placeholder="Tell us about your musical journey..." style="display: none; text-align: center; background: transparent; border: 2px solid var(--primary-gradient); border-radius: 8px; padding: 0.5rem; resize: vertical;"><?= htmlspecialchars($artist['bio'] ?? '') ?></textarea>
<!-- Social Links -->
<?php if ($artist['social_links']): ?>
<div class="social-links">
<?php
$social_links = json_decode($artist['social_links'], true);
if ($social_links):
foreach ($social_links as $platform => $url):
?>
<a href="<?= htmlspecialchars($url) ?>" target="_blank" class="social-link">
<?php
$icon = match($platform) {
'facebook' => '๐',
'twitter' => '๐ฆ',
'instagram' => '๐ท',
'youtube' => '๐บ',
'soundcloud' => 'โ๏ธ',
'spotify' => '๐ต',
default => '๐'
};
echo $icon;
?>
</a>
<?php
endforeach;
endif;
?>
</div>
<?php endif; ?>
</div>
<!-- Stats Section -->
<div class="artist-stats">
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['followers_count']) ?></div>
<div class="stat-label">Followers</div>
</div>
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['total_plays']) ?></div>
<div class="stat-label">Total Plays</div>
</div>
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['completed_tracks']) ?></div>
<div class="stat-label">Tracks</div>
</div>
</div>
<div class="artist-actions">
<?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $artist['id']): ?>
<!-- Edit Profile Button for own profile -->
<button class="btn-primary" onclick="toggleEditMode()" id="editProfileBtn">
<i class="fas fa-edit"></i> Edit Profile
</button>
<button class="btn-success" onclick="saveProfileChanges()" id="saveProfileBtn" style="display: none;">
<i class="fas fa-save"></i> Save Changes
</button>
<button class="btn-secondary" onclick="cancelEditMode()" id="cancelProfileBtn" style="display: none;">
<i class="fas fa-times"></i> Cancel
</button>
<?php else: ?>
<!-- Follow/Play buttons for other profiles -->
<button class="btn-primary" onclick="playArtistRadio()">
๐ต Play Artist Radio
</button>
<button class="btn-follow <?= $is_following ? 'following' : '' ?>"
onclick="toggleFollow(<?= $artist['id'] ?>, this)"
data-artist-id="<?= $artist['id'] ?>">
<?= $is_following ? 'โค๏ธ Following' : 'โ Follow' ?>
</button>
<button class="btn-friend <?= $is_friend ? 'friend' : '' ?>"
onclick="toggleFriend(<?= $artist['id'] ?>, this)"
data-artist-id="<?= $artist['id'] ?>">
<?= $is_friend ? '๐ฅ Friends' : '๐ค Add Friend' ?>
</button>
<button class="btn-message" onclick="openMessageModal(<?= $artist['id'] ?>, '<?= htmlspecialchars($artist['username']) ?>')">
๐ฌ Message
</button>
<?php endif; ?>
<button class="btn-secondary" onclick="shareArtist()">
๐ค Share
</button>
</div>
</div>
<!-- Quick Stats -->
<div class="artist-stats">
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['following_count']) ?></div>
<div class="stat-label">Following</div>
</div>
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['total_plays']) ?></div>
<div class="stat-label">Total Plays</div>
</div>
<div class="stat-item">
<div class="stat-number"><?= number_format($artist['completed_tracks']) ?></div>
<div class="stat-label">Tracks</div>
</div>
</div>
<div class="artist-actions">
<button class="btn-secondary" onclick="viewAllTracks()">
๐ผ View All Tracks
</button>
<button class="btn-secondary" onclick="viewDiscography()">
๐ Discography
</button>
</div>
</div>
</div>
</div>
<!-- NEW: Top Artist Information Section - Feng Shui Reorganization -->
<div class="artist-info-top">
<div class="info-container">
<!-- Artist Highlights - Always show with placeholder if empty -->
<div class="info-card highlights-card">
<h3 class="info-title">โญ Highlights</h3>
<div class="highlights-list">
<?php
$highlights = json_decode($artist['artist_highlights'] ?? '[]', true);
if (!empty($highlights)):
foreach ($highlights as $highlight): ?>
<div class="highlight-item">
<i class="fas fa-star"></i>
<span><?= htmlspecialchars($highlight) ?></span>
</div>
<?php endforeach;
else: ?>
<div class="highlight-item placeholder">
<i class="fas fa-star"></i>
<span>No highlights yet. Add your achievements!</span>
</div>
<?php endif; ?>
</div>
</div>
<!-- About Section - Always show -->
<div class="info-card about-card">
<h3 class="info-title">๐ About</h3>
<div class="bio-content">
<?php if ($artist['bio']): ?>
<?= nl2br(htmlspecialchars(substr($artist['bio'], 0, 300))) ?>
<?php if (strlen($artist['bio']) > 300): ?>
<span class="bio-more" onclick="showFullBio()">... read more</span>
<?php endif; ?>
<?php else: ?>
<span class="placeholder-text">No bio yet. Tell us about your musical journey!</span>
<?php endif; ?>
</div>
</div>
<!-- Influences - Always show -->
<div class="info-card influences-card">
<h3 class="info-title">๐ญ Influences</h3>
<div class="influences-content">
<?php if ($artist['influences']): ?>
<?= nl2br(htmlspecialchars($artist['influences'])) ?>
<?php else: ?>
<span class="placeholder-text">No influences listed yet. Share your musical inspirations!</span>
<?php endif; ?>
</div>
</div>
<!-- Equipment - Always show -->
<div class="info-card equipment-card">
<h3 class="info-title">๐๏ธ Equipment</h3>
<div class="equipment-content">
<?php if ($artist['equipment']): ?>
<?= nl2br(htmlspecialchars($artist['equipment'])) ?>
<?php else: ?>
<span class="placeholder-text">No equipment listed yet. Share your studio setup!</span>
<?php endif; ?>
</div>
</div>
<!-- Achievements - Always show -->
<div class="info-card achievements-card">
<h3 class="info-title">๐ Achievements</h3>
<div class="achievements-list">
<?php
$achievements = json_decode($artist['achievements'] ?? '[]', true);
if (!empty($achievements)):
foreach ($achievements as $achievement): ?>
<div class="achievement-item">
<i class="fas fa-trophy"></i>
<span><?= htmlspecialchars($achievement) ?></span>
</div>
<?php endforeach;
else: ?>
<div class="achievement-item placeholder">
<i class="fas fa-trophy"></i>
<span>No achievements yet. Add your accomplishments!</span>
</div>
<?php endif; ?>
</div>
</div>
<!-- Artist Statement - Always show -->
<div class="info-card statement-card">
<h3 class="info-title">๐ญ Artist Statement</h3>
<div class="statement-content">
<?php if ($artist['artist_statement']): ?>
<em>"<?= htmlspecialchars($artist['artist_statement']) ?>"</em>
<?php else: ?>
<span class="placeholder-text">No artist statement yet. Share your vision!</span>
<?php endif; ?>
</div>
</div>
</div>
</div>
<div class="main-content">
<div class="content-container">
<!-- Music Marketplace Section -->
<div class="music-marketplace">
<div class="marketplace-header">
<div class="header-content">
<h2 class="marketplace-title">๐ต Music Store</h2>
<p class="marketplace-subtitle">Purchase and download high-quality tracks</p>
</div>
<div class="header-actions">
<button class="filter-btn" onclick="toggleFilters()">
<i class="fas fa-filter"></i>
Filters
</button>
<button class="sort-btn" onclick="toggleSortOptions()">
<i class="fas fa-sort"></i>
Sort
</button>
</div>
</div>
<!-- Filter Bar -->
<div class="filter-bar" id="filterBar" style="display: none;">
<div class="filter-group">
<label>Genre:</label>
<select class="filter-select" onchange="filterTracks()">
<option value="">All Genres</option>
<option value="rock">Rock</option>
<option value="pop">Pop</option>
<option value="electronic">Electronic</option>
<option value="hip-hop">Hip-Hop</option>
<option value="jazz">Jazz</option>
</select>
</div>
<div class="filter-group">
<label>Price Range:</label>
<select class="filter-select" onchange="filterTracks()">
<option value="">All Prices</option>
<option value="0-5">$0 - $5</option>
<option value="5-10">$5 - $10</option>
<option value="10+">$10+</option>
</select>
</div>
<div class="filter-group">
<label>Duration:</label>
<select class="filter-select" onchange="filterTracks()">
<option value="">Any Duration</option>
<option value="0-60">Under 1 min</option>
<option value="60-180">1-3 min</option>
<option value="180+">Over 3 min</option>
</select>
</div>
</div>
<!-- Music Grid -->
<div class="music-grid">
<?php if (empty($tracks)): ?>
<div class="empty-store">
<div class="empty-icon">๐ต</div>
<h3>No Music Available</h3>
<p>This artist hasn't published any tracks for sale yet.</p>
<button class="btn-primary" onclick="contactArtist()">Contact Artist</button>
</div>
<?php else: ?>
<?php foreach ($tracks as $track): ?>
<?php
$status = $track['status'];
$hasAudio = !empty($track['audio_url']);
$isPlayable = $status === 'complete' && $hasAudio;
// Use actual pricing from database
$price = $track['price'] ?? '1.99';
$originalPrice = '14.99';
$isOnSale = false; // No sales for now
$discount = 0;
// Use default genre and mood (can be extracted from metadata later)
$genre = 'Electronic';
$mood = 'Energetic';
// Try to extract genre/mood from metadata if available
if (!empty($track['metadata'])) {
$metadata = json_decode($track['metadata'], true);
if ($metadata) {
if (!empty($metadata['genre'])) $genre = $metadata['genre'];
if (!empty($metadata['mood'])) $mood = $metadata['mood'];
}
}
$displayTitle = $track['title'];
if (empty($displayTitle)) {
// Generate title from prompt if available
if (!empty($track['prompt'])) {
$displayTitle = substr($track['prompt'], 0, 50);
if (strlen($track['prompt']) > 50) {
$displayTitle .= '...';
}
} else {
$displayTitle = 'Untitled Track';
}
}
?>
<div class="music-card" data-track-id="<?= $track['id'] ?>" data-genre="<?= strtolower($genre) ?>" data-price="<?= $price ?>" data-duration="<?= $track['duration'] ?? 0 ?>" data-audio-url="<?= htmlspecialchars($track['audio_url']) ?>" data-title="<?= htmlspecialchars($displayTitle) ?>">
<div class="card-header">
<div class="music-artwork">
<div class="artwork-placeholder">
<span><?= substr(htmlspecialchars($displayTitle), 0, 1) ?></span>
</div>
<?php if ($isOnSale): ?>
<div class="sale-badge">-<?= $discount ?>%</div>
<?php endif; ?>
</div>
<div class="music-info">
<h3 class="music-title"><?= htmlspecialchars($displayTitle) ?></h3>
<div class="music-meta">
<span class="genre-tag"><?= $genre ?></span>
<span class="mood-tag"><?= $mood ?></span>
</div>
<div class="music-details">
<span class="duration">
<i class="fas fa-clock"></i>
<?= $track['duration'] ? gmdate('i:s', $track['duration']) : '0:00' ?>
</span>
<span class="quality">
<i class="fas fa-music"></i>
High Quality
</span>
</div>
</div>
</div>
<div class="card-body">
<div class="preview-section">
<div class="waveform-preview">
<canvas class="waveform-canvas" width="300" height="40"></canvas>
</div>
<div class="preview-controls">
<button class="preview-btn play-track-btn"
onclick="playTrack(<?= $track['id'] ?>, '<?= htmlspecialchars($track['audio_url'], ENT_QUOTES) ?>', '<?= htmlspecialchars($displayTitle, ENT_QUOTES) ?>', '<?= htmlspecialchars($artist['username'], ENT_QUOTES) ?>')"
data-audio-url="<?= htmlspecialchars($track['audio_url']) ?>"
data-title="<?= htmlspecialchars($displayTitle) ?>"
data-artist="<?= htmlspecialchars($artist['username']) ?>"
data-track-id="<?= $track['id'] ?>">
<i class="fas fa-play"></i>
Preview
</button>
<span class="preview-duration">30s</span>
</div>
</div>
<div class="pricing-section">
<div class="price-info">
<?php if ($isOnSale): ?>
<div class="original-price">$<?= number_format($originalPrice, 2) ?></div>
<?php endif; ?>
<div class="current-price">$<?= $price ?></div>
</div>
<div class="purchase-actions">
<button class="buy-btn" onclick="purchaseTrack(<?= $track['id'] ?>, '<?= htmlspecialchars($displayTitle) ?>', <?= $price ?>)">
<i class="fas fa-shopping-cart"></i>
Buy Now
</button>
<button class="wishlist-btn" onclick="toggleWishlist(<?= $track['id'] ?>, this)">
<i class="far fa-heart"></i>
</button>
</div>
</div>
</div>
<div class="card-footer">
<div class="track-stats">
<span class="stat-item">
<i class="fas fa-play"></i>
<?= number_format($track['play_count']) ?>
</span>
<span class="stat-item">
<i class="fas fa-heart"></i>
<?= number_format($track['like_count']) ?>
</span>
<span class="stat-item">
<i class="fas fa-download"></i>
<?= number_format($track['play_count'] ?? 0) ?>
</span>
</div>
<div class="license-info">
<span class="license-badge">Commercial License</span>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- Load More Section -->
<div class="load-more-section">
<button class="load-more-btn" onclick="loadMoreTracks()">
<i class="fas fa-plus"></i>
Load More Tracks
</button>
</div>
</div>
<!-- Enhanced Sidebar - Modern Design -->
<div class="sidebar enhanced-sidebar">
<!-- Enhanced Similar Artists Section -->
<div class="enhanced-sidebar-section similar-artists-section">
<div class="section-header-modern">
<div class="header-content">
<div class="header-icon">๐ต</div>
<div class="header-text">
<h3 class="section-title-modern">Similar Artists</h3>
<p class="section-subtitle">Artists you might like</p>
</div>
</div>
<div class="header-action">
<button class="refresh-btn" onclick="refreshSimilarArtists()">
<i class="fas fa-sync-alt"></i>
</button>
</div>
</div>
<div class="artists-grid">
<?php if (!empty($similar_artists)): ?>
<?php foreach ($similar_artists as $similar): ?>
<div class="artist-card-modern" onclick="loadArtistProfile(<?= $similar['id'] ?>)">
<div class="artist-card-header">
<div class="artist-avatar-modern">
<div class="avatar-placeholder">
<span><?= strtoupper(substr($similar['username'], 0, 1)) ?></span>
</div>
</div>
<div class="artist-status">
<div class="status-dot online"></div>
</div>
</div>
<div class="artist-card-body">
<h4 class="artist-name-modern"><?= htmlspecialchars($similar['username']) ?></h4>
<div class="artist-meta">
<span class="meta-item">
<i class="fas fa-users"></i>
<?= number_format($similar['followers_count']) ?>
</span>
<span class="meta-item">
<i class="fas fa-music"></i>
<?= $similar['track_count'] ?>
</span>
</div>
</div>
<div class="artist-card-footer">
<button class="follow-btn-mini" onclick="event.stopPropagation(); toggleFollow(<?= $similar['id'] ?>, this)">
<i class="fas fa-heart"></i>
<span>Follow</span>
</button>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<div class="empty-state">
<div class="empty-icon">๐ญ</div>
<h4>No Similar Artists</h4>
<p>We're still discovering artists like this one</p>
</div>
<?php endif; ?>
</div>
</div>
<!-- Enhanced Quick Stats Section -->
<div class="enhanced-sidebar-section stats-section">
<div class="section-header-modern">
<div class="header-content">
<div class="header-icon">๐</div>
<div class="header-text">
<h3 class="section-title-modern">Artist Statistics</h3>
<p class="section-subtitle">Performance overview</p>
</div>
</div>
<div class="header-action">
<button class="stats-toggle" onclick="toggleStatsView()">
<i class="fas fa-chart-line"></i>
</button>
</div>
</div>
<div class="stats-grid-modern">
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-music"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= number_format($artist['completed_tracks']) ?></div>
<div class="stat-label">Tracks Created</div>
</div>
<div class="stat-trend positive">
<i class="fas fa-arrow-up"></i>
<span>12%</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-user-plus"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= number_format($artist['following_count']) ?></div>
<div class="stat-label">Following</div>
</div>
<div class="stat-trend positive">
<i class="fas fa-arrow-up"></i>
<span>8%</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-headphones"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= number_format($artist['total_plays']) ?></div>
<div class="stat-label">Total Plays</div>
</div>
<div class="stat-trend positive">
<i class="fas fa-arrow-up"></i>
<span>23%</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-heart"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= number_format($artist['total_likes']) ?></div>
<div class="stat-label">Total Likes</div>
</div>
<div class="stat-trend positive">
<i class="fas fa-arrow-up"></i>
<span>15%</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-clock"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= number_format(floor($artist['total_duration'] / 3600)) ?></div>
<div class="stat-label">Hours of Music</div>
</div>
<div class="stat-trend neutral">
<i class="fas fa-minus"></i>
<span>0%</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="fas fa-calendar-alt"></i>
</div>
<div class="stat-content">
<div class="stat-number"><?= date('M Y', strtotime($artist['joined_date'])) ?></div>
<div class="stat-label">Member Since</div>
</div>
<div class="stat-trend neutral">
<i class="fas fa-minus"></i>
<span>-</span>
</div>
</div>
</div>
<div class="stats-summary">
<div class="summary-item">
<span class="summary-label">Average Rating</span>
<div class="rating-display">
<div class="stars">
<i class="fas fa-star"></i>
<i class="fas fa-star"></i>
<i class="fas fa-star"></i>
<i class="fas fa-star"></i>
<i class="far fa-star"></i>
</div>
<span class="rating-text">4.2/5</span>
</div>
</div>
<div class="summary-item">
<span class="summary-label">Engagement Rate</span>
<div class="engagement-bar">
<div class="engagement-fill" style="width: 78%"></div>
<span class="engagement-text">78%</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// ULTIMATE ARTIST PROFILE JAVASCRIPT
// Simple notification system if not already defined
if (typeof window.showNotification === 'undefined') {
window.showNotification = function(message, type = 'info') {
console.log(`[${type.toUpperCase()}] ${message}`);
// Create notification element
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? '#48bb78' : type === 'error' ? '#e53e3e' : '#667eea'};
color: white;
padding: 1rem 2rem;
border-radius: 8px;
z-index: 10000;
font-weight: 600;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
transform: translateX(100%);
transition: transform 0.3s ease;
`;
notification.textContent = message;
document.body.appendChild(notification);
// Animate in
setTimeout(() => {
notification.style.transform = 'translateX(0)';
}, 100);
// Remove after 3 seconds
setTimeout(() => {
notification.style.transform = 'translateX(100%)';
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 3000);
};
}
// Toggle follow function with heart burst effect
function toggleFollow(artistId, button) {
console.log('toggleFollow called with artistId:', artistId);
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
alert('Please log in to follow artists');
return;
}
// Show loading state
const originalText = button.innerHTML;
button.innerHTML = 'โณ...';
button.disabled = true;
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'follow', user_id: artistId })
})
.then(response => {
console.log('Response status:', response.status);
return response.json();
})
.then(data => {
console.log('Follow response:', data);
if (data.success) {
const wasFollowing = button.classList.contains('following');
button.classList.toggle('following');
if (!wasFollowing) {
button.innerHTML = 'โค๏ธ Following';
createHeartBurst(button);
if (typeof window.showNotification === 'function') {
window.showNotification('Successfully followed! ๐', 'success');
}
} else {
button.innerHTML = 'โ Follow';
if (typeof window.showNotification === 'function') {
window.showNotification('Unfollowed artist', 'info');
}
}
// Update follower count
updateFollowerCount();
} else {
console.error('Follow action failed:', data.message);
button.innerHTML = originalText;
if (typeof window.showNotification === 'function') {
window.showNotification(data.message || 'Failed to follow artist', 'error');
}
}
})
.catch(error => {
console.error('Follow request failed:', error);
button.innerHTML = originalText;
if (typeof window.showNotification === 'function') {
window.showNotification('Network error - please try again', 'error');
}
})
.finally(() => {
button.disabled = false;
});
}
// Create heart burst effect
function createHeartBurst(button) {
const buttonRect = button.getBoundingClientRect();
const buttonCenterX = buttonRect.left + buttonRect.width / 2;
const buttonCenterY = buttonRect.top + buttonRect.height / 2;
// Create multiple hearts with different delays and positions
for (let i = 0; i < 8; i++) {
setTimeout(() => {
const heart = document.createElement('div');
heart.innerHTML = '๐';
heart.style.cssText = `
position: fixed;
left: ${buttonCenterX + (Math.random() - 0.5) * 40}px;
top: ${buttonCenterY + (Math.random() - 0.5) * 20}px;
font-size: ${20 + Math.random() * 15}px;
z-index: 9999;
pointer-events: none;
animation: float-heart 2s ease-out forwards;
`;
document.body.appendChild(heart);
// Remove heart after animation
setTimeout(() => {
if (heart.parentNode) {
heart.parentNode.removeChild(heart);
}
}, 2000);
}, i * 100);
}
}
// Toggle friend function
function toggleFriend(artistId, button) {
console.log('toggleFriend called with artistId:', artistId);
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
alert('Please log in to add friends');
return;
}
// Show loading state
const originalText = button.innerHTML;
button.innerHTML = 'โณ...';
button.disabled = true;
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'friend_request', friend_id: artistId })
})
.then(response => response.json())
.then(data => {
console.log('Friend response:', data);
if (data.success) {
const wasFriend = button.classList.contains('friend');
button.classList.toggle('friend');
if (!wasFriend) {
button.innerHTML = '๐ฅ Friends';
if (typeof window.showNotification === 'function') {
window.showNotification('Friend request sent! ๐ฅ', 'success');
}
} else {
button.innerHTML = '๐ค Add Friend';
if (typeof window.showNotification === 'function') {
window.showNotification('Friend removed', 'info');
}
}
} else {
console.error('Friend action failed:', data.message);
button.innerHTML = originalText;
if (typeof window.showNotification === 'function') {
window.showNotification(data.message || 'Failed to send friend request', 'error');
}
}
})
.catch(error => {
console.error('Friend request failed:', error);
button.innerHTML = originalText;
if (typeof window.showNotification === 'function') {
window.showNotification('Network error - please try again', 'error');
}
})
.finally(() => {
button.disabled = false;
});
}
// Open message modal
function openMessageModal(artistId, artistName) {
console.log('openMessageModal called with artistId:', artistId, 'artistName:', artistName);
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
alert('Please log in to send messages');
return;
}
// Create modal HTML
const modalHTML = `
<div id="messageModal" class="message-modal">
<div class="message-modal-content">
<div class="message-modal-header">
<h3>
<a href="/messages.php?user_id=${artistId}" class="message-modal-title-link" onclick="closeMessageModal()">
๐ฌ Message ${artistName}
</a>
</h3>
<button class="close-modal" onclick="closeMessageModal()">ร</button>
</div>
<div class="message-modal-body">
<div id="messageHistory" class="message-history">
<div class="loading-messages">Loading messages...</div>
</div>
<div class="message-input-container">
<textarea id="messageInput" placeholder="Type your message..." maxlength="500"></textarea>
<button onclick="sendMessage(${artistId})" class="send-message-btn">
<i class="fas fa-paper-plane"></i> Send
</button>
</div>
</div>
</div>
</div>
`;
// Add modal to page
document.body.insertAdjacentHTML('beforeend', modalHTML);
// Load existing messages
loadMessages(artistId);
// Focus on input
setTimeout(() => {
const messageInput = document.getElementById('messageInput');
if (messageInput) {
messageInput.focus();
}
}, 100);
}
// Close message modal
function closeMessageModal() {
const modal = document.getElementById('messageModal');
if (modal) {
modal.remove();
}
}
// Load messages
function loadMessages(artistId) {
const messageHistory = document.getElementById('messageHistory');
fetch(`/api_social.php?action=get_messages&user_id=${artistId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
displayMessages(data.messages);
} else {
messageHistory.innerHTML = '<div class="no-messages">No messages yet. Start a conversation!</div>';
}
})
.catch(error => {
console.error('Failed to load messages:', error);
messageHistory.innerHTML = '<div class="error-messages">Failed to load messages</div>';
});
}
// Display messages
function displayMessages(messages) {
const messageHistory = document.getElementById('messageHistory');
if (messages.length === 0) {
messageHistory.innerHTML = '<div class="no-messages">No messages yet. Start a conversation!</div>';
return;
}
const messagesHTML = messages.map(message => {
const isOwnMessage = message.sender_id == <?= $_SESSION['user_id'] ?? 0 ?>;
const messageClass = isOwnMessage ? 'own-message' : 'other-message';
const time = new Date(message.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
return `
<div class="message ${messageClass}">
<div class="message-content">
<div class="message-text">${escapeHtml(message.message)}</div>
<div class="message-time">${time}</div>
</div>
</div>
`;
}).join('');
messageHistory.innerHTML = messagesHTML;
messageHistory.scrollTop = messageHistory.scrollHeight;
}
// Send message
function sendMessage(artistId) {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value.trim();
if (!message) {
return;
}
// Disable input and button
messageInput.disabled = true;
const sendBtn = document.querySelector('.send-message-btn');
sendBtn.disabled = true;
sendBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'send_message',
receiver_id: artistId,
message: message
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
messageInput.value = '';
loadMessages(artistId); // Reload messages to show new one
if (typeof window.showNotification === 'function') {
window.showNotification('Message sent! ๐ฌ', 'success');
}
} else {
if (typeof window.showNotification === 'function') {
window.showNotification(data.message || 'Failed to send message', 'error');
}
}
})
.catch(error => {
console.error('Failed to send message:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Network error - please try again', 'error');
}
})
.finally(() => {
messageInput.disabled = false;
sendBtn.disabled = false;
sendBtn.innerHTML = '<i class="fas fa-paper-plane"></i> Send';
});
}
// Helper function to escape HTML
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Update follower count
function updateFollowerCount() {
const followerElements = document.querySelectorAll('.stat-number');
followerElements.forEach(element => {
const label = element.nextElementSibling;
if (label && label.textContent === 'Followers') {
const currentCount = parseInt(element.textContent.replace(/,/g, ''));
element.textContent = (currentCount + 1).toLocaleString();
}
});
}
// Play artist radio
function playArtistRadio() {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ต Starting artist radio...', 'info');
}
// This would integrate with your music player
setTimeout(() => {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ต Now playing: <?= htmlspecialchars($artist['username']) ?> Radio', 'success');
}
}, 1000);
}
// Share artist
function shareArtist() {
const shareData = {
title: '<?= htmlspecialchars($artist['username']) ?> on SoundStudioPro',
text: 'Check out <?= htmlspecialchars($artist['username']) ?>\'s amazing music on SoundStudioPro!',
url: window.location.href
};
if (navigator.share) {
navigator.share(shareData);
} else {
// Fallback: copy to clipboard
navigator.clipboard.writeText(window.location.href);
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Link copied to clipboard!', 'success');
}
}
}
// View all tracks
function viewAllTracks() {
// This would navigate to a full tracks page
if (typeof window.showNotification === 'function') {
window.showNotification('๐ผ Loading all tracks...', 'info');
}
}
// View discography
function viewDiscography() {
// This would show a comprehensive discography
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Loading discography...', 'info');
}
}
// REMOVED: playTrackDirectly function - using simplified approach
// Simple test function to debug play button
async function testPlayButton(audioUrl, title, artist, trackId) {
// Validate audio URL
if (!audioUrl || audioUrl === 'null' || audioUrl === 'undefined') {
console.error('๐ต Invalid audio URL:', audioUrl);
if (typeof window.showNotification === 'function') {
window.showNotification('Invalid audio URL', 'error');
}
return false;
}
// Check if global function exists
// Try global player first (preferred method)
if (typeof window.playTrackWithGlobalPlayer === 'function') {
try {
// Ensure global player is ready
if (typeof window.ensureGlobalPlayer === 'function') {
await window.ensureGlobalPlayer();
}
const result = window.playTrackWithGlobalPlayer(audioUrl, title, artist, trackId);
if (result) {
if (typeof window.showNotification === 'function') {
window.showNotification(`๐ต Now playing: ${title}`, 'success');
}
// Record play for this specific track
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'play', track_id: trackId })
}).catch(error => console.error('Play tracking failed:', error));
return true;
} else {
console.error('๐ต Global player failed to start');
throw new Error('Global player returned false');
}
} catch (error) {
console.error('๐ต Global player error:', error);
// Fall through to direct audio method
}
}
// Fallback to direct audio if global player fails
try {
const audio = new Audio(audioUrl);
audio.volume = 0.8;
// Add loading indicator
const playBtn = document.querySelector(`[data-track-id="${trackId}"]`);
if (playBtn) {
const originalContent = playBtn.innerHTML;
playBtn.innerHTML = '<span>โณ</span>';
playBtn.disabled = true;
// Reset button after a delay
setTimeout(() => {
playBtn.innerHTML = originalContent;
playBtn.disabled = false;
}, 2000);
}
audio.addEventListener('loadedmetadata', () => {
audio.play().then(() => {
if (typeof window.showNotification === 'function') {
window.showNotification(`๐ต Now playing: ${title}`, 'success');
}
// Record play for this specific track
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'play', track_id: trackId })
}).catch(error => console.error('Play tracking failed:', error));
}).catch(error => {
console.error('๐ต Direct audio play failed:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Failed to play track: ' + error.message, 'error');
}
});
});
audio.addEventListener('error', (error) => {
console.error('๐ต Audio load error:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Failed to load track: ' + error.message, 'error');
}
});
} catch (error) {
console.error('๐ต General error:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Failed to play track: ' + error.message, 'error');
}
}
}
// REMOVED: playTrackWithGlobalPlayer function - using global function directly
// Play track (legacy function)
function playTrackLegacy(trackId) {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ต Playing track...', 'info');
}
// This would integrate with your music player
}
// Like track
function likeTrack(trackId) {
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
const likeBtn = trackItem.querySelector('.like-btn');
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
alert('Please log in to like tracks');
return;
}
// Send like request to server
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'like', track_id: trackId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Toggle like state
likeBtn.classList.toggle('liked');
if (likeBtn.classList.contains('liked')) {
likeBtn.innerHTML = 'โค๏ธ';
likeBtn.style.color = '#e53e3e';
if (typeof window.showNotification === 'function') {
window.showNotification('โค๏ธ Track liked!', 'success');
}
} else {
likeBtn.innerHTML = '๐ค';
likeBtn.style.color = 'white';
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Track unliked', 'info');
}
}
} else {
console.error('Like action failed:', data.message);
if (typeof window.showNotification === 'function') {
window.showNotification(data.message || 'Failed to like track', 'error');
}
}
})
.catch(error => {
console.error('Like request failed:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Network error - please try again', 'error');
}
});
}
// Share track
function shareTrack(trackId) {
const shareData = {
title: 'Check out this track on SoundStudioPro',
text: 'Listen to amazing music on SoundStudioPro!',
url: window.location.href
};
if (navigator.share) {
navigator.share(shareData);
} else {
// Fallback: copy to clipboard
navigator.clipboard.writeText(window.location.href);
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Track link copied to clipboard!', 'success');
}
}
}
// Add to playlist
function addToPlaylist(trackId) {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Added to playlist!', 'success');
}
// This would add track to user's playlist
}
// Show comments
function showComments(trackId) {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ฌ Loading comments...', 'info');
}
// This would show comments modal
}
// Retry track
function retryTrack(trackId) {
if (confirm('Are you sure you want to retry this track? This will create a new version.')) {
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Retrying track generation...', 'info');
}
// This would retry track generation
}
}
// Delete track
function deleteTrack(trackId) {
if (confirm('Are you sure you want to delete this track? This action cannot be undone.')) {
if (typeof window.showNotification === 'function') {
window.showNotification('๐๏ธ Deleting track...', 'info');
}
// This would delete the track
}
}
// Add to playlist
function addToPlaylist(trackId) {
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
alert('Please log in to add tracks to playlist');
return;
}
if (typeof window.showNotification === 'function') {
window.showNotification('๐ Track added to playlist!', 'success');
}
// This would open a playlist selection modal
// For now, just show a notification
}
// Add genre function
function addGenre(genre) {
const genreInput = document.getElementById('genreInput');
if (genreInput) {
const currentGenres = genreInput.value.split(',').map(g => g.trim()).filter(g => g.length > 0);
if (!currentGenres.includes(genre)) {
currentGenres.push(genre);
genreInput.value = currentGenres.join(', ');
}
}
}
// Show full bio
function showFullBio() {
const bioContent = document.querySelector('.bio-content');
const fullBio = `<?= nl2br(htmlspecialchars($artist['bio'])) ?>`;
bioContent.innerHTML = fullBio;
}
// Load artist profile
function loadArtistProfile(artistId) {
window.location.href = `/artist_profile.php?id=${artistId}`;
}
// Initialize page
document.addEventListener('DOMContentLoaded', function() {
// Debug global player availability
console.log('- window.playTrackWithGlobalPlayer exists:', typeof window.playTrackWithGlobalPlayer === 'function');
console.log('- window.globalPlayer exists:', typeof window.globalPlayer !== 'undefined');
console.log('- globalAudioPlayer element exists:', !!document.getElementById('globalAudioPlayer'));
console.log('- globalPlayer element exists:', !!document.getElementById('globalPlayer'));
console.log('- globalMusicPlayer element exists:', !!document.getElementById('globalMusicPlayer'));
// Check if global player is properly initialized
if (typeof window.globalPlayer !== 'undefined') {
playTrack: typeof window.globalPlayer.playTrack,
init: typeof window.globalPlayer.init,
isPlaying: window.globalPlayer.isPlaying,
wasPlaying: window.globalPlayer.wasPlaying,
userInteracted: window.globalPlayer.userInteracted
});
}
// Add smooth scrolling
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
// Test global player function if available
if (typeof window.playTrackWithGlobalPlayer === 'function') {
} else {
console.warn('๐ต Global playTrackWithGlobalPlayer function is NOT available');
}
// NOTE: Event listeners for preview buttons are set up in the DOMContentLoaded section below
// to avoid conflicts and ensure proper initialization
// Test global player functionality
if (typeof window.testGlobalPlayer === 'function') {
window.testGlobalPlayer();
}
// Add a test button to the page for debugging
const testButton = document.createElement('button');
testButton.textContent = '๐งช Test Global Player';
testButton.style.cssText = 'position: fixed; top: 10px; right: 10px; z-index: 10000; background: red; color: white; padding: 10px; border: none; border-radius: 5px; cursor: pointer;';
testButton.onclick = function() {
if (typeof window.playTrackWithGlobalPlayer === 'function') {
try {
const result = window.playTrackWithGlobalPlayer(
'https://www.soundjay.com/misc/sounds/bell-ringing-05.wav',
'Test Track',
'Test Artist',
999
);
alert('Test result: ' + result);
} catch (error) {
console.error('๐ต Test error:', error);
alert('Test error: ' + error.message);
}
} else {
alert('Global player function not found!');
}
};
document.body.appendChild(testButton);
// Add a test button for the actual track URL
const actualTrackButton = document.createElement('button');
actualTrackButton.textContent = '๐ต Test Actual Track';
actualTrackButton.style.cssText = 'position: fixed; top: 90px; right: 10px; z-index: 10000; background: green; color: white; padding: 10px; border: none; border-radius: 5px; cursor: pointer;';
actualTrackButton.onclick = function() {
// Get the first track's data
const firstTrack = document.querySelector('.preview-btn.play-track-btn');
if (firstTrack) {
const audioUrl = firstTrack.getAttribute('data-audio-url');
const title = firstTrack.getAttribute('data-title');
const artist = firstTrack.getAttribute('data-artist');
const trackId = firstTrack.getAttribute('data-track-id');
if (typeof window.playTrackWithGlobalPlayer === 'function') {
try {
const result = window.playTrackWithGlobalPlayer(audioUrl, title, artist, trackId);
alert('Actual track test result: ' + result);
} catch (error) {
console.error('๐ต Actual track test error:', error);
alert('Actual track test error: ' + error.message);
}
} else {
alert('Global player function not found!');
}
} else {
alert('No track found on page!');
}
};
document.body.appendChild(actualTrackButton);
// Add a simple audio test button
const audioTestButton = document.createElement('button');
audioTestButton.textContent = '๐ Test Direct Audio';
audioTestButton.style.cssText = 'position: fixed; top: 50px; right: 10px; z-index: 10000; background: blue; color: white; padding: 10px; border: none; border-radius: 5px; cursor: pointer;';
audioTestButton.onclick = function() {
const audio = new Audio('https://www.soundjay.com/misc/sounds/bell-ringing-05.wav');
audio.volume = 0.5;
audio.play().then(() => {
alert('Direct audio test successful!');
}).catch(error => {
console.error('๐ต Direct audio test failed:', error);
alert('Direct audio test failed: ' + error.message);
});
};
document.body.appendChild(audioTestButton);
});
// Global Player Integration Variables
let currentTrackId = null;
let audioContext = null;
let analyser = null;
// Initialize audio context for waveform
function initAudioContext() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
}
}
// REMOVED: playTrackWithGlobalPlayerIntegration function - using simplified approach
// Update track playing state
function updateTrackPlayingState(trackId, isPlaying) {
// Reset all tracks
document.querySelectorAll('.track-item').forEach(item => {
item.classList.remove('playing');
const playBtn = item.querySelector('.play-btn');
if (playBtn) {
playBtn.classList.remove('playing');
const playIcon = playBtn.querySelector('.play-icon');
const pauseIcon = playBtn.querySelector('.pause-icon');
if (playIcon && pauseIcon) {
playIcon.style.display = 'block';
pauseIcon.style.display = 'none';
}
}
// Stop waveform animation
animateWaveform(item, false);
});
// Set current track as playing
if (isPlaying && trackId) {
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
if (trackItem) {
trackItem.classList.add('playing');
const playBtn = trackItem.querySelector('.play-btn');
if (playBtn) {
playBtn.classList.add('playing');
const playIcon = playBtn.querySelector('.play-icon');
const pauseIcon = playBtn.querySelector('.pause-icon');
if (playIcon && pauseIcon) {
playIcon.style.display = 'none';
pauseIcon.style.display = 'block';
}
}
// Start waveform animation
animateWaveform(trackItem, true);
}
currentTrackId = trackId;
} else {
currentTrackId = null;
}
}
// Fallback function for individual player (if global player not available)
function playTrackFallback(trackId) {
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
const playBtn = trackItem.querySelector('.play-btn');
const playIcon = playBtn.querySelector('.play-icon');
const pauseIcon = playBtn.querySelector('.pause-icon');
// Get track data
const trackTitle = trackItem.querySelector('.track-title').textContent;
const audioUrl = trackItem.getAttribute('data-audio-url');
// Create audio element
const audio = new Audio();
audio.src = audioUrl;
audio.addEventListener('loadedmetadata', () => {
initAudioContext();
audio.play();
// Update UI
updateTrackPlayingState(trackId, true);
// Generate waveform
generateWaveform(trackItem);
if (typeof window.showNotification === 'function') {
window.showNotification(`๐ต Now playing: ${trackTitle}`, 'success');
}
});
audio.addEventListener('ended', () => {
updateTrackPlayingState(trackId, false);
});
audio.addEventListener('error', () => {
if (typeof window.showNotification === 'function') {
window.showNotification('โ Error loading track', 'error');
}
});
}
playBtn.classList.remove('playing');
playIcon.style.display = 'block';
pauseIcon.style.display = 'none';
}
}
// Reset player state
function resetPlayer(trackId) {
updateTrackPlayingState(trackId, false);
}
// Reset all players
function resetAllPlayers() {
document.querySelectorAll('.track-item').forEach(item => {
const trackId = item.getAttribute('data-track-id');
resetPlayer(trackId);
});
}
// Listen for global player state changes (moved to main DOMContentLoaded)
// Generate waveforms for all tracks on page load
document.querySelectorAll('.track-item').forEach(trackItem => {
generateWaveform(trackItem);
});
// Listen for global player events
window.addEventListener('globalPlayerTrackChanged', function(event) {
const { trackId } = event.detail;
updateTrackPlayingState(trackId, true);
});
window.addEventListener('globalPlayerStopped', function() {
updateTrackPlayingState(null, false);
});
// Format time
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
// Generate waveform
function generateWaveform(trackItem) {
const canvas = trackItem.querySelector('.waveform');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Generate realistic waveform data
const bars = 80;
const barWidth = width / bars;
// Create gradient for better visual appeal
const gradient = ctx.createLinearGradient(0, 0, 0, height);
gradient.addColorStop(0, 'rgba(102, 126, 234, 0.8)');
gradient.addColorStop(1, 'rgba(102, 126, 234, 0.3)');
ctx.fillStyle = gradient;
// Generate waveform pattern
for (let i = 0; i < bars; i++) {
// Create more realistic waveform pattern
const baseHeight = Math.random() * 0.3 + 0.1; // Base height between 10-40%
const variation = Math.sin(i * 0.2) * 0.3; // Sine wave variation
const randomFactor = Math.random() * 0.4; // Random factor
const barHeight = (baseHeight + variation + randomFactor) * height * 0.8;
const x = i * barWidth;
const y = (height - barHeight) / 2;
// Add some bars with different heights for variety
const finalHeight = Math.max(2, barHeight); // Minimum 2px height
ctx.fillRect(x, y, barWidth - 1, finalHeight);
}
}
// Animate waveform for playing tracks
function animateWaveform(trackItem, isPlaying) {
const canvas = trackItem.querySelector('.waveform');
if (!canvas) return;
if (isPlaying) {
// Add pulsing animation to the track item
trackItem.style.animation = 'waveformPulse 2s ease-in-out infinite';
} else {
// Remove animation
trackItem.style.animation = 'none';
}
}
// Progress bar click handler (for global player integration)
document.addEventListener('click', (e) => {
if (e.target.classList.contains('progress-bar')) {
const trackItem = e.target.closest('.track-item');
const trackId = trackItem.getAttribute('data-track-id');
// If this track is currently playing in global player, handle seek
if (currentTrackId === trackId && typeof window.seekGlobalPlayer === 'function') {
const rect = e.target.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const percentage = clickX / rect.width;
window.seekGlobalPlayer(percentage);
}
}
});
// Retry track function
function retryTrack(trackId) {
if (confirm('Are you sure you want to retry this track? This will create a new version.')) {
// Redirect to the main creation page with track info
window.location.href = '/index.php?retry=' + trackId;
}
}
// Delete track function
function deleteTrack(trackId) {
if (confirm('Are you sure you want to delete this track? This action cannot be undone.')) {
fetch('/api/delete_track.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
track_id: trackId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove the track from the UI
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
if (trackItem) {
trackItem.style.opacity = '0.5';
trackItem.style.pointerEvents = 'none';
setTimeout(() => {
trackItem.remove();
}, 500);
}
alert('Track deleted successfully!');
} else {
alert('Error deleting track: ' + (data.message || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('Error deleting track. Please try again.');
});
}
}
// Volume control
document.addEventListener('input', (e) => {
if (e.target.classList.contains('volume-slider') && currentAudio) {
const volume = e.target.value / 100;
currentAudio.volume = volume;
}
});
// Profile editing functions
let isEditMode = false;
let originalData = {};
function toggleEditMode() {
isEditMode = !isEditMode;
if (isEditMode) {
// Store original data
originalData = {
name: document.getElementById('artistNameEdit').value,
location: document.getElementById('locationEdit').value,
bio: document.getElementById('bioEdit').value,
style: document.getElementById('styleEdit')?.value || '',
genres: document.getElementById('genreInput')?.value || ''
};
// Show edit fields
document.getElementById('artistNameDisplay').style.display = 'none';
document.getElementById('artistNameEdit').style.display = 'block';
document.getElementById('locationDisplay').style.display = 'none';
document.getElementById('locationEdit').style.display = 'block';
document.getElementById('bioDisplay').style.display = 'none';
document.getElementById('bioEdit').style.display = 'block';
// Show genre and style edit fields
const genreDisplay = document.getElementById('genreDisplay');
const genreEdit = document.getElementById('genreEdit');
const styleDisplay = document.getElementById('styleDisplay');
const styleEdit = document.getElementById('styleEdit');
if (genreDisplay && genreEdit) {
genreDisplay.style.display = 'none';
genreEdit.style.display = 'block';
}
if (styleDisplay && styleEdit) {
styleDisplay.style.display = 'none';
styleEdit.style.display = 'block';
}
// Show save/cancel buttons
document.getElementById('editProfileBtn').style.display = 'none';
document.getElementById('saveProfileBtn').style.display = 'inline-block';
document.getElementById('cancelProfileBtn').style.display = 'inline-block';
// Focus on name field
document.getElementById('artistNameEdit').focus();
} else {
exitEditMode();
}
}
function exitEditMode() {
// Hide edit fields
document.getElementById('artistNameDisplay').style.display = 'block';
document.getElementById('artistNameEdit').style.display = 'none';
document.getElementById('locationDisplay').style.display = 'block';
document.getElementById('locationEdit').style.display = 'none';
document.getElementById('bioDisplay').style.display = 'block';
document.getElementById('bioEdit').style.display = 'none';
// Hide genre and style edit fields
const genreDisplay = document.getElementById('genreDisplay');
const genreEdit = document.getElementById('genreEdit');
const styleDisplay = document.getElementById('styleDisplay');
const styleEdit = document.getElementById('styleEdit');
if (genreDisplay && genreEdit) {
genreDisplay.style.display = 'block';
genreEdit.style.display = 'none';
}
if (styleDisplay && styleEdit) {
styleDisplay.style.display = 'block';
styleEdit.style.display = 'none';
}
// Show edit button
document.getElementById('editProfileBtn').style.display = 'inline-block';
document.getElementById('saveProfileBtn').style.display = 'none';
document.getElementById('cancelProfileBtn').style.display = 'none';
isEditMode = false;
}
function cancelEditMode() {
// Restore original data
document.getElementById('artistNameEdit').value = originalData.name;
document.getElementById('locationEdit').value = originalData.location;
document.getElementById('bioEdit').value = originalData.bio;
if (document.getElementById('styleEdit')) {
document.getElementById('styleEdit').value = originalData.style;
}
if (document.getElementById('genreInput')) {
document.getElementById('genreInput').value = originalData.genres;
}
exitEditMode();
}
// Profile image upload functionality (moved to main DOMContentLoaded)
// This will be set up in the main DOMContentLoaded listener
function uploadProfileImage(file) {
const formData = new FormData();
formData.append('profile_image', file);
// Show loading state
const avatarContainer = document.getElementById('artistAvatarContainer');
const originalContent = avatarContainer.innerHTML;
avatarContainer.innerHTML = '<div class="default-avatar"><i class="fas fa-spinner fa-spin"></i></div>';
fetch('/api/upload_profile_image.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update avatar display
updateAvatarDisplay(data.image_url);
showNotification('Profile image uploaded successfully!', 'success');
} else {
alert('Error uploading image: ' + (data.error || 'Unknown error'));
avatarContainer.innerHTML = originalContent;
}
})
.catch(error => {
console.error('Error:', error);
alert('Error uploading image. Please try again.');
avatarContainer.innerHTML = originalContent;
});
}
function updateAvatarDisplay(imageUrl) {
const avatarContainer = document.getElementById('artistAvatarContainer');
const artistName = document.getElementById('artistNameDisplay').textContent;
avatarContainer.innerHTML = `
<img src="${imageUrl}" alt="${artistName}" id="artistAvatarImage">
<div class="avatar-upload-overlay" id="avatarUploadOverlay" style="display: none;">
<label for="profileImageUpload" class="upload-label">
<i class="fas fa-camera"></i>
<span>Change Photo</span>
</label>
<input type="file" id="profileImageUpload" accept="image/*" style="display: none;">
</label>
</div>
`;
// Reattach event listeners
const profileImageUpload = document.getElementById('profileImageUpload');
const avatarUploadOverlay = document.getElementById('avatarUploadOverlay');
if (profileImageUpload && avatarContainer) {
avatarContainer.addEventListener('mouseenter', function() {
if (avatarUploadOverlay) {
avatarUploadOverlay.style.display = 'flex';
}
});
avatarContainer.addEventListener('mouseleave', function() {
if (avatarUploadOverlay) {
avatarUploadOverlay.style.display = 'none';
}
});
profileImageUpload.addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
alert('Please select a valid image file.');
return;
}
if (file.size > 5 * 1024 * 1024) {
alert('File size must be less than 5MB.');
return;
}
uploadProfileImage(file);
});
}
}
function saveProfileChanges() {
const name = document.getElementById('artistNameEdit').value.trim();
const location = document.getElementById('locationEdit').value.trim();
const bio = document.getElementById('bioEdit').value.trim();
const musicStyle = document.getElementById('styleEdit')?.value.trim() || '';
const genresInput = document.getElementById('genreInput')?.value.trim() || '';
if (!name) {
alert('Artist name is required!');
return;
}
// Parse genres from comma-separated input
const genres = genresInput.split(',').map(g => g.trim()).filter(g => g.length > 0);
// Show loading state
const saveBtn = document.getElementById('saveProfileBtn');
const originalText = saveBtn.innerHTML;
saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Saving...';
saveBtn.disabled = true;
fetch('/api/update_profile.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name,
location: location,
bio: bio,
music_style: musicStyle,
genres: genres
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update display fields with proper capitalization
const capitalizedName = name.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
document.getElementById('artistNameDisplay').textContent = capitalizedName;
document.getElementById('locationDisplay').innerHTML = location ? `๐ ${location}` : '';
document.getElementById('bioDisplay').innerHTML = bio ? `<p>${bio}</p>` : '';
// Update music style display
const styleDisplay = document.getElementById('styleDisplay');
if (styleDisplay && musicStyle) {
styleDisplay.innerHTML = `
<div class="style-label">๐ต Style:</div>
<div class="style-text">${musicStyle}</div>
`;
}
// Update genre tags display
const genreDisplay = document.getElementById('genreDisplay');
if (genreDisplay && genres.length > 0) {
genreDisplay.innerHTML = genres.map(genre =>
`<span class="genre-tag">${genre}</span>`
).join('');
}
// Update avatar default letter if no image
const avatarDefault = document.getElementById('artistAvatarDefault');
if (avatarDefault) {
avatarDefault.textContent = capitalizedName.charAt(0).toUpperCase();
}
// Update session data in header if it exists
if (typeof updateHeaderUsername === 'function') {
updateHeaderUsername(capitalizedName);
}
// Exit edit mode
exitEditMode();
// Show success message
showNotification('Profile updated successfully!', 'success');
} else {
alert('Error updating profile: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('Error updating profile. Please try again.');
})
.finally(() => {
// Restore button state
saveBtn.innerHTML = originalText;
saveBtn.disabled = false;
});
}
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
// Animate in
setTimeout(() => notification.classList.add('show'), 100);
// Remove after 3 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => document.body.removeChild(notification), 300);
}, 3000);
}
// Comments Modal System
let commentsModal = null;
let currentTrackId = null;
function showComments(trackId) {
currentTrackId = trackId;
// Create modal if it doesn't exist
if (!commentsModal) {
createCommentsModal();
}
// Load comments
loadComments(trackId);
// Show modal
commentsModal.style.display = 'flex';
document.body.style.overflow = 'hidden';
}
function createCommentsModal() {
commentsModal = document.createElement('div');
commentsModal.className = 'comments-modal';
commentsModal.innerHTML = `
<div class="comments-modal-content">
<div class="comments-modal-header">
<h3>Comments</h3>
<button class="close-modal" onclick="closeCommentsModal()">
<i class="fas fa-times"></i>
</button>
</div>
<div class="comments-list" id="commentsList">
<div class="loading-comments">
<i class="fas fa-spinner fa-spin"></i> Loading comments...
</div>
</div>
<div class="comment-form">
<textarea id="commentText" placeholder="Write a comment..." rows="3"></textarea>
<button onclick="addComment()" class="btn btn-primary">
<i class="fas fa-paper-plane"></i> Post Comment
</button>
</div>
</div>
`;
document.body.appendChild(commentsModal);
// Close modal when clicking outside
commentsModal.addEventListener('click', (e) => {
if (e.target === commentsModal) {
closeCommentsModal();
}
});
}
function closeCommentsModal() {
if (commentsModal) {
commentsModal.style.display = 'none';
document.body.style.overflow = 'auto';
}
}
function loadComments(trackId) {
const commentsList = document.getElementById('commentsList');
commentsList.innerHTML = '<div class="loading-comments"><i class="fas fa-spinner fa-spin"></i> Loading comments...</div>';
fetch(`/api_social.php?action=get_comments&track_id=${trackId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
displayComments(data.comments);
} else {
commentsList.innerHTML = '<div class="no-comments">Error loading comments</div>';
}
})
.catch(error => {
console.error('Error loading comments:', error);
commentsList.innerHTML = '<div class="no-comments">Error loading comments</div>';
});
}
function displayComments(comments) {
const commentsList = document.getElementById('commentsList');
if (comments.length === 0) {
commentsList.innerHTML = '<div class="no-comments">No comments yet. Be the first to comment!</div>';
return;
}
commentsList.innerHTML = comments.map(comment => `
<div class="comment-item">
<div class="comment-avatar">
${comment.profile_image ?
`<img src="${comment.profile_image}" alt="${comment.user_name}" onerror="this.parentElement.innerHTML='<div class=\'default-avatar\'>${comment.user_name.charAt(0)}</div>'">` :
`<div class="default-avatar">${comment.user_name.charAt(0)}</div>`
}
</div>
<div class="comment-content">
<div class="comment-header">
<span class="comment-author">${comment.user_name}</span>
<span class="comment-date">${formatDate(comment.created_at)}</span>
</div>
<div class="comment-text">${escapeHtml(comment.comment)}</div>
</div>
</div>
`).join('');
}
function addComment() {
const commentText = document.getElementById('commentText').value.trim();
if (!commentText) {
showNotification('Please enter a comment', 'error');
return;
}
const button = document.querySelector('.comment-form button');
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Posting...';
button.disabled = true;
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'comment',
track_id: currentTrackId,
comment: commentText
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('commentText').value = '';
loadComments(currentTrackId);
showNotification('Comment posted successfully!', 'success');
} else {
showNotification(data.message || 'Error posting comment', 'error');
}
})
.catch(error => {
console.error('Comment error:', error);
showNotification('Error posting comment', 'error');
})
.finally(() => {
button.innerHTML = originalText;
button.disabled = false;
});
}
// Utility functions
function formatDate(dateString) {
const date = new Date(dateString);
const now = new Date();
const diff = now - date;
if (diff < 60000) return 'Just now';
if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
if (diff < 2592000000) return `${Math.floor(diff / 86400000)}d ago`;
return date.toLocaleDateString();
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Enhanced Sidebar Functions
function refreshSimilarArtists() {
const refreshBtn = document.querySelector('.refresh-btn');
const originalIcon = refreshBtn.innerHTML;
// Show loading state
refreshBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
refreshBtn.disabled = true;
// Simulate refresh (in real implementation, this would fetch new data)
setTimeout(() => {
refreshBtn.innerHTML = originalIcon;
refreshBtn.disabled = false;
showNotification('Similar artists refreshed!', 'success');
}, 1500);
}
function toggleStatsView() {
const statsToggle = document.querySelector('.stats-toggle');
const statsGrid = document.querySelector('.stats-grid-modern');
const statsSummary = document.querySelector('.stats-summary');
if (statsGrid.style.display === 'none') {
// Show detailed view
statsGrid.style.display = 'grid';
statsSummary.style.display = 'block';
statsToggle.innerHTML = '<i class="fas fa-chart-line"></i>';
statsToggle.title = 'Switch to compact view';
} else {
// Show compact view
statsGrid.style.display = 'none';
statsSummary.style.display = 'none';
statsToggle.innerHTML = '<i class="fas fa-chart-bar"></i>';
statsToggle.title = 'Switch to detailed view';
}
}
// Enhanced artist card interactions (moved to main DOMContentLoaded)
// This will be set up in the main DOMContentLoaded listener
// Enhanced follow button functionality
function enhancedToggleFollow(artistId, button) {
const originalContent = button.innerHTML;
// Show loading state
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
button.disabled = true;
// Simulate API call
setTimeout(() => {
const wasFollowing = button.classList.contains('following');
if (wasFollowing) {
button.classList.remove('following');
button.innerHTML = '<i class="fas fa-heart"></i><span>Follow</span>';
showNotification('Unfollowed artist', 'info');
} else {
button.classList.add('following');
button.innerHTML = '<i class="fas fa-heart"></i><span>Following</span>';
// Add heart burst effect
const heartBurst = document.createElement('div');
heartBurst.className = 'heart-burst';
heartBurst.innerHTML = '<i class="fas fa-heart"></i>';
button.appendChild(heartBurst);
setTimeout(() => {
if (heartBurst.parentNode) {
heartBurst.parentNode.removeChild(heartBurst);
}
}, 1000);
showNotification('Now following artist!', 'success');
}
button.disabled = false;
}, 800);
}
// Add CSS for heart burst effect
const heartBurstStyle = document.createElement('style');
heartBurstStyle.textContent = `
.heart-burst {
position: absolute;
top: -10px;
right: -10px;
color: #e53e3e;
font-size: 1.5rem;
animation: heartBurst 1s ease-out forwards;
pointer-events: none;
}
@keyframes heartBurst {
0% {
transform: scale(0) rotate(0deg);
opacity: 1;
}
50% {
transform: scale(1.5) rotate(180deg);
opacity: 1;
}
100% {
transform: scale(2) rotate(360deg);
opacity: 0;
}
}
.follow-btn-mini {
position: relative;
}
`;
document.head.appendChild(heartBurstStyle);
// Music Marketplace Functions
function toggleFilters() {
const filterBar = document.getElementById('filterBar');
const filterBtn = document.querySelector('.filter-btn');
if (filterBar.style.display === 'none') {
filterBar.style.display = 'flex';
filterBtn.innerHTML = '<i class="fas fa-times"></i> Hide Filters';
} else {
filterBar.style.display = 'none';
filterBtn.innerHTML = '<i class="fas fa-filter"></i> Filters';
}
}
function toggleSortOptions() {
// Create sort dropdown
const sortOptions = ['Price: Low to High', 'Price: High to Low', 'Duration: Short to Long', 'Duration: Long to Short', 'Most Popular', 'Newest First'];
const sortBtn = document.querySelector('.sort-btn');
// Toggle sort dropdown (simplified for demo)
showNotification('Sort options: ' + sortOptions.join(', '), 'info');
}
function filterTracks() {
const genreFilter = document.querySelector('select[onchange="filterTracks()"]:nth-of-type(1)').value;
const priceFilter = document.querySelector('select[onchange="filterTracks()"]:nth-of-type(2)').value;
const durationFilter = document.querySelector('select[onchange="filterTracks()"]:nth-of-type(3)').value;
const musicCards = document.querySelectorAll('.music-card');
musicCards.forEach(card => {
let show = true;
// Apply filters
if (genreFilter && card.dataset.genre !== genreFilter) {
show = false;
}
if (priceFilter) {
const price = parseFloat(card.dataset.price);
if (priceFilter === '0-5' && price > 5) show = false;
if (priceFilter === '5-10' && (price < 5 || price > 10)) show = false;
if (priceFilter === '10+' && price < 10) show = false;
}
if (durationFilter) {
const duration = parseInt(card.dataset.duration);
if (durationFilter === '0-60' && duration > 60) show = false;
if (durationFilter === '60-180' && (duration < 60 || duration > 180)) show = false;
if (durationFilter === '180+' && duration < 180) show = false;
}
card.style.display = show ? 'block' : 'none';
});
showNotification('Filters applied!', 'success');
}
function playTrackFromCard(audioUrl, title, trackId) {
if (!audioUrl) {
showNotification('Audio not available for this track', 'error');
return;
}
console.log('Playing track from card:', { audioUrl, title, trackId });
// Use the same approach as community_fixed.php
if (!window.enhancedGlobalPlayer || typeof window.enhancedGlobalPlayer.playTrack !== 'function') {
console.error('โ Global player not available');
fallbackPlayTrack(audioUrl, title);
return;
}
try {
// Call the global player's playTrack function
const success = window.enhancedGlobalPlayer.playTrack(audioUrl, title, '<?= htmlspecialchars($artist['username']) ?>');
if (success) {
showNotification(`Now playing: ${title}`, 'success');
// Update UI - Mark this track as currently playing
document.querySelectorAll('.music-card').forEach(card => {
card.classList.remove('currently-playing', 'playing');
});
const currentCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (currentCard) {
currentCard.classList.add('currently-playing', 'playing');
}
console.log('โ
Track playing successfully');
} else {
console.error('โ Global player returned false');
fallbackPlayTrack(audioUrl, title);
}
} catch (error) {
console.error('โ Error during playback:', error);
fallbackPlayTrack(audioUrl, title);
}
}
function fallbackPlayTrack(audioUrl, title) {
// Create a simple audio player if global player is not available
const audio = new Audio(audioUrl);
audio.currentTime = 0;
audio.volume = 0.8;
audio.play().then(() => {
showNotification(`Now playing: ${title}`, 'success');
// Update any existing global player UI if available
updateGlobalPlayerUI(title, '<?= htmlspecialchars($artist['username']) ?>');
}).catch(error => {
console.error('Audio play error:', error);
showNotification('Error playing track', 'error');
});
}
function updateGlobalPlayerUI(title, artist) {
// Try to update global player UI elements if they exist
const playerTitle = document.querySelector('.player-title, .global-player-title, #playerTitle');
const playerArtist = document.querySelector('.player-artist, .global-player-artist, #playerArtist');
if (playerTitle) playerTitle.textContent = title;
if (playerArtist) playerArtist.textContent = artist;
// Update play button state
const playBtn = document.querySelector('.play-btn, .global-play-btn, #playBtn');
if (playBtn) {
playBtn.innerHTML = '<i class="fas fa-pause"></i>';
playBtn.classList.add('playing');
}
}
function previewTrack(audioUrl, title) {
// Alias for playTrackFromCard for backward compatibility
playTrackFromCard(audioUrl, title, 0);
}
// Use global player for track playback (SAME AS COMMUNITY_FIXED.PHP)
function playTrack(trackId, audioUrl, title, artist) {
// Validate audio URL
if (!audioUrl || audioUrl === 'null' || audioUrl === 'undefined' || audioUrl === '') {
console.error('๐ต INVALID AUDIO URL:', audioUrl);
showNotification('Invalid audio URL', 'error');
return;
}
// Use the same approach as community_fixed.php
if (!window.enhancedGlobalPlayer || typeof window.enhancedGlobalPlayer.playTrack !== 'function') {
console.error('โ Global player not available');
showNotification('Audio player not ready. Please refresh the page.', 'error');
return;
}
try {
// Call the global player's playTrack function
const success = window.enhancedGlobalPlayer.playTrack(audioUrl, title, artist);
if (success) {
// Update UI - Mark this track as currently playing
document.querySelectorAll('.music-card').forEach(card => {
card.classList.remove('currently-playing', 'playing');
});
// Reset all play buttons
document.querySelectorAll('.preview-btn.play-track-btn').forEach(btn => {
btn.classList.remove('playing');
const icon = btn.querySelector('i');
if (icon) {
icon.className = 'fas fa-play';
}
});
const currentCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (currentCard) {
currentCard.classList.add('currently-playing', 'playing');
// Update the play button
const currentButton = currentCard.querySelector('.preview-btn.play-track-btn');
if (currentButton) {
currentButton.classList.add('playing');
const icon = currentButton.querySelector('i');
if (icon) icon.className = 'fas fa-pause';
}
}
// Record play analytics if function exists
if (typeof window.recordTrackPlay === 'function') {
window.recordTrackPlay(trackId);
}
// Show notification
showNotification('๐ต Now playing: ' + title, 'success');
console.log('โ
Track playing successfully');
} else {
console.error('โ Global player returned false');
showNotification('Failed to start playback. Please try again.', 'error');
}
} catch (error) {
console.error('โ Error during playback:', error);
showNotification('Playback error: ' + error.message, 'error');
}
}
// Record Track Play (SAME AS COMMUNITY_FIXED.PHP)
function recordTrackPlay(trackId) {
fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=play&track_id=${trackId}`
})
.catch(error => console.error('Play tracking error:', error));
}
// Track play when play button is clicked (EXACTLY LIKE COMMUNITY PAGE)
function trackPlay(trackId) {
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'play', track_id: trackId })
});
}
function purchaseTrack(trackId, title, price) {
if (!<?= isset($_SESSION['user_id']) ? 'true' : 'false' ?>) {
showNotification('Please log in to purchase tracks', 'error');
return;
}
// Redirect to the main artists page with track purchase
window.location.href = `/artists.php?purchase_track=${trackId}`;
}
function loadMoreTracks() {
const loadMoreBtn = document.querySelector('.load-more-btn');
const originalText = loadMoreBtn.innerHTML;
loadMoreBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Loading...';
loadMoreBtn.disabled = true;
// Simulate loading more tracks
setTimeout(() => {
loadMoreBtn.innerHTML = originalText;
loadMoreBtn.disabled = false;
showNotification('No more tracks available', 'info');
}, 1500);
}
function contactArtist() {
showNotification('Contact feature coming soon!', 'info');
}
</script>
<?php
// Global player is handled by footer.php - no need to include here
// include 'global_player.php';
// Include footer
include 'includes/footer.php';
?>
<script>
// Initialize global player integration (SAME AS COMMUNITY_FIXED.PHP)
document.addEventListener('DOMContentLoaded', function() {
// Check if global player is already ready
if (window.globalPlayerReady && window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
enablePlayButtons();
return;
}
// Wait for global player to be ready, then enable play buttons
waitForGlobalPlayer(() => {
enablePlayButtons();
});
});
</script>