![]() 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/.cursor-server/data/User/History/2da5ea9f/ |
<?php
/**
* Fix Stuck Processing Tracks
*
* Finds tracks that are "processing" in the database but "complete" on API.Box
* and processes them like a callback would (downloads audio, extracts metadata, etc.)
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once 'config/database.php';
// Include callback functions
require_once 'callback.php';
$api_key = '63edba40620216c5aa2c04240ac41dbd';
$logFile = 'fix_stuck_tracks_log.txt';
echo "<h1>🔧 Fix Stuck Processing Tracks</h1>";
echo "<p>This script finds tracks stuck in 'processing' status that are actually 'complete' on API.Box</p>";
$pdo = getDBConnection();
if (!$pdo) {
die("<p style='color: red;'>❌ Database connection failed</p>");
}
// Get all tracks with status='processing' that have a valid task_id
$stmt = $pdo->prepare("
SELECT id, task_id, title, user_id, prompt, created_at
FROM music_tracks
WHERE status = 'processing'
AND task_id IS NOT NULL
AND task_id != ''
AND task_id != 'unknown'
AND task_id NOT LIKE 'temp_%'
AND task_id NOT LIKE 'retry_%'
ORDER BY created_at DESC
LIMIT 100
");
$stmt->execute();
$stuckTracks = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($stuckTracks)) {
echo "<p style='color: green;'>✅ No stuck tracks found!</p>";
exit;
}
echo "<p>Found " . count($stuckTracks) . " track(s) with 'processing' status</p>";
echo "<hr>";
$fixedCount = 0;
$stillProcessingCount = 0;
$failedCount = 0;
$errorCount = 0;
foreach ($stuckTracks as $track) {
$trackId = $track['id'];
$taskId = $track['task_id'];
$title = $track['title'];
echo "<div style='border: 1px solid #ccc; padding: 15px; margin: 10px 0;'>";
echo "<h3>Track #{$trackId}: " . htmlspecialchars($title) . "</h3>";
echo "<p><strong>Task ID:</strong> {$taskId}</p>";
echo "<p><strong>Created:</strong> {$track['created_at']}</p>";
// Check API.Box status
$api_url = "https://api.api.box/api/v1/status/{$taskId}";
$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-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) {
echo "<p style='color: red;'>❌ cURL Error: {$curl_error}</p>";
$errorCount++;
echo "</div>";
continue;
}
if ($http_code !== 200) {
echo "<p style='color: orange;'>⚠️ API returned HTTP {$http_code}</p>";
if ($http_code === 404) {
echo "<p>Track not found on API.Box (may have been deleted or task_id is wrong)</p>";
}
$errorCount++;
echo "</div>";
continue;
}
$api_data = json_decode($response, true);
if (!$api_data) {
echo "<p style='color: red;'>❌ Invalid JSON response from API</p>";
$errorCount++;
echo "</div>";
continue;
}
// Check for error codes
if (isset($api_data['code']) && ($api_data['code'] == 400 || $api_data['code'] == 531 || $api_data['code'] >= 400)) {
echo "<p style='color: red;'>❌ API returned error code: {$api_data['code']}</p>";
echo "<p><strong>Error:</strong> " . htmlspecialchars($api_data['msg'] ?? 'Unknown error') . "</p>";
// Mark as failed
$error_metadata = json_encode([
'code' => $api_data['code'],
'msg' => $api_data['msg'] ?? 'Generation failed',
'error_type' => ($api_data['code'] == 400) ? 'content_violation' : 'generation_failed',
'timestamp' => date('Y-m-d H:i:s'),
'fixed_by' => 'fix_stuck_processing_tracks'
]);
$update_stmt = $pdo->prepare("UPDATE music_tracks SET status = 'failed', metadata = ?, updated_at = NOW() WHERE id = ?");
if ($update_stmt->execute([$error_metadata, $trackId])) {
echo "<p style='color: green;'>✅ Updated track to 'failed' status</p>";
$failedCount++;
} else {
echo "<p style='color: red;'>❌ Failed to update database</p>";
}
echo "</div>";
continue;
}
// Get API status
$api_status = $api_data['status'] ?? null;
// Check if it's complete
if ($api_status === 'complete' || $api_status === 'completed' ||
(isset($api_data['data']['callbackType']) && $api_data['data']['callbackType'] === 'complete')) {
echo "<p style='color: green;'>✅ Track is COMPLETE on API.Box - processing...</p>";
// Simulate callback processing
// We need to format the API response like a callback would be
$callbackData = $api_data;
// If the API response has a different structure, normalize it
if (isset($api_data['data']) && !isset($callbackData['task_id'])) {
$callbackData['task_id'] = $taskId;
$callbackData['status'] = 'complete';
}
// Log the fix attempt
$logEntry = "[" . date('Y-m-d H:i:s') . "] Fixing stuck track #{$trackId} (task_id: {$taskId})\n";
$logEntry .= "API Status: complete\n";
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
// Process like a callback - we'll use the callback processing logic
// But we need to call it in a way that works
// Get original track data for metadata extraction
$originalData = getTrackOriginalData($taskId);
$originalPrompt = $originalData['prompt'] ?? $track['prompt'];
// Extract comprehensive metadata
$enhanced_metadata = extractComprehensiveMetadata($callbackData, $originalPrompt);
// Extract title, duration, tags, model_name, lyrics
$apiTitle = extractTitleFromCallback($callbackData);
$title = $track['title'] ?: $apiTitle;
$duration = extractDurationFromCallback($callbackData);
$tagsRaw = extractTagsFromCallback($callbackData);
$tags = formatTagsForStorage($tagsRaw);
$modelName = extractModelNameFromCallback($callbackData);
// Extract lyrics
$lyrics = '';
if (isset($callbackData['data']['data']) && is_array($callbackData['data']['data'])) {
foreach ($callbackData['data']['data'] as $item) {
if (isset($item['prompt']) && !empty($item['prompt'])) {
$lyrics = $item['prompt'];
break;
}
}
}
if ($lyrics) {
$lyrics = str_replace(['[Verse]', '[Chorus]', '[Bridge]', '[Outro]', '[Intro]'], '', $lyrics);
$lyrics = preg_replace('/\[.*?\]/', '', $lyrics);
$lyrics = trim($lyrics);
}
// Extract and download image
$imageUrl = extractImageUrlFromCallback($callbackData);
$localImageUrl = null;
if ($imageUrl) {
$localImageUrl = downloadAndStoreImage($imageUrl, $taskId);
}
// Extract audio URL - check multiple possible locations
$audioUrl = null;
if (isset($callbackData['data']['data']) && is_array($callbackData['data']['data'])) {
foreach ($callbackData['data']['data'] as $audio) {
$audioUrl = (!empty($audio['audio_url'])) ? $audio['audio_url'] :
((!empty($audio['source_audio_url'])) ? $audio['source_audio_url'] :
((!empty($audio['stream_audio_url'])) ? $audio['stream_audio_url'] : null));
if ($audioUrl) break;
}
} else {
$audioUrl = $callbackData['audio_url'] ??
$callbackData['result']['audio_url'] ??
$callbackData['data']['audio_url'] ?? null;
}
$localAudioUrl = null;
if ($audioUrl) {
$localAudioUrl = downloadAndStoreAudio($audioUrl, $taskId, 'main');
}
// Store tags in metadata
if ($tags) {
$enhanced_metadata['tags'] = $tags;
}
$metadata = json_encode($enhanced_metadata);
// Update the track
$updateResult = updateMusicTrack(
$taskId,
'complete',
$localAudioUrl ?: $audioUrl,
null,
!empty($lyrics) ? $lyrics : null,
$metadata,
$duration,
$title,
$tags,
$modelName,
$localImageUrl
);
if ($updateResult) {
echo "<p style='color: green;'>✅ Successfully updated track to 'complete'!</p>";
if ($localAudioUrl) {
echo "<p>✅ Audio downloaded locally: {$localAudioUrl}</p>";
} elseif ($audioUrl) {
echo "<p>⚠️ Using external audio URL: {$audioUrl}</p>";
}
if ($localImageUrl) {
echo "<p>✅ Image downloaded locally: {$localImageUrl}</p>";
}
if ($lyrics) {
echo "<p>✅ Lyrics extracted (" . strlen($lyrics) . " chars)</p>";
}
$fixedCount++;
$logEntry = "✅ Successfully fixed track #{$trackId}\n";
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
} else {
echo "<p style='color: red;'>❌ Failed to update track in database</p>";
$errorCount++;
}
} elseif ($api_status === 'processing') {
echo "<p style='color: orange;'>⏳ Still processing on API.Box</p>";
$stillProcessingCount++;
} elseif ($api_status === 'failed' || $api_status === 'error' || $api_status === 'rejected') {
echo "<p style='color: red;'>❌ Track failed on API.Box</p>";
// Mark as failed
$error_metadata = json_encode([
'code' => 531,
'msg' => $api_data['msg'] ?? 'Generation failed',
'error_type' => 'generation_failed',
'timestamp' => date('Y-m-d H:i:s'),
'fixed_by' => 'fix_stuck_processing_tracks'
]);
$update_stmt = $pdo->prepare("UPDATE music_tracks SET status = 'failed', metadata = ?, updated_at = NOW() WHERE id = ?");
if ($update_stmt->execute([$error_metadata, $trackId])) {
echo "<p style='color: green;'>✅ Updated track to 'failed' status</p>";
$failedCount++;
}
} else {
echo "<p style='color: orange;'>⚠️ Unknown API status: " . htmlspecialchars($api_status ?? 'N/A') . "</p>";
echo "<pre>" . htmlspecialchars(json_encode($api_data, JSON_PRETTY_PRINT)) . "</pre>";
$errorCount++;
}
echo "</div>";
}
echo "<hr>";
echo "<h2>📊 Summary</h2>";
echo "<p><strong>Fixed (processing → complete):</strong> {$fixedCount}</p>";
echo "<p><strong>Still Processing:</strong> {$stillProcessingCount}</p>";
echo "<p><strong>Marked as Failed:</strong> {$failedCount}</p>";
echo "<p><strong>Errors:</strong> {$errorCount}</p>";
echo "<p><strong>Total Checked:</strong> " . count($stuckTracks) . "</p>";
if ($fixedCount > 0) {
echo "<p style='color: green; font-size: 18px; font-weight: bold;'>✅ Successfully fixed {$fixedCount} track(s)!</p>";
}
echo "<p><a href='admin.php?tab=track-status'>← Back to Admin</a></p>";