![]() 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();
// ALWAYS check if user is logged in - no exceptions
if (!isset($_SESSION['user_id'])) {
header('Location: /auth/login.php');
exit;
}
// Include database configuration
require_once 'config/database.php';
$user = getUserById($_SESSION['user_id']);
$user_name = $user['name'] ?? 'User';
$credits = $_SESSION['credits'] ?? 5;
// Get user stats
$pdo = getDBConnection();
$stmt = $pdo->prepare("
SELECT
COUNT(*) as total_tracks,
COUNT(CASE WHEN status = 'complete' THEN 1 END) as completed_tracks,
COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing_tracks,
COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed_tracks,
AVG(CASE WHEN status = 'complete' THEN duration END) as avg_duration,
SUM(CASE WHEN status = 'complete' THEN duration END) as total_duration
FROM music_tracks
WHERE user_id = ?
");
$stmt->execute([$_SESSION['user_id']]);
$user_stats = $stmt->fetch();
// Get user's music tracks with enhanced data and variations
$status_filter = $_GET['status'] ?? 'all';
$sort_filter = $_GET['sort'] ?? 'latest';
// Build WHERE clause for status filtering
$where_clause = "WHERE mt.user_id = ?";
$params = [$_SESSION['user_id']];
if ($status_filter !== 'all') {
$where_clause .= " AND mt.status = ?";
$params[] = $status_filter;
}
// Build ORDER BY clause for sorting
$order_clause = "ORDER BY ";
switch ($sort_filter) {
case 'oldest':
$order_clause .= "mt.created_at ASC";
break;
case 'popular':
$order_clause = "LEFT JOIN (SELECT track_id, COUNT(*) as like_count FROM track_likes GROUP BY track_id) likes ON mt.id = likes.track_id ORDER BY likes.like_count DESC, mt.created_at DESC";
break;
case 'most-played':
$order_clause = "LEFT JOIN (SELECT track_id, COUNT(*) as play_count FROM track_plays GROUP BY track_id) plays ON mt.id = plays.track_id ORDER BY plays.play_count DESC, mt.created_at DESC";
break;
case 'latest':
default:
$order_clause .= "mt.created_at DESC";
break;
}
// Get tracks
$stmt = $pdo->prepare("
SELECT
mt.*,
COALESCE(vars.variation_count, 0) as variation_count,
CASE
WHEN mt.created_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR) THEN 'π₯ Hot'
WHEN mt.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR) THEN 'β New'
ELSE ''
END as badge
FROM music_tracks mt
LEFT JOIN (
SELECT track_id, COUNT(*) as variation_count
FROM audio_variations
GROUP BY track_id
) vars ON mt.id = vars.track_id
$where_clause
$order_clause
");
$stmt->execute($params);
$user_tracks = $stmt->fetchAll();
// Get variations for each track
$tracks_with_variations = [];
foreach ($user_tracks as $track) {
$track['variations'] = [];
if ($track['variation_count'] > 0) {
$stmt = $pdo->prepare("
SELECT
variation_index,
audio_url,
duration,
title,
tags,
image_url,
source_audio_url,
created_at
FROM audio_variations
WHERE track_id = ?
ORDER BY variation_index ASC
");
$stmt->execute([$track['id']]);
$track['variations'] = $stmt->fetchAll();
}
$tracks_with_variations[] = $track;
}
include 'includes/header.php';
// Build time filter condition
$time_condition = '';
switch ($time_filter) {
case 'today':
$time_condition = 'AND mt.created_at >= CURDATE()';
break;
case 'week':
$time_condition = 'AND mt.created_at >= DATE_SUB(NOW(), INTERVAL 1 WEEK)';
break;
case 'month':
$time_condition = 'AND mt.created_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH)';
break;
}
// Build genre filter condition
$genre_condition = '';
$genre_params = [];
if (!empty($genre_filter)) {
$genre_condition = "AND (JSON_UNQUOTE(JSON_EXTRACT(mt.metadata, '$.genre')) = ? OR JSON_CONTAINS(mt.metadata, JSON_QUOTE(?), '$.genres'))";
$genre_params = [$genre_filter, $genre_filter];
}
// Simple sort order function
function getSortOrder($sort_filter) {
switch ($sort_filter) {
case 'latest':
return "mt.created_at DESC";
case 'popular':
// OPTIMIZED: Use JOIN alias instead of subquery
return "COALESCE(like_stats.like_count, 0) DESC, mt.created_at DESC";
default:
return "mt.created_at DESC";
}
}
// Pagination setup
$tracks_per_page = 20; // Increased from 10 to 20
$current_page = max(1, intval($_GET['page'] ?? 1));
$offset = ($current_page - 1) * $tracks_per_page;
$per_page = $tracks_per_page;
// Get total count for pagination
$count_query = "SELECT COUNT(*) as total FROM music_tracks mt JOIN users u ON mt.user_id = u.id WHERE mt.status = 'complete' AND mt.audio_url IS NOT NULL AND mt.audio_url != '' $time_condition $genre_condition";
$count_stmt = $pdo->prepare($count_query);
$count_params = [];
if (!empty($genre_filter)) {
$count_params = $genre_params;
}
$count_stmt->execute($count_params);
$total_tracks = $count_stmt->fetch()['total'];
$total_pages = ceil($total_tracks / $tracks_per_page);
// Get community tracks with social data and artist info (safe query)
try {
// OPTIMIZED: Using JOINs instead of correlated subqueries for better performance
$stmt = $pdo->prepare("
SELECT
mt.id,
mt.title,
mt.prompt,
mt.audio_url,
mt.duration,
mt.created_at,
mt.user_id,
mt.price,
mt.metadata,
u.name as artist_name,
u.profile_image,
u.plan,
COALESCE(like_stats.like_count, 0) as like_count,
COALESCE(comment_stats.comment_count, 0) as comment_count,
COALESCE(share_stats.share_count, 0) as share_count,
COALESCE(play_stats.play_count, 0) as play_count,
COALESCE(view_stats.view_count, 0) as view_count,
COALESCE((SELECT COUNT(*) FROM user_follows WHERE follower_id = ? AND following_id = mt.user_id), 0) as is_following,
CASE WHEN user_like_stats.track_id IS NOT NULL THEN 1 ELSE 0 END as user_liked,
COALESCE(artist_stats.total_tracks, 0) as artist_total_tracks
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
LEFT JOIN (SELECT track_id, COUNT(*) as like_count FROM track_likes GROUP BY track_id) like_stats ON mt.id = like_stats.track_id
LEFT JOIN (SELECT track_id, COUNT(*) as comment_count FROM track_comments GROUP BY track_id) comment_stats ON mt.id = comment_stats.track_id
LEFT JOIN (SELECT track_id, COUNT(*) as share_count FROM track_shares GROUP BY track_id) share_stats ON mt.id = share_stats.track_id
LEFT JOIN (SELECT track_id, COUNT(*) as play_count FROM track_plays GROUP BY track_id) play_stats ON mt.id = play_stats.track_id
LEFT JOIN (SELECT track_id, COUNT(*) as view_count FROM track_views GROUP BY track_id) view_stats ON mt.id = view_stats.track_id
LEFT JOIN (SELECT user_id, COUNT(*) as total_tracks FROM music_tracks WHERE status = 'complete' GROUP BY user_id) artist_stats ON mt.user_id = artist_stats.user_id
WHERE mt.status = 'complete'
AND mt.audio_url IS NOT NULL
AND mt.audio_url != ''
$time_condition
$genre_condition
ORDER BY " . getSortOrder($sort_filter) . "
LIMIT ? OFFSET ?
");
// Parameters: user_like_stats.user_id, is_following user_id (2 total)
$params = [$user_id ?? 0, $user_id ?? 0];
if (!empty($genre_filter)) {
$params = array_merge($params, $genre_params);
}
// Add LIMIT and OFFSET parameters
$params[] = $per_page;
$params[] = $offset;
$stmt->execute($params);
$recent_tracks = $stmt->fetchAll();
} catch (Exception $e) {
// Fallback to basic query if social features fail
$stmt = $pdo->prepare("
SELECT
mt.id,
mt.title,
mt.prompt,
mt.audio_url,
mt.duration,
mt.created_at,
mt.user_id,
mt.price,
mt.metadata,
u.name as artist_name,
u.profile_image,
u.plan,
0 as like_count,
0 as comment_count,
0 as share_count,
0 as play_count,
0 as view_count,
0 as is_following,
0 as user_liked,
1 as artist_total_tracks
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
WHERE mt.status = 'complete'
AND mt.audio_url IS NOT NULL
AND mt.audio_url != ''
$time_condition
$genre_condition
ORDER BY mt.created_at DESC
LIMIT ? OFFSET ?
");
$fallback_params = [];
if (!empty($genre_filter)) {
$fallback_params = $genre_params;
}
// Add LIMIT and OFFSET parameters
$fallback_params[] = $per_page;
$fallback_params[] = $offset;
$stmt->execute($fallback_params);
$recent_tracks = $stmt->fetchAll();
}
// Get all available genres from tracks
$genres_query = $pdo->prepare("
SELECT DISTINCT JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.genre')) as genre
FROM music_tracks
WHERE status = 'complete'
AND metadata IS NOT NULL
AND JSON_EXTRACT(metadata, '$.genre') IS NOT NULL
AND JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.genre')) != ''
ORDER BY genre ASC
");
$genres_query->execute();
$available_genres = $genres_query->fetchAll(PDO::FETCH_COLUMN);
// Add popular genres if missing from database
$popular_genres = ['Electronic', 'House', 'Techno', 'Pop', 'Hip Hop', 'Rock', 'Jazz', 'Classical', 'Ambient', 'Trance', 'Dubstep', 'R&B', 'Reggae', 'Country', 'Folk', 'Blues', 'Funk', 'Disco', 'Drum & Bass', 'Progressive', 'Chillout', 'Lofi'];
foreach ($popular_genres as $genre) {
if (!in_array($genre, $available_genres)) {
$available_genres[] = $genre;
}
}
$available_genres = array_unique($available_genres);
sort($available_genres);
// Get total count for pagination
$count_stmt = $pdo->prepare("
SELECT COUNT(*) as total
FROM music_tracks mt
WHERE mt.status = 'complete'
AND mt.audio_url IS NOT NULL
AND mt.audio_url != ''
$time_condition
");
$count_stmt->execute();
$total_tracks = $count_stmt->fetch()['total'];
$total_pages = ceil($total_tracks / $per_page);
// Get community stats
$community_stats = [
'total_tracks' => $total_tracks,
'total_artists' => count(array_unique(array_column($recent_tracks, 'artist_name'))),
'total_likes' => 0,
'total_comments' => 0,
'total_shares' => 0
];
?>
<div class="main-content">
<style>
body {
padding-bottom: 120px; /* Space for global player */
}
/* Hero Section Styling */
.hero {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
padding: 6rem 0 4rem;
position: relative;
overflow: hidden;
}
.hero .container {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 300px;
}
.hero-content {
flex: 1;
max-width: 600px;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: rgba(102, 126, 234, 0.2);
color: #667eea;
padding: 0.8rem 1.5rem;
border-radius: 25px;
font-size: 1rem;
font-weight: 600;
margin-bottom: 2rem;
border: 1px solid rgba(102, 126, 234, 0.3);
}
.hero-title {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1.5rem;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1.2;
}
.hero-subtitle {
font-size: 1.1rem;
color: #a0aec0;
line-height: 1.6;
margin-bottom: 2rem;
}
.hero-visual {
flex: 1;
max-width: 400px;
height: 300px;
position: relative;
}
/* Floating Notes Animation */
.floating-elements {
position: relative;
height: 100%;
width: 100%;
}
.floating-note {
position: absolute;
font-size: 2.5rem;
color: rgba(102, 126, 234, 0.4);
animation: float 8s ease-in-out infinite;
user-select: none;
pointer-events: none;
}
.floating-note:nth-child(1) {
top: 20%;
left: 10%;
animation-delay: 0s;
font-size: 3rem;
}
.floating-note:nth-child(2) {
top: 60%;
right: 15%;
animation-delay: 1.6s;
font-size: 2.5rem;
}
.floating-note:nth-child(3) {
bottom: 30%;
left: 20%;
animation-delay: 3.2s;
font-size: 2.8rem;
}
.floating-note:nth-child(4) {
top: 40%;
right: 30%;
animation-delay: 4.8s;
font-size: 2.2rem;
}
.floating-note:nth-child(5) {
bottom: 60%;
left: 50%;
animation-delay: 6.4s;
font-size: 2.6rem;
}
@keyframes float {
0%, 100% {
transform: translateY(0px) rotate(0deg);
opacity: 0.4;
}
25% {
transform: translateY(-15px) rotate(5deg);
opacity: 0.7;
}
50% {
transform: translateY(-25px) rotate(10deg);
opacity: 1;
}
75% {
transform: translateY(-15px) rotate(5deg);
opacity: 0.7;
}
}
/* Library-specific Styles */
.empty-state {
text-align: center;
padding: 4rem 2rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.3) 0%,
rgba(15, 15, 25, 0.4) 100%);
border-radius: 20px;
border: 1px solid rgba(102, 126, 234, 0.2);
margin: 2rem 0;
}
.empty-icon {
font-size: 4rem;
color: #667eea;
margin-bottom: 1rem;
opacity: 0.7;
}
.empty-title {
font-size: 1.5rem;
font-weight: 700;
color: #e2e8f0;
margin-bottom: 1rem;
}
.empty-description {
color: #a0aec0;
margin-bottom: 2rem;
line-height: 1.6;
}
.create-first-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.create-first-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.track-badge {
display: inline-block;
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 1rem;
box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
}
.status-indicator {
margin-top: 0.5rem;
}
.status-complete {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 2px 8px rgba(72, 187, 120, 0.3);
}
.status-processing {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
}
.status-failed {
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
}
.error-message-modern {
background: linear-gradient(135deg,
rgba(239, 68, 68, 0.1) 0%,
rgba(220, 38, 38, 0.05) 100%);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 12px;
padding: 1rem;
margin: 1rem 1.5rem;
}
.error-header {
color: #ef4444;
font-weight: 700;
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.error-content {
color: #fca5a5;
font-size: 0.9rem;
line-height: 1.5;
margin-bottom: 0.5rem;
}
.error-tip {
background: rgba(102, 126, 234, 0.1);
border-left: 3px solid #667eea;
padding: 0.5rem 1rem;
border-radius: 0 8px 8px 0;
color: #a0aec0;
font-size: 0.85rem;
font-style: italic;
}
.track-actions-modern {
display: flex;
gap: 1rem;
padding: 1.5rem;
flex-wrap: wrap;
justify-content: center;
}
.action-btn {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
border: 1px solid rgba(102, 126, 234, 0.4);
color: #667eea;
padding: 0.8rem 1.5rem;
border-radius: 12px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
display: flex;
align-items: center;
gap: 0.5rem;
}
.action-btn:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
border-color: rgba(102, 126, 234, 0.6);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.action-btn.primary {
background: linear-gradient(135deg, #667eea, #764ba2);
border-color: #667eea;
color: white;
}
.action-btn.primary:hover {
background: linear-gradient(135deg, #5a67d8, #6b46c1);
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.action-btn.primary.playing {
background: linear-gradient(135deg, #f59e0b, #d97706);
border-color: #f59e0b;
animation: playingPulse 2s ease-in-out infinite;
}
.action-btn.danger {
background: linear-gradient(135deg, rgba(239, 68, 68, 0.2), rgba(220, 38, 38, 0.2));
border-color: rgba(239, 68, 68, 0.4);
color: #ef4444;
}
.action-btn.danger:hover {
background: linear-gradient(135deg, rgba(239, 68, 68, 0.3), rgba(220, 38, 38, 0.3));
border-color: rgba(239, 68, 68, 0.6);
}
@keyframes playingPulse {
0%, 100% { box-shadow: 0 0 20px rgba(245, 158, 11, 0.5); }
50% { box-shadow: 0 0 30px rgba(245, 158, 11, 0.8); }
}
/* Modal Styles */
.variations-modal, .lyrics-modal, .download-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(10px);
display: none;
align-items: center;
justify-content: center;
z-index: 999999;
}
.variations-modal.active, .lyrics-modal.active, .download-modal.active {
display: flex;
}
.variations-content, .lyrics-content, .download-content {
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.9) 0%,
rgba(15, 15, 25, 0.95) 100%);
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 20px;
max-width: 90%;
max-height: 90%;
overflow-y: auto;
position: relative;
backdrop-filter: blur(20px);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.variations-header, .lyrics-header, .download-header {
background: linear-gradient(135deg, #667eea, #764ba2);
padding: 1.5rem;
border-radius: 20px 20px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.variations-title, .lyrics-title, .download-title {
color: white;
font-size: 1.5rem;
font-weight: 700;
margin: 0;
}
.close-variations, .close-lyrics, .close-download {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
}
.close-variations:hover, .close-lyrics:hover, .close-download:hover {
background: rgba(255, 255, 255, 0.2);
}
.variations-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
padding: 1.5rem;
}
.variation-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(102, 126, 234, 0.2);
border-radius: 12px;
padding: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.variation-card:hover {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.4);
transform: translateY(-2px);
}
.variation-card.selected {
border-color: #667eea;
background: rgba(102, 126, 234, 0.2);
}
.variation-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.variation-title {
font-weight: 600;
color: #e2e8f0;
}
.variation-index {
background: #667eea;
color: white;
padding: 0.2rem 0.5rem;
border-radius: 8px;
font-size: 0.8rem;
font-weight: 600;
}
.variation-duration {
color: #a0aec0;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.variation-tags {
display: flex;
gap: 0.3rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.variation-tag {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
padding: 0.2rem 0.5rem;
border-radius: 6px;
font-size: 0.7rem;
}
.variation-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.variation-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 0.5rem 1rem;
border-radius: 8px;
cursor: pointer;
font-size: 0.8rem;
transition: all 0.3s ease;
}
.variation-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.variation-btn.play {
background: linear-gradient(135deg, #667eea, #764ba2);
border-color: #667eea;
}
.variation-btn.download {
background: linear-gradient(135deg, #48bb78, #38a169);
border-color: #48bb78;
}
.variation-btn.select {
background: linear-gradient(135deg, #f59e0b, #d97706);
border-color: #f59e0b;
}
.variation-btn.select.selected {
background: linear-gradient(135deg, #48bb78, #38a169);
border-color: #48bb78;
}
.variations-footer, .lyrics-footer, .download-footer {
padding: 1.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.3);
border-radius: 0 0 20px 20px;
}
.variations-info {
color: #a0aec0;
font-size: 0.9rem;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.variations-actions, .lyrics-actions, .download-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
}
.variations-btn, .lyrics-btn, .download-btn {
padding: 0.8rem 1.5rem;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
border: none;
}
.variations-btn.cancel, .lyrics-btn.cancel, .download-btn.cancel {
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.variations-btn.save {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}
.variations-btn.save:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.lyrics-btn.copy, .download-btn.download-all {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
}
.lyrics-body, .download-body {
padding: 1.5rem;
max-height: 400px;
overflow-y: auto;
}
/* Filter Controls */
.filter-controls {
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.4) 0%,
rgba(15, 15, 25, 0.6) 100%);
border: 1px solid rgba(102, 126, 234, 0.2);
border-radius: 16px;
padding: 1.5rem;
margin: 2rem 0;
backdrop-filter: blur(10px);
}
.filter-row {
display: flex;
gap: 1rem;
align-items: center;
flex-wrap: wrap;
}
.filter-group {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-label {
font-size: 0.9rem;
font-weight: 600;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 1px;
}
.filter-select {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(102, 126, 234, 0.3);
color: white;
padding: 0.5rem 1rem;
border-radius: 8px;
font-size: 0.9rem;
transition: all 0.3s ease;
}
.filter-select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
/* Mobile Responsive Design */
@media (max-width: 768px) {
.hero {
padding: 4rem 0 2rem;
}
.hero .container {
flex-direction: column;
text-align: center;
min-height: auto;
}
.hero-content {
max-width: 100%;
margin-bottom: 2rem;
}
.hero-title {
font-size: 2.5rem;
}
.filter-row {
flex-direction: column;
align-items: stretch;
}
.track-actions-modern {
flex-direction: column;
}
.action-btn {
justify-content: center;
}
}
.hero-visual {
max-width: 300px;
height: 200px;
}
.floating-note {
font-size: 2rem;
}
.floating-note:nth-child(1) { font-size: 2.2rem; }
.floating-note:nth-child(2) { font-size: 2rem; }
.floating-note:nth-child(3) { font-size: 2.1rem; }
.floating-note:nth-child(4) { font-size: 1.8rem; }
.floating-note:nth-child(5) { font-size: 2rem; }
.community-stats {
grid-template-columns: repeat(2, 1fr);
}
.tracks-grid {
grid-template-columns: 1fr;
}
.filters {
flex-direction: column;
gap: 0.5rem;
}
.filters select {
width: 100%;
}
}
.community-content {
padding: 4rem 0;
}
.community-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 2rem;
margin-bottom: 4rem;
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 2rem;
text-align: center;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: #667eea;
margin-bottom: 0.5rem;
}
.stat-label {
color: #a0aec0;
font-size: 1.1rem;
}
.filters {
display: flex;
gap: 1rem;
margin-bottom: 3rem;
align-items: center;
}
.filters select {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 0.8rem 1.2rem;
border-radius: 8px;
font-size: 1rem;
}
.tracks-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 2rem;
}
.track-card {
background: linear-gradient(145deg,
rgba(15, 15, 35, 0.95) 0%,
rgba(25, 25, 45, 0.9) 50%,
rgba(35, 35, 55, 0.85) 100%);
border: 1px solid rgba(102, 126, 234, 0.2);
border-radius: 24px;
padding: 0;
margin-bottom: 2rem;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
overflow: hidden;
position: relative;
backdrop-filter: blur(20px);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
0 2px 16px rgba(102, 126, 234, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.track-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg,
transparent 0%,
#667eea 25%,
#764ba2 50%,
#667eea 75%,
transparent 100%);
opacity: 0;
transition: opacity 0.3s ease;
}
.track-card:hover {
transform: translateY(-8px) scale(1.02);
border-color: rgba(102, 126, 234, 0.5);
box-shadow:
0 20px 60px rgba(0, 0, 0, 0.4),
0 8px 40px rgba(102, 126, 234, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.track-card:hover::before {
opacity: 1;
}
/* Premium Artist Info Section */
.artist-info {
padding: 1.5rem 1.5rem 1rem;
background: linear-gradient(135deg,
rgba(102, 126, 234, 0.1) 0%,
rgba(118, 75, 162, 0.05) 100%);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
position: relative;
}
.artist-profile img, .default-avatar {
width: 56px;
height: 56px;
border-radius: 16px;
border: 2px solid rgba(102, 126, 234, 0.3);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.track-card:hover .artist-profile img,
.track-card:hover .default-avatar {
border-color: rgba(102, 126, 234, 0.6);
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
transform: scale(1.05);
}
.default-avatar {
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
font-size: 1.4rem;
color: white;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.track-artist {
font-size: 1rem;
color: #e2e8f0;
font-weight: 600;
margin-bottom: 0.3rem;
}
.artist-plan {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 2px 8px rgba(72, 187, 120, 0.3);
}
.artist-plan.pro {
background: linear-gradient(135deg, #f59e0b, #d97706);
box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
}
.artist-plan.starter {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);
}
.artist-stats {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
font-size: 0.85rem;
color: #a0aec0;
}
.artist-stats span {
display: flex;
align-items: center;
gap: 0.3rem;
}
.artist-stats i {
color: #667eea;
font-size: 0.8rem;
}
/* Enhanced Follow Button */
.btn-follow {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
border: 1px solid rgba(102, 126, 234, 0.4);
color: #667eea;
padding: 0.6rem 1.2rem;
border-radius: 12px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.btn-follow:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
border-color: rgba(102, 126, 234, 0.6);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-follow.following {
background: linear-gradient(135deg, #48bb78, #38a169);
border-color: #48bb78;
color: white;
}
/* Premium Track Header */
.track-header {
padding: 0 1.5rem;
margin-bottom: 1rem;
}
.track-title {
font-size: 1.6rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #e2e8f0, #f7fafc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1.3;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Professional Track Prompt */
.track-prompt {
padding: 1rem 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.3) 0%,
rgba(15, 15, 25, 0.4) 100%);
border-left: 3px solid #667eea;
margin: 1rem 1.5rem;
border-radius: 0 8px 8px 0;
font-size: 0.95rem;
line-height: 1.5;
color: #cbd5e0;
font-style: italic;
position: relative;
}
.track-prompt::before {
content: '"';
position: absolute;
left: -0.5rem;
top: -0.5rem;
font-size: 2rem;
color: #667eea;
font-weight: bold;
}
/* Studio-Quality Waveform */
.track-waveform {
padding: 1.5rem;
margin: 1rem 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.6) 0%,
rgba(15, 15, 25, 0.8) 100%);
border-radius: 16px;
border: 1px solid rgba(102, 126, 234, 0.2);
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.track-waveform::before {
content: 'βΆ Click to Play';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(102, 126, 234, 0.9);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
opacity: 0;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.track-waveform:hover::before {
opacity: 1;
}
.track-waveform:hover {
border-color: rgba(102, 126, 234, 0.5);
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
.waveform-bars {
display: flex;
align-items: end;
gap: 2px;
height: 60px;
justify-content: space-between;
}
.waveform-bar {
background: linear-gradient(to top,
#667eea 0%,
#764ba2 50%,
#48bb78 100%);
width: 3px;
border-radius: 2px;
transition: all 0.3s ease;
opacity: 0.7;
}
.waveform-bar:hover {
opacity: 1;
box-shadow: 0 0 8px rgba(102, 126, 234, 0.5);
}
/* Professional Metadata Grid */
.track-metadata {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
padding: 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.2) 0%,
rgba(15, 15, 25, 0.3) 100%);
border-top: 1px solid rgba(255, 255, 255, 0.05);
}
.metadata-item {
text-align: center;
padding: 0.8rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.05);
transition: all 0.3s ease;
}
.metadata-item:hover {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
.metadata-label {
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: #a0aec0;
margin-bottom: 0.3rem;
}
.metadata-value {
font-size: 1rem;
font-weight: 800;
color: #e2e8f0;
}
/* Premium Track Price Section */
.track-price {
padding: 1.5rem;
background: linear-gradient(135deg,
rgba(102, 126, 234, 0.1) 0%,
rgba(118, 75, 162, 0.05) 100%);
border-top: 1px solid rgba(255, 255, 255, 0.08);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.price-display {
font-size: 1.4rem;
font-weight: 800;
color: #48bb78;
display: flex;
align-items: center;
gap: 0.5rem;
}
.price-display.free {
color: #f59e0b;
}
.track-actions {
display: flex;
gap: 0.8rem;
align-items: center;
flex-wrap: wrap;
}
.play-track-btn, .add-to-cart-btn, .share-track-btn {
padding: 0.8rem 1.5rem;
border-radius: 12px;
border: none;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
text-decoration: none;
}
.play-track-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
}
.play-track-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.5);
}
.play-track-btn.playing {
background: linear-gradient(135deg, #f59e0b, #d97706);
animation: playingPulse 2s infinite;
}
@keyframes playingPulse {
0%, 100% { box-shadow: 0 4px 16px rgba(245, 158, 11, 0.3); }
50% { box-shadow: 0 8px 32px rgba(245, 158, 11, 0.6); }
}
/* Initially disable play buttons until global player is ready */
.action-btn.play-btn, .play-track-btn {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
.action-btn.play-btn.ready, .play-track-btn.ready {
opacity: 1;
cursor: pointer;
pointer-events: auto;
}
.add-to-cart-btn {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
box-shadow: 0 4px 16px rgba(72, 187, 120, 0.3);
}
.add-to-cart-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(72, 187, 120, 0.5);
}
.share-track-btn {
background: rgba(255, 255, 255, 0.1);
color: #a0aec0;
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
.share-track-btn:hover {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
/* Social Interaction Buttons */
.social-actions {
padding: 2rem 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.4) 0%,
rgba(15, 15, 25, 0.6) 100%);
border-top: 1px solid rgba(255, 255, 255, 0.1);
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.social-btn {
background: linear-gradient(135deg,
rgba(255, 255, 255, 0.1) 0%,
rgba(255, 255, 255, 0.05) 100%);
border: 2px solid rgba(255, 255, 255, 0.2);
color: #cbd5e0;
padding: 1.2rem 1rem;
border-radius: 20px;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
font-size: 0.9rem;
font-weight: 600;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.8rem;
position: relative;
overflow: hidden;
backdrop-filter: blur(10px);
text-align: center;
}
.social-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, transparent, rgba(255, 255, 255, 0.1), transparent);
opacity: 0;
transition: opacity 0.3s ease;
}
.social-btn:hover::before {
opacity: 1;
}
.social-btn i {
font-size: 1.8rem;
transition: all 0.3s ease;
}
.social-count {
font-size: 1.1rem;
font-weight: 800;
letter-spacing: 0.5px;
}
/* Individual Social Button Styles */
.like-btn:hover {
background: linear-gradient(135deg, #ff6b9d, #e91e63);
border-color: #ff6b9d;
color: white;
transform: translateY(-8px) scale(1.05);
box-shadow: 0 15px 40px rgba(255, 107, 157, 0.4);
}
.like-btn.liked {
background: linear-gradient(135deg, #ff6b9d, #e91e63);
border-color: #ff6b9d;
color: white;
animation: heartBeat 1.5s ease-in-out infinite;
}
@keyframes heartBeat {
0%, 100% { transform: scale(1); }
25% { transform: scale(1.1); }
50% { transform: scale(1); }
75% { transform: scale(1.05); }
}
.comment-btn:hover {
background: linear-gradient(135deg, #4ecdc4, #20b2aa);
border-color: #4ecdc4;
color: white;
transform: translateY(-8px) scale(1.05);
box-shadow: 0 15px 40px rgba(78, 205, 196, 0.4);
}
.share-btn:hover {
background: linear-gradient(135deg, #667eea, #764ba2);
border-color: #667eea;
color: white;
transform: translateY(-8px) scale(1.05);
box-shadow: 0 15px 40px rgba(102, 126, 234, 0.4);
}
.stats-btn:hover {
background: linear-gradient(135deg, #feca57, #ff9ff3);
border-color: #feca57;
color: white;
transform: translateY(-8px) scale(1.05);
box-shadow: 0 15px 40px rgba(254, 202, 87, 0.4);
}
/* Enhanced DJ Tech Grid with Mood & Energy */
.dj-tech-grid {
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.6) 0%,
rgba(15, 15, 25, 0.8) 100%);
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 20px;
padding: 2rem 1.5rem;
margin: 1.5rem;
cursor: pointer;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
}
.dj-tech-grid::before {
content: 'ποΈ DJ MODE - Click to activate mixing';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(102, 126, 234, 0.95);
color: white;
padding: 0.8rem 1.5rem;
border-radius: 25px;
font-size: 0.9rem;
font-weight: 700;
opacity: 0;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
white-space: nowrap;
}
.dj-tech-grid:hover::before {
opacity: 1;
}
.dj-tech-grid:hover {
border-color: rgba(102, 126, 234, 0.8);
box-shadow:
0 20px 60px rgba(102, 126, 234, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transform: translateY(-5px);
}
.tech-primary {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.tech-secondary {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
align-items: center;
}
.bpm-display, .key-display, .time-display, .mood-display, .energy-display {
text-align: center;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
}
.bpm-display:hover, .key-display:hover, .time-display:hover,
.mood-display:hover, .energy-display:hover {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-3px) scale(1.05);
}
.tech-label {
font-size: 0.8rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1.5px;
color: #a0aec0;
margin-bottom: 0.5rem;
display: block;
}
.tech-value {
font-size: 1.4rem;
font-weight: 900;
color: #e2e8f0;
display: block;
}
.bpm-value {
color: #ff6b6b;
text-shadow: 0 0 20px rgba(255, 107, 107, 0.5);
}
.key-value {
color: #4ecdc4;
text-shadow: 0 0 20px rgba(78, 205, 196, 0.5);
}
.mood-value {
color: #feca57;
text-shadow: 0 0 20px rgba(254, 202, 87, 0.5);
text-transform: capitalize;
}
.energy-value {
color: #ff9ff3;
text-shadow: 0 0 20px rgba(255, 159, 243, 0.5);
text-transform: capitalize;
}
/* Responsive for mobile */
@media (max-width: 768px) {
.social-actions {
grid-template-columns: repeat(2, 1fr);
gap: 0.8rem;
padding: 1.5rem 1rem;
}
.tech-primary {
grid-template-columns: repeat(2, 1fr);
}
.tech-secondary {
grid-template-columns: 1fr;
}
.social-btn {
padding: 1rem 0.8rem;
}
.social-btn i {
font-size: 1.5rem;
}
}
/* Mobile Responsive Design */
@media (max-width: 768px) {
.track-card {
border-radius: 16px;
margin-bottom: 1.5rem;
}
.track-title {
font-size: 1.3rem;
}
.track-metadata {
grid-template-columns: repeat(2, 1fr);
}
.track-price {
flex-direction: column;
align-items: stretch;
}
.track-actions {
justify-content: center;
}
}
.track-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1.5rem;
}
.artist-profile img {
width: 50px;
height: 50px;
border-radius: 50%;
object-fit: cover;
}
.default-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1.2rem;
}
.track-title {
font-size: 1.4rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.track-artist {
color: #a0aec0;
}
.track-prompt {
color: #cbd5e0;
margin: 1rem 0;
line-height: 1.5;
}
.track-details {
display: flex;
gap: 1rem;
margin: 1rem 0;
color: #a0aec0;
font-size: 0.9rem;
}
.track-actions {
display: flex;
gap: 1rem;
margin: 1.5rem 0;
}
.play-track-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 600;
}
.play-track-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.play-track-btn.playing {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
box-shadow: 0 0 20px rgba(102, 126, 234, 0.5);
animation: playingPulse 2s ease-in-out infinite;
}
.play-track-btn.playing i {
animation: playingIcon 1s ease-in-out infinite alternate;
}
@keyframes playingPulse {
0%, 100% { box-shadow: 0 0 20px rgba(102, 126, 234, 0.5); }
50% { box-shadow: 0 0 30px rgba(102, 126, 234, 0.8); }
}
@keyframes playingIcon {
0% { transform: scale(1); }
100% { transform: scale(1.1); }
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 0.8rem 1.5rem;
border-radius: 8px;
text-decoration: none;
font-size: 0.9rem;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.social-actions {
display: flex;
gap: 1rem;
padding-top: 1.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.social-btn {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: #a0aec0;
padding: 0.8rem 1.2rem;
border-radius: 12px;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.6rem;
font-size: 1rem;
font-weight: 500;
transition: all 0.3s ease;
}
.social-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: white;
}
.social-btn.liked {
color: #e53e3e;
background: rgba(229, 62, 62, 0.1);
}
.social-btn.following {
color: #48bb78;
background: rgba(72, 187, 120, 0.1);
}
/* Professional Music Feed Styles */
.artist-info {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.artist-details {
flex: 1;
}
.artist-plan {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
}
.artist-plan.pro {
background: linear-gradient(135deg, #f093fb, #f5576c);
}
.artist-plan.starter {
background: linear-gradient(135deg, #4facfe, #00f2fe);
}
.artist-stats {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
font-size: 0.9rem;
color: #a0aec0;
}
.track-genre {
display: inline-block;
background: rgba(255, 255, 255, 0.1);
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.8rem;
color: #cbd5e0;
margin-right: 0.5rem;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
}
.track-genre:hover {
background: rgba(102, 126, 234, 0.3);
color: white;
transform: translateY(-1px);
}
.track-genre.clickable {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
border: 1px solid rgba(102, 126, 234, 0.3);
}
.track-genre.clickable:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.4), rgba(118, 75, 162, 0.4));
border-color: rgba(102, 126, 234, 0.6);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
.track-price {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;
}
.price-tag {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
padding: 0.5rem 1rem;
border-radius: 8px;
font-weight: 600;
}
.price-tag.free {
background: linear-gradient(135deg, #4299e1, #3182ce);
}
.btn-cart {
background: linear-gradient(135deg, #ed8936, #dd6b20);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-cart:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(237, 137, 54, 0.4);
}
.btn-cart.added {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
}
.btn-cart:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.btn-follow {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 0.8rem 1.5rem;
border-radius: 8px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-follow:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.btn-follow.following {
background: rgba(72, 187, 120, 0.2);
border-color: rgba(72, 187, 120, 0.5);
color: #48bb78;
}
.track-waveform {
height: 60px;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
margin: 1rem 0;
position: relative;
overflow: hidden;
cursor: pointer;
}
.waveform-bars {
display: flex;
align-items: end;
height: 100%;
padding: 8px;
gap: 2px;
}
.waveform-bar {
flex: 1;
background: rgba(102, 126, 234, 0.3);
border-radius: 2px;
transition: all 0.3s ease;
}
.waveform-bar.playing {
background: linear-gradient(180deg, #667eea, #764ba2);
}
.track-metadata {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
margin: 1rem 0;
padding: 1rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 8px;
font-size: 0.9rem;
}
.metadata-item {
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.metadata-label {
color: #a0aec0;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.metadata-value {
color: white;
font-weight: 500;
}
/* Comments Modal */
.comments-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.comments-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.comments-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
width: 100%;
max-width: 600px;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.comments-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.comments-header h3 {
color: white;
font-size: 2rem;
margin: 0;
}
.close-btn {
background: none;
border: none;
color: white;
font-size: 2.4rem;
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.1);
}
.comments-list {
flex: 1;
overflow-y: auto;
padding: 2rem;
max-height: 400px;
}
.comment-item {
display: flex;
gap: 1rem;
margin-bottom: 1.5rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
}
.comment-avatar {
flex-shrink: 0;
}
.default-avatar-small {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.6rem;
font-weight: 700;
}
.comment-avatar img {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
.comment-content {
flex: 1;
}
.comment-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.5rem;
}
.comment-author {
color: white;
font-weight: 600;
}
.comment-time {
color: #a0aec0;
font-size: 0.9rem;
}
.comment-text {
color: #cbd5e0;
line-height: 1.5;
}
.comment-form {
padding: 2rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.comment-form textarea {
width: 100%;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem;
color: white;
resize: vertical;
min-height: 80px;
margin-bottom: 1rem;
}
.comment-form textarea::placeholder {
color: #a0aec0;
}
.comment-form .btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
}
.comment-form .btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.no-comments {
text-align: center;
color: #a0aec0;
padding: 2rem;
}
.loading {
text-align: center;
color: #a0aec0;
padding: 2rem;
}
/* Notification System */
.notification {
position: fixed;
top: 2rem;
right: 2rem;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem 1.5rem;
color: white;
z-index: 10000;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
}
.notification.show {
opacity: 1;
transform: translateX(0);
}
.notification-success {
border-left: 4px solid #48bb78;
}
.notification-error {
border-left: 4px solid #f56565;
}
.notification-warning {
border-left: 4px solid #ed8936;
}
/* Social Share Modal */
.share-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
backdrop-filter: blur(5px);
display: none;
}
.share-modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
padding: 2rem;
width: 90%;
max-width: 500px;
color: white;
}
.share-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.share-platforms {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.share-platform {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 1.5rem 1rem;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
color: white;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.share-platform:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}
.share-platform.twitter { background: rgba(29, 161, 242, 0.2); }
.share-platform.facebook { background: rgba(24, 119, 242, 0.2); }
.share-platform.instagram { background: rgba(225, 48, 108, 0.2); }
.share-platform.whatsapp { background: rgba(37, 211, 102, 0.2); }
.share-platform.linkedin { background: rgba(10, 102, 194, 0.2); }
.share-platform.discord { background: rgba(114, 137, 218, 0.2); }
.share-platform i {
font-size: 2rem;
}
.share-url-section {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 1rem;
}
.share-url-input {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.share-url {
flex: 1;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 0.8rem;
color: white;
font-family: monospace;
font-size: 0.9rem;
}
.copy-btn {
background: linear-gradient(135deg, #48bb78, #38a169);
border: none;
color: white;
padding: 0.8rem 1.5rem;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
}
.copy-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(72, 187, 120, 0.4);
}
.copy-btn.copied {
background: linear-gradient(135deg, #667eea, #764ba2);
}
/* Track Highlight Effect */
.track-card.highlighted {
animation: trackHighlight 3s ease-in-out;
border: 2px solid rgba(102, 126, 234, 0.8);
box-shadow: 0 0 30px rgba(102, 126, 234, 0.4);
}
@keyframes trackHighlight {
0% {
box-shadow: 0 0 5px rgba(102, 126, 234, 0.4);
border-color: rgba(102, 126, 234, 0.3);
}
50% {
box-shadow: 0 0 40px rgba(102, 126, 234, 0.8);
border-color: rgba(102, 126, 234, 1);
}
100% {
box-shadow: 0 0 30px rgba(102, 126, 234, 0.4);
border-color: rgba(102, 126, 234, 0.8);
}
}
/* DJ Technical Information Grid */
.dj-tech-grid {
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.6) 0%,
rgba(15, 15, 25, 0.8) 100%);
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 20px;
padding: 2rem 1.5rem;
margin: 1.5rem;
cursor: pointer;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
}
.dj-tech-grid::before {
content: 'ποΈ DJ MODE - Click to activate mixing';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(102, 126, 234, 0.95);
color: white;
padding: 0.8rem 1.5rem;
border-radius: 25px;
font-size: 0.9rem;
font-weight: 700;
opacity: 0;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
white-space: nowrap;
}
.dj-tech-grid:hover::before {
opacity: 1;
}
.dj-tech-grid:hover {
border-color: rgba(102, 126, 234, 0.8);
box-shadow:
0 20px 60px rgba(102, 126, 234, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transform: translateY(-5px);
}
.tech-primary {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.tech-secondary {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
align-items: center;
}
.bpm-display, .key-display, .time-display, .mood-display, .energy-display {
text-align: center;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
}
.bpm-display:hover, .key-display:hover, .time-display:hover,
.mood-display:hover, .energy-display:hover {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-3px) scale(1.05);
}
.tech-label {
font-size: 0.8rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1.5px;
color: #a0aec0;
margin-bottom: 0.5rem;
display: block;
}
.tech-value {
font-size: 1.4rem;
font-weight: 900;
color: #e2e8f0;
display: block;
}
.bpm-value {
color: #ff6b6b;
text-shadow: 0 0 20px rgba(255, 107, 107, 0.5);
}
.key-value {
color: #4ecdc4;
text-shadow: 0 0 20px rgba(78, 205, 196, 0.5);
}
.mood-value {
color: #feca57;
text-shadow: 0 0 20px rgba(254, 202, 87, 0.5);
text-transform: capitalize;
}
.energy-value {
color: #ff9ff3;
text-shadow: 0 0 20px rgba(255, 159, 243, 0.5);
text-transform: capitalize;
}
/* Responsive for mobile */
@media (max-width: 768px) {
.social-actions {
grid-template-columns: repeat(2, 1fr);
gap: 0.8rem;
padding: 1.5rem 1rem;
}
.tech-primary {
grid-template-columns: repeat(2, 1fr);
}
.tech-secondary {
grid-template-columns: 1fr;
}
.social-btn {
padding: 1rem 0.8rem;
}
.social-btn i {
font-size: 1.5rem;
}
}
/* Mobile responsive */
@media (max-width: 768px) {
.tech-primary {
grid-template-columns: repeat(2, 1fr);
}
.time-display {
grid-column: span 2;
}
.tech-secondary {
flex-direction: column;
align-items: flex-start;
}
.tech-value {
font-size: 1rem;
}
.bpm-value {
font-size: 1.1rem;
}
}
/* DJ Mixing Panel */
.dj-mixing-panel {
position: fixed;
top: 20px;
right: 20px;
width: 300px;
background: rgba(0, 0, 0, 0.95);
border: 2px solid #667eea;
border-radius: 15px;
backdrop-filter: blur(20px);
z-index: 10000;
display: none;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.dj-panel-header {
background: linear-gradient(135deg, #667eea, #764ba2);
padding: 1rem;
border-radius: 13px 13px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.dj-panel-header h3 {
margin: 0;
color: white;
font-size: 1.1rem;
}
.close-dj-panel {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.close-dj-panel:hover {
background: rgba(255, 255, 255, 0.2);
}
.dj-panel-content {
padding: 1rem;
color: white;
}
.current-track-info {
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(102, 126, 234, 0.3);
}
.dj-info-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.dj-info-item label {
color: #a0aec0;
font-weight: 600;
}
.dj-bpm {
color: #ff6b6b;
font-weight: 800;
font-size: 1.1rem;
}
.dj-key {
color: #48bb78;
font-weight: 800;
font-size: 1.1rem;
}
.mixing-suggestions h4 {
color: #667eea;
margin-bottom: 0.8rem;
font-size: 1rem;
}
.bpm-suggestions, .key-suggestions {
margin-bottom: 1rem;
}
.bpm-suggestions p, .key-suggestions p {
margin: 0.3rem 0;
font-size: 0.9rem;
color: #cbd5e0;
}
/* DJ Mode Highlighting */
.track-card.dj-selected {
border: 2px solid #667eea;
box-shadow: 0 0 25px rgba(102, 126, 234, 0.6);
transform: scale(1.02);
}
.track-card.perfect-mix-match {
border: 2px solid #48bb78;
box-shadow: 0 0 25px rgba(72, 187, 120, 0.6);
}
.track-card.perfect-mix-match::before {
content: "π― PERFECT MIX";
position: absolute;
top: 10px;
right: 10px;
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 15px;
font-size: 0.7rem;
font-weight: 700;
z-index: 5;
}
.bpm-compatible {
box-shadow: 0 0 15px rgba(255, 107, 107, 0.5) !important;
border-color: rgba(255, 107, 107, 0.6) !important;
}
.key-compatible {
box-shadow: 0 0 15px rgba(72, 187, 120, 0.5) !important;
border-color: rgba(72, 187, 120, 0.6) !important;
}
/* DJ Mode Cursor */
.dj-tech-grid {
cursor: pointer;
transition: all 0.3s ease;
}
.dj-tech-grid:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
/* Premium Animated Effects */
.track-card::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent,
rgba(102, 126, 234, 0.1),
transparent);
transition: left 0.5s ease;
pointer-events: none;
}
.track-card:hover::after {
left: 100%;
}
/* Animated Music Particles */
.track-card .music-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
}
.track-card:hover .music-particles {
opacity: 1;
}
.music-particle {
position: absolute;
width: 4px;
height: 4px;
background: #667eea;
border-radius: 50%;
animation: floatParticle 4s linear infinite;
}
.music-particle:nth-child(2) { left: 20%; animation-delay: 0.5s; background: #764ba2; }
.music-particle:nth-child(3) { left: 40%; animation-delay: 1s; background: #48bb78; }
.music-particle:nth-child(4) { left: 60%; animation-delay: 1.5s; background: #f59e0b; }
.music-particle:nth-child(5) { left: 80%; animation-delay: 2s; background: #ef4444; }
@keyframes floatParticle {
0% {
bottom: 0;
opacity: 1;
transform: translateX(0);
}
100% {
bottom: 100%;
opacity: 0;
transform: translateX(20px);
}
}
/* Glow Effects for Playing Track */
.track-card.currently-playing {
border: 2px solid #f59e0b;
box-shadow:
0 0 30px rgba(245, 158, 11, 0.5),
0 20px 60px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
animation: playingGlow 2s ease-in-out infinite alternate;
}
@keyframes playingGlow {
0% { box-shadow: 0 0 30px rgba(245, 158, 11, 0.5), 0 20px 60px rgba(0, 0, 0, 0.4); }
100% { box-shadow: 0 0 50px rgba(245, 158, 11, 0.8), 0 20px 60px rgba(0, 0, 0, 0.4); }
}
/* Enhanced Button Animations */
.play-track-btn {
position: relative;
overflow: hidden;
}
.play-track-btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: all 0.6s ease;
}
.play-track-btn:active::before {
width: 300px;
height: 300px;
}
/* Premium Loading States */
.track-card.loading {
position: relative;
overflow: hidden;
}
.track-card.loading::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent,
rgba(102, 126, 234, 0.3),
transparent);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
/* Audio Visualization Effect */
.waveform-visualizer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg,
#667eea 0%,
#764ba2 25%,
#48bb78 50%,
#f59e0b 75%,
#ef4444 100%);
opacity: 0;
transition: opacity 0.3s ease;
animation: audioWave 2s ease-in-out infinite;
}
.track-card.currently-playing .waveform-visualizer {
opacity: 1;
}
@keyframes audioWave {
0%, 100% { transform: scaleX(0.3); }
50% { transform: scaleX(1); }
}
/* Premium Tooltips */
.tooltip {
position: relative;
}
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: 120%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 0.5rem 1rem;
border-radius: 8px;
font-size: 0.8rem;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 1000;
}
.tooltip:hover::after {
opacity: 1;
visibility: visible;
}
/* Enhanced Pricing Display */
.price-section {
margin-bottom: 1.5rem;
}
.price-display {
background: linear-gradient(135deg,
rgba(72, 187, 120, 0.2) 0%,
rgba(72, 187, 120, 0.1) 100%);
border: 2px solid rgba(72, 187, 120, 0.4);
border-radius: 16px;
padding: 1rem 1.5rem;
text-align: center;
transition: all 0.3s ease;
}
.price-display.admin-revenue {
background: linear-gradient(135deg,
rgba(245, 158, 11, 0.2) 0%,
rgba(245, 158, 11, 0.1) 100%);
border-color: rgba(245, 158, 11, 0.4);
}
.price-display.free {
background: linear-gradient(135deg,
rgba(139, 92, 246, 0.2) 0%,
rgba(139, 92, 246, 0.1) 100%);
border-color: rgba(139, 92, 246, 0.4);
}
.price-amount {
display: block;
font-size: 1.8rem;
font-weight: 900;
color: #48bb78;
margin-bottom: 0.3rem;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.price-display.admin-revenue .price-amount {
color: #f59e0b;
}
.price-display.free .price-amount {
color: #8b5cf6;
}
.revenue-type {
font-size: 0.8rem;
font-weight: 600;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 1px;
}
/* Premium 10-Star Rating System */
.track-rating-section {
padding: 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.4) 0%,
rgba(15, 15, 25, 0.6) 100%);
border-top: 1px solid rgba(255, 255, 255, 0.1);
text-align: center;
}
.rating-label {
display: block;
font-size: 0.9rem;
font-weight: 700;
color: #a0aec0;
margin-bottom: 1rem;
text-transform: uppercase;
letter-spacing: 1px;
}
.star-rating {
display: flex;
justify-content: center;
gap: 0.3rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.star {
font-size: 1.5rem;
color: rgba(255, 255, 255, 0.2);
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
position: relative;
}
.star:hover {
transform: scale(1.2);
color: #ffd700;
text-shadow: 0 0 15px rgba(255, 215, 0, 0.8);
}
.star.filled {
color: #ffd700;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.6);
}
.star.user-rated {
color: #ff6b9d;
text-shadow: 0 0 10px rgba(255, 107, 157, 0.6);
}
/* Rating hover effects */
.star-rating:hover .star {
color: rgba(255, 255, 255, 0.3);
}
.star-rating .star:hover,
.star-rating .star:hover ~ .star {
color: #ffd700;
text-shadow: 0 0 15px rgba(255, 215, 0, 0.8);
}
.rating-stats {
display: flex;
justify-content: center;
gap: 1rem;
align-items: center;
}
.avg-rating {
font-size: 1.2rem;
font-weight: 800;
color: #ffd700;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.rating-count {
font-size: 0.85rem;
color: #a0aec0;
}
/* Enhanced Track Actions */
.track-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
padding: 0;
}
.play-track-btn, .add-to-cart-btn, .share-track-btn {
padding: 1rem 1.2rem;
border-radius: 16px;
border: none;
font-weight: 700;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
text-decoration: none;
backdrop-filter: blur(10px);
position: relative;
overflow: hidden;
}
.play-track-btn i, .add-to-cart-btn i, .share-track-btn i {
font-size: 1.3rem;
}
/* Mobile Responsive Updates */
@media (max-width: 768px) {
.track-card {
border-radius: 20px;
margin-bottom: 2rem;
}
.social-actions {
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
padding: 1.5rem 1rem;
}
.social-btn {
padding: 1rem 0.8rem;
}
.social-btn i {
font-size: 1.4rem;
}
.track-actions {
grid-template-columns: 1fr;
gap: 0.8rem;
}
.star-rating {
gap: 0.2rem;
}
.star {
font-size: 1.3rem;
}
.price-amount {
font-size: 1.5rem;
}
.tech-primary {
grid-template-columns: repeat(2, 1fr);
}
.tech-secondary {
grid-template-columns: 1fr;
}
.dj-tech-grid {
padding: 1.5rem 1rem;
margin: 1rem;
}
.artist-info {
padding: 1rem;
}
.track-title {
font-size: 1.4rem;
}
.track-metadata {
grid-template-columns: repeat(2, 1fr);
padding: 1rem;
}
}
/* Premium Header Rating System */
.track-rating-header {
padding: 1.5rem;
background: linear-gradient(135deg,
rgba(255, 215, 0, 0.1) 0%,
rgba(255, 215, 0, 0.05) 100%);
border-bottom: 2px solid rgba(255, 215, 0, 0.3);
text-align: center;
position: relative;
}
.track-rating-header .star-rating {
display: flex;
justify-content: center;
gap: 0.4rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.track-rating-header .star {
font-size: 1.8rem;
color: rgba(255, 255, 255, 0.2);
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
position: relative;
}
.track-rating-header .star:hover {
transform: scale(1.3);
color: #ffd700;
text-shadow: 0 0 20px rgba(255, 215, 0, 1);
}
.track-rating-header .star.filled {
color: #ffd700;
text-shadow: 0 0 15px rgba(255, 215, 0, 0.8);
animation: starGlow 2s ease-in-out infinite alternate;
}
.track-rating-header .star.user-rated {
color: #ff6b9d;
text-shadow: 0 0 15px rgba(255, 107, 157, 0.8);
}
@keyframes starGlow {
0% { text-shadow: 0 0 15px rgba(255, 215, 0, 0.8); }
100% { text-shadow: 0 0 25px rgba(255, 215, 0, 1); }
}
/* Rating hover effects - LEFT TO RIGHT FIX */
.track-rating-header .star-rating:hover .star {
color: rgba(255, 255, 255, 0.3);
}
.track-rating-header .star-rating .star:hover ~ .star {
color: rgba(255, 255, 255, 0.3);
}
.track-rating-header .star-rating .star:hover,
.track-rating-header .star-rating .star:hover ~ .star:has(~ .star:hover) {
color: #ffd700;
text-shadow: 0 0 20px rgba(255, 215, 0, 1);
}
.track-rating-header .rating-stats {
display: flex;
justify-content: center;
gap: 1.5rem;
align-items: center;
flex-wrap: wrap;
}
.track-rating-header .avg-rating {
font-size: 1.4rem;
font-weight: 900;
color: #ffd700;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.track-rating-header .rating-count {
font-size: 0.9rem;
color: #a0aec0;
}
.chart-position {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.4rem 1rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
/* Enhanced Revenue Display */
.price-display.free-tier {
background: linear-gradient(135deg,
rgba(102, 126, 234, 0.2) 0%,
rgba(118, 75, 162, 0.1) 100%);
border-color: rgba(102, 126, 234, 0.4);
}
.price-display.pro-tier {
background: linear-gradient(135deg,
rgba(72, 187, 120, 0.2) 0%,
rgba(72, 187, 120, 0.1) 100%);
border-color: rgba(72, 187, 120, 0.4);
}
.price-display.free-track {
background: linear-gradient(135deg,
rgba(139, 92, 246, 0.2) 0%,
rgba(139, 92, 246, 0.1) 100%);
border-color: rgba(139, 92, 246, 0.4);
}
.revenue-breakdown {
font-size: 0.85rem;
font-weight: 600;
color: #cbd5e0;
line-height: 1.4;
margin-top: 0.5rem;
display: block;
}
.upgrade-incentive {
display: block;
font-size: 0.8rem;
font-weight: 700;
color: #48bb78;
margin-top: 0.5rem;
padding: 0.3rem 0.8rem;
background: rgba(72, 187, 120, 0.1);
border-radius: 12px;
border: 1px solid rgba(72, 187, 120, 0.3);
}
.view-charts-btn {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
color: white;
box-shadow: 0 4px 16px rgba(139, 92, 246, 0.3);
}
.view-charts-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(139, 92, 246, 0.5);
}
.plan-indicator {
font-size: 0.8rem;
font-weight: 600;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 1px;
}
.premium-feature-btn {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
box-shadow: 0 4px 16px rgba(245, 158, 11, 0.3);
}
.premium-feature-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(245, 158, 11, 0.5);
}
/* Chart Position as Clickable Button */
.chart-position {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.4rem 1rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
cursor: pointer;
transition: all 0.3s ease;
border: none;
text-decoration: none;
}
.chart-position:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5);
background: linear-gradient(135deg, #764ba2, #667eea);
}
/* Charts Modal */
.charts-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
backdrop-filter: blur(5px);
display: none;
align-items: center;
justify-content: center;
padding: 2rem;
}
.charts-modal-content {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
padding: 2rem;
width: 90%;
max-width: 800px;
max-height: 80vh;
overflow-y: auto;
color: white;
}
.charts-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.charts-modal h3 {
font-size: 1.8rem;
font-weight: 700;
background: linear-gradient(135deg, #ffd700, #ff6b9d);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.chart-preview {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 1.5rem;
margin-bottom: 1.5rem;
text-align: center;
}
.current-position {
font-size: 3rem;
font-weight: 900;
color: #ffd700;
margin-bottom: 0.5rem;
}
.position-change {
font-size: 1rem;
color: #48bb78;
}
.position-change.down {
color: #f56565;
}
.view-full-charts {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
width: 100%;
margin-top: 1rem;
transition: all 0.3s ease;
}
.view-full-charts:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
/* Fixed Genres Section */
.genres-section {
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 2rem;
margin-bottom: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.genres-section h3 {
text-align: center;
margin-bottom: 1.5rem;
font-size: 1.4rem;
font-weight: 700;
color: #e2e8f0;
}
.genres-cloud {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
justify-content: center;
align-items: center;
}
.genre-pill {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #cbd5e0;
padding: 0.6rem 1.2rem;
border-radius: 20px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
white-space: nowrap;
}
.genre-pill:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
border-color: rgba(102, 126, 234, 0.6);
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
.genre-pill.active {
background: linear-gradient(135deg, #667eea, #764ba2);
border-color: #667eea;
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
/* Premium Track Actions - Glassmorphism Style */
.track-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
padding: 0;
margin-top: 1rem;
}
.play-track-btn, .add-to-cart-btn, .premium-feature-btn {
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.15) 0%,
rgba(255, 255, 255, 0.05) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
padding: 1rem 1.2rem;
color: white;
font-weight: 700;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.6rem;
font-size: 0.85rem;
text-decoration: none;
position: relative;
overflow: hidden;
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.play-track-btn::before, .add-to-cart-btn::before, .premium-feature-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent);
transition: left 0.6s ease;
}
.play-track-btn:hover::before, .add-to-cart-btn:hover::before, .premium-feature-btn:hover::before {
left: 100%;
}
.play-track-btn i, .add-to-cart-btn i, .premium-feature-btn i {
font-size: 1.4rem;
transition: all 0.3s ease;
}
.play-track-btn:hover, .add-to-cart-btn:hover, .premium-feature-btn:hover {
transform: translateY(-4px) scale(1.02);
border-color: rgba(255, 255, 255, 0.4);
box-shadow:
0 15px 45px rgba(0, 0, 0, 0.2),
0 8px 25px rgba(102, 126, 234, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.play-track-btn:hover i, .add-to-cart-btn:hover i, .premium-feature-btn:hover i {
transform: scale(1.1);
}
/* Individual Button Accents */
.play-track-btn {
background: linear-gradient(145deg,
rgba(102, 126, 234, 0.3) 0%,
rgba(118, 75, 162, 0.2) 100%);
border-color: rgba(102, 126, 234, 0.4);
}
.play-track-btn:hover {
background: linear-gradient(145deg,
rgba(102, 126, 234, 0.5) 0%,
rgba(118, 75, 162, 0.4) 100%);
border-color: rgba(102, 126, 234, 0.6);
box-shadow:
0 15px 45px rgba(0, 0, 0, 0.2),
0 8px 25px rgba(102, 126, 234, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.play-track-btn.playing {
background: linear-gradient(145deg,
rgba(245, 158, 11, 0.4) 0%,
rgba(217, 119, 6, 0.3) 100%);
border-color: rgba(245, 158, 11, 0.6);
animation: playingGlow 2s ease-in-out infinite alternate;
}
@keyframes playingGlow {
0% {
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
0 4px 16px rgba(245, 158, 11, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
100% {
box-shadow:
0 15px 45px rgba(0, 0, 0, 0.2),
0 8px 32px rgba(245, 158, 11, 0.7),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
}
.add-to-cart-btn {
background: linear-gradient(145deg,
rgba(72, 187, 120, 0.3) 0%,
rgba(56, 161, 105, 0.2) 100%);
border-color: rgba(72, 187, 120, 0.4);
}
.add-to-cart-btn:hover {
background: linear-gradient(145deg,
rgba(72, 187, 120, 0.5) 0%,
rgba(56, 161, 105, 0.4) 100%);
border-color: rgba(72, 187, 120, 0.6);
box-shadow:
0 15px 45px rgba(0, 0, 0, 0.2),
0 8px 25px rgba(72, 187, 120, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.premium-feature-btn {
background: linear-gradient(145deg,
rgba(245, 158, 11, 0.3) 0%,
rgba(217, 119, 6, 0.2) 100%);
border-color: rgba(245, 158, 11, 0.4);
}
.premium-feature-btn:hover {
background: linear-gradient(145deg,
rgba(245, 158, 11, 0.5) 0%,
rgba(217, 119, 6, 0.4) 100%);
border-color: rgba(245, 158, 11, 0.6);
box-shadow:
0 15px 45px rgba(0, 0, 0, 0.2),
0 8px 25px rgba(245, 158, 11, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
/* Button Loading States */
.track-actions button[disabled] {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
}
.track-actions button.loading {
pointer-events: none;
}
.track-actions button.loading i {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Mobile Responsive */
@media (max-width: 768px) {
.track-actions {
grid-template-columns: 1fr;
gap: 0.8rem;
}
.play-track-btn, .add-to-cart-btn, .premium-feature-btn {
padding: 1rem;
flex-direction: row;
justify-content: center;
}
.play-track-btn i, .add-to-cart-btn i, .premium-feature-btn i {
font-size: 1.2rem;
}
}
/* Premium Lyrics Section */
.track-lyrics-section {
margin: 1.5rem;
background: linear-gradient(135deg,
rgba(0, 0, 0, 0.4) 0%,
rgba(15, 15, 25, 0.6) 100%);
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
overflow: hidden;
backdrop-filter: blur(10px);
}
.lyrics-toggle {
width: 100%;
background: transparent;
border: none;
color: white;
padding: 1rem 1.5rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 1rem;
font-size: 0.95rem;
font-weight: 600;
transition: all 0.3s ease;
border-radius: 16px;
}
.lyrics-toggle:hover {
background: rgba(255, 255, 255, 0.05);
}
.lyrics-toggle span {
flex: 1;
text-align: left;
}
.toggle-icon {
transition: transform 0.3s ease;
color: #667eea;
}
.lyrics-toggle.active .toggle-icon {
transform: rotate(180deg);
}
.lyrics-toggle.active span {
color: #667eea;
}
.lyrics-content {
border-top: 1px solid rgba(255, 255, 255, 0.1);
max-height: 0;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.lyrics-content.expanded {
max-height: 400px;
overflow-y: auto;
}
.lyrics-text {
padding: 1.5rem;
line-height: 1.8;
color: #cbd5e0;
font-size: 0.95rem;
white-space: pre-line;
font-family: 'Georgia', serif;
text-align: center;
background: linear-gradient(135deg,
rgba(255, 255, 255, 0.02) 0%,
rgba(255, 255, 255, 0.05) 100%);
position: relative;
}
.lyrics-text::before {
content: '"';
position: absolute;
top: 0.5rem;
left: 1rem;
font-size: 3rem;
color: rgba(102, 126, 234, 0.3);
font-weight: bold;
line-height: 1;
}
.lyrics-text::after {
content: '"';
position: absolute;
bottom: 0.5rem;
right: 1rem;
font-size: 3rem;
color: rgba(102, 126, 234, 0.3);
font-weight: bold;
line-height: 1;
}
/* COMPACT TRACK CARDS - 50% SMALLER */
.track-card.compact-card {
background: linear-gradient(145deg,
rgba(15, 15, 35, 0.95) 0%,
rgba(25, 25, 45, 0.9) 50%,
rgba(35, 35, 55, 0.85) 100%);
border: 1px solid rgba(102, 126, 234, 0.2);
border-radius: 16px;
padding: 1rem;
margin-bottom: 1rem;
max-width: 320px;
transition: all 0.3s ease;
backdrop-filter: blur(20px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.track-card.compact-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.4);
}
/* Compact Header */
.compact-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.artist-mini {
display: flex;
align-items: center;
gap: 0.8rem;
flex: 1;
}
.artist-avatar-mini {
width: 32px;
height: 32px;
border-radius: 8px;
overflow: hidden;
}
.artist-avatar-mini img,
.default-avatar-mini {
width: 100%;
height: 100%;
object-fit: cover;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
border-radius: 8px;
}
.artist-info-mini {
flex: 1;
min-width: 0;
}
.track-title-mini {
color: white;
font-size: 1rem;
font-weight: 700;
margin-bottom: 0.2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.artist-name-mini {
color: #a0aec0;
font-size: 0.8rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Quick Actions */
.quick-actions {
display: flex;
align-items: center;
gap: 0.5rem;
}
.action-btn {
width: 32px;
height: 32px;
border-radius: 8px;
border: none;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
font-size: 0.9rem;
}
.action-btn:hover {
transform: scale(1.1);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
.action-btn.play-btn.playing {
background: linear-gradient(135deg, #48bb78, #38a169);
animation: playingPulse 1.5s ease-in-out infinite;
}
.track-card.playing {
border-color: rgba(67, 233, 123, 0.6);
box-shadow: 0 8px 30px rgba(67, 233, 123, 0.3);
}
@keyframes playingPulse {
0%, 100% {
box-shadow: 0 4px 15px rgba(72, 187, 120, 0.4);
transform: scale(1);
}
50% {
box-shadow: 0 8px 25px rgba(72, 187, 120, 0.7);
transform: scale(1.05);
}
}
.price-mini {
font-size: 0.8rem;
color: #ffd700;
font-weight: 600;
white-space: nowrap;
}
/* Compact DJ Tech Grid */
.dj-tech-compact {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.5rem;
margin-bottom: 1rem;
padding: 0.8rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
border: 1px solid rgba(102, 126, 234, 0.2);
}
.tech-item {
text-align: center;
padding: 0.3rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
transition: all 0.3s ease;
}
.tech-item:hover {
background: rgba(102, 126, 234, 0.1);
transform: scale(1.05);
}
.tech-label {
font-size: 0.7rem;
color: #a0aec0;
display: block;
margin-bottom: 0.2rem;
}
.tech-value {
font-size: 0.8rem;
font-weight: 700;
color: white;
}
.tech-value.bpm-value { color: #ff6b6b; }
.tech-value.key-value { color: #4ecdc4; }
.tech-value.mood-value { color: #feca57; }
.tech-value.energy-value { color: #ff9ff3; }
/* Clickable Genres */
.track-genres {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.genre-tag {
padding: 0.3rem 0.8rem;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 12px;
font-size: 0.7rem;
color: #667eea;
cursor: pointer;
transition: all 0.3s ease;
}
.genre-tag:hover {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
transform: scale(1.05);
color: white;
}
/* Compact Waveform */
.waveform-compact {
height: 40px;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
padding: 0.5rem;
display: flex;
align-items: end;
gap: 2px;
cursor: pointer;
margin-bottom: 1rem;
transition: all 0.3s ease;
}
.waveform-compact:hover {
background: rgba(102, 126, 234, 0.1);
}
.wave-bar {
flex: 1;
background: linear-gradient(to top, #667eea, #764ba2);
border-radius: 1px;
min-height: 8px;
transition: all 0.3s ease;
}
.waveform-compact:hover .wave-bar {
background: linear-gradient(to top, #5a67d8, #6b46c1);
}
/* Bottom Section */
.bottom-section {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
.track-stats {
display: flex;
gap: 0.8rem;
font-size: 0.8rem;
color: #a0aec0;
}
.track-stats span {
display: flex;
align-items: center;
gap: 0.3rem;
}
.track-stats i {
font-size: 0.7rem;
}
/* Compact Rating */
.rating-compact {
display: flex;
align-items: center;
gap: 0.5rem;
}
.star-rating-mini {
display: flex;
gap: 2px;
}
.star-mini {
font-size: 0.9rem;
color: #4a5568;
cursor: pointer;
transition: all 0.2s ease;
}
.star-mini.filled {
color: #ffd700;
}
.star-mini:hover {
color: #ffd700;
transform: scale(1.2);
}
.rating-text {
font-size: 0.8rem;
color: #a0aec0;
font-weight: 600;
}
/* Compact Social Actions */
.social-compact {
display: flex;
gap: 0.3rem;
}
.social-btn-mini {
width: 24px;
height: 24px;
border: none;
background: rgba(255, 255, 255, 0.1);
color: #a0aec0;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
font-size: 0.8rem;
}
.social-btn-mini:hover {
background: rgba(102, 126, 234, 0.2);
color: white;
transform: scale(1.1);
}
.social-btn-mini.like-btn.liked {
background: linear-gradient(135deg, #ff6b9d, #c44569);
color: white;
}
/* Pagination Controls */
.pagination-container {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin: 3rem 0;
padding: 2rem;
}
.pagination-info {
color: #a0aec0;
font-size: 1.4rem;
}
.pagination-controls {
display: flex;
gap: 0.5rem;
align-items: center;
}
.page-btn {
padding: 0.8rem 1.2rem;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: #a0aec0;
text-decoration: none;
transition: all 0.3s ease;
font-weight: 500;
}
.page-btn:hover,
.page-btn.active {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-color: transparent;
transform: translateY(-2px);
}
.page-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Grid Layout for Compact Cards */
.tracks-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
padding: 0 1rem;
justify-items: center;
max-width: 1400px;
margin-left: auto;
margin-right: auto;
}
/* Share Modal Styles */
.share-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(5px);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.share-modal.show {
opacity: 1;
}
.share-modal-content {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(25px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
padding: 2rem;
width: 90%;
max-width: 500px;
color: white;
animation: modalSlideIn 0.3s ease;
}
@keyframes modalSlideIn {
from {
transform: translateY(-50px) scale(0.9);
opacity: 0;
}
to {
transform: translateY(0) scale(1);
opacity: 1;
}
}
.share-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.share-header h3 {
margin: 0;
font-size: 1.5rem;
}
.close-modal {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
}
.close-modal:hover {
background: rgba(255, 255, 255, 0.1);
}
.share-options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.share-option {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1rem;
color: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.8rem;
font-size: 1rem;
}
.share-option:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateY(-2px);
}
.share-option i {
font-size: 1.2rem;
}
/* Mobile Responsiveness */
@media (max-width: 768px) {
.tracks-grid {
grid-template-columns: 1fr;
}
.track-card.compact-card {
max-width: 100%;
}
.dj-tech-compact {
grid-template-columns: repeat(2, 1fr);
gap: 0.3rem;
}
.bottom-section {
flex-direction: column;
gap: 0.8rem;
}
.share-options {
grid-template-columns: 1fr;
}
}
</style>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<div class="hero-content">
<div class="hero-badge">
<i class="fas fa-music"></i>
Your Music Library
</div>
<h1 class="hero-title">Your Studio Collection</h1>
<p class="hero-subtitle">Manage, play, and share your AI-generated tracks. Every creation is a masterpiece waiting to be discovered.</p>
</div>
<div class="hero-visual">
<div class="floating-elements">
<div class="floating-note">βͺ</div>
<div class="floating-note">β«</div>
<div class="floating-note">β¬</div>
<div class="floating-note">π΅</div>
<div class="floating-note">πΆ</div>
</div>
</div>
</div>
</section>
<!-- Community Content -->
<section class="community-content">
<div class="container">
<!-- Library Stats -->
<div class="community-stats">
<div class="stat-card">
<div class="stat-number"><?= $user_stats['total_tracks'] ?></div>
<div class="stat-label">Total Tracks</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $user_stats['completed_tracks'] ?></div>
<div class="stat-label">Completed</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $user_stats['processing_tracks'] ?></div>
<div class="stat-label">Processing</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $credits ?></div>
<div class="stat-label">Credits Left</div>
</div>
</div>
<!-- Filter Controls -->
<div class="filter-controls">
<div class="filter-row">
<div class="filter-group">
<label class="filter-label">Status:</label>
<select class="filter-select" onchange="window.location.href='?status=' + this.value + '&sort=<?= $sort_filter ?>'">
<option value="all" <?= $status_filter === 'all' ? 'selected' : '' ?>>All Tracks</option>
<option value="complete" <?= $status_filter === 'complete' ? 'selected' : '' ?>>Completed</option>
<option value="processing" <?= $status_filter === 'processing' ? 'selected' : '' ?>>Processing</option>
<option value="failed" <?= $status_filter === 'failed' ? 'selected' : '' ?>>Failed</option>
</select>
</div>
<div class="filter-group">
<label class="filter-label">Sort By:</label>
<select class="filter-select" onchange="window.location.href='?status=<?= $status_filter ?>&sort=' + this.value">
<option value="latest" <?= $sort_filter === 'latest' ? 'selected' : '' ?>>Latest First</option>
<option value="oldest" <?= $sort_filter === 'oldest' ? 'selected' : '' ?>>Oldest First</option>
<option value="popular" <?= $sort_filter === 'popular' ? 'selected' : '' ?>>Most Popular</option>
<option value="most-played" <?= $sort_filter === 'most-played' ? 'selected' : '' ?>>Most Played</option>
</select>
</div>
</div>
</div>
<!-- Filters -->
<div class="filters">
<label>Sort by:</label>
<select id="sort-filter" onchange="filterTracks()">
<option value="latest" <?= $sort_filter === 'latest' ? 'selected' : '' ?>>Latest</option>
<option value="popular" <?= $sort_filter === 'popular' ? 'selected' : '' ?>>Most Liked</option>
</select>
<label>Time:</label>
<select id="time-filter" onchange="filterTracks()">
<option value="all" <?= $time_filter === 'all' ? 'selected' : '' ?>>All Time</option>
<option value="today" <?= $time_filter === 'today' ? 'selected' : '' ?>>Today</option>
<option value="week" <?= $time_filter === 'week' ? 'selected' : '' ?>>This Week</option>
<option value="month" <?= $time_filter === 'month' ? 'selected' : '' ?>>This Month</option>
</select>
<label>Genre:</label>
<select id="genre-filter" onchange="filterTracks()">
<option value="">All Genres (<?= count($available_genres) ?>)</option>
<?php foreach ($available_genres as $genre): ?>
<option value="<?= htmlspecialchars($genre) ?>" <?= $genre_filter === $genre ? 'selected' : '' ?>>
<?= htmlspecialchars($genre) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Tracks Grid -->
<div class="tracks-grid">
<?php if (empty($recent_tracks)): ?>
<div style="grid-column: 1 / -1; text-align: center; padding: 4rem;">
<h3>No tracks found</h3>
<p>Be the first to create amazing AI music!</p>
</div>
<?php else: ?>
<!-- Library Tracks Grid -->
<div class="tracks-grid">
<?php if (empty($tracks_with_variations)): ?>
<div class="empty-state">
<div class="empty-icon">π΅</div>
<h2 class="empty-title">No Tracks Yet</h2>
<p class="empty-description">
Start creating your first AI-generated track and build your music library.
</p>
<a href="/#create" class="create-first-btn">
<i class="fas fa-plus"></i>
Create Your First Track
</a>
</div>
<?php else: ?>
<?php foreach ($tracks_with_variations as $track):
$displayTitle = $track['title'] ?: 'Untitled Track';
$duration = floor($track['duration'] / 60) . 'm ' . ($track['duration'] % 60) . 's';
$created_date = date('M j, Y', strtotime($track['created_at']));
$error_message = $track['error_message'] ?? null;
?>
<div class="track-card compact-card" data-track-id="<?= $track['id'] ?>" data-status="<?= $track['status'] ?>" data-variations="<?= htmlspecialchars(json_encode($track['variations'] ?? [])) ?>" data-selected-variation="<?= $track['selected_variation_index'] ?? 0 ?>">
<!-- Track Header -->
<div class="compact-header">
<div class="artist-mini">
<div class="artist-avatar-mini">
<div class="default-avatar-mini"><?= substr(htmlspecialchars($user_name), 0, 1) ?></div>
</div>
<div class="artist-info-mini">
<div class="track-title-mini"><?= htmlspecialchars($displayTitle) ?></div>
<div class="artist-name-mini">by <?= htmlspecialchars($user_name) ?></div>
</div>
</div>
<!-- Status Badge -->
<?php if ($track['badge']): ?>
<div class="track-badge"><?= $track['badge'] ?></div>
<?php endif; ?>
<!-- Status Indicator -->
<div class="status-indicator">
<?php if ($track['status'] === 'complete'): ?>
<span class="status-complete">Complete</span>
<?php elseif ($track['status'] === 'processing'): ?>
<span class="status-processing">Processing</span>
<?php elseif ($track['status'] === 'failed'): ?>
<span class="status-failed">Failed</span>
<?php endif; ?>
</div>
</div>
<!-- Track Prompt -->
<?php if ($track['prompt']): ?>
<div class="track-prompt">
<?= htmlspecialchars($track['prompt']) ?>
</div>
<?php endif; ?>
<!-- Error Message for Failed Tracks -->
<?php if ($track['status'] === 'failed' && $error_message): ?>
<div class="error-message-modern">
<div class="error-header">
<i class="fas fa-exclamation-triangle"></i>
<strong>Error Details:</strong>
</div>
<div class="error-content">
<?= htmlspecialchars($error_message) ?>
</div>
<div class="error-tip">
<i class="fas fa-lightbulb"></i>
<strong>Quick Fix:</strong>
<?php if (stripos($error_message, 'artist name') !== false): ?>
Avoid mentioning existing artists or bands. Use music genres and styles instead.
<?php elseif (stripos($error_message, 'copyright') !== false): ?>
Don't reference existing songs, lyrics, or copyrighted material.
<?php elseif (stripos($error_message, 'inappropriate') !== false): ?>
Keep content family-friendly and appropriate.
<?php else: ?>
Try modifying your prompt to be more generic and avoid specific names.
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<!-- Track Metadata -->
<div class="track-metadata">
<div class="metadata-item">
<div class="metadata-label">Duration</div>
<div class="metadata-value"><?= $duration ?></div>
</div>
<div class="metadata-item">
<div class="metadata-label">Created</div>
<div class="metadata-value"><?= $created_date ?></div>
</div>
<?php if ($track['variation_count'] > 0): ?>
<div class="metadata-item">
<div class="metadata-label">Variations</div>
<div class="metadata-value"><?= $track['variation_count'] ?></div>
</div>
<?php endif; ?>
</div>
<!-- Track Actions -->
<div class="track-actions-modern">
<?php if ($track['status'] === 'complete'): ?>
<button class="action-btn primary" onclick="playTrackFromButton(this)"
data-audio-url="<?= htmlspecialchars($track['audio_url']) ?>"
data-title="<?= htmlspecialchars($displayTitle) ?>"
data-artist="<?= htmlspecialchars($user_name) ?>"
title="Play Track">
<i class="fas fa-play"></i>
Play
</button>
<button class="action-btn" onclick="downloadTrack(<?= $track['id'] ?>)" title="Download Track">
<i class="fas fa-download"></i>
Download
</button>
<?php if ($track['variation_count'] > 0): ?>
<button class="action-btn" onclick="showVariations(<?= $track['id'] ?>)" title="View Variations">
<i class="fas fa-layer-group"></i>
Variations
</button>
<?php endif; ?>
<button class="action-btn" onclick="showLyrics(<?= $track['id'] ?>)" title="View Lyrics">
<i class="fas fa-music"></i>
Lyrics
</button>
<?php elseif ($track['status'] === 'processing'): ?>
<div class="processing-actions">
<button class="action-btn" onclick="checkTrackStatus(<?= $track['id'] ?>)" title="Check Status">
<i class="fas fa-sync-alt"></i>
Check Status
</button>
</div>
<?php elseif ($track['status'] === 'failed'): ?>
<div class="failed-actions-modern">
<button class="action-btn primary" onclick="retryTrack(<?= $track['id'] ?>)" title="Create a new version with the same prompt">
<i class="fas fa-redo"></i>
Retry
</button>
<button class="action-btn" onclick="showFailureHelp(<?= $track['id'] ?>)" title="Why did this fail?">
<i class="fas fa-question-circle"></i>
Help
</button>
<button class="action-btn danger" onclick="deleteFailedTrack(<?= $track['id'] ?>)" title="Delete this failed track">
<i class="fas fa-trash"></i>
Delete
</button>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- Pagination Controls -->
<?php if ($total_pages > 1): ?>
<div class="pagination-container">
<div class="pagination-info">
Showing <?= (($current_page - 1) * $tracks_per_page) + 1 ?> - <?= min($current_page * $tracks_per_page, $total_tracks) ?> of <?= $total_tracks ?> tracks
</div>
<div class="pagination-controls">
<?php if ($current_page > 1): ?>
<a href="?page=<?= $current_page - 1 ?><?= $genre_filter ? '&genre=' . urlencode($genre_filter) : '' ?><?= $sort_filter !== 'latest' ? '&sort=' . urlencode($sort_filter) : '' ?>" class="page-btn">
<i class="fas fa-chevron-left"></i> Previous
</a>
<?php endif; ?>
<?php
$start_page = max(1, $current_page - 2);
$end_page = min($total_pages, $current_page + 2);
for ($i = $start_page; $i <= $end_page; $i++): ?>
<a href="?page=<?= $i ?><?= $genre_filter ? '&genre=' . urlencode($genre_filter) : '' ?><?= $sort_filter !== 'latest' ? '&sort=' . urlencode($sort_filter) : '' ?>"
class="page-btn <?= $i == $current_page ? 'active' : '' ?>">
<?= $i ?>
</a>
<?php endfor; ?>
<?php if ($current_page < $total_pages): ?>
<a href="?page=<?= $current_page + 1 ?><?= $genre_filter ? '&genre=' . urlencode($genre_filter) : '' ?><?= $sort_filter !== 'latest' ? '&sort=' . urlencode($sort_filter) : '' ?>" class="page-btn">
Next <i class="fas fa-chevron-right"></i>
</a>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</section>
</div>
<script>
console.log('π΅ Community Fixed - JavaScript loading');
// Enhanced filter function with genre support
function filterTracks() {
const sortFilter = document.getElementById('sort-filter').value;
const timeFilter = document.getElementById('time-filter').value;
const genreFilter = document.getElementById('genre-filter').value;
const url = new URL(window.location);
url.searchParams.set('sort', sortFilter);
url.searchParams.set('time', timeFilter);
if (genreFilter) {
url.searchParams.set('genre', genreFilter);
} else {
url.searchParams.delete('genre');
}
window.location.href = url.toString();
}
function filterByGenre(genre) {
const currentUrl = new URL(window.location);
currentUrl.searchParams.set('genre', genre);
currentUrl.searchParams.delete('page'); // Reset to page 1 when filtering
window.location.href = currentUrl.toString();
}
// Working like function with API integration
function toggleLike(trackId, button) {
console.log('π΅ User ID from PHP:', <?= $user_id ? $user_id : 'null' ?>);
console.log('π΅ Is logged in:', <?= $user_id ? 'true' : 'false' ?>);
if (!<?= $user_id ? 'true' : 'false' ?>) {
showNotification('Please log in to like tracks', 'warning');
return;
}
console.log('π΅ Toggling like for track:', trackId);
// Add loading state
button.style.pointerEvents = 'none';
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'like', track_id: trackId })
})
.then(response => {
console.log('π΅ Like API response status:', response.status);
return response.json();
})
.then(data => {
console.log('π΅ Like API response data:', data);
if (data.success) {
button.classList.toggle('liked');
const countSpan = button.querySelector('.social-count');
if (countSpan) {
const currentCount = parseInt(countSpan.textContent);
countSpan.textContent = button.classList.contains('liked') ? currentCount + 1 : currentCount - 1;
}
// Show success notification
const action = button.classList.contains('liked') ? 'liked' : 'unliked';
showNotification(`Track ${action}!`, 'success');
} else {
showNotification(data.message || 'Failed to like track', 'error');
}
})
.catch(error => {
console.error('π΅ Like error:', error);
showNotification('Failed to like track. Please try again.', 'error');
})
.finally(() => {
// Restore button
button.style.pointerEvents = 'auto';
button.innerHTML = originalText;
});
}
// Working comments function with modal
function showComments(trackId) {
// Create and show comments modal
const modal = document.createElement('div');
modal.className = 'comments-modal';
modal.innerHTML = `
<div class="comments-overlay">
<div class="comments-container">
<div class="comments-header">
<h3>Comments</h3>
<button class="close-btn" onclick="closeComments()">Γ</button>
</div>
<div class="comments-list" id="comments-list-${trackId}">
<div class="loading">Loading comments...</div>
</div>
<div class="comment-form">
<textarea id="comment-text-${trackId}" placeholder="Write a comment..." maxlength="500"></textarea>
<button onclick="addComment(${trackId})" class="btn btn-primary">Post Comment</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
// Load comments
loadComments(trackId);
}
function closeComments() {
const modal = document.querySelector('.comments-modal');
if (modal) {
modal.remove();
}
}
function loadComments(trackId) {
console.log('π΅ Loading comments for track:', trackId);
fetch(`/api_social.php?action=get_comments&track_id=${trackId}`)
.then(response => {
console.log('π΅ Load comments API response status:', response.status);
return response.json();
})
.then(data => {
console.log('π΅ Load comments API response data:', data);
const commentsList = document.getElementById(`comments-list-${trackId}`);
if (data.success && data.comments && data.comments.length > 0) {
commentsList.innerHTML = data.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-small\'>${comment.user_name.charAt(0)}</div>'">` :
`<div class="default-avatar-small">${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-time">${comment.created_at}</span>
</div>
<div class="comment-text">${comment.comment}</div>
</div>
</div>
`).join('');
} else {
commentsList.innerHTML = '<div class="no-comments">No comments yet. Be the first to comment!</div>';
}
})
.catch(error => {
console.error('π΅ Load comments error:', error);
document.getElementById(`comments-list-${trackId}`).innerHTML = '<div class="error">Failed to load comments</div>';
});
}
function addComment(trackId) {
if (!<?= $user_id ? 'true' : 'false' ?>) {
showNotification('Please log in to comment', 'warning');
return;
}
const textarea = document.getElementById(`comment-text-${trackId}`);
const comment = textarea.value.trim();
if (!comment) {
showNotification('Please enter a comment', 'warning');
return;
}
// Show loading state
const submitBtn = textarea.nextElementSibling;
const originalText = submitBtn.textContent;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Posting...';
submitBtn.disabled = true;
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'comment',
track_id: trackId,
comment: comment
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
textarea.value = '';
loadComments(trackId); // Reload comments
showNotification('Comment posted!', 'success');
} else {
showNotification(data.message || 'Failed to post comment', 'error');
}
})
.catch(error => {
console.error('π΅ Comment error:', error);
showNotification('Failed to post comment. Please try again.', 'error');
})
.finally(() => {
// Restore button
submitBtn.textContent = originalText;
submitBtn.disabled = false;
});
}
// Notification system
function showNotification(message, type = 'info') {
// Remove existing notifications
const existingNotifications = document.querySelectorAll('.notification');
existingNotifications.forEach(notification => notification.remove());
// Create notification element
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="notification-icon ${getNotificationIcon(type)}"></i>
<span class="notification-message">${message}</span>
<button class="notification-close" onclick="this.parentElement.parentElement.remove()">
<i class="fas fa-times"></i>
</button>
</div>
`;
// Add to page
document.body.appendChild(notification);
// Show animation
setTimeout(() => {
notification.classList.add('show');
}, 100);
// Auto remove after 5 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 300);
}, 5000);
}
function getNotificationIcon(type) {
switch (type) {
case 'success': return 'fas fa-check-circle';
case 'error': return 'fas fa-exclamation-circle';
case 'warning': return 'fas fa-exclamation-triangle';
default: return 'fas fa-info-circle';
}
}
// Global player initialization check
function waitForGlobalPlayer(callback, maxAttempts = 20) {
if (window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
callback();
return;
}
if (maxAttempts > 0) {
setTimeout(() => waitForGlobalPlayer(callback, maxAttempts - 1), 250);
} else {
console.error('β Global player failed to initialize');
showNotification('Audio player not available. Please refresh the page.', 'error');
}
}
// Enable play buttons when global player is ready
function enablePlayButtons() {
console.log('π΅ Enabling play buttons - global player ready');
// Enable all play buttons
document.querySelectorAll('.action-btn.play-btn, .play-track-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
showNotification('π΅ Audio player ready!', 'success');
}
// Professional music feed functions
function playTrack(trackId, audioUrl, title, artist) {
console.log('π΅ Playing track:', { trackId, audioUrl, title, artist });
// Ensure global player is ready before attempting playback
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('.track-card').forEach(card => {
card.classList.remove('currently-playing', 'playing');
});
// Reset all play buttons
document.querySelectorAll('.action-btn.play-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 compact play button
const compactPlayBtn = currentCard.querySelector('.action-btn.play-btn');
if (compactPlayBtn) {
compactPlayBtn.classList.add('playing');
const icon = compactPlayBtn.querySelector('i');
if (icon) icon.className = 'fas fa-pause';
}
// Update full play button if exists
const fullPlayBtn = currentCard.querySelector('.play-track-btn');
if (fullPlayBtn) {
fullPlayBtn.classList.add('playing');
fullPlayBtn.innerHTML = '<i class="fas fa-pause"></i> <span>Playing</span>';
}
}
// Record play analytics
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');
}
}
function playTrackFromWaveform(trackId, audioUrl, title, artist) {
playTrack(trackId, audioUrl, title, artist);
}
function addToCart(trackId, title, price, artistPlan = 'free') {
if (!<?= $user_id ? 'true' : 'false' ?>) {
showNotification('Please log in to add tracks to cart', 'warning');
return;
}
console.log('π Adding to cart:', { trackId, title, price, artistPlan });
// Add loading state to button
const button = event.target.closest('.btn-cart');
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Adding...';
button.disabled = true;
// Send to cart.php via POST with artist plan info
const formData = new FormData();
formData.append('track_id', trackId);
formData.append('action', 'add');
formData.append('artist_plan', artistPlan);
fetch('cart.php', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(responseText => {
console.log('π Raw cart response:', responseText);
let data;
try {
data = JSON.parse(responseText);
console.log('π Parsed cart response:', data);
} catch (e) {
console.error('π Failed to parse JSON response:', e);
console.error('π Raw response was:', responseText);
throw new Error('Invalid JSON response from cart');
}
if (!data.success) {
throw new Error(data.message || 'Failed to add to cart');
}
if (price == 0) {
// Free track - make it feel like a premium purchase experience!
showNotification(`π΅ "${title}" added to cart for FREE! π Ready to purchase and own!`, 'success');
} else {
// Paid track added to cart
const revenueInfo = (artistPlan === 'free') ? ' (Platform Revenue)' : '';
showNotification(`"${title}" added to cart! ($${price})${revenueInfo}`, 'success');
}
// Update cart UI if there's a cart counter
const cartCounter = document.querySelector('.cart-count, .cart-counter');
if (cartCounter && data.cart_count) {
cartCounter.textContent = data.cart_count;
}
// Log debug info if available
if (data.debug) {
console.log('π Debug info:', data.debug);
}
// Change button to "Added" state temporarily
button.innerHTML = '<i class="fas fa-check"></i> Added!';
button.classList.add('added');
setTimeout(() => {
button.innerHTML = originalText;
button.classList.remove('added');
button.disabled = false;
}, 2000);
})
.catch(error => {
console.error('π Cart error:', error);
showNotification('Failed to add to cart: ' + error.message, 'error');
// Restore button
button.innerHTML = originalText;
button.disabled = false;
});
}
function toggleFollow(userId, button) {
if (!<?= $user_id ? 'true' : 'false' ?>) {
showNotification('Please log in to follow artists', 'warning');
return;
}
console.log('π€ Toggling follow for user:', userId);
// Add loading state
button.style.pointerEvents = 'none';
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'follow', user_id: userId })
})
.then(response => {
console.log('π€ Follow API response status:', response.status);
return response.json();
})
.then(data => {
console.log('π€ Follow API response data:', data);
if (data.success) {
button.classList.toggle('following');
const isFollowing = button.classList.contains('following');
button.innerHTML = `<i class="fas fa-user-${isFollowing ? 'check' : 'plus'}"></i> ${isFollowing ? 'Following' : 'Follow'}`;
// Show success notification
const action = isFollowing ? 'followed' : 'unfollowed';
showNotification(`Artist ${action}!`, 'success');
} else {
showNotification(data.message || 'Failed to follow artist', 'error');
}
})
.catch(error => {
console.error('π€ Follow error:', error);
showNotification('Failed to follow artist. Please try again.', 'error');
})
.finally(() => {
// Restore button
button.style.pointerEvents = 'auto';
if (!button.innerHTML.includes('Following') && !button.innerHTML.includes('Follow')) {
button.innerHTML = originalText;
}
});
}
// Track play count functionality
function recordTrackPlay(trackId) {
// Only record if not already recorded recently
const lastPlayed = sessionStorage.getItem(`played_${trackId}`);
const now = Date.now();
if (!lastPlayed || (now - parseInt(lastPlayed)) > 30000) { // 30 seconds minimum between plays
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'play', track_id: trackId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
sessionStorage.setItem(`played_${trackId}`, now.toString());
console.log('π΅ Play count recorded for track:', trackId);
}
})
.catch(error => {
console.error('π΅ Play count error:', error);
});
}
}
// Play button functionality is now handled by inline onclick="togglePlayPause()" calls
// This prevents conflicts and ensures proper parameter passing
document.addEventListener('DOMContentLoaded', function() {
console.log('π΅ Community Fixed - Initialized (play buttons use inline handlers)');
});
// π VIRAL TRACK SHARING SYSTEM
function showShareModal(trackId, title, artist) {
const trackUrl = `https://soundstudiopro.com/track/${trackId}`;
const shareText = `π΅ Check out "${title}" by ${artist}`;
// Update share URL input
document.getElementById('shareUrl').value = trackUrl;
// Update social share links
const platforms = {
twitter: `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(trackUrl)}`,
facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(trackUrl)}`,
whatsapp: `https://wa.me/?text=${encodeURIComponent(shareText + ' ' + trackUrl)}`,
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(trackUrl)}`,
discord: `https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=${encodeURIComponent(trackUrl)}&response_type=code&scope=webhook.incoming`
};
// Update platform buttons
document.querySelector('[data-platform="twitter"]').onclick = () => openShare(platforms.twitter, 'twitter', trackId);
document.querySelector('[data-platform="facebook"]').onclick = () => openShare(platforms.facebook, 'facebook', trackId);
document.querySelector('[data-platform="whatsapp"]').onclick = () => openShare(platforms.whatsapp, 'whatsapp', trackId);
document.querySelector('[data-platform="linkedin"]').onclick = () => openShare(platforms.linkedin, 'linkedin', trackId);
document.querySelector('[data-platform="discord"]').onclick = () => copyDiscordLink(trackUrl, trackId);
document.getElementById('shareModal').style.display = 'block';
document.body.style.overflow = 'hidden';
}
function openShare(url, platform, trackId) {
window.open(url, '_blank', 'width=600,height=400');
recordShare(trackId, platform);
closeShareModal();
}
function copyShareUrl() {
const shareUrl = document.getElementById('shareUrl');
shareUrl.select();
shareUrl.setSelectionRange(0, 99999);
navigator.clipboard.writeText(shareUrl.value);
const copyBtn = document.querySelector('.copy-btn');
const originalText = copyBtn.textContent;
copyBtn.textContent = 'Copied!';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = originalText;
copyBtn.classList.remove('copied');
}, 2000);
// Record share
const trackId = shareUrl.value.split('/track/')[1];
recordShare(trackId, 'copy-link');
}
function copyDiscordLink(url, text, trackId) {
const discordText = `π΅ ${text}\\n${url}`;
navigator.clipboard.writeText(discordText).then(() => {
recordShare(trackId, 'discord');
showNotification('Discord message copied! Paste it in your server π', 'success');
});
}
function copyInstagramLink(url, text, trackId) {
navigator.clipboard.writeText(url).then(() => {
recordShare(trackId, 'instagram');
showNotification('Link copied! Add it to your Instagram story πΈ', 'success');
});
}
function recordShare(trackId, platform) {
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'share',
track_id: trackId,
platform: platform
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log(`π Share recorded: ${platform} for track ${trackId}`);
// Update share count in UI
const shareButton = document.querySelector(`[onclick*="${trackId}"] .social-count`);
if (shareButton) {
const currentCount = parseInt(shareButton.textContent);
shareButton.textContent = currentCount + 1;
}
}
})
.catch(error => {
console.error('π Share recording error:', error);
});
}
// Handle shared track highlighting from URL
function handleSharedTrack() {
const urlParams = new URLSearchParams(window.location.search);
const trackId = urlParams.get('track');
if (trackId) {
// Find the track card
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`)?.closest('.track-card');
if (trackCard) {
// Scroll to the track
setTimeout(() => {
trackCard.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
// Add highlight effect
trackCard.classList.add('highlighted');
// Optional: Auto-play the track
const playButton = trackCard.querySelector('.play-track-btn');
if (playButton) {
setTimeout(() => {
playButton.click();
}, 1000);
}
// Remove highlight after animation
setTimeout(() => {
trackCard.classList.remove('highlighted');
}, 3000);
}, 500);
showNotification('π΅ Shared track found! Playing now...', 'success');
} else {
showNotification('Track not found on this page', 'warning');
}
}
}
// Initialize shared track handling
document.addEventListener('DOMContentLoaded', function() {
handleSharedTrack();
});
// Close modal when clicking outside
document.addEventListener('click', function(e) {
if (e.target.classList.contains('share-modal')) {
closeShareModal();
}
});
// DJ Mixing Features
function highlightCompatibleTracks(currentBpm, currentKey) {
const tracks = document.querySelectorAll('.track-card');
tracks.forEach(track => {
const bpmElement = track.querySelector('.bpm-value');
const keyElement = track.querySelector('.key-value');
if (bpmElement && keyElement) {
const trackBpm = parseInt(bpmElement.textContent);
const trackKey = keyElement.textContent;
// BPM compatibility (within 6% for mixing)
const bpmDiff = Math.abs(trackBpm - currentBpm);
const bpmCompatible = bpmDiff <= (currentBpm * 0.06);
// Key compatibility (same key, relative major/minor, perfect 5th)
const keyCompatible = isKeyCompatible(currentKey, trackKey);
// Add visual indicators
if (bpmCompatible) {
bpmElement.parentElement.classList.add('bpm-compatible');
}
if (keyCompatible) {
keyElement.parentElement.classList.add('key-compatible');
}
if (bpmCompatible && keyCompatible) {
track.classList.add('perfect-mix-match');
}
}
});
}
function isKeyCompatible(key1, key2) {
// Simplified key compatibility - same key, relative major/minor
if (key1 === key2) return true;
// Basic major/minor relative matching
const keyMap = {
'C major': 'A minor',
'A minor': 'C major',
'G major': 'E minor',
'E minor': 'G major',
'D major': 'B minor',
'B minor': 'D major',
'A major': 'F# minor',
'F# minor': 'A major',
'E major': 'C# minor',
'C# minor': 'E major',
'F major': 'D minor',
'D minor': 'F major',
'Bb major': 'G minor',
'G minor': 'Bb major'
};
return keyMap[key1] === key2;
}
function calculateBpmRange(bpm) {
const range = Math.round(bpm * 0.06);
return {
min: bpm - range,
max: bpm + range,
half: Math.round(bpm / 2),
double: bpm * 2
};
}
// Enhanced track clicking for DJ mode
function selectTrackForDjMode(trackElement) {
// Clear previous selections
document.querySelectorAll('.track-card.dj-selected').forEach(card => {
card.classList.remove('dj-selected');
});
// Mark as selected
trackElement.classList.add('dj-selected');
// Get technical info
const bpmElement = trackElement.querySelector('.bpm-value');
const keyElement = trackElement.querySelector('.key-value');
if (bpmElement && keyElement) {
const bpm = parseInt(bpmElement.textContent);
const key = keyElement.textContent;
// Highlight compatible tracks
highlightCompatibleTracks(bpm, key);
// Show DJ info panel
showDjMixingPanel(bpm, key);
}
}
function showDjMixingPanel(bpm, key) {
const bpmRange = calculateBpmRange(bpm);
// Create or update DJ panel
let djPanel = document.getElementById('dj-mixing-panel');
if (!djPanel) {
djPanel = document.createElement('div');
djPanel.id = 'dj-mixing-panel';
djPanel.className = 'dj-mixing-panel';
document.body.appendChild(djPanel);
}
djPanel.innerHTML = `
<div class="dj-panel-header">
<h3>π§ DJ Mixing Info</h3>
<button onclick="closeDjPanel()" class="close-dj-panel">Γ</button>
</div>
<div class="dj-panel-content">
<div class="current-track-info">
<div class="dj-info-item">
<label>Current BPM:</label>
<span class="dj-bpm">${bpm}</span>
</div>
<div class="dj-info-item">
<label>Current Key:</label>
<span class="dj-key">${key}</span>
</div>
</div>
<div class="mixing-suggestions">
<h4>π― Mixing Compatibility</h4>
<div class="bpm-suggestions">
<p><strong>BPM Range:</strong> ${bpmRange.min} - ${bpmRange.max}</p>
<p><strong>Half Time:</strong> ${bpmRange.half} BPM</p>
<p><strong>Double Time:</strong> ${bpmRange.double} BPM</p>
</div>
<div class="key-suggestions">
<p><strong>Compatible Keys:</strong> Same key, relative major/minor</p>
</div>
</div>
</div>
`;
djPanel.style.display = 'block';
}
function closeDjPanel() {
const djPanel = document.getElementById('dj-mixing-panel');
if (djPanel) {
djPanel.style.display = 'none';
}
// Clear all highlighting
document.querySelectorAll('.track-card').forEach(card => {
card.classList.remove('dj-selected', 'perfect-mix-match');
});
document.querySelectorAll('.bpm-compatible').forEach(el => {
el.classList.remove('bpm-compatible');
});
document.querySelectorAll('.key-compatible').forEach(el => {
el.classList.remove('key-compatible');
});
}
// Add click handlers for DJ mode
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.dj-tech-grid').forEach(grid => {
grid.addEventListener('click', function(e) {
e.preventDefault();
const trackCard = this.closest('.track-card');
selectTrackForDjMode(trackCard);
});
});
});
// Premium Rating System
function rateTrack(trackId, rating, starElement) {
if (!<?= $user_id ? 'true' : 'false' ?>) {
showNotification('Please log in to rate tracks', 'warning');
return;
}
console.log('β Rating track:', trackId, 'with', rating, 'stars');
// Add loading state
const ratingContainer = starElement.closest('.star-rating');
ratingContainer.style.pointerEvents = 'none';
fetch('/api_social.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'rate',
track_id: trackId,
rating: rating
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update visual rating
const stars = ratingContainer.querySelectorAll('.star');
stars.forEach((star, index) => {
star.classList.remove('filled', 'user-rated');
if (index < data.average_rating) {
star.classList.add('filled');
}
if (index < rating) {
star.classList.add('user-rated');
}
});
// Update stats
const avgElement = ratingContainer.closest('.track-rating-section').querySelector('.avg-rating');
const countElement = ratingContainer.closest('.track-rating-section').querySelector('.rating-count');
if (avgElement) avgElement.textContent = data.average_rating.toFixed(1) + '/10';
if (countElement) countElement.textContent = `(${data.rating_count} ratings)`;
showNotification(`β Rated ${rating}/10 stars!`, 'success');
} else {
showNotification(data.message || 'Failed to rate track', 'error');
}
})
.catch(error => {
console.error('β Rating error:', error);
showNotification('Failed to rate track. Please try again.', 'error');
})
.finally(() => {
ratingContainer.style.pointerEvents = 'auto';
});
}
// Enhanced Play/Pause Logic
let currentlyPlayingTrackId = null;
function togglePlayPause(button, trackId, audioUrl, title, artist) {
const isCurrentlyPlaying = currentlyPlayingTrackId === trackId;
const globalPlayer = window.enhancedGlobalPlayer;
if (isCurrentlyPlaying && globalPlayer && globalPlayer.isPlaying) {
// Pause current track
globalPlayer.pause();
button.innerHTML = '<i class="fas fa-play"></i><span>Play</span>';
button.classList.remove('playing');
// Remove playing states
document.querySelectorAll('.track-card').forEach(card => {
card.classList.remove('currently-playing');
});
currentlyPlayingTrackId = null;
showNotification('βΈοΈ Paused', 'success');
} else {
// Play new track or resume
if (globalPlayer && typeof globalPlayer.playTrack === 'function') {
globalPlayer.playTrack(audioUrl, title, artist);
// Update all play buttons
document.querySelectorAll('.play-track-btn').forEach(btn => {
btn.classList.remove('playing');
btn.innerHTML = '<i class="fas fa-play"></i><span>Play</span>';
});
// Update current button
button.classList.add('playing');
button.innerHTML = '<i class="fas fa-pause"></i><span>Playing</span>';
// Update track cards
document.querySelectorAll('.track-card').forEach(card => {
card.classList.remove('currently-playing');
});
const currentCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (currentCard) {
currentCard.classList.add('currently-playing');
}
currentlyPlayingTrackId = trackId;
recordTrackPlay(trackId);
showNotification('π΅ Now playing: ' + title, 'success');
} else {
showNotification('Player not ready, please try again', 'error');
}
}
}
// View Track Charts Function
function viewTrackCharts(trackId, genre) {
// Build chart URL with track context
const chartUrl = `/charts.php?track=${trackId}&genre=${encodeURIComponent(genre)}&highlight=true`;
// Open charts in new tab or redirect
if (confirm('View this track in the global charts?')) {
window.open(chartUrl, '_blank');
}
}
// Charts Modal Functions
function showChartsModal(trackId, position, title, genre) {
document.getElementById('currentPosition').textContent = '#' + position;
document.getElementById('trackTitle').textContent = title;
document.getElementById('genreRanking').textContent = '#' + Math.floor(Math.random() * 20 + 1) + ' in ' + genre;
document.getElementById('weeklyPlays').textContent = (Math.floor(Math.random() * 1000) + 100).toLocaleString();
document.getElementById('totalRating').textContent = (Math.random() * 3 + 7).toFixed(1) + '/10';
// Random position change
const change = Math.floor(Math.random() * 20) - 10;
const changeElement = document.getElementById('positionChange');
if (change > 0) {
changeElement.textContent = 'β +' + change + ' this week';
changeElement.className = 'position-change';
} else if (change < 0) {
changeElement.textContent = 'β ' + change + ' this week';
changeElement.className = 'position-change down';
} else {
changeElement.textContent = 'β No change';
changeElement.className = 'position-change';
}
document.getElementById('chartsModal').style.display = 'flex';
document.body.style.overflow = 'hidden';
}
function closeChartsModal() {
document.getElementById('chartsModal').style.display = 'none';
document.body.style.overflow = 'auto';
}
function openFullCharts() {
closeChartsModal();
window.open('/charts.php', '_blank');
}
// Premium Modal Functions
function showPremiumModal() {
document.getElementById('premiumModal').style.display = 'flex';
document.body.style.overflow = 'hidden';
}
function closePremiumModal() {
document.getElementById('premiumModal').style.display = 'none';
document.body.style.overflow = 'auto';
}
function upgradeToPremium() {
closePremiumModal();
window.location.href = '/upgrade.php';
}
// Close modals when clicking outside
window.onclick = function(event) {
const chartsModal = document.getElementById('chartsModal');
const premiumModal = document.getElementById('premiumModal');
if (event.target === chartsModal) {
closeChartsModal();
}
if (event.target === premiumModal) {
closePremiumModal();
}
}
// Toggle Lyrics Function
function toggleLyrics(trackId) {
const lyricsContent = document.getElementById('lyrics-' + trackId);
const toggleButton = lyricsContent.previousElementSibling;
const toggleSpan = toggleButton.querySelector('span');
const toggleIcon = toggleButton.querySelector('.toggle-icon');
if (lyricsContent.style.display === 'none') {
lyricsContent.style.display = 'block';
lyricsContent.classList.add('expanded');
toggleButton.classList.add('active');
toggleSpan.textContent = 'Hide Lyrics';
} else {
lyricsContent.classList.remove('expanded');
toggleButton.classList.remove('active');
toggleSpan.textContent = 'Show Lyrics';
setTimeout(() => {
lyricsContent.style.display = 'none';
}, 400);
}
}
// Add to Playlist Function
function addToPlaylist(trackId) {
// TODO: Implement playlist functionality
showNotification('π΅ Playlist feature coming soon!', 'info');
}
// Toggle Like Function
function toggleLike(trackId, button) {
const isLiked = button.classList.contains('liked');
const action = isLiked ? 'unlike' : 'like';
fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=${action}&track_id=${trackId}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
button.classList.toggle('liked');
const icon = button.querySelector('i');
if (isLiked) {
icon.className = 'fas fa-heart';
showNotification('π Removed from favorites', 'info');
} else {
icon.className = 'fas fa-heart';
button.classList.add('liked');
showNotification('β€οΈ Added to favorites!', 'success');
}
} else {
showNotification('Failed to update like status', 'error');
}
})
.catch(error => {
console.error('Like error:', error);
showNotification('Network error', 'error');
});
}
// Show Comments Function
function showComments(trackId) {
showNotification('π¬ Comments feature coming soon!', 'info');
}
// Show Share Modal Function
function showShareModal(trackId, title, artist) {
const trackUrl = `${window.location.origin}/track/${trackId}`;
// Create modal
const modal = document.createElement('div');
modal.className = 'share-modal';
modal.style.display = 'block';
modal.innerHTML = `
<div class="share-modal-content">
<div class="share-header">
<h3>Share "${title}" by ${artist}</h3>
<button class="close-modal" onclick="this.closest('.share-modal').remove()">
<i class="fas fa-times"></i>
</button>
</div>
<div class="share-options">
<button class="share-option" onclick="copyShareUrl('${trackUrl}')">
<i class="fas fa-link"></i>
Copy Link
</button>
<button class="share-option" onclick="shareToTwitter('${trackUrl}', '${title}', '${artist}')">
<i class="fab fa-twitter"></i>
Twitter
</button>
<button class="share-option" onclick="shareToFacebook('${trackUrl}')">
<i class="fab fa-facebook"></i>
Facebook
</button>
<button class="share-option" onclick="shareToWhatsApp('${trackUrl}', '${title}', '${artist}')">
<i class="fab fa-whatsapp"></i>
WhatsApp
</button>
</div>
</div>
`;
document.body.appendChild(modal);
setTimeout(() => modal.classList.add('show'), 10);
}
// Share Functions
function copyShareUrl(url) {
navigator.clipboard.writeText(url).then(() => {
showNotification('π Link copied to clipboard!', 'success');
document.querySelector('.share-modal').remove();
}).catch(() => {
showNotification('Failed to copy link', 'error');
});
}
function shareToTwitter(url, title, artist) {
const text = `Check out "${title}" by ${artist} on SoundStudioPro! π΅`;
const twitterUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}&url=${encodeURIComponent(url)}`;
window.open(twitterUrl, '_blank');
}
function shareToFacebook(url) {
const facebookUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`;
window.open(facebookUrl, '_blank');
}
function shareToWhatsApp(url, title, artist) {
const text = `Check out "${title}" by ${artist} on SoundStudioPro! ${url}`;
const whatsappUrl = `https://wa.me/?text=${encodeURIComponent(text)}`;
window.open(whatsappUrl, '_blank');
}
// Rating System
function rateTrack(trackId, rating, starElement) {
fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=rate&track_id=${trackId}&rating=${rating}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update star display
const ratingContainer = starElement.closest('.star-rating-mini');
const stars = ratingContainer.querySelectorAll('.star-mini');
stars.forEach((star, index) => {
if (index < rating / 2) { // Convert 10-star to 5-star
star.classList.add('filled');
} else {
star.classList.remove('filled');
}
});
// Update rating text
const ratingText = ratingContainer.parentElement.querySelector('.rating-text');
if (ratingText) {
ratingText.textContent = (rating / 2).toFixed(1);
}
showNotification(`β Rated ${rating/2}/5 stars!`, 'success');
} else {
showNotification('Failed to rate track', 'error');
}
})
.catch(error => {
console.error('Rating error:', error);
showNotification('Network error', 'error');
});
}
// Add to Cart Function
function addToCart(trackId, title, price, button) {
button.disabled = true;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
fetch('/cart.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=add&track_id=${trackId}&title=${encodeURIComponent(title)}&price=${price}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification(`π "${title}" added to cart!`, 'success');
// Update cart counter if it exists
const cartCounter = document.querySelector('.cart-counter');
if (cartCounter) {
cartCounter.textContent = data.cart_count || '';
cartCounter.style.display = data.cart_count > 0 ? 'block' : 'none';
}
} else {
showNotification(data.message || 'Failed to add to cart', 'error');
}
})
.catch(error => {
console.error('Cart error:', error);
showNotification('Network error', 'error');
})
.finally(() => {
button.disabled = false;
button.innerHTML = '<i class="fas fa-shopping-cart"></i>';
});
}
// 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));
}
// Toggle Follow Function
function toggleFollow(userId, button) {
const isFollowing = button.classList.contains('following');
const action = isFollowing ? 'unfollow' : 'follow';
fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=${action}&user_id=${userId}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
button.classList.toggle('following');
const icon = button.querySelector('i');
const text = button.querySelector('span') || button.childNodes[1];
if (isFollowing) {
icon.className = 'fas fa-user-plus';
if (text) text.textContent = ' Follow';
showNotification('Unfollowed artist', 'info');
} else {
icon.className = 'fas fa-user-check';
if (text) text.textContent = ' Following';
showNotification('Following artist!', 'success');
}
} else {
showNotification('Failed to update follow status', 'error');
}
})
.catch(error => {
console.error('Follow error:', error);
showNotification('Network error', 'error');
});
}
</script>
<!-- Include the existing modals and JavaScript functions -->
<!-- This ensures all functionality is preserved -->
<!-- Variations Modal -->
<div id="variationsModal" class="variations-modal">
<div class="variations-content">
<div class="variations-header">
<h2 class="variations-title">Choose Your Track Variation</h2>
<button class="close-variations" onclick="closeVariations()">
<i class="fas fa-times"></i>
</button>
</div>
<div id="variationsGrid" class="variations-grid">
<!-- Variations will be loaded here -->
</div>
<div class="variations-footer">
<div class="variations-info">
<i class="fas fa-info-circle"></i>
Select which variation will be your main track for sale and public display. You can also download individual variations or all versions at once.
</div>
<div class="variations-actions">
<button class="variations-btn cancel" onclick="closeVariations()">
Cancel
</button>
<button id="saveVariationBtn" class="variations-btn save" onclick="saveVariationSelection()" disabled>
Save Selection
</button>
</div>
</div>
</div>
</div>
<!-- Lyrics Modal -->
<div id="lyricsModal" class="lyrics-modal">
<div class="lyrics-content">
<div class="lyrics-header">
<h2 class="lyrics-title">Track Lyrics</h2>
<button class="close-lyrics" onclick="closeLyrics()">
<i class="fas fa-times"></i>
</button>
</div>
<div id="lyricsContent" class="lyrics-body">
<!-- Lyrics will be loaded here -->
</div>
<div class="lyrics-footer">
<div class="lyrics-actions">
<button class="lyrics-btn cancel" onclick="closeLyrics()">
Close
</button>
<button class="lyrics-btn copy" onclick="copyLyrics()">
<i class="fas fa-copy"></i> Copy Lyrics
</button>
</div>
</div>
</div>
</div>
<!-- Download Modal -->
<div id="downloadModal" class="download-modal">
<div class="download-content">
<div class="download-header">
<h2 class="download-title">Download Track</h2>
<button class="close-download" onclick="closeDownload()">
<i class="fas fa-times"></i>
</button>
</div>
<div id="downloadContent" class="download-body">
<!-- Download options will be loaded here -->
</div>
<div class="download-footer">
<div class="download-actions">
<button class="download-btn cancel" onclick="closeDownload()">
Cancel
</button>
<button class="download-btn download-all" onclick="downloadAllVariations()">
<i class="fas fa-download"></i> Download All Variations
</button>
</div>
</div>
</div>
</div>
<script>
// Global variables for variations functionality
window.trackVariations = [];
window.currentTrackId = null;
window.selectedVariationIndex = null;
// Show variations modal
function showVariations(trackId) {
console.log('π΅ Showing variations for track:', trackId);
// Get track data from PHP
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (!trackCard) {
console.error('π΅ Track card not found for track ID:', trackId);
alert('Track not found. Please refresh the page and try again.');
return;
}
console.log('π΅ Track card found:', trackCard);
// Get variations data from PHP
const variationsData = trackCard.getAttribute('data-variations');
console.log('π΅ Raw variations data:', variationsData);
if (!variationsData || variationsData === '[]') {
console.error('π΅ No variations data found');
alert('No variations available for this track.');
return;
}
try {
if (typeof window.trackVariations === 'undefined') {
window.trackVariations = [];
}
window.trackVariations = JSON.parse(variationsData);
console.log('π΅ Parsed variations:', window.trackVariations);
if (!Array.isArray(window.trackVariations) || window.trackVariations.length === 0) {
console.error('π΅ No variations in array');
alert('No variations available for this track.');
return;
}
window.currentTrackId = trackId;
// Get current selection
const currentSelection = trackCard.getAttribute('data-selected-variation') || '0';
window.selectedVariationIndex = parseInt(currentSelection);
console.log('π΅ About to populate variations grid');
// Populate variations grid
populateVariationsGrid();
console.log('π΅ About to show modal');
// Show modal
const modal = document.getElementById('variationsModal');
if (!modal) {
console.error('π΅ Variations modal not found');
alert('Modal not found. Please refresh the page and try again.');
return;
}
modal.classList.add('active');
console.log('π΅ Modal should now be visible');
} catch (error) {
console.error('π΅ Error parsing variations data:', error);
alert('Error loading variations. Please refresh the page and try again.');
}
}
// Populate variations grid
function populateVariationsGrid() {
const grid = document.getElementById('variationsGrid');
grid.innerHTML = '';
window.trackVariations.forEach((variation, index) => {
const card = document.createElement('div');
card.className = `variation-card ${index === window.selectedVariationIndex ? 'selected' : ''}`;
card.onclick = () => selectVariation(index);
const duration = Math.floor(variation.duration / 60) + 'm ' + Math.floor(variation.duration % 60) + 's';
const tags = variation.tags ? variation.tags.split(',').slice(0, 3) : [];
card.innerHTML = `
<div class="variation-header">
<div class="variation-title">${variation.title || 'Variation ' + (index + 1)}</div>
<div class="variation-index">${index + 1}</div>
</div>
<div class="variation-duration">
<i class="fas fa-clock"></i> ${duration}
</div>
${tags.length > 0 ? `
<div class="variation-tags">
${tags.map(tag => `<span class="variation-tag">${tag.trim()}</span>`).join('')}
</div>
` : ''}
<div class="variation-actions">
<button class="variation-btn play" onclick="playVariation(${index})">
<i class="fas fa-play"></i> Play
</button>
<button class="variation-btn download" onclick="downloadVariation(${index})">
<i class="fas fa-download"></i> Download
</button>
<button class="variation-btn select ${index === window.selectedVariationIndex ? 'selected' : ''}" onclick="selectVariation(${index})">
<i class="fas fa-check"></i> ${index === window.selectedVariationIndex ? 'Selected' : 'Select'}
</button>
</div>
`;
grid.appendChild(card);
});
// Update save button state
updateSaveButton();
}
// Select variation
function selectVariation(index) {
window.selectedVariationIndex = index;
// Update visual selection
document.querySelectorAll('.variation-card').forEach((card, i) => {
card.classList.toggle('selected', i === index);
});
document.querySelectorAll('.variation-btn.select').forEach((btn, i) => {
btn.classList.toggle('selected', i === index);
btn.innerHTML = `<i class="fas fa-check"></i> ${i === index ? 'Selected' : 'Select'}`;
});
updateSaveButton();
}
// Play variation
async function playVariation(index) {
const variation = window.trackVariations[index];
if (!variation) return;
console.log('π΅ Playing variation:', variation);
// Wait for global player to be ready
await waitForGlobalPlayer();
// Use the global player
if (typeof window.playTrackWithGlobalPlayer === 'function') {
console.log('π΅ Using window.playTrackWithGlobalPlayer function for variation');
window.playTrackWithGlobalPlayer(variation.audio_url, variation.title || 'Variation ' + (index + 1), '<?= htmlspecialchars($user_name) ?>', <?= $_SESSION['user_id'] ?>);
} else if (typeof window.globalPlayer !== 'undefined' && typeof window.globalPlayer.playTrack === 'function') {
console.log('π΅ Using direct global player fallback for variation');
window.globalPlayer.wasPlaying = true;
window.globalPlayer.playTrack(variation.audio_url, variation.title || 'Variation ' + (index + 1), '<?= htmlspecialchars($user_name) ?>', <?= $_SESSION['user_id'] ?>);
} else {
console.error('π΅ No global player available for variation playback');
alert('Audio player not available. Please refresh the page and try again.');
}
}
// Download variation
function downloadVariation(index) {
const variation = window.trackVariations[index];
if (!variation) return;
console.log('π΅ Downloading variation:', variation);
// Create a temporary link element to trigger download
const link = document.createElement('a');
link.href = variation.audio_url;
// Create a meaningful filename
const trackTitle = variation.title || 'Variation ' + (index + 1);
const artistName = '<?= htmlspecialchars($user_name) ?>';
const filename = `${artistName} - ${trackTitle} (Variation ${index + 1}).mp3`;
link.download = filename;
link.target = '_blank';
// Add to DOM, click, and remove
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Show success message
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: rgba(72, 187, 120, 0.9);
color: white;
padding: 1rem 1.5rem;
border-radius: 8px;
font-weight: 600;
z-index: 10000;
backdrop-filter: blur(10px);
`;
toast.textContent = 'β
Variation downloaded successfully!';
document.body.appendChild(toast);
setTimeout(() => {
document.body.removeChild(toast);
}, 3000);
}
// Update save button state
function updateSaveButton() {
const saveBtn = document.getElementById('saveVariationBtn');
if (!saveBtn) {
console.error('π΅ Save button not found');
return;
}
if (window.currentTrackId === null) {
saveBtn.disabled = true;
saveBtn.textContent = 'No Track Selected';
return;
}
const trackCard = document.querySelector(`[data-track-id="${window.currentTrackId}"]`);
if (!trackCard) {
saveBtn.disabled = true;
saveBtn.textContent = 'Track Not Found';
return;
}
const currentSelection = trackCard.getAttribute('data-selected-variation') || '0';
if (window.selectedVariationIndex !== parseInt(currentSelection)) {
saveBtn.disabled = false;
saveBtn.textContent = 'Save Selection';
} else {
saveBtn.disabled = true;
saveBtn.textContent = 'No Changes';
}
}
// Save variation selection
function saveVariationSelection() {
if (window.selectedVariationIndex === null || window.currentTrackId === null) {
console.error('π΅ No variation or track selected');
return;
}
console.log('π΅ Saving variation selection:', { trackId: window.currentTrackId, variationIndex: window.selectedVariationIndex });
// Disable save button during request
const saveBtn = document.getElementById('saveVariationBtn');
saveBtn.disabled = true;
saveBtn.textContent = 'Saving...';
fetch('/api_select_variation.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
track_id: window.currentTrackId,
variation_index: window.selectedVariationIndex
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log('π΅ Variation selection saved:', data);
// Update the track card
const trackCard = document.querySelector(`[data-track-id="${window.currentTrackId}"]`);
if (trackCard) {
trackCard.setAttribute('data-selected-variation', window.selectedVariationIndex);
// Update the main audio URL and duration
const variation = window.trackVariations[window.selectedVariationIndex];
if (variation) {
// Update play button
const playBtn = trackCard.querySelector('.play-track-btn');
if (playBtn) {
playBtn.setAttribute('data-audio-url', variation.audio_url);
}
// Update duration display
const durationSpan = trackCard.querySelector('.track-details span:first-child');
if (durationSpan) {
const duration = Math.floor(variation.duration / 60) + 'm ' + Math.floor(variation.duration % 60) + 's';
durationSpan.innerHTML = `<i class="fas fa-clock"></i> ${duration}`;
}
}
}
// Show success message
if (typeof window.showNotification === 'function') {
window.showNotification('Variation selection saved successfully!', 'success');
} else {
alert('β
Variation selection saved successfully!');
}
// Close modal
closeVariations();
} else {
console.error('π΅ Failed to save variation selection:', data.error);
if (typeof window.showNotification === 'function') {
window.showNotification('Failed to save variation selection: ' + (data.error || 'Unknown error'), 'error');
} else {
alert('β Failed to save variation selection: ' + (data.error || 'Unknown error'));
}
}
})
.catch(error => {
console.error('π΅ Error saving variation selection:', error);
if (typeof window.showNotification === 'function') {
window.showNotification('Network error saving selection. Please check your connection and try again.', 'error');
} else {
alert('β Network error saving selection. Please check your connection and try again.');
}
})
.finally(() => {
// Re-enable save button
saveBtn.disabled = false;
updateSaveButton();
});
}
// Close variations modal
function closeVariations() {
const modal = document.getElementById('variationsModal');
modal.classList.remove('active');
// Reset variables
window.trackVariations = [];
window.currentTrackId = null;
window.selectedVariationIndex = null;
}
// Show lyrics modal
function showLyrics(trackId) {
console.log('π΅ Showing lyrics for track:', trackId);
// Get track data
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (!trackCard) {
console.error('π΅ Track card not found for track ID:', trackId);
alert('Track not found. Please refresh the page and try again.');
return;
}
console.log('π΅ Track card found:', trackCard);
// Get track title
const titleElement = trackCard.querySelector('.track-title-mini');
const trackTitle = titleElement ? titleElement.textContent : 'Unknown Track';
console.log('π΅ Track title:', trackTitle);
// Show lyrics modal
const modal = document.getElementById('lyricsModal');
const lyricsContent = document.getElementById('lyricsContent');
console.log('π΅ Modal element:', modal);
console.log('π΅ Lyrics content element:', lyricsContent);
if (!modal || !lyricsContent) {
console.error('π΅ Modal elements not found');
alert('Modal not found. Please refresh the page and try again.');
return;
}
// For now, show placeholder lyrics since lyrics functionality needs to be implemented
lyricsContent.innerHTML = `
<div style="text-align: center; padding: 2rem;">
<i class="fas fa-music" style="font-size: 3rem; color: #667eea; margin-bottom: 1rem;"></i>
<h3 style="color: #ffffff; margin-bottom: 1rem;">${trackTitle}</h3>
<p style="color: #a0aec0; margin-bottom: 2rem;">π΅ Lyrics feature coming soon!</p>
<div style="background: rgba(102, 126, 234, 0.1); padding: 1.5rem; border-radius: 8px; border: 1px solid rgba(102, 126, 234, 0.3);">
<p style="color: #cccccc; font-style: italic;">
"This will show the AI-generated lyrics for your track.<br>
Stay tuned for this exciting feature!"
</p>
</div>
</div>
`;
// Show modal
modal.classList.add('active');
console.log('π΅ Lyrics modal activated');
// Force modal to be visible and on top
modal.style.zIndex = '999999';
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.display = 'flex';
modal.style.alignItems = 'center';
modal.style.justifyContent = 'center';
console.log('π΅ Lyrics modal styles applied:', {
zIndex: modal.style.zIndex,
position: modal.style.position,
display: modal.style.display
});
// Close on outside click
modal.addEventListener('click', function(e) {
if (e.target === this) {
closeLyrics();
}
});
}
// Close lyrics modal
function closeLyrics() {
const modal = document.getElementById('lyricsModal');
modal.classList.remove('active');
}
// Copy lyrics to clipboard
function copyLyrics() {
const lyricsContent = document.getElementById('lyricsContent');
if (lyricsContent) {
const text = lyricsContent.textContent || lyricsContent.innerText;
navigator.clipboard.writeText(text).then(() => {
alert('β
Lyrics copied to clipboard!');
}).catch(() => {
alert('β Failed to copy lyrics. Please select and copy manually.');
});
}
}
// Download track
function downloadTrack(trackId) {
console.log('π΅ Downloading track:', trackId);
// Get track data
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (!trackCard) {
console.error('π΅ Track card not found for track ID:', trackId);
alert('Track not found. Please refresh the page and try again.');
return;
}
// Show download modal
const modal = document.getElementById('downloadModal');
const downloadContent = document.getElementById('downloadContent');
if (!modal || !downloadContent) {
console.error('π΅ Download modal elements not found');
alert('Download modal not found. Please refresh the page and try again.');
return;
}
// Get track title
const titleElement = trackCard.querySelector('.track-title-mini');
const trackTitle = titleElement ? titleElement.textContent : 'Unknown Track';
// Populate download modal
downloadContent.innerHTML = `
<div style="text-align: center; padding: 2rem;">
<i class="fas fa-download" style="font-size: 3rem; color: #667eea; margin-bottom: 1rem;"></i>
<h3 style="color: #ffffff; margin-bottom: 1rem;">${trackTitle}</h3>
<p style="color: #a0aec0; margin-bottom: 2rem;">Choose your download option:</p>
<div style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;">
<button onclick="downloadSingleTrack(${trackId})" style="background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 1rem 2rem; border-radius: 8px; cursor: pointer;">
<i class="fas fa-download"></i> Download Main Track
</button>
<button onclick="downloadAllVariations(${trackId})" style="background: linear-gradient(135deg, #48bb78, #38a169); color: white; border: none; padding: 1rem 2rem; border-radius: 8px; cursor: pointer;">
<i class="fas fa-layer-group"></i> Download All Variations
</button>
</div>
</div>
`;
// Show modal
modal.classList.add('active');
console.log('π΅ Download modal activated');
// Force modal to be visible and on top
modal.style.zIndex = '999999';
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.display = 'flex';
modal.style.alignItems = 'center';
modal.style.justifyContent = 'center';
}
// Close download modal
function closeDownload() {
const modal = document.getElementById('downloadModal');
modal.classList.remove('active');
}
// Download single track
function downloadSingleTrack(trackId) {
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (!trackCard) return;
const playBtn = trackCard.querySelector('.action-btn.primary');
if (!playBtn) return;
const audioUrl = playBtn.getAttribute('data-audio-url');
const title = playBtn.getAttribute('data-title');
const artist = playBtn.getAttribute('data-artist');
if (!audioUrl) {
alert('β Audio URL not found. Please try again.');
return;
}
// Create download link
const link = document.createElement('a');
link.href = audioUrl;
link.download = `${artist} - ${title}.mp3`;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Show success message
alert('β
Track downloaded successfully!');
closeDownload();
}
// Download all variations
function downloadAllVariations(trackId) {
const trackCard = document.querySelector(`[data-track-id="${trackId}"]`);
if (!trackCard) return;
const variationsData = trackCard.getAttribute('data-variations');
if (!variationsData || variationsData === '[]') {
alert('β No variations available for this track.');
return;
}
try {
const variations = JSON.parse(variationsData);
if (!Array.isArray(variations) || variations.length === 0) {
alert('β No variations available for this track.');
return;
}
// Download each variation
variations.forEach((variation, index) => {
setTimeout(() => {
const link = document.createElement('a');
link.href = variation.audio_url;
link.download = `Variation ${index + 1}.mp3`;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, index * 500); // Stagger downloads
});
alert('β
All variations download started!');
closeDownload();
} catch (error) {
console.error('Error downloading variations:', error);
alert('β Error downloading variations. Please try again.');
}
}
// Other library functions
function playTrackFromButton(button) {
const audioUrl = button.getAttribute('data-audio-url');
const title = button.getAttribute('data-title');
const artist = button.getAttribute('data-artist');
if (!audioUrl) {
alert('β Audio URL not found. Please try again.');
return;
}
// Use the global player
if (typeof window.playTrackWithGlobalPlayer === 'function') {
window.playTrackWithGlobalPlayer(audioUrl, title, artist, <?= $_SESSION['user_id'] ?>);
} else if (typeof window.globalPlayer !== 'undefined' && typeof window.globalPlayer.playTrack === 'function') {
window.globalPlayer.wasPlaying = true;
window.globalPlayer.playTrack(audioUrl, title, artist, <?= $_SESSION['user_id'] ?>);
} else {
console.error('No global player available');
alert('Audio player not available. Please refresh the page and try again.');
}
}
function checkTrackStatus(trackId) {
console.log('Checking status for track:', trackId);
// Implementation for checking track status
alert('Status check feature coming soon!');
}
function retryTrack(trackId) {
console.log('Retrying track:', trackId);
// Implementation for retrying failed tracks
alert('Retry feature coming soon!');
}
function showFailureHelp(trackId) {
console.log('Showing failure help for track:', trackId);
// Implementation for showing failure help
alert('Failure help feature coming soon!');
}
function deleteFailedTrack(trackId) {
if (confirm('Are you sure you want to delete this failed track?')) {
console.log('Deleting failed track:', trackId);
// Implementation for deleting failed tracks
alert('Delete feature coming soon!');
}
}
// Close modal when clicking outside
document.addEventListener('DOMContentLoaded', function() {
const modal = document.getElementById('variationsModal');
if (modal) {
modal.addEventListener('click', function(e) {
if (e.target === this) {
closeVariations();
}
});
}
});
</script>
<?php include 'includes/footer.php'; ?>