![]() 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
require_once 'config/database.php';
session_start();
$user_id = $_SESSION['user_id'] ?? null;
$track_id = $_GET['id'] ?? null;
if (!$track_id) {
header('Location: /community_fixed.php');
exit;
}
try {
$pdo = getDBConnection();
// Get the specific track with all details
$track_query = "
SELECT
mt.*,
u.name as artist_name,
u.plan as artist_plan,
COALESCE(tp.play_count, 0) as play_count,
COALESCE(tl.like_count, 0) as like_count,
0 as vote_count,
CASE WHEN tl_user.track_id IS NOT NULL THEN 1 ELSE 0 END as user_liked,
NULL as user_vote
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
LEFT JOIN (SELECT track_id, COUNT(*) as play_count FROM track_plays GROUP BY track_id) tp ON mt.id = tp.track_id
LEFT JOIN (SELECT track_id, COUNT(*) as like_count FROM track_likes GROUP BY track_id) tl ON mt.id = tl.track_id
LEFT JOIN track_likes tl_user ON mt.id = tl_user.track_id AND tl_user.user_id = ?
WHERE mt.id = ? AND mt.status = 'complete'
";
$stmt = $pdo->prepare($track_query);
$stmt->execute([$user_id, $track_id]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
header('Location: /community_fixed.php');
exit;
}
// Parse metadata
$metadata = json_decode($track['metadata'] ?? '{}', true) ?: [];
$genre = $metadata['genre'] ?? 'Electronic';
$bpm = $metadata['bpm'] ?? 120;
$key = $metadata['key'] ?? 'C major';
$time_signature = $metadata['time_signature'] ?? '4/4';
$instruments = $metadata['instruments'] ?? [];
$mood = $metadata['mood'] ?? 'Neutral';
$energy = $metadata['energy'] ?? 'Medium';
} catch (Exception $e) {
error_log("Track page error: " . $e->getMessage());
header('Location: /community_fixed.php');
exit;
}
$page_title = htmlspecialchars($track['title']) . ' by ' . htmlspecialchars($track['artist_name']);
$page_description = 'Listen to ' . htmlspecialchars($track['title']) . ' by ' . htmlspecialchars($track['artist_name']) . ' - ' . htmlspecialchars($track['prompt'] ?: 'AI-generated music') . ' on SoundStudioPro';
$page_url = 'https://soundstudiopro.com/track.php?id=' . $track_id;
$page_image = !empty($track['image_url']) ? $track['image_url'] : 'https://soundstudiopro.com/uploads/track_covers/track_45_1754191923.jpg';
$track_duration = gmdate("i:s", $track['duration'] ?? 180);
$release_date = date('Y-m-d', strtotime($track['created_at']));
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $page_title ?> - SoundStudioPro</title>
<!-- SEO Meta Tags -->
<meta name="description" content="<?= $page_description ?>">
<meta name="keywords" content="<?= htmlspecialchars($track['title']) ?>, <?= htmlspecialchars($track['artist_name']) ?>, AI music, SoundStudioPro, <?= htmlspecialchars($genre) ?>, <?= htmlspecialchars($mood) ?>">
<meta name="author" content="<?= htmlspecialchars($track['artist_name']) ?>">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="music.song">
<meta property="og:url" content="<?= $page_url ?>">
<meta property="og:title" content="<?= $page_title ?>">
<meta property="og:description" content="<?= $page_description ?>">
<meta property="og:image" content="<?= $page_image ?>">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="<?= $page_url ?>">
<meta property="twitter:title" content="<?= $page_title ?>">
<meta property="twitter:description" content="<?= $page_description ?>">
<meta property="twitter:image" content="<?= $page_image ?>">
<!-- Music Meta Tags -->
<meta property="music:musician" content="<?= htmlspecialchars($track['artist_name']) ?>">
<meta property="music:album" content="<?= htmlspecialchars($track['title']) ?>">
<meta property="music:duration" content="<?= $track['duration'] ?? 180 ?>">
<meta property="music:release_date" content="<?= $release_date ?>">
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MusicRecording",
"name": "<?= htmlspecialchars($track['title']) ?>",
"byArtist": {
"@type": "MusicGroup",
"name": "<?= htmlspecialchars($track['artist_name']) ?>"
},
"duration": "PT<?= gmdate("i:s", $track['duration'] ?? 180) ?>",
"genre": "<?= htmlspecialchars($genre) ?>",
"description": "<?= htmlspecialchars($track['prompt'] ?: 'AI-generated music') ?>",
"url": "<?= $page_url ?>",
"image": "<?= $page_image ?>"
}
</script>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
color: #ffffff;
line-height: 1.6;
overflow-x: hidden;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header */
.header {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
position: sticky;
top: 0;
z-index: 1000;
}
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.back-btn {
display: flex;
align-items: center;
gap: 0.5rem;
color: #667eea;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
}
.back-btn:hover {
color: #ffffff;
transform: translateX(-5px);
}
.logo {
display: flex;
align-items: center;
gap: 1.2rem;
text-decoration: none;
color: white;
}
.logo-icon {
font-size: 3rem;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.logo-text {
font-size: 2.4rem;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Track Hero Section */
.track-hero {
padding: 1.5rem 0;
text-align: center;
}
.track-cover {
width: 250px;
height: 250px;
margin: 0 auto 1rem;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
position: relative;
}
.track-cover img {
width: 100%;
height: 100%;
object-fit: cover;
}
.track-title {
font-size: 2rem;
font-weight: 800;
margin-bottom: 0.3rem;
background: linear-gradient(135deg, #ffffff, #667eea);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.track-artist {
font-size: 1rem;
color: #a0aec0;
margin-bottom: 0.5rem;
}
.artist-link {
color: #667eea;
text-decoration: none;
font-weight: 600;
}
.track-prompt {
color: #718096;
font-size: 0.9rem;
max-width: 500px;
margin: 0 auto 1rem;
}
/* Audio Player */
.audio-player {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 1.5rem;
margin: 1rem 0;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.player-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-bottom: 1rem;
}
.play-btn {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
border: 2px solid #fff;
color: white;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 9999;
pointer-events: auto;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}
.play-btn:hover {
transform: scale(1.1);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
}
.play-btn.playing {
background: linear-gradient(135deg, #e53e3e, #c53030);
}
.time-display {
font-size: 0.9rem;
color: #a0aec0;
min-width: 100px;
text-align: center;
}
.progress-container {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
cursor: pointer;
position: relative;
margin: 1rem 0;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 3px;
width: 0%;
transition: width 0.1s ease;
}
.volume-control {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;
}
.volume-slider {
width: 100px;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
outline: none;
cursor: pointer;
}
/* Track Stats */
.track-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0.8rem;
margin: 1rem 0;
}
.stat-item {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 1rem;
text-align: center;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.stat-value {
display: block;
font-size: 1.2rem;
font-weight: 700;
color: #667eea;
margin-bottom: 0.3rem;
}
.stat-label {
font-size: 0.9rem;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Track Info Grid */
.track-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.8rem;
margin: 1rem 0;
}
.info-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 1rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.info-label {
font-size: 0.9rem;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 0.5rem;
}
.info-value {
font-size: 1rem;
font-weight: 600;
color: #ffffff;
}
/* Action Buttons */
.action-buttons {
display: flex;
gap: 0.8rem;
justify-content: center;
flex-wrap: wrap;
margin: 1rem 0;
}
.action-btn {
padding: 0.6rem 1.2rem;
border-radius: 20px;
border: none;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.4rem;
text-decoration: none;
color: white;
}
.primary-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
}
.secondary-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.like-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.like-btn.liked {
background: linear-gradient(135deg, #e53e3e, #c53030);
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
/* Comments Section */
.comments-section {
margin: 1.5rem 0;
}
.section-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1.5rem;
text-align: center;
}
.comment-form {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 1.5rem;
margin-bottom: 2rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.comment-input {
width: 100%;
min-height: 100px;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
padding: 1rem;
color: white;
font-family: inherit;
resize: vertical;
}
.comment-input::placeholder {
color: #a0aec0;
}
.comments-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.comment {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 1.5rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.comment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.comment-author {
font-weight: 600;
color: #667eea;
}
.comment-date {
font-size: 0.9rem;
color: #a0aec0;
}
.comment-text {
color: #e2e8f0;
line-height: 1.6;
}
/* Related Tracks */
.related-tracks {
margin: 3rem 0;
}
.tracks-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.track-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
overflow: hidden;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
.track-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}
.track-card img {
width: 100%;
height: 150px;
object-fit: cover;
}
.track-card-content {
padding: 1rem;
}
.track-card-title {
font-weight: 600;
margin-bottom: 0.5rem;
color: #ffffff;
}
.track-card-artist {
font-size: 0.9rem;
color: #a0aec0;
}
/* Responsive Design */
@media (max-width: 768px) {
.container {
padding: 0 1.5rem;
}
.track-hero {
padding: 2rem 1.5rem;
flex-direction: column;
text-align: center;
gap: 2rem;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border-radius: 20px;
border: 2px solid rgba(255, 255, 255, 0.1);
margin-bottom: 2rem;
}
.track-cover {
width: 180px;
height: 180px;
margin: 0 auto;
border-radius: 16px;
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.track-title {
font-size: 2.8rem;
margin-bottom: 0.8rem;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.track-artist {
font-size: 1.8rem;
margin-bottom: 1.5rem;
color: #a0aec0;
}
.track-prompt {
font-size: 1.5rem;
line-height: 1.6;
color: #cbd5e0;
}
.audio-player {
padding: 2rem;
border-radius: 20px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
margin-bottom: 2rem;
}
.player-controls {
flex-direction: column;
gap: 1.5rem;
align-items: center;
}
.play-btn {
width: 70px;
height: 70px;
font-size: 2.8rem;
background: linear-gradient(135deg, #667eea, #764ba2);
border: 3px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.play-btn:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 12px 35px rgba(102, 126, 234, 0.5);
}
.time-display {
font-size: 1.6rem;
font-weight: 600;
color: #a0aec0;
}
.progress-container {
margin: 1.5rem 0;
height: 10px;
border-radius: 5px;
background: rgba(255, 255, 255, 0.1);
cursor: pointer;
touch-action: manipulation;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 5px;
transition: width 0.1s ease;
}
.volume-control {
flex-direction: column;
gap: 1rem;
align-items: center;
}
.volume-slider {
width: 150px;
height: 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
outline: none;
cursor: pointer;
touch-action: manipulation;
}
.track-stats {
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
margin: 2rem 0;
}
.stat-item {
padding: 1.5rem;
border-radius: 16px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.stat-item:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.3);
}
.stat-value {
font-size: 2rem;
font-weight: 700;
color: #667eea;
}
.stat-label {
font-size: 1.3rem;
color: #a0aec0;
}
.track-info {
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
margin: 2rem 0;
}
.info-card {
padding: 1.5rem;
border-radius: 16px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.info-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.3);
}
.info-label {
font-size: 1.3rem;
color: #a0aec0;
font-weight: 600;
}
.info-value {
font-size: 1.6rem;
font-weight: 700;
color: #667eea;
}
.action-buttons {
flex-direction: column;
gap: 1.5rem;
margin: 2rem 0;
}
.action-btn {
width: 100%;
padding: 1.5rem 2rem;
font-size: 1.8rem;
justify-content: center;
border-radius: 16px;
font-weight: 600;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.action-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.5s ease;
}
.action-btn:hover::before {
left: 100%;
}
.action-btn:hover {
transform: translateY(-3px);
box-shadow: 0 12px 35px rgba(102, 126, 234, 0.4);
}
.comments-section {
padding: 2rem;
border-radius: 20px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
margin: 2rem 0;
}
.comment-form {
margin-bottom: 2rem;
}
.comment-input {
padding: 1.5rem 2rem;
font-size: 1.6rem;
min-height: 60px;
border-radius: 16px;
border: 2px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
color: white;
resize: vertical;
}
.comment-input:focus {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
outline: none;
}
.comment {
padding: 1.5rem;
margin-bottom: 1.5rem;
border-radius: 16px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
}
.comment-author {
font-size: 1.5rem;
font-weight: 600;
color: #667eea;
}
.comment-text {
font-size: 1.5rem;
line-height: 1.6;
color: #e2e8f0;
}
.comment-date {
font-size: 1.3rem;
color: #a0aec0;
}
.related-tracks {
grid-template-columns: 1fr;
gap: 2rem;
margin: 2rem 0;
}
.track-card {
padding: 1.5rem;
border-radius: 16px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05));
border: 2px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.track-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 35px rgba(102, 126, 234, 0.3);
border-color: rgba(102, 126, 234, 0.4);
}
.track-card-title {
font-size: 1.8rem;
font-weight: 600;
color: #e2e8f0;
}
.track-card-artist {
font-size: 1.5rem;
color: #a0aec0;
}
}
@media (max-width: 480px) {
.container {
padding: 0 1rem;
}
.track-hero {
padding: 1.5rem 1rem;
}
.track-cover {
width: 150px;
height: 150px;
}
.track-title {
font-size: 2.4rem;
}
.track-artist {
font-size: 1.6rem;
}
.play-btn {
width: 60px;
height: 60px;
font-size: 2.4rem;
}
.action-btn {
padding: 1.2rem 1.5rem;
font-size: 1.6rem;
}
.track-stats {
grid-template-columns: 1fr;
}
.track-info {
grid-template-columns: 1fr;
}
.comments-section {
padding: 1.5rem;
}
.comment-input {
padding: 1.2rem 1.5rem;
font-size: 1.5rem;
min-height: 50px;
}
}
/* Loading States */
.loading {
opacity: 0.6;
pointer-events: none;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.6s ease-out;
}
/* Waveform */
.waveform {
width: 100%;
height: 60px;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
margin: 1rem 0;
position: relative;
overflow: hidden;
}
.waveform-bar {
position: absolute;
bottom: 0;
background: linear-gradient(180deg, #667eea, #764ba2);
border-radius: 2px;
transition: height 0.1s ease;
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<nav class="nav">
<a href="/community_fixed.php" class="back-btn">
<i class="fas fa-arrow-left"></i>
Back to Community
</a>
<a href="/" class="logo">
<i class="fas fa-music logo-icon"></i>
<span class="logo-text">SoundStudioPro</span>
</a>
<div></div>
</nav>
</header>
<!-- Track Hero Section -->
<section class="track-hero fade-in">
<div class="track-cover">
<?php if (!empty($track['image_url'])): ?>
<img src="<?= htmlspecialchars($track['image_url']) ?>" alt="Track Cover">
<?php else: ?>
<img src="/uploads/track_covers/track_45_1754191923.jpg" alt="Default Track Cover">
<?php endif; ?>
</div>
<h1 class="track-title"><?= htmlspecialchars($track['title'] ?: 'Untitled Track') ?></h1>
<div class="track-artist">
by <a href="/artist_profile.php?id=<?= $track['user_id'] ?>" class="artist-link"><?= htmlspecialchars($track['artist_name']) ?></a>
</div>
<p class="track-prompt"><?= htmlspecialchars($track['prompt'] ?: 'A creative AI-generated track') ?></p>
</section>
<!-- Audio Player -->
<section class="audio-player fade-in">
<div class="player-controls">
<button class="play-btn" id="playBtn" onclick="togglePlay()">
<i class="fas fa-play" id="playIcon"></i>
</button>
<div class="time-display">
<span id="currentTime">0:00</span> / <span id="totalTime"><?= $track_duration ?></span>
</div>
</div>
<div class="progress-container" onclick="seekTo(event)">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="volume-control">
<i class="fas fa-volume-up"></i>
<input type="range" class="volume-slider" id="volumeSlider" min="0" max="100" value="50">
</div>
<div class="waveform" id="waveform"></div>
</section>
<!-- Track Stats -->
<section class="track-stats fade-in">
<div class="stat-item">
<span class="stat-value"><?= number_format($track['play_count']) ?></span>
<span class="stat-label">Plays</span>
</div>
<div class="stat-item">
<span class="stat-value"><?= number_format($track['like_count']) ?></span>
<span class="stat-label">Likes</span>
</div>
<div class="stat-item">
<span class="stat-value"><?= $track_duration ?></span>
<span class="stat-label">Duration</span>
</div>
<div class="stat-item">
<span class="stat-value"><?= date('M j', strtotime($track['created_at'])) ?></span>
<span class="stat-label">Released</span>
</div>
</section>
<!-- Track Info -->
<section class="track-info fade-in">
<div class="info-card">
<div class="info-label">BPM</div>
<div class="info-value"><?= $bpm ?></div>
</div>
<div class="info-card">
<div class="info-label">Key</div>
<div class="info-value"><?= $key ?></div>
</div>
<div class="info-card">
<div class="info-label">Time Signature</div>
<div class="info-value"><?= $time_signature ?></div>
</div>
<div class="info-card">
<div class="info-label">Genre</div>
<div class="info-value"><?= htmlspecialchars($genre) ?></div>
</div>
<div class="info-card">
<div class="info-label">Mood</div>
<div class="info-value"><?= htmlspecialchars($mood) ?></div>
</div>
<div class="info-card">
<div class="info-label">Energy</div>
<div class="info-value"><?= htmlspecialchars($energy) ?></div>
</div>
</section>
<!-- Action Buttons -->
<section class="action-buttons fade-in">
<button class="action-btn primary-btn" onclick="addToCart(<?= $track['id'] ?>, '<?= htmlspecialchars($track['title'], ENT_QUOTES) ?>', <?= $track['price'] ?? 1.99 ?>)">
<i class="fas fa-shopping-cart"></i>
Add to Cart
</button>
<button class="action-btn like-btn <?= $track['user_liked'] ? 'liked' : '' ?>" onclick="toggleLike(<?= $track['id'] ?>, this)">
<i class="fas fa-heart"></i>
<?= $track['user_liked'] ? 'Liked' : 'Like' ?>
</button>
<button class="action-btn secondary-btn" onclick="shareTrack(<?= $track['id'] ?>, '<?= htmlspecialchars($track['title'], ENT_QUOTES) ?>', '<?= htmlspecialchars($track['artist_name'], ENT_QUOTES) ?>')">
<i class="fas fa-share"></i>
Share
</button>
</section>
<!-- Comments Section -->
<section class="comments-section fade-in">
<h2 class="section-title">Comments</h2>
<?php if ($user_id): ?>
<div class="comment-form">
<textarea class="comment-input" id="commentInput" placeholder="Share your thoughts about this track..."></textarea>
<button class="action-btn primary-btn" onclick="addComment(<?= $track['id'] ?>)">
<i class="fas fa-paper-plane"></i>
Post Comment
</button>
</div>
<?php endif; ?>
<div class="comments-list" id="commentsList">
<!-- Comments will be loaded here -->
</div>
</section>
<!-- Related Tracks -->
<section class="related-tracks fade-in">
<h2 class="section-title">More from <?= htmlspecialchars($track['artist_name']) ?></h2>
<div class="tracks-grid" id="relatedTracks">
<!-- Related tracks will be loaded here -->
</div>
</section>
</div>
<!-- Audio Element -->
<audio id="audioPlayer" preload="metadata">
<source src="<?= htmlspecialchars($track['audio_url']) ?>" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<script>
// Global variables
let isPlaying = false;
let currentTrackId = <?= $track['id'] ?>;
let audioPlayer = document.getElementById('audioPlayer');
let playBtn = document.getElementById('playBtn');
let playIcon = document.getElementById('playIcon');
let progressBar = document.getElementById('progressBar');
let currentTimeSpan = document.getElementById('currentTime');
let totalTimeSpan = document.getElementById('totalTime');
let volumeSlider = document.getElementById('volumeSlider');
let waveform = document.getElementById('waveform');
// Initialize page
document.addEventListener('DOMContentLoaded', function() {
console.log('🎵 Page loaded, initializing...');
initializeAudioPlayer();
loadComments(currentTrackId);
loadRelatedTracks();
generateWaveform();
// Ensure play button is clickable
const playBtn = document.getElementById('playBtn');
if (playBtn) {
console.log('🎵 Play button found:', playBtn);
playBtn.addEventListener('click', function(e) {
console.log('🎵 Play button clicked via event listener');
e.preventDefault();
e.stopPropagation();
togglePlay();
});
} else {
console.error('❌ Play button not found!');
}
});
// Audio Player Functions
function initializeAudioPlayer() {
console.log('🎵 Initializing audio player...');
console.log('🎵 Audio element:', audioPlayer);
if (!audioPlayer) {
console.error('❌ Audio player element not found!');
return;
}
audioPlayer.addEventListener('loadedmetadata', function() {
console.log('🎵 Audio metadata loaded, duration:', audioPlayer.duration);
totalTimeSpan.textContent = formatTime(audioPlayer.duration);
});
audioPlayer.addEventListener('timeupdate', function() {
const progress = (audioPlayer.currentTime / audioPlayer.duration) * 100;
progressBar.style.width = progress + '%';
currentTimeSpan.textContent = formatTime(audioPlayer.currentTime);
});
audioPlayer.addEventListener('ended', function() {
console.log('🎵 Audio ended');
isPlaying = false;
playIcon.className = 'fas fa-play';
playBtn.classList.remove('playing');
recordPlay();
});
audioPlayer.addEventListener('error', function(e) {
console.error('❌ Audio error:', e);
});
volumeSlider.addEventListener('input', function() {
audioPlayer.volume = this.value / 100;
});
console.log('✅ Audio player initialized');
}
function togglePlay() {
console.log('🎵 Play button clicked!');
console.log('🎵 Current state:', { isPlaying, audioPlayer: !!audioPlayer });
if (isPlaying) {
console.log('🎵 Pausing track...');
audioPlayer.pause();
isPlaying = false;
playIcon.className = 'fas fa-play';
playBtn.classList.remove('playing');
} else {
console.log('🎵 Playing track...');
audioPlayer.play().then(() => {
console.log('✅ Audio started successfully');
isPlaying = true;
playIcon.className = 'fas fa-pause';
playBtn.classList.add('playing');
recordPlay();
}).catch(error => {
console.error('❌ Audio play failed:', error);
alert('Failed to play audio. Please try again.');
});
}
}
function seekTo(event) {
const rect = event.currentTarget.getBoundingClientRect();
const clickX = event.clientX - rect.left;
const width = rect.width;
const seekTime = (clickX / width) * audioPlayer.duration;
audioPlayer.currentTime = seekTime;
}
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
function recordPlay() {
fetch('/api/record_play.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
track_id: currentTrackId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
updatePlayCount();
}
})
.catch(error => console.error('Error recording play:', error));
}
function updatePlayCount() {
const playCountElement = document.querySelector('.stat-item:first-child .stat-value');
if (playCountElement) {
const currentCount = parseInt(playCountElement.textContent.replace(/,/g, '')) || 0;
const newCount = currentCount + 1;
playCountElement.textContent = newCount.toLocaleString();
}
}
// Like Function
function toggleLike(trackId, button) {
fetch('/api/toggle_like.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
track_id: trackId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
if (data.liked) {
button.classList.add('liked');
button.innerHTML = '<i class="fas fa-heart"></i> Liked';
} else {
button.classList.remove('liked');
button.innerHTML = '<i class="fas fa-heart"></i> Like';
}
updateLikeCount(data.like_count);
}
})
.catch(error => console.error('Error toggling like:', error));
}
function updateLikeCount(count) {
const likeCountElement = document.querySelector('.stat-item:nth-child(2) .stat-value');
if (likeCountElement) {
likeCountElement.textContent = count.toLocaleString();
}
}
// Comment Functions
function addComment(trackId) {
const commentInput = document.getElementById('commentInput');
const comment = commentInput.value.trim();
if (!comment) return;
fetch('/api/add_comment.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
track_id: trackId,
comment: comment
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
commentInput.value = '';
loadComments(trackId);
}
})
.catch(error => console.error('Error adding comment:', error));
}
function loadComments(trackId) {
fetch(`/api/get_comments.php?track_id=${trackId}`)
.then(response => response.json())
.then(data => {
const commentsList = document.getElementById('commentsList');
commentsList.innerHTML = '';
data.comments.forEach(comment => {
const commentElement = document.createElement('div');
commentElement.className = 'comment fade-in';
commentElement.innerHTML = `
<div class="comment-header">
<span class="comment-author">${comment.author_name}</span>
<span class="comment-date">${formatDate(comment.created_at)}</span>
</div>
<div class="comment-text">${comment.comment}</div>
`;
commentsList.appendChild(commentElement);
});
})
.catch(error => console.error('Error loading comments:', error));
}
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString();
}
// Related Tracks
function loadRelatedTracks() {
fetch(`/api/get_related_tracks.php?track_id=${currentTrackId}&artist_id=${<?= $track['user_id'] ?>}`)
.then(response => response.json())
.then(data => {
const relatedTracksContainer = document.getElementById('relatedTracks');
relatedTracksContainer.innerHTML = '';
data.tracks.forEach(track => {
const trackElement = document.createElement('div');
trackElement.className = 'track-card fade-in';
trackElement.onclick = () => window.location.href = `/track.php?id=${track.id}`;
trackElement.innerHTML = `
<img src="${track.image_url || '/uploads/track_covers/track_45_1754191923.jpg'}" alt="${track.title}">
<div class="track-card-content">
<div class="track-card-title">${track.title}</div>
<div class="track-card-artist">by ${track.artist_name}</div>
</div>
`;
relatedTracksContainer.appendChild(trackElement);
});
})
.catch(error => console.error('Error loading related tracks:', error));
}
// Utility Functions
function addToCart(trackId, title, price) {
// Use FormData to match cart.php expectations
const formData = new FormData();
formData.append('track_id', trackId);
formData.append('action', 'add');
formData.append('artist_plan', 'free'); // Default to free plan
fetch('/cart.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Track added to cart!');
} else {
alert('Error adding track to cart: ' + (data.message || 'Unknown error'));
}
})
.catch(error => console.error('Error adding to cart:', error));
}
function shareTrack(trackId, title, artist) {
const url = `${window.location.origin}/track.php?id=${trackId}`;
const text = `Check out "${title}" by ${artist} on SoundStudioPro!`;
if (navigator.share) {
navigator.share({
title: title,
text: text,
url: url
});
} else {
navigator.clipboard.writeText(`${text} ${url}`);
alert('Link copied to clipboard!');
}
}
// Waveform Generation
function generateWaveform() {
const bars = 50;
const waveformContainer = document.getElementById('waveform');
for (let i = 0; i < bars; i++) {
const bar = document.createElement('div');
bar.className = 'waveform-bar';
bar.style.left = `${(i / bars) * 100}%`;
bar.style.width = `${100 / bars}%`;
bar.style.height = `${Math.random() * 60 + 10}%`;
waveformContainer.appendChild(bar);
}
}
</script>
</body>
</html>