![]() 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/ |
<?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>