T.ME/BIBIL_0DAY
CasperSecurity


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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/private_html/crate.php
<?php
/**
 * Public Crate View Page
 * Displays a shared crate with all its tracks
 * URL: /crate/123 or /crate.php?id=123
 */
session_start();

require_once 'config/database.php';
require_once 'includes/translations.php';

// Get crate ID from URL
$crate_id = 0;
if (isset($_GET['id'])) {
    $crate_id = (int)$_GET['id'];
}

if (!$crate_id) {
    header('Location: /community.php');
    exit;
}

$pdo = getDBConnection();

// IMPORTANT: Allow bots/crawlers (like Facebook scraper) to access crates even without session
// This is critical for Facebook, Twitter, etc. to scrape the page and show previews
$isBot = isset($_SERVER['HTTP_USER_AGENT']) && (
    stripos($_SERVER['HTTP_USER_AGENT'], 'facebookexternalhit') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'Twitterbot') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'LinkedInBot') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'WhatsApp') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'bot') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'crawler') !== false ||
    stripos($_SERVER['HTTP_USER_AGENT'], 'spider') !== false
);

// Check if is_description_public column exists
$checkDescCol = $pdo->query("SHOW COLUMNS FROM artist_playlists LIKE 'is_description_public'");
$hasDescPublicColumn = $checkDescCol->rowCount() > 0;
$descPublicField = $hasDescPublicColumn ? ", ap.is_description_public" : "";

// Get crate details (only public crates)
// IMPORTANT: Bots can access public crates for OG tag scraping
$stmt = $pdo->prepare("
    SELECT 
        ap.id,
        ap.name,
        ap.description,
        ap.user_id,
        ap.created_at,
        ap.updated_at $descPublicField,
        u.name as artist_name,
        u.id as artist_id,
        up.profile_image
    FROM artist_playlists ap
    JOIN users u ON ap.user_id = u.id
    LEFT JOIN user_profiles up ON u.id = up.user_id
    WHERE ap.id = ? AND ap.is_public = 1
");
$stmt->execute([$crate_id]);
$crate = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$crate) {
    // Crate not found or is private
    header('Location: /community.php');
    exit;
}

// Hide description if not public
$descPublic = $hasDescPublicColumn ? ($crate['is_description_public'] ?? 1) : 1;
if (!$descPublic) {
    $crate['description'] = null;
}

// Check if is_public column exists in playlist_tracks
$checkColumn = $pdo->query("SHOW COLUMNS FROM playlist_tracks LIKE 'is_public'");
$hasTrackPublicColumn = $checkColumn->rowCount() > 0;
$trackPublicFilter = $hasTrackPublicColumn ? "AND (pt.is_public = 1 OR pt.is_public IS NULL)" : "";

// Get tracks in crate - SECURITY: Never expose audio_url, task_id, or metadata in public view
// Client must use get_audio_token.php API to get signed URLs for playback
$stmt = $pdo->prepare("
    SELECT 
        mt.id,
        mt.title,
        mt.duration,
        mt.price,
        u.name as artist_name,
        u.id as artist_id,
        pt.position
    FROM playlist_tracks pt
    JOIN music_tracks mt ON pt.track_id = mt.id
    JOIN users u ON mt.user_id = u.id
    WHERE pt.playlist_id = ? AND mt.status = 'complete' $trackPublicFilter
    ORDER BY pt.position ASC
");
$stmt->execute([$crate_id]);
$tracks = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Calculate totals
$total_duration = 0;
$set_duration_minutes = 0;
foreach ($tracks as $track) {
    $total_duration += intval($track['duration']);
    $trackDuration = intval($track['duration']);
    if ($trackDuration >= 300) {
        $set_duration_minutes += 2.5;
    } else {
        $set_duration_minutes += $trackDuration * 0.5 / 60;
    }
}
$is_2_hour_set = $set_duration_minutes >= 120;

// Format duration
$hours = floor($total_duration / 3600);
$minutes = floor(($total_duration % 3600) / 60);
$duration_formatted = $hours > 0 
    ? sprintf('%dh %dm', $hours, $minutes)
    : sprintf('%dm', $minutes);

// Page metadata
$page_title = htmlspecialchars($crate['name']) . ' - Crate by ' . htmlspecialchars($crate['artist_name']) . ' | SoundStudioPro';
$page_description = 'Listen to ' . htmlspecialchars($crate['name']) . ', a curated crate by ' . htmlspecialchars($crate['artist_name']) . ' with ' . count($tracks) . ' tracks on SoundStudioPro.';

include 'includes/header.php';
?>

<style>
.crate-page {
    background: linear-gradient(180deg, #0a0a0a 0%, #1a1a1a 100%);
    min-height: 100vh;
    padding: 2rem 0 4rem;
}

.crate-page-container {
    max-width: 1000px;
    margin: 0 auto;
    padding: 0 2rem;
}

/* Crate Hero */
.crate-hero {
    display: flex;
    gap: 3rem;
    padding: 3rem;
    background: rgba(255, 255, 255, 0.03);
    border-radius: 24px;
    border: 1px solid rgba(102, 126, 234, 0.2);
    margin-bottom: 3rem;
}

.crate-artwork {
    width: 220px;
    height: 220px;
    background: linear-gradient(135deg, rgba(102, 126, 234, 0.4) 0%, rgba(118, 75, 162, 0.4) 100%);
    border-radius: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    position: relative;
    overflow: hidden;
}

.crate-artwork::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="vinyl" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="8" fill="none" stroke="rgba(255,255,255,0.15)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23vinyl)"/></svg>');
}

.crate-artwork .crate-icon {
    font-size: 5rem;
    color: white;
    z-index: 1;
    text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.crate-details {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.crate-type-label {
    font-size: 0.85rem;
    color: #667eea;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.crate-title {
    font-size: 3rem;
    font-weight: 700;
    color: white;
    margin: 0 0 1rem 0;
    line-height: 1.2;
}

.crate-artist-link {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    color: #e0e0e0;
    text-decoration: none;
    font-size: 1.1rem;
    margin-bottom: 1.5rem;
    transition: color 0.2s ease;
}

.crate-artist-link:hover {
    color: #667eea;
}

.crate-artist-link img {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
}

.crate-artist-link .artist-initial {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: linear-gradient(135deg, #667eea, #764ba2);
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-weight: 600;
    font-size: 0.9rem;
}

.crate-stats {
    display: flex;
    gap: 2rem;
    margin-bottom: 1.5rem;
}

.crate-stat {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: #a0aec0;
    font-size: 1rem;
}

.crate-stat i {
    color: #667eea;
}

.crate-description {
    color: #a0aec0;
    font-size: 1.05rem;
    line-height: 1.6;
    margin-bottom: 1.5rem;
}

/* Set Progress */
.crate-set-progress {
    background: rgba(255, 255, 255, 0.05);
    padding: 1rem 1.5rem;
    border-radius: 12px;
    margin-bottom: 1.5rem;
}

.set-progress-bar {
    height: 8px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 0.5rem;
}

.set-progress-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 0.3s ease;
}

.set-progress-fill.complete {
    background: linear-gradient(90deg, #10b981, #059669);
}

.set-progress-fill.incomplete {
    background: linear-gradient(90deg, #f59e0b, #d97706);
}

.set-progress-label {
    display: flex;
    justify-content: space-between;
    font-size: 0.9rem;
    color: #a0aec0;
}

.set-progress-label .ready {
    color: #10b981;
    font-weight: 600;
}

/* Action Buttons */
.crate-actions {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.crate-action-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 2rem;
    border-radius: 12px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: all 0.2s ease;
}

.crate-action-btn.primary {
    background: linear-gradient(135deg, #10b981, #059669);
    color: white;
}

.crate-action-btn.primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(16, 185, 129, 0.3);
}

.crate-action-btn.secondary {
    background: rgba(102, 126, 234, 0.15);
    color: #667eea;
    border: 1px solid rgba(102, 126, 234, 0.3);
}

.crate-action-btn.secondary:hover {
    background: rgba(102, 126, 234, 0.25);
}

/* Tracks List */
.crate-tracks-section {
    background: rgba(255, 255, 255, 0.03);
    border-radius: 20px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.tracks-header {
    padding: 1.5rem 2rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.tracks-header h3 {
    margin: 0;
    color: white;
    font-size: 1.3rem;
    font-weight: 600;
}

.tracks-header .track-count {
    color: #a0aec0;
    font-size: 0.95rem;
}

.tracks-list {
    padding: 1rem;
}

.track-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.5rem;
    border-radius: 12px;
    transition: background 0.2s ease;
}

.track-item:hover {
    background: rgba(255, 255, 255, 0.05);
}

.track-number {
    width: 28px;
    text-align: center;
    color: #666;
    font-size: 0.95rem;
    font-weight: 500;
}

.track-play-btn {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: rgba(102, 126, 234, 0.15);
    border: none;
    color: #667eea;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    font-size: 1rem;
}

.track-play-btn:hover {
    background: #667eea;
    color: white;
    transform: scale(1.1);
}

.track-play-btn.playing {
    background: #667eea;
    color: white;
    box-shadow: 0 0 15px rgba(102, 126, 234, 0.5);
}

.track-info {
    flex: 1;
    min-width: 0;
}

.track-title {
    color: white;
    font-weight: 500;
    font-size: 1.05rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-bottom: 0.25rem;
    text-decoration: none;
    display: block;
    transition: all 0.2s ease;
    cursor: pointer;
    position: relative;
    z-index: 10;
}

.track-title:hover {
    color: #667eea;
    text-decoration: underline;
}

.track-artist {
    font-size: 0.9rem;
    color: #a0aec0;
    text-decoration: none;
    display: block;
    transition: all 0.2s ease;
    cursor: pointer;
    position: relative;
    z-index: 10;
}

.track-artist:hover {
    color: #667eea;
    text-decoration: underline;
}

.track-duration {
    color: #666;
    font-size: 0.95rem;
    font-family: monospace;
    min-width: 50px;
    text-align: right;
}

.track-actions {
    display: flex;
    gap: 0.5rem;
}

.track-cart-btn {
    background: linear-gradient(135deg, #10b981, #059669);
    border: none;
    color: white;
    padding: 0.6rem 1.2rem;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    transition: all 0.2s ease;
}

.track-cart-btn:hover {
    transform: scale(1.05);
    box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}

.track-cart-btn.added {
    background: linear-gradient(135deg, #22c55e, #16a34a);
    pointer-events: none;
}

.track-cart-btn:disabled {
    opacity: 0.8;
    cursor: wait;
}

/* Responsive */
@media (max-width: 768px) {
    .crate-hero {
        flex-direction: column;
        text-align: center;
        padding: 2rem;
    }
    
    .crate-artwork {
        width: 180px;
        height: 180px;
        margin: 0 auto;
    }
    
    .crate-title {
        font-size: 2rem;
    }
    
    .crate-stats {
        justify-content: center;
        flex-wrap: wrap;
    }
    
    .crate-artist-link {
        justify-content: center;
    }
    
    .crate-actions {
        justify-content: center;
    }
    
    .track-item {
        flex-wrap: wrap;
        gap: 0.75rem;
    }
    
    .track-actions {
        width: 100%;
        margin-top: 0.5rem;
        justify-content: flex-end;
    }
}
</style>

<div class="crate-page">
    <div class="crate-page-container">
        <!-- Crate Hero -->
        <div class="crate-hero">
            <div class="crate-artwork">
                <div class="crate-icon">📦</div>
            </div>
            
            <div class="crate-details">
                <div class="crate-type-label">Public Crate</div>
                <h1 class="crate-title"><?= htmlspecialchars($crate['name']) ?></h1>
                
                <a href="/artist/<?= $crate['artist_id'] ?>" class="crate-artist-link">
                    <?php if (!empty($crate['profile_image'])): ?>
                        <img src="<?= htmlspecialchars($crate['profile_image']) ?>" alt="<?= htmlspecialchars($crate['artist_name']) ?>">
                    <?php else: ?>
                        <span class="artist-initial"><?= strtoupper(substr($crate['artist_name'], 0, 1)) ?></span>
                    <?php endif; ?>
                    <span><?= htmlspecialchars($crate['artist_name']) ?></span>
                </a>
                
                <div class="crate-stats">
                    <div class="crate-stat">
                        <i class="fas fa-music"></i>
                        <span><?= count($tracks) ?> tracks</span>
                    </div>
                    <div class="crate-stat">
                        <i class="fas fa-clock"></i>
                        <span><?= $duration_formatted ?></span>
                    </div>
                </div>
                
                <?php if (!empty($crate['description'])): ?>
                    <p class="crate-description"><?= htmlspecialchars($crate['description']) ?></p>
                <?php endif; ?>
                
                <!-- Actions -->
                <div class="crate-actions">
                    <button class="crate-action-btn primary" onclick="playAllTracks()">
                        <i class="fas fa-play"></i>
                        Play All
                    </button>
                    <button class="crate-action-btn secondary" onclick="shareCrate()">
                        <i class="fas fa-share-alt"></i>
                        Share
                    </button>
                </div>
            </div>
        </div>
        
        <!-- Tracks List -->
        <div class="crate-tracks-section">
            <div class="tracks-header">
                <h3><i class="fas fa-list"></i> Tracks</h3>
                <span class="track-count"><?= count($tracks) ?> tracks</span>
            </div>
            
            <div class="tracks-list">
                <?php if (empty($tracks)): ?>
                    <div style="text-align: center; padding: 3rem; color: #a0aec0;">
                        <div style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.5;">🎵</div>
                        <p>No tracks in this crate yet.</p>
                    </div>
                <?php else: ?>
                    <?php foreach ($tracks as $index => $track): 
                        $trackDuration = intval($track['duration']);
                        $mins = floor($trackDuration / 60);
                        $secs = $trackDuration % 60;
                        $durationFormatted = sprintf('%d:%02d', $mins, $secs);
                        $price = floatval($track['price'] ?? 0);
                    ?>
                        <div class="track-item" data-track-id="<?= $track['id'] ?>" data-index="<?= $index ?>">
                            <div class="track-number"><?= $index + 1 ?></div>
                            <button class="track-play-btn" data-index="<?= $index ?>" onclick="togglePlayTrack(<?= $index ?>, this)">
                                <i class="fas fa-play"></i>
                            </button>
                            <div class="track-info">
                                <a href="/track/<?= $track['id'] ?>" class="track-title" target="_blank" onclick="event.stopPropagation();"><?= htmlspecialchars($track['title'] ?? 'Untitled') ?></a>
                                <a href="/artist/<?= $track['artist_id'] ?>" class="track-artist" target="_blank" onclick="event.stopPropagation();"><?= htmlspecialchars($track['artist_name']) ?></a>
                            </div>
                            <div class="track-duration"><?= $durationFormatted ?></div>
                            <div class="track-actions">
                                <?php if ($price > 0): ?>
                                    <button class="track-cart-btn" onclick="addToCart(<?= $track['id'] ?>, '<?= htmlspecialchars($track['title'], ENT_QUOTES) ?>', <?= $price ?>, this)">
                                        <i class="fas fa-cart-plus"></i>
                                        $<?= number_format($price, 2) ?>
                                    </button>
                                <?php endif; ?>
                            </div>
                        </div>
                    <?php endforeach; ?>
                <?php endif; ?>
            </div>
        </div>
    </div>
</div>

<script>
// SECURITY: Track metadata only - NO audio URLs exposed
// Audio URLs are fetched via signed tokens when needed
const crateTracks = <?= json_encode(array_map(function($t) {
    return [
        'id' => $t['id'],
        'title' => $t['title'] ?? 'Untitled',
        'artist_name' => $t['artist_name'],
        'artist_id' => $t['artist_id'],
        'duration' => $t['duration']
    ];
}, $tracks)) ?>;

// Get tracks already in cart from session
const tracksInCart = <?php
    $cartTrackIds = [];
    if (isset($_SESSION['cart']) && !empty($_SESSION['cart'])) {
        foreach ($_SESSION['cart'] as $item) {
            if (isset($item['track_id'])) {
                $cartTrackIds[] = (int)$item['track_id'];
            }
        }
    }
    echo json_encode($cartTrackIds);
?>;

// Translations for cart buttons
const cartTranslations = {
    inCart: <?= json_encode(t('crates.in_cart')) ?>,
    added: <?= json_encode(t('crates.added')) ?>,
    addedToCart: <?= json_encode(t('crates.added_to_cart')) ?>,
    alreadyInCart: <?= json_encode(t('crates.already_in_cart')) ?>,
    failedToAdd: <?= json_encode(t('crates.failed_to_add')) ?>
};

let currentPlayingIndex = -1;

// Toggle play/pause for crate track
function togglePlayTrack(index, button) {
    const audioElement = document.getElementById('globalAudioElement');
    const isCurrentlyPlaying = currentPlayingIndex === index;
    
    // If this track is currently playing, toggle pause/play
    if (isCurrentlyPlaying && audioElement) {
        if (audioElement.paused) {
            audioElement.play();
            updatePlayButtons(index, true);
        } else {
            audioElement.pause();
            updatePlayButtons(index, false);
        }
        return;
    }
    
    // Otherwise play new track
    playTrackSecure(index, button);
}

// Secure play - fetches signed token before playing
async function playTrackSecure(index, button) {
    if (!crateTracks[index]) return;
    
    const track = crateTracks[index];
    const trackId = track.id;
    const title = track.title;
    const artist = track.artist_name;
    const artistId = track.artist_id;
    const duration = track.duration || 300;
    
    // Show loading state
    if (button) {
        button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
        button.disabled = true;
    }
    
    try {
        // Fetch signed audio token from API
        const response = await fetch(`/api/get_audio_token.php?track_id=${trackId}&duration=${duration}`);
        const data = await response.json();
        
        if (!data.success || !data.url) {
            throw new Error(data.error || 'Failed to get audio');
        }
        
        const signedUrl = data.url;
        currentPlayingIndex = index;
        
        // Update button to pause
        updatePlayButtons(index, true);
        if (button) button.disabled = false;
        
        // Show now playing notification
        if (typeof window.showNotification === 'function') {
            window.showNotification('🎵 Now playing: ' + title, 'info');
        }
        
        // Play using global player
        if (window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
            // Set up crate as playlist so auto-advance works
            if (typeof window.enhancedGlobalPlayer.loadPagePlaylist === 'function') {
                window.enhancedGlobalPlayer.loadPagePlaylist(crateTracks, 'crate', index);
            }
            window.enhancedGlobalPlayer.playTrack(signedUrl, title, artist, trackId, artistId);
        } else if (typeof window.playTrack === 'function') {
            // Fallback: set playlist on window for global player to pick up
            window._communityPlaylist = crateTracks;
            window._communityPlaylistType = 'crate';
            window._communityTrackIndex = index;
            window.playTrack(signedUrl, title, artist, trackId, artistId);
        } else {
            // Fallback to basic audio
            const audio = document.getElementById('globalAudioElement');
            if (audio) {
                audio.src = signedUrl;
                audio.play();
            }
        }
        
        // Set up event listeners for button sync
        const audioElement = document.getElementById('globalAudioElement');
        if (audioElement) {
            audioElement.onpause = () => updatePlayButtons(currentPlayingIndex, false);
            audioElement.onplay = () => updatePlayButtons(currentPlayingIndex, true);
            audioElement.onended = () => {
                updatePlayButtons(-1, false);
                // Auto-play next track
                if (currentPlayingIndex < crateTracks.length - 1) {
                    playTrackSecure(currentPlayingIndex + 1, null);
                }
            };
        }
        
    } catch (error) {
        console.error('Error playing track:', error);
        if (button) {
            button.innerHTML = '<i class="fas fa-play"></i>';
            button.disabled = false;
        }
        if (typeof window.showNotification === 'function') {
            window.showNotification('Error loading track. Please try again.', 'error');
        }
    }
}

function updatePlayButtons(playingIndex, isPlaying) {
    document.querySelectorAll('.track-play-btn').forEach((btn, idx) => {
        const btnIndex = parseInt(btn.getAttribute('data-index'));
        if (btnIndex === playingIndex && isPlaying) {
            btn.innerHTML = '<i class="fas fa-pause"></i>';
            btn.classList.add('playing');
        } else {
            btn.innerHTML = '<i class="fas fa-play"></i>';
            btn.classList.remove('playing');
        }
    });
}

function playAllTracks() {
    if (crateTracks.length === 0) return;
    
    // Pre-load the crate as playlist before playing
    if (window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.loadPagePlaylist === 'function') {
        window.enhancedGlobalPlayer.loadPagePlaylist(crateTracks, 'crate', 0);
    } else {
        // Fallback for window-based playlist
        window._communityPlaylist = crateTracks;
        window._communityPlaylistType = 'crate';
        window._communityTrackIndex = 0;
    }
    
    // Start playing from first track
    playTrackSecure(0, document.querySelector('.track-play-btn[data-index="0"]'));
}

function shareCrate() {
    const url = window.location.href;
    
    if (navigator.clipboard && navigator.clipboard.writeText) {
        navigator.clipboard.writeText(url)
            .then(() => {
                if (typeof window.showNotification === 'function') {
                    window.showNotification('Crate link copied to clipboard!', 'success');
                } else {
                    alert('Link copied!');
                }
            });
    } else {
        const textarea = document.createElement('textarea');
        textarea.value = url;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        alert('Link copied!');
    }
}

function addToCart(trackId, title, price, button) {
    console.log('🛒 Adding to cart:', { trackId, title, price });
    
    // Store original button content
    const originalHTML = button ? button.innerHTML : null;
    
    // Add loading state to button
    if (button) {
        button.disabled = true;
        button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
    }
    
    const formData = new FormData();
    formData.append('action', 'add');
    formData.append('track_id', trackId);
    
    fetch('/cart.php', {
        method: 'POST',
        body: formData
    })
    .then(response => response.json())
    .then(data => {
        console.log('🛒 Cart response:', data);
        
        if (data.success) {
            // Add track to tracksInCart array immediately
            if (!tracksInCart.includes(trackId)) {
                tracksInCart.push(trackId);
            }
            
            // Show success state on button
            if (button) {
                button.innerHTML = '<i class="fas fa-check"></i> ' + cartTranslations.added;
                button.classList.add('added');
                
                // After showing "Added!", change to "In Cart" and keep it
                setTimeout(() => {
                    if (button) {
                        button.innerHTML = '<i class="fas fa-check"></i> ' + cartTranslations.inCart;
                        button.disabled = false;
                        // Keep the 'added' class to maintain the visual state
                    }
                }, 1500);
            }
            
            // Update cart counter in header
            const cartCounts = document.querySelectorAll('.cart-count, .cart-counter');
            if (cartCounts.length > 0 && data.cart_count !== undefined) {
                cartCounts.forEach(count => {
                    count.textContent = data.cart_count;
                    if (data.cart_count > 0) {
                        count.style.display = 'flex';
                    }
                });
            } else if (cartCounts.length > 0) {
                // Fallback: manually increment
                cartCounts.forEach(count => {
                    const currentCount = parseInt(count.textContent) || 0;
                    count.textContent = currentCount + 1;
                    count.style.display = 'flex';
                });
            }
            
            // Refresh cart modal if open
            const cartModal = document.getElementById('cartModal');
            if (cartModal && cartModal.style.display === 'flex') {
                if (typeof refreshCartModal === 'function') {
                    refreshCartModal();
                }
            }
            
            if (typeof window.showNotification === 'function') {
                window.showNotification(`🛒 "${title}" ${cartTranslations.addedToCart}`, 'success');
            }
        } else {
            // Handle "already in cart" case - IMMEDIATELY show "In Cart" and keep it
            if (data.already_in_cart) {
                // Ensure track is in tracksInCart array
                if (!tracksInCart.includes(trackId)) {
                    tracksInCart.push(trackId);
                }
                
                if (button) {
                    button.innerHTML = '<i class="fas fa-check"></i> ' + cartTranslations.inCart;
                    button.classList.add('added');
                    button.disabled = false;
                    // Don't reset - keep it in "In Cart" state permanently
                }
                if (typeof window.showNotification === 'function') {
                    window.showNotification(cartTranslations.alreadyInCart, 'info');
                }
            } else {
                // Reset button on error
                if (button) {
                    button.innerHTML = originalHTML;
                    button.disabled = false;
                }
                if (typeof window.showNotification === 'function') {
                    window.showNotification(data.message || data.error || cartTranslations.failedToAdd, 'error');
                }
            }
        }
    })
    .catch(error => {
        console.error('🛒 Cart error:', error);
        // Reset button on error
        if (button) {
            button.innerHTML = originalHTML;
            button.disabled = false;
        }
        if (typeof window.showNotification === 'function') {
            window.showNotification(cartTranslations.failedToAdd, 'error');
        }
    });
}

// Check which tracks are already in cart on page load
function checkCartStatus() {
    // Get all track items from the page
    const trackItems = document.querySelectorAll('.track-item[data-track-id]');
    if (trackItems.length === 0) return;
    
    // Update buttons for tracks that are in cart
    trackItems.forEach(item => {
        const trackId = parseInt(item.getAttribute('data-track-id'));
        if (tracksInCart.includes(trackId)) {
            const cartButton = item.querySelector('.track-cart-btn');
            if (cartButton && !cartButton.classList.contains('added')) {
                // Store original price for potential future use
                const originalHTML = cartButton.innerHTML;
                cartButton.setAttribute('data-original-html', originalHTML);
                
                cartButton.innerHTML = '<i class="fas fa-check"></i> ' + cartTranslations.inCart;
                cartButton.classList.add('added');
                cartButton.disabled = false;
            }
        }
    });
}

// Run cart status check on page load
document.addEventListener('DOMContentLoaded', function() {
    checkCartStatus();
});
</script>

<?php include 'includes/footer.php'; ?>


CasperSecurity Mini