![]() 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/public_html/ |
<?php
/**
* Check Track 313 Variations
* Diagnostic script to find missing variations for track 313
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once __DIR__ . '/config/database.php';
$pdo = getDBConnection();
if (!$pdo) {
die("<h2>❌ Database connection failed</h2><p>Could not connect to database. Please check your database configuration.</p>");
}
$track_id = 313;
echo "<h2>🔍 Diagnostic Report for Track #313 (Feu Sacré)</h2>";
echo "<style>
body { font-family: Arial, sans-serif; padding: 20px; background: #0a0a0a; color: #fff; }
.section { background: rgba(255,255,255,0.05); padding: 20px; margin: 20px 0; border-radius: 12px; border: 1px solid rgba(102,126,234,0.3); }
.error { color: #f59e0b; }
.success { color: #48bb78; }
.info { color: #667eea; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid rgba(255,255,255,0.1); }
th { background: rgba(102,126,234,0.2); }
pre { background: rgba(0,0,0,0.3); padding: 15px; border-radius: 8px; overflow-x: auto; }
</style>";
// Get track info
try {
$stmt = $pdo->prepare("
SELECT
id,
title,
task_id,
variations_count,
status,
created_at,
audio_url,
metadata
FROM music_tracks
WHERE id = ?
");
$stmt->execute([$track_id]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
die("<div class='section error'><h3>❌ Track #313 not found in database</h3></div>");
}
} catch (Exception $e) {
die("<div class='section error'><h3>❌ Database Error</h3><p>" . htmlspecialchars($e->getMessage()) . "</p></div>");
}
echo "<div class='section'>";
echo "<h3>📊 Track Information</h3>";
echo "<table>";
echo "<tr><th>Field</th><th>Value</th></tr>";
echo "<tr><td>ID</td><td>#{$track['id']}</td></tr>";
echo "<tr><td>Title</td><td>" . htmlspecialchars($track['title']) . "</td></tr>";
echo "<tr><td>Task ID</td><td>" . htmlspecialchars($track['task_id'] ?? 'N/A') . "</td></tr>";
echo "<tr><td>variations_count (stored)</td><td><strong>{$track['variations_count']}</strong></td></tr>";
echo "<tr><td>Status</td><td>{$track['status']}</td></tr>";
echo "<tr><td>Created</td><td>{$track['created_at']}</td></tr>";
echo "</table>";
echo "</div>";
// Get actual variations from database
try {
$stmt = $pdo->prepare("
SELECT
id,
variation_index,
audio_url,
source_audio_url,
stream_audio_url,
duration,
title,
tags,
image_url,
created_at,
metadata
FROM audio_variations
WHERE track_id = ?
ORDER BY variation_index ASC
");
$stmt->execute([$track_id]);
$variations = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
$variations = [];
echo "<div class='section error'><p>Error fetching variations: " . htmlspecialchars($e->getMessage()) . "</p></div>";
}
$actual_count = count($variations);
echo "<div class='section'>";
echo "<h3>🎵 Variations in Database</h3>";
echo "<p class='info'><strong>Actual count:</strong> {$actual_count}</p>";
if ($track['variations_count'] != $actual_count) {
echo "<p class='error'><strong>⚠️ MISMATCH!</strong> Track says {$track['variations_count']} variations but database has {$actual_count}</p>";
}
if (empty($variations)) {
echo "<p class='error'>❌ No variations found in audio_variations table!</p>";
} else {
echo "<table>";
echo "<tr><th>Index</th><th>Audio URL</th><th>Duration</th><th>Title</th><th>Has Audio?</th></tr>";
foreach ($variations as $var) {
$hasAudio = !empty($var['audio_url']) || !empty($var['source_audio_url']) || !empty($var['stream_audio_url']);
$audioUrl = $var['audio_url'] ?: $var['source_audio_url'] ?: $var['stream_audio_url'] ?: 'NO URL';
echo "<tr>";
echo "<td>{$var['variation_index']}</td>";
echo "<td style='font-size: 0.85rem; word-break: break-all;'>" . htmlspecialchars(substr($audioUrl, 0, 100)) . "...</td>";
echo "<td>" . ($var['duration'] ? gmdate('i:s', $var['duration']) : 'N/A') . "</td>";
echo "<td>" . htmlspecialchars($var['title'] ?: 'N/A') . "</td>";
echo "<td class='" . ($hasAudio ? 'success' : 'error') . "'>" . ($hasAudio ? '✅ Yes' : '❌ No') . "</td>";
echo "</tr>";
}
echo "</table>";
}
echo "</div>";
// Check task_results JSON file FIRST (most reliable source)
if (!empty($track['task_id'])) {
$taskResultsFile = __DIR__ . "/task_results/{$track['task_id']}.json";
$jsonVariations = null;
$json_count = 0;
if (file_exists($taskResultsFile)) {
echo "<div class='section' style='border: 2px solid #48bb78; background: rgba(72,187,120,0.1);'>";
echo "<h3>📄 Task Results JSON File (Primary Source)</h3>";
echo "<p class='success'>✅ File exists: task_results/{$track['task_id']}.json</p>";
$jsonContent = file_get_contents($taskResultsFile);
$callbackData = json_decode($jsonContent, true);
if ($callbackData && isset($callbackData['data']['data']) && is_array($callbackData['data']['data'])) {
$jsonVariations = $callbackData['data']['data'];
$json_count = count($jsonVariations);
echo "<p class='info'><strong>Variations found in JSON file:</strong> <strong style='font-size: 1.2em; color: #48bb78;'>{$json_count}</strong></p>";
echo "<p class='info'><strong>Variations listed in database:</strong> <strong style='font-size: 1.2em; color: " . ($actual_count < $json_count ? '#f59e0b' : '#48bb78') . ";'>{$actual_count}</strong></p>";
if ($json_count > $actual_count) {
echo "<div style='background: rgba(245,158,11,0.3); padding: 20px; border-radius: 8px; margin: 20px 0; border: 2px solid #f59e0b;'>";
echo "<p class='error' style='font-size: 1.3em;'><strong>⚠️ MISMATCH DETECTED!</strong></p>";
echo "<p style='font-size: 1.1em;'><strong>{$json_count} variations found</strong> but <strong>only {$actual_count} variation(s) listed</strong> for this track.</p>";
echo "<p style='margin-top: 15px;'><strong>🔧 Auto-fixing now...</strong></p>";
echo "</div>";
// Auto-fix from JSON (code continues below...)
$autoFixFromJson = true;
} else {
$autoFixFromJson = false;
echo "<p class='success'>✅ Variation counts match!</p>";
}
} else {
echo "<p class='error'>❌ Invalid JSON structure or no variations found</p>";
$autoFixFromJson = false;
}
echo "</div>";
} else {
echo "<div class='section'>";
echo "<h3>📄 Task Results JSON File</h3>";
echo "<p class='error'>❌ File not found: task_results/{$track['task_id']}.json</p>";
echo "<p class='info'>💡 This file is created when the callback is received. If missing, the variations may have been lost.</p>";
echo "</div>";
$autoFixFromJson = false;
}
}
// Check API.Box if we have task_id (secondary source, may not work for old tasks)
if (!empty($track['task_id'])) {
echo "<div class='section'>";
echo "<h3>☁️ API.Box Source Data (Secondary - May Not Work for Old Tasks)</h3>";
echo "<p class='info'>💡 <strong>Note:</strong> API.Box may return 404 for old/completed tasks as they expire from their system. This is normal.</p>";
$api_key = '63edba40620216c5aa2c04240ac41dbd';
$api_url = "https://api.api.box/api/v1/status/{$track['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-Diagnostic/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_close($ch);
if ($http_code === 200) {
$api_data = json_decode($response, true);
// Extract variations
$api_variations = [];
if (isset($api_data['data']['data']) && is_array($api_data['data']['data'])) {
$api_variations = $api_data['data']['data'];
} elseif (isset($api_data['data']) && is_array($api_data['data'])) {
$api_variations = $api_data['data'];
}
$api_count = count($api_variations);
echo "<p class='info'><strong>Variations found in API.Box:</strong> <strong style='font-size: 1.2em; color: #48bb78;'>{$api_count}</strong></p>";
echo "<p class='info'><strong>Variations listed in database:</strong> <strong style='font-size: 1.2em; color: " . ($actual_count < $api_count ? '#f59e0b' : '#48bb78') . ";'>{$actual_count}</strong></p>";
if ($api_count != $actual_count) {
echo "<div style='background: rgba(245,158,11,0.3); padding: 20px; border-radius: 8px; margin: 20px 0; border: 2px solid #f59e0b;'>";
echo "<p class='error' style='font-size: 1.3em;'><strong>⚠️ MISMATCH DETECTED!</strong></p>";
echo "<p style='font-size: 1.1em;'><strong>{$api_count} variations found</strong> but <strong>only {$actual_count} variation(s) listed</strong> for this track.</p>";
echo "<p style='margin-top: 15px;'><strong>🔧 Auto-fixing now...</strong></p>";
echo "</div>";
// Auto-fix: Restore missing variations
$autoFixTriggered = true;
} else {
$autoFixTriggered = false;
}
if (!empty($api_variations)) {
echo "<table>";
echo "<tr><th>Index</th><th>Has audio_url</th><th>Has source_audio_url</th><th>Has stream_audio_url</th><th>Title</th></tr>";
foreach ($api_variations as $idx => $api_var) {
$has_audio_url = !empty($api_var['audio_url']);
$has_source = !empty($api_var['source_audio_url']);
$has_stream = !empty($api_var['stream_audio_url']);
echo "<tr>";
echo "<td>{$idx}</td>";
echo "<td class='" . ($has_audio_url ? 'success' : 'error') . "'>" . ($has_audio_url ? '✅' : '❌') . "</td>";
echo "<td class='" . ($has_source ? 'success' : 'error') . "'>" . ($has_source ? '✅' : '❌') . "</td>";
echo "<td class='" . ($has_stream ? 'success' : 'error') . "'>" . ($has_stream ? '✅' : '❌') . "</td>";
echo "<td>" . htmlspecialchars($api_var['title'] ?? 'N/A') . "</td>";
echo "</tr>";
}
echo "</table>";
// Auto-fix missing variations if mismatch detected
if (isset($autoFixTriggered) && $autoFixTriggered && $api_count > $actual_count) {
echo "<div class='section' style='border: 2px solid #48bb78; background: rgba(72,187,120,0.1);'>";
echo "<h3>🔧 Auto-Fixing Missing Variations</h3>";
// Check which variation indices we have
$stored_indices = array_column($variations, 'variation_index');
echo "<p><strong>Currently stored variation indices:</strong> " . (empty($stored_indices) ? 'None' : implode(', ', $stored_indices)) . "</p>";
// Find and restore missing ones
$missing = [];
$restored_count = 0;
// Download function
function downloadAndStoreAudio($audioUrl, $taskId, $type = 'main', $variationIndex = null) {
if (empty($audioUrl) || !filter_var($audioUrl, FILTER_VALIDATE_URL)) {
return null;
}
$audioDir = __DIR__ . '/audio_files/';
if (!is_dir($audioDir)) {
mkdir($audioDir, 0755, true);
}
$extension = pathinfo(parse_url($audioUrl, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'mp3';
if ($type === 'variation' && $variationIndex !== null) {
$filename = "{$taskId}_variation_{$variationIndex}.{$extension}";
} else {
$filename = "{$taskId}.{$extension}";
}
$localPath = $audioDir . $filename;
$webPath = '/audio_files/' . $filename;
if (file_exists($localPath)) {
return $webPath;
}
$context = stream_context_create([
'http' => ['timeout' => 300, 'user_agent' => 'Mozilla/5.0']
]);
$audioContent = @file_get_contents($audioUrl, false, $context);
if ($audioContent === false) {
return null;
}
if (file_put_contents($localPath, $audioContent, LOCK_EX)) {
chmod($localPath, 0644);
return $webPath;
}
return null;
}
$pdo->beginTransaction();
try {
foreach ($api_variations as $idx => $api_var) {
if (!in_array($idx, $stored_indices)) {
$missing[] = $idx;
// Get audio URL from any available field
$variationAudioUrl = $api_var['audio_url'] ?? $api_var['source_audio_url'] ?? $api_var['stream_audio_url'] ?? null;
if (empty($variationAudioUrl)) {
echo "<p class='error'>⚠️ Skipping variation index {$idx} - no audio URL available</p>";
continue;
}
echo "<p class='info'>📥 Restoring variation index <strong>{$idx}</strong>...</p>";
// Download audio
$localVariationUrl = downloadAndStoreAudio($variationAudioUrl, $track['task_id'], 'variation', $idx);
// Generate title
$variationTitle = $api_var['title'] ?? null;
if (!$variationTitle) {
$titleParts = [];
if (!empty($api_var['tags'])) {
$tags = is_array($api_var['tags']) ? $api_var['tags'] : explode(',', $api_var['tags']);
$titleParts = array_slice($tags, 0, 3);
}
$variationTitle = !empty($titleParts) ? implode(', ', $titleParts) : "Variation " . ($idx + 1);
}
// Prepare metadata
$variationMetadata = [
'genre' => $api_var['genre'] ?? null,
'style' => $api_var['style'] ?? null,
'bpm' => $api_var['bpm'] ?? null,
'key' => $api_var['key'] ?? null,
'mood' => $api_var['mood'] ?? null,
'energy' => $api_var['energy'] ?? null,
'instruments' => $api_var['instruments'] ?? null,
'tags' => $api_var['tags'] ?? null,
'duration' => $api_var['duration'] ?? null,
'title' => $variationTitle,
'original_index' => $idx
];
// Insert variation
$stmt = $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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$result = $stmt->execute([
$track_id,
$idx,
$localVariationUrl ?: $variationAudioUrl,
$api_var['duration'] ?? null,
$variationTitle,
is_array($api_var['tags']) ? implode(', ', $api_var['tags']) : ($api_var['tags'] ?? null),
$api_var['image_url'] ?? null,
$api_var['source_audio_url'] ?? null,
$api_var['stream_audio_url'] ?? null,
json_encode($variationMetadata)
]);
if ($result) {
$restored_count++;
echo "<p class='success'>✅ Successfully restored variation index {$idx}</p>";
} else {
echo "<p class='error'>❌ Failed to store variation index {$idx}</p>";
}
}
}
$pdo->commit();
if ($restored_count > 0) {
echo "<div style='background: rgba(72,187,120,0.2); padding: 15px; border-radius: 8px; margin-top: 15px; border: 2px solid #48bb78;'>";
echo "<p class='success' style='font-size: 1.2em;'><strong>✅ SUCCESS!</strong> Restored {$restored_count} missing variation(s)!</p>";
echo "<p><a href='/track.php?id={$track_id}' style='color: #667eea; font-size: 1.1em; font-weight: bold;'>👉 View Track Page</a></p>";
echo "</div>";
} else {
echo "<p class='error'>⚠️ No variations could be restored (missing audio URLs or other issues)</p>";
}
} catch (Exception $e) {
$pdo->rollBack();
echo "<p class='error'>❌ Error during restore: " . htmlspecialchars($e->getMessage()) . "</p>";
}
echo "</div>";
} else if ($api_count > $actual_count) {
// Show missing analysis without auto-fix
echo "<div style='background: rgba(245,158,11,0.2); padding: 15px; border-radius: 8px; margin-top: 15px;'>";
echo "<h4 class='error'>🔍 Missing Variation Analysis</h4>";
echo "<p>API.Box has {$api_count} variations but only {$actual_count} are stored.</p>";
$stored_indices = array_column($variations, 'variation_index');
echo "<p><strong>Stored variation indices:</strong> " . (empty($stored_indices) ? 'None' : implode(', ', $stored_indices)) . "</p>";
$missing = [];
foreach ($api_variations as $idx => $api_var) {
if (!in_array($idx, $stored_indices)) {
$missing[] = $idx;
}
}
if (!empty($missing)) {
echo "<p><strong>Missing indices:</strong> " . implode(', ', $missing) . "</p>";
echo "<p><strong>💡 Solution:</strong> Use the restore tool or sync from API.Box to recover missing variations.</p>";
echo "<p><a href='restore_variations.php?track_id={$track_id}&confirm=yes' style='color: #667eea;'>🔧 Restore from task_results JSON</a></p>";
}
echo "</div>";
}
}
} else if ($http_code === 404) {
echo "<p class='info'>ℹ️ API.Box returned 404 - This is <strong>normal for old/completed tasks</strong>.</p>";
echo "<p class='info'>API.Box doesn't keep completed tasks indefinitely. The task may have expired from their system.</p>";
echo "<p class='success'>✅ <strong>Solution:</strong> Use the task_results JSON file above (it's more reliable anyway!)</p>";
if ($response) {
$errorData = json_decode($response, true);
if ($errorData) {
echo "<p><strong>API Response:</strong></p>";
echo "<pre style='background: rgba(0,0,0,0.3); padding: 10px; border-radius: 8px;'>" . htmlspecialchars(json_encode($errorData, JSON_PRETTY_PRINT)) . "</pre>";
}
}
} else {
echo "<p class='error'>❌ Failed to fetch from API.Box: HTTP {$http_code}</p>";
if ($response) {
echo "<pre>" . htmlspecialchars(substr($response, 0, 500)) . "</pre>";
}
}
echo "</div>";
}
// Check callback logs
echo "<div class='section'>";
echo "<h3>📝 Callback Logs</h3>";
$log_file = "callback_log.txt";
if (file_exists($log_file) && !empty($track['task_id'])) {
$log_content = file_get_contents($log_file);
$task_id_pattern = preg_quote($track['task_id'], '/');
preg_match_all("/.*task.*{$task_id_pattern}.*variation.*/i", $log_content, $matches);
if (!empty($matches[0])) {
echo "<p class='info'>Found " . count($matches[0]) . " relevant log entries:</p>";
echo "<pre style='max-height: 400px; overflow-y: auto;'>";
echo htmlspecialchars(implode("\n", array_slice($matches[0], -20)));
echo "</pre>";
} else {
echo "<p class='error'>No callback logs found for task_id: {$track['task_id']}</p>";
}
} else {
echo "<p class='error'>No task_id available or log file not found</p>";
}
echo "</div>";
// Auto-fix from JSON if needed (moved here to avoid duplication)
if (isset($autoFixFromJson) && $autoFixFromJson && isset($jsonVariations) && $json_count > $actual_count) {
echo "<div class='section' style='border: 2px solid #48bb78; background: rgba(72,187,120,0.1);'>";
echo "<h3>🔧 Auto-Fixing from JSON File</h3>";
// Download function (reuse if not already defined)
if (!function_exists('downloadAndStoreAudio')) {
function downloadAndStoreAudio($audioUrl, $taskId, $type = 'main', $variationIndex = null) {
if (empty($audioUrl) || !filter_var($audioUrl, FILTER_VALIDATE_URL)) {
return null;
}
$audioDir = __DIR__ . '/audio_files/';
if (!is_dir($audioDir)) {
mkdir($audioDir, 0755, true);
}
$extension = pathinfo(parse_url($audioUrl, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'mp3';
if ($type === 'variation' && $variationIndex !== null) {
$filename = "{$taskId}_variation_{$variationIndex}.{$extension}";
} else {
$filename = "{$taskId}.{$extension}";
}
$localPath = $audioDir . $filename;
$webPath = '/audio_files/' . $filename;
if (file_exists($localPath)) {
return $webPath;
}
$context = stream_context_create([
'http' => ['timeout' => 300, 'user_agent' => 'Mozilla/5.0']
]);
$audioContent = @file_get_contents($audioUrl, false, $context);
if ($audioContent === false) {
return null;
}
if (file_put_contents($localPath, $audioContent, LOCK_EX)) {
chmod($localPath, 0644);
return $webPath;
}
return null;
}
}
$stored_indices = array_column($variations, 'variation_index');
$restored_count = 0;
$pdo->beginTransaction();
try {
foreach ($jsonVariations as $originalIndex => $variation) {
if (!in_array($originalIndex, $stored_indices)) {
$variationAudioUrl = $variation['audio_url'] ?? $variation['source_audio_url'] ?? $variation['stream_audio_url'] ?? null;
if (empty($variationAudioUrl)) {
echo "<p class='error'>⚠️ Skipping variation {$originalIndex} - no audio URL</p>";
continue;
}
echo "<p class='info'>📥 Restoring variation index <strong>{$originalIndex}</strong>...</p>";
$localVariationUrl = downloadAndStoreAudio($variationAudioUrl, $track['task_id'], 'variation', $originalIndex);
$variationTitle = $variation['title'] ?? null;
if (!$variationTitle) {
$titleParts = [];
if (!empty($variation['tags'])) {
$tags = is_array($variation['tags']) ? $variation['tags'] : explode(',', $variation['tags']);
$titleParts = array_slice($tags, 0, 3);
}
$variationTitle = !empty($titleParts) ? implode(', ', $titleParts) : "Variation " . ($originalIndex + 1);
}
$variationMetadata = [
'genre' => $variation['genre'] ?? null,
'style' => $variation['style'] ?? null,
'bpm' => $variation['bpm'] ?? 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,
'original_index' => $originalIndex
];
$stmt = $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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$result = $stmt->execute([
$track_id,
$originalIndex,
$localVariationUrl ?: $variationAudioUrl,
$variation['duration'] ?? null,
$variationTitle,
is_array($variation['tags']) ? implode(', ', $variation['tags']) : ($variation['tags'] ?? null),
$variation['image_url'] ?? null,
$variation['source_audio_url'] ?? null,
$variation['stream_audio_url'] ?? null,
json_encode($variationMetadata)
]);
if ($result) {
$restored_count++;
echo "<p class='success'>✅ Successfully restored variation index {$originalIndex}</p>";
}
}
}
$pdo->commit();
if ($restored_count > 0) {
echo "<div style='background: rgba(72,187,120,0.2); padding: 15px; border-radius: 8px; margin-top: 15px; border: 2px solid #48bb78;'>";
echo "<p class='success' style='font-size: 1.2em;'><strong>✅ SUCCESS!</strong> Restored {$restored_count} missing variation(s)!</p>";
echo "<p><a href='/track.php?id={$track_id}' style='color: #667eea; font-size: 1.1em; font-weight: bold;'>👉 View Track Page</a></p>";
echo "</div>";
}
} catch (Exception $e) {
$pdo->rollBack();
echo "<p class='error'>❌ Error: " . htmlspecialchars($e->getMessage()) . "</p>";
}
echo "</div>";
}
echo "<div class='section'>";
echo "<h3>💡 Summary</h3>";
echo "<ul>";
echo "<li><strong>Expected variations:</strong> {$track['variations_count']}</li>";
echo "<li><strong>Actual variations in DB:</strong> {$actual_count}</li>";
if (!empty($track['task_id'])) {
echo "<li><strong>Can restore from:</strong> task_results JSON file or API.Box</li>";
}
echo "</ul>";
if ($track['variations_count'] > $actual_count) {
echo "<p class='error'><strong>⚠️ ISSUE CONFIRMED:</strong> Track is missing " . ($track['variations_count'] - $actual_count) . " variation(s)</p>";
echo "<p><strong>Most likely cause:</strong> The callback skipped storing the second variation because it didn't have a valid audio URL at the time, or the INSERT failed silently.</p>";
} else {
echo "<p class='success'>✅ Variation counts match</p>";
}
echo "</div>";
?>