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/public_html/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/public_html/admin/comprehensive_metadata_sync.php
<?php
session_start();

// Check if user is admin
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
    header('Location: login.php');
    exit;
}

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

$pdo = getDBConnection();

// Handle form submissions
$message = '';
$action = $_POST['action'] ?? $_GET['action'] ?? '';

// Function to download and store audio files locally
function downloadAndStoreAudio($audioUrl, $taskId, $type = 'main', $variationIndex = null) {
    if (empty($audioUrl) || !filter_var($audioUrl, FILTER_VALIDATE_URL)) {
        return null;
    }
    
    // Create audio storage directory
    $audioDir = '../audio_files/';
    if (!is_dir($audioDir)) {
        mkdir($audioDir, 0755, true);
    }
    
    // Generate filename
    $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;
    
    // Skip if file already exists
    if (file_exists($localPath)) {
        return $webPath;
    }
    
    // Download the file
    $context = stream_context_create([
        'http' => [
            'timeout' => 300, // 5 minutes timeout
            'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        ]
    ]);
    
    $audioContent = file_get_contents($audioUrl, false, $context);
    
    if ($audioContent === false) {
        error_log("Failed to download audio from: $audioUrl");
        return null;
    }
    
    // Save the file
    if (file_put_contents($localPath, $audioContent, LOCK_EX)) {
        // Set proper permissions
        chmod($localPath, 0644);
        
        // Log the download
        $downloadLog = [
            'timestamp' => date('Y-m-d H:i:s'),
            'action' => 'audio_downloaded_sync',
            'task_id' => $taskId,
            'original_url' => $audioUrl,
            'local_path' => $localPath,
            'web_path' => $webPath,
            'file_size' => strlen($audioContent),
            'type' => $type,
            'variation_index' => $variationIndex
        ];
        
        $downloadLogFile = '../logs/audio_downloads.log';
        file_put_contents($downloadLogFile, json_encode($downloadLog) . "\n", FILE_APPEND | LOCK_EX);
        
        return $webPath;
    }
    
    return null;
}

// Function to extract comprehensive metadata from existing data
function extractComprehensiveMetadata($data) {
    return [
        // Raw callback data for debugging
        'raw_callback' => $data,
        
        // Basic music information
        'genre' => $data['genre'] ?? $data['tags'][0] ?? 'Electronic',
        'style' => $data['style'] ?? '',
        'tags' => $data['tags'] ?? [],
        'bpm' => $data['bpm'] ?? $data['tempo'] ?? 120,
        'key' => $data['key'] ?? 'C major',
        'time_signature' => $data['time_signature'] ?? '4/4',
        'mood' => $data['mood'] ?? 'neutral',
        'energy' => $data['energy'] ?? 'medium',
        'instruments' => $data['instruments'] ?? ['synthesizer'],
        
        // Audio Quality Metrics
        'audio_quality' => [
            'bitrate' => $data['bitrate'] ?? $data['audio_bitrate'] ?? null,
            'sample_rate' => $data['sample_rate'] ?? $data['audio_sample_rate'] ?? null,
            'format' => $data['format'] ?? $data['audio_format'] ?? 'mp3',
            'channels' => $data['channels'] ?? $data['audio_channels'] ?? 2,
            'file_size' => $data['file_size'] ?? null,
            'duration' => $data['duration'] ?? null,
            'audio_quality_score' => $data['audio_quality_score'] ?? null
        ],
        
        // Generation Parameters
        'generation_parameters' => [
            'model_version' => $data['model_version'] ?? $data['model'] ?? 'v3',
            'model_name' => $data['model_name'] ?? null,
            'temperature' => $data['temperature'] ?? null,
            'top_p' => $data['top_p'] ?? null,
            'max_tokens' => $data['max_tokens'] ?? null,
            'seed' => $data['seed'] ?? null,
            'parameters' => $data['parameters'] ?? $data['generation_params'] ?? []
        ],
        
        // Processing Information
        'processing_info' => [
            'processing_time' => $data['processing_time'] ?? $data['generation_time'] ?? null,
            'queue_time' => $data['queue_time'] ?? null,
            'total_time' => $data['total_time'] ?? null,
            'start_time' => $data['start_time'] ?? null,
            'end_time' => $data['end_time'] ?? null,
            'server_id' => $data['server_id'] ?? null,
            'worker_id' => $data['worker_id'] ?? null
        ],
        
        // Cost Information
        'cost_info' => [
            'api_cost' => $data['api_cost'] ?? $data['cost'] ?? null,
            'credits_used' => $data['credits_used'] ?? null,
            'currency' => $data['currency'] ?? 'USD',
            'pricing_tier' => $data['pricing_tier'] ?? null,
            'cost_per_second' => $data['cost_per_second'] ?? null
        ],
        
        // Waveform Data
        'waveform_data' => [
            'waveform' => $data['waveform'] ?? $data['waveform_data'] ?? null,
            'waveform_url' => $data['waveform_url'] ?? null,
            'waveform_points' => $data['waveform_points'] ?? null,
            'waveform_resolution' => $data['waveform_resolution'] ?? null
        ],
        
        // Spectrum Analysis
        'spectrum_analysis' => [
            'spectrum' => $data['spectrum'] ?? $data['spectrum_data'] ?? null,
            'spectrum_url' => $data['spectrum_url'] ?? null,
            'frequency_data' => $data['frequency_data'] ?? null,
            'spectral_centroid' => $data['spectral_centroid'] ?? null,
            'spectral_rolloff' => $data['spectral_rolloff'] ?? null,
            'spectral_bandwidth' => $data['spectral_bandwidth'] ?? null
        ],
        
        // Audio Segments
        'audio_segments' => [
            'segments' => $data['segments'] ?? $data['audio_segments'] ?? [],
            'verse_timestamps' => $data['verse_timestamps'] ?? null,
            'chorus_timestamps' => $data['chorus_timestamps'] ?? null,
            'bridge_timestamps' => $data['bridge_timestamps'] ?? null,
            'intro_timestamps' => $data['intro_timestamps'] ?? null,
            'outro_timestamps' => $data['outro_timestamps'] ?? null,
            'section_labels' => $data['section_labels'] ?? null
        ],
        
        // Error Details (for failed generations)
        'error_details' => [
            'error_code' => $data['error_code'] ?? $data['code'] ?? null,
            'error_message' => $data['error_message'] ?? $data['msg'] ?? null,
            'error_type' => $data['error_type'] ?? null,
            'error_category' => $data['error_category'] ?? null,
            'error_suggestions' => $data['error_suggestions'] ?? null,
            'retry_available' => $data['retry_available'] ?? null,
            'error_timestamp' => $data['error_timestamp'] ?? null
        ],
        
        // Additional Analysis
        'audio_analysis' => [
            'loudness' => $data['loudness'] ?? null,
            'dynamic_range' => $data['dynamic_range'] ?? null,
            'peak_amplitude' => $data['peak_amplitude'] ?? null,
            'rms_amplitude' => $data['rms_amplitude'] ?? null,
            'zero_crossing_rate' => $data['zero_crossing_rate'] ?? null,
            'harmonic_content' => $data['harmonic_content'] ?? null,
            'percussive_content' => $data['percussive_content'] ?? null
        ],
        
        // System Information
        'system_info' => [
            'created_with' => 'AI Music Generation',
            'version' => '3.0',
            'sync_processed' => date('Y-m-d H:i:s'),
            'api_version' => $data['api_version'] ?? null,
            'api_endpoint' => $data['api_endpoint'] ?? null
        ]
    ];
}

if ($action === 'sync_all_metadata') {
    try {
        // Get all tracks with existing metadata
        $stmt = $pdo->query("
            SELECT id, title, metadata, task_id, audio_url, video_url, status 
            FROM music_tracks 
            WHERE status = 'complete' 
            AND metadata IS NOT NULL 
            AND metadata != ''
        ");
        $tracks = $stmt->fetchAll();
        
        $updated_count = 0;
        $processed_count = 0;
        $files_downloaded = 0;
        
        foreach ($tracks as $track) {
            $processed_count++;
            $metadata = json_decode($track['metadata'], true);
            
            if (!$metadata) {
                continue;
            }
            
            // Extract comprehensive metadata
            $enhanced_metadata = extractComprehensiveMetadata($metadata);
            
            // Download audio files locally
            $localAudioUrl = null;
            $localVideoUrl = null;
            
            if ($track['audio_url'] && strpos($track['audio_url'], 'http') === 0) {
                $localAudioUrl = downloadAndStoreAudio($track['audio_url'], $track['task_id'], 'main');
                if ($localAudioUrl) {
                    $files_downloaded++;
                }
            }
            
            if ($track['video_url'] && strpos($track['video_url'], 'http') === 0) {
                $localVideoUrl = downloadAndStoreAudio($track['video_url'], $track['task_id'], 'video');
                if ($localVideoUrl) {
                    $files_downloaded++;
                }
            }
            
            // Update individual metadata fields
            $updates = [];
            $params = [];
            
            // Update main metadata
            $updates[] = 'metadata = ?';
            $params[] = json_encode($enhanced_metadata);
            
            // Update individual fields
            if (isset($enhanced_metadata['audio_quality'])) {
                $updates[] = 'audio_quality = ?';
                $params[] = json_encode($enhanced_metadata['audio_quality']);
            }
            
            if (isset($enhanced_metadata['generation_parameters'])) {
                $updates[] = 'generation_parameters = ?';
                $params[] = json_encode($enhanced_metadata['generation_parameters']);
            }
            
            if (isset($enhanced_metadata['processing_info'])) {
                $updates[] = 'processing_info = ?';
                $params[] = json_encode($enhanced_metadata['processing_info']);
            }
            
            if (isset($enhanced_metadata['cost_info'])) {
                $updates[] = 'cost_info = ?';
                $params[] = json_encode($enhanced_metadata['cost_info']);
            }
            
            if (isset($enhanced_metadata['waveform_data'])) {
                $updates[] = 'waveform_data = ?';
                $params[] = json_encode($enhanced_metadata['waveform_data']);
            }
            
            if (isset($enhanced_metadata['spectrum_analysis'])) {
                $updates[] = 'spectrum_analysis = ?';
                $params[] = json_encode($enhanced_metadata['spectrum_analysis']);
            }
            
            if (isset($enhanced_metadata['audio_segments'])) {
                $updates[] = 'audio_segments = ?';
                $params[] = json_encode($enhanced_metadata['audio_segments']);
            }
            
            if (isset($enhanced_metadata['error_details'])) {
                $updates[] = 'error_details = ?';
                $params[] = json_encode($enhanced_metadata['error_details']);
            }
            
            if (isset($enhanced_metadata['audio_analysis'])) {
                $updates[] = 'audio_analysis = ?';
                $params[] = json_encode($enhanced_metadata['audio_analysis']);
            }
            
            if (isset($enhanced_metadata['system_info'])) {
                $updates[] = 'system_info = ?';
                $params[] = json_encode($enhanced_metadata['system_info']);
            }
            
            // Update audio URLs if local files were downloaded
            if ($localAudioUrl) {
                $updates[] = 'audio_url = ?';
                $params[] = $localAudioUrl;
            }
            
            if ($localVideoUrl) {
                $updates[] = 'video_url = ?';
                $params[] = $localVideoUrl;
            }
            
            $params[] = $track['id'];
            
            $sql = "UPDATE music_tracks SET " . implode(', ', $updates) . ", updated_at = NOW() WHERE id = ?";
            $update_stmt = $pdo->prepare($sql);
            $update_stmt->execute($params);
            
            $updated_count++;
        }
        
        $message = "✅ Sync completed! Processed: $processed_count, Updated: $updated_count, Files Downloaded: $files_downloaded";
        
    } catch (Exception $e) {
        $message = "❌ Error during sync: " . $e->getMessage();
    }
}

// Get statistics
$stats = [];
try {
    // Total tracks
    $stmt = $pdo->query("SELECT COUNT(*) as total FROM music_tracks WHERE status = 'complete'");
    $stats['total_tracks'] = $stmt->fetch()['total'];
    
    // Tracks with metadata
    $stmt = $pdo->query("SELECT COUNT(*) as total FROM music_tracks WHERE status = 'complete' AND metadata IS NOT NULL AND metadata != ''");
    $stats['tracks_with_metadata'] = $stmt->fetch()['total'];
    
    // Tracks with local files
    $stmt = $pdo->query("SELECT COUNT(*) as total FROM music_tracks WHERE status = 'complete' AND audio_url LIKE '/audio_files/%'");
    $stats['tracks_with_local_files'] = $stmt->fetch()['total'];
    
    // Tracks with enhanced metadata
    $stmt = $pdo->query("SELECT COUNT(*) as total FROM music_tracks WHERE status = 'complete' AND audio_quality IS NOT NULL");
    $stats['tracks_with_enhanced_metadata'] = $stmt->fetch()['total'];
    
} catch (Exception $e) {
    $stats['error'] = $e->getMessage();
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Comprehensive Metadata Sync - Admin</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <style>
        :root {
            --primary: #667eea;
            --secondary: #764ba2;
            --accent: #4facfe;
            --bg-primary: #0a0a0a;
            --bg-secondary: #1a1a1a;
            --bg-card: rgba(26, 26, 26, 0.9);
            --text-primary: #ffffff;
            --text-secondary: #a0aec0;
            --border-light: rgba(255, 255, 255, 0.1);
            --shadow-medium: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
            --success: #48bb78;
            --error: #f56565;
            --warning: #ed8936;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            background: var(--bg-primary);
            color: var(--text-primary);
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            line-height: 1.6;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 40px 20px;
        }

        .header {
            text-align: center;
            margin-bottom: 40px;
        }

        .header h1 {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            font-size: 36px;
            margin-bottom: 10px;
        }

        .header p {
            color: var(--text-secondary);
            font-size: 18px;
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin: 30px 0;
        }

        .stat-card {
            background: var(--bg-card);
            border: 1px solid var(--border-light);
            border-radius: 12px;
            padding: 25px;
            text-align: center;
            transition: all 0.3s ease;
        }

        .stat-card:hover {
            transform: translateY(-2px);
            border-color: var(--primary);
        }

        .stat-number {
            font-size: 2.5em;
            font-weight: bold;
            color: var(--success);
            margin-bottom: 10px;
        }

        .stat-label {
            font-size: 1em;
            color: var(--text-secondary);
            font-weight: 500;
        }

        .sync-section {
            background: var(--bg-card);
            border: 1px solid var(--border-light);
            border-radius: 12px;
            padding: 30px;
            margin: 30px 0;
        }

        .sync-button {
            background: linear-gradient(135deg, var(--success), #38a169);
            color: white;
            border: none;
            padding: 15px 30px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1.1em;
            font-weight: 600;
            transition: all 0.3s ease;
            display: inline-flex;
            align-items: center;
            gap: 10px;
        }

        .sync-button:hover {
            transform: translateY(-2px);
            box-shadow: var(--shadow-medium);
        }

        .message {
            padding: 20px;
            border-radius: 12px;
            margin: 20px 0;
            font-weight: 500;
        }

        .success { 
            background: rgba(72, 187, 120, 0.2); 
            border: 1px solid var(--success);
            color: var(--success);
        }

        .error { 
            background: rgba(245, 101, 101, 0.2); 
            border: 1px solid var(--error);
            color: var(--error);
        }

        .info { 
            background: rgba(102, 126, 234, 0.2); 
            border: 1px solid var(--primary);
            color: var(--primary);
        }

        .warning { 
            background: rgba(237, 137, 54, 0.2); 
            border: 1px solid var(--warning);
            color: var(--warning);
        }

        .info-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .info-card {
            background: rgba(255, 255, 255, 0.05);
            padding: 20px;
            border-radius: 8px;
            border: 1px solid var(--border-light);
        }

        .info-card h3 {
            color: var(--accent);
            margin-bottom: 15px;
            font-size: 1.2em;
        }

        .info-card ul {
            list-style: none;
            padding: 0;
        }

        .info-card li {
            padding: 8px 0;
            border-bottom: 1px solid var(--border-light);
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .info-card li:last-child {
            border-bottom: none;
        }

        .back-link {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            margin-top: 30px;
            color: var(--accent);
            text-decoration: none;
            font-weight: 600;
            padding: 10px 20px;
            background: var(--bg-card);
            border: 1px solid var(--border-light);
            border-radius: 8px;
            transition: all 0.3s ease;
        }

        .back-link:hover {
            border-color: var(--accent);
            transform: translateY(-2px);
        }

        .progress-bar {
            width: 100%;
            height: 8px;
            background: var(--bg-secondary);
            border-radius: 4px;
            overflow: hidden;
            margin: 20px 0;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, var(--success), var(--accent));
            transition: width 0.3s ease;
        }

        .sync-controls {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }

        .sync-button.secondary {
            background: linear-gradient(135deg, var(--primary), var(--secondary));
        }

        .sync-button.stop {
            background: linear-gradient(135deg, var(--error), #c53030);
        }

        .progress-stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .stat-item {
            background: rgba(255, 255, 255, 0.05);
            padding: 15px;
            border-radius: 8px;
            text-align: center;
        }

        .stat-label {
            display: block;
            font-size: 0.9em;
            color: var(--text-secondary);
            margin-bottom: 5px;
        }

        .stat-value {
            display: block;
            font-size: 1.5em;
            font-weight: bold;
            color: var(--success);
        }

        .status-display {
            background: var(--bg-card);
            border: 1px solid var(--border-light);
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
        }

        .status-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 0;
            border-bottom: 1px solid var(--border-light);
        }

        .status-item:last-child {
            border-bottom: none;
        }

        .status-label {
            font-weight: 600;
            color: var(--text-secondary);
        }

        .status-value {
            font-weight: bold;
            color: var(--accent);
        }

        .sync-log, .sync-summary {
            background: var(--bg-card);
            border: 1px solid var(--border-light);
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
        }

        .log-content, .summary-content {
            max-height: 300px;
            overflow-y: auto;
            background: rgba(0, 0, 0, 0.3);
            padding: 15px;
            border-radius: 5px;
            font-family: monospace;
            font-size: 0.9em;
        }

        .log-entry {
            padding: 5px 0;
            border-bottom: 1px solid var(--border-light);
        }

        .log-entry:last-child {
            border-bottom: none;
        }

        .log-success { color: var(--success); }
        .log-error { color: var(--error); }
        .log-info { color: var(--accent); }
        .log-warning { color: var(--warning); }

        @media (max-width: 768px) {
            .stats-grid {
                grid-template-columns: repeat(2, 1fr);
            }
            
            .info-grid {
                grid-template-columns: 1fr;
            }

            .sync-controls {
                flex-direction: column;
            }

            .progress-stats {
                grid-template-columns: repeat(2, 1fr);
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🔄 Comprehensive Metadata Sync</h1>
            <p>Sync all tracks with enhanced metadata and local file storage</p>
        </div>
        
        <?php if ($message): ?>
            <div class="message <?= strpos($message, '✅') !== false ? 'success' : 'error' ?>">
                <i class="fas <?= strpos($message, '✅') !== false ? 'fa-check-circle' : 'fa-exclamation-triangle' ?>"></i>
                <?= htmlspecialchars($message) ?>
            </div>
        <?php endif; ?>
        
        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-number"><?= number_format($stats['total_tracks'] ?? 0) ?></div>
                <div class="stat-label">Total Tracks</div>
            </div>
            <div class="stat-card">
                <div class="stat-number"><?= number_format($stats['tracks_with_metadata'] ?? 0) ?></div>
                <div class="stat-label">With Metadata</div>
            </div>
            <div class="stat-card">
                <div class="stat-number"><?= number_format($stats['tracks_with_local_files'] ?? 0) ?></div>
                <div class="stat-label">Local Files</div>
            </div>
            <div class="stat-card">
                <div class="stat-number"><?= number_format($stats['tracks_with_enhanced_metadata'] ?? 0) ?></div>
                <div class="stat-label">Enhanced Metadata</div>
            </div>
        </div>
        
        <div class="sync-section">
            <h2><i class="fas fa-sync-alt"></i> Sync Actions</h2>
            
            <!-- Sync Control Buttons -->
            <div class="sync-controls">
                <button id="startSync" class="sync-button">
                    <i class="fas fa-download"></i>
                    🔄 Start Async Sync
                </button>
                <button id="stopSync" class="sync-button stop" style="display: none;">
                    <i class="fas fa-stop"></i>
                    âšī¸ Stop Sync
                </button>
                <button id="refreshStats" class="sync-button secondary">
                    <i class="fas fa-refresh"></i>
                    📊 Refresh Stats
                </button>
            </div>
            
            <!-- Progress Section -->
            <div id="syncProgress" style="display: none;">
                <div class="progress-bar">
                    <div id="progressFill" class="progress-fill" style="width: 0%"></div>
                </div>
                
                <div class="progress-stats">
                    <div class="stat-item">
                        <span class="stat-label">Processed:</span>
                        <span id="processedCount" class="stat-value">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Updated:</span>
                        <span id="updatedCount" class="stat-value">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Files Downloaded:</span>
                        <span id="filesDownloaded" class="stat-value">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Errors:</span>
                        <span id="errorCount" class="stat-value">0</span>
                    </div>
                </div>
            </div>
            
            <!-- Current Status -->
            <div id="currentStatus" class="status-display">
                <div class="status-item">
                    <span class="status-label">Current Task:</span>
                    <span id="currentTask" class="status-value">Ready to start</span>
                </div>
                <div class="status-item">
                    <span class="status-label">Current Track:</span>
                    <span id="currentTrack" class="status-value">-</span>
                </div>
                <div class="status-item">
                    <span class="status-label">ETA:</span>
                    <span id="eta" class="status-value">-</span>
                </div>
            </div>
            
            <!-- Detailed Log -->
            <div id="syncLog" class="sync-log" style="display: none;">
                <h3><i class="fas fa-list"></i> Sync Log</h3>
                <div id="logContent" class="log-content"></div>
            </div>
            
            <!-- Summary Report -->
            <div id="syncSummary" class="sync-summary" style="display: none;">
                <h3><i class="fas fa-chart-pie"></i> Sync Summary</h3>
                <div id="summaryContent" class="summary-content"></div>
            </div>
        </div>
        
        <div class="info-grid">
            <div class="info-card">
                <h3><i class="fas fa-cogs"></i> What This Sync Does</h3>
                <ul>
                    <li><i class="fas fa-check text-success"></i> Extracts comprehensive metadata from existing callback data</li>
                    <li><i class="fas fa-check text-success"></i> Downloads all audio files locally to /audio_files/</li>
                    <li><i class="fas fa-check text-success"></i> Updates database with individual metadata columns</li>
                    <li><i class="fas fa-check text-success"></i> Preserves original data while adding new structure</li>
                    <li><i class="fas fa-check text-success"></i> Logs all download activities</li>
                </ul>
            </div>
            
            <div class="info-card">
                <h3><i class="fas fa-chart-bar"></i> Missing Data on Cards</h3>
                <ul>
                    <li><i class="fas fa-music"></i> Audio Quality: Bitrate, Sample Rate, Format</li>
                    <li><i class="fas fa-clock"></i> Processing Time: How long generation took</li>
                    <li><i class="fas fa-dollar-sign"></i> Cost Info: API cost, credits used</li>
                    <li><i class="fas fa-sliders-h"></i> Generation Parameters: Model version, temperature</li>
                    <li><i class="fas fa-chart-line"></i> Audio Analysis: Loudness, dynamic range</li>
                    <li><i class="fas fa-list"></i> Audio Segments: Verse/chorus timestamps</li>
                    <li><i class="fas fa-wave-square"></i> Waveform Data: Visual waveform display</li>
                    <li><i class="fas fa-chart-area"></i> Spectrum Analysis: Frequency data</li>
                </ul>
            </div>
        </div>
        
        <div class="info-card">
            <h3><i class="fas fa-info-circle"></i> Benefits of In-House Storage</h3>
            <ul>
                <li><i class="fas fa-shield-alt"></i> Complete Control: Full ownership of all files</li>
                <li><i class="fas fa-rocket"></i> Faster Access: Local files serve instantly</li>
                <li><i class="fas fa-lock"></i> Better Security: Files protected by your authentication</li>
                <li><i class="fas fa-coins"></i> Cost Control: No external storage costs</li>
                <li><i class="fas fa-wifi"></i> Offline Access: Works without internet</li>
                <li><i class="fas fa-chart-pie"></i> Rich Analytics: Detailed metadata for insights</li>
            </ul>
        </div>
        
        <div style="text-align: center;">
            <a href="index.php" class="back-link">
                <i class="fas fa-arrow-left"></i>
                Back to Admin Dashboard
            </a>
        </div>
    </div>

    <script>
        let syncRunning = false;
        let syncInterval = null;
        let startTime = null;

        // Initialize the page
        document.addEventListener('DOMContentLoaded', function() {
            const startSyncBtn = document.getElementById('startSync');
            const stopSyncBtn = document.getElementById('stopSync');
            const refreshStatsBtn = document.getElementById('refreshStats');

            startSyncBtn.addEventListener('click', startAsyncSync);
            stopSyncBtn.addEventListener('click', stopAsyncSync);
            refreshStatsBtn.addEventListener('click', refreshStats);
        });

        async function startAsyncSync() {
            if (syncRunning) return;

            syncRunning = true;
            startTime = Date.now();

            // Update UI
            document.getElementById('startSync').style.display = 'none';
            document.getElementById('stopSync').style.display = 'inline-flex';
            document.getElementById('syncProgress').style.display = 'block';
            document.getElementById('syncLog').style.display = 'block';
            document.getElementById('syncSummary').style.display = 'none';

            // Reset counters
            document.getElementById('processedCount').textContent = '0';
            document.getElementById('updatedCount').textContent = '0';
            document.getElementById('filesDownloaded').textContent = '0';
            document.getElementById('errorCount').textContent = '0';
            document.getElementById('progressFill').style.width = '0%';

            // Clear log
            document.getElementById('logContent').innerHTML = '';

            // Start the sync process
            await performAsyncSync();
        }

        function stopAsyncSync() {
            syncRunning = false;
            if (syncInterval) {
                clearInterval(syncInterval);
            }

            // Update UI
            document.getElementById('startSync').style.display = 'inline-flex';
            document.getElementById('stopSync').style.display = 'none';
            document.getElementById('currentTask').textContent = 'Sync stopped by user';
            document.getElementById('currentTrack').textContent = '-';
            document.getElementById('eta').textContent = '-';

            addLogEntry('Sync stopped by user', 'warning');
        }

        async function performAsyncSync() {
            try {
                addLogEntry('Starting comprehensive metadata sync...', 'info');
                updateStatus('Initializing sync process', '-', '-');

                // Get total tracks to process
                const response = await fetch('async_sync_handler.php?action=get_tracks');
                const data = await response.json();

                if (!data.success) {
                    throw new Error(data.error || 'Failed to get tracks');
                }

                const totalTracks = data.total_tracks;
                addLogEntry(`Found ${totalTracks} tracks to process`, 'info');

                if (totalTracks === 0) {
                    addLogEntry('No tracks to sync', 'warning');
                    completeSync();
                    return;
                }

                // Process tracks in batches
                let processed = 0;
                let updated = 0;
                let filesDownloaded = 0;
                let errors = 0;

                for (let i = 0; i < totalTracks && syncRunning; i += 5) { // Process 5 tracks at a time
                    const batch = await fetch('async_sync_handler.php?action=process_batch&offset=' + i + '&limit=5');
                    const batchData = await batch.json();

                    if (batchData.success) {
                        processed += batchData.processed;
                        updated += batchData.updated;
                        filesDownloaded += batchData.files_downloaded;
                        errors += batchData.errors;

                        // Update counters
                        document.getElementById('processedCount').textContent = processed;
                        document.getElementById('updatedCount').textContent = updated;
                        document.getElementById('filesDownloaded').textContent = filesDownloaded;
                        document.getElementById('errorCount').textContent = errors;

                        // Update progress
                        const progress = (processed / totalTracks) * 100;
                        document.getElementById('progressFill').style.width = progress + '%';

                        // Update status
                        const currentTrack = batchData.current_track || 'Processing batch ' + (i/5 + 1);
                        const eta = calculateETA(processed, totalTracks, startTime);
                        updateStatus('Processing tracks', currentTrack, eta);

                        // Add log entries
                        if (batchData.log_entries) {
                            batchData.log_entries.forEach(entry => {
                                addLogEntry(entry.message, entry.type);
                            });
                        }

                        // Small delay to prevent overwhelming the server
                        await new Promise(resolve => setTimeout(resolve, 100));
                    } else {
                        errors++;
                        document.getElementById('errorCount').textContent = errors;
                        addLogEntry('Batch processing error: ' + batchData.error, 'error');
                    }
                }

                if (syncRunning) {
                    completeSync(processed, updated, filesDownloaded, errors);
                }

            } catch (error) {
                addLogEntry('Sync error: ' + error.message, 'error');
                updateStatus('Error occurred', '-', '-');
                syncRunning = false;
                document.getElementById('startSync').style.display = 'inline-flex';
                document.getElementById('stopSync').style.display = 'none';
            }
        }

        function completeSync(processed = 0, updated = 0, filesDownloaded = 0, errors = 0) {
            syncRunning = false;
            document.getElementById('startSync').style.display = 'inline-flex';
            document.getElementById('stopSync').style.display = 'none';
            document.getElementById('currentTask').textContent = 'Sync completed';
            document.getElementById('currentTrack').textContent = '-';
            document.getElementById('eta').textContent = '-';

            addLogEntry('Sync completed successfully!', 'success');
            addLogEntry(`Processed: ${processed}, Updated: ${updated}, Files Downloaded: ${filesDownloaded}, Errors: ${errors}`, 'info');

            // Show summary
            showSummary(processed, updated, filesDownloaded, errors);
        }

        function showSummary(processed, updated, filesDownloaded, errors) {
            const summaryContent = document.getElementById('summaryContent');
            summaryContent.innerHTML = `
                <div class="summary-item">
                    <h4>Sync Results</h4>
                    <p><strong>Total Processed:</strong> ${processed}</p>
                    <p><strong>Successfully Updated:</strong> ${updated}</p>
                    <p><strong>Files Downloaded:</strong> ${filesDownloaded}</p>
                    <p><strong>Errors:</strong> ${errors}</p>
                    <p><strong>Success Rate:</strong> ${processed > 0 ? Math.round((updated / processed) * 100) : 0}%</p>
                </div>
                <div class="summary-item">
                    <h4>What Was Synced</h4>
                    <ul>
                        <li>✅ Comprehensive metadata extraction</li>
                        <li>✅ Audio quality metrics</li>
                        <li>✅ Generation parameters</li>
                        <li>✅ Processing information</li>
                        <li>✅ Cost information</li>
                        <li>✅ Waveform data</li>
                        <li>✅ Spectrum analysis</li>
                        <li>✅ Audio segments</li>
                        <li>✅ Local file downloads</li>
                    </ul>
                </div>
            `;
            document.getElementById('syncSummary').style.display = 'block';
        }

        function updateStatus(task, track, eta) {
            document.getElementById('currentTask').textContent = task;
            document.getElementById('currentTrack').textContent = track;
            document.getElementById('eta').textContent = eta;
        }

        function addLogEntry(message, type = 'info') {
            const logContent = document.getElementById('logContent');
            const timestamp = new Date().toLocaleTimeString();
            const entry = document.createElement('div');
            entry.className = `log-entry log-${type}`;
            entry.innerHTML = `[${timestamp}] ${message}`;
            logContent.appendChild(entry);
            logContent.scrollTop = logContent.scrollHeight;
        }

        function calculateETA(processed, total, startTime) {
            if (processed === 0) return 'Calculating...';
            
            const elapsed = Date.now() - startTime;
            const rate = processed / elapsed;
            const remaining = total - processed;
            const etaMs = remaining / rate;
            
            if (etaMs < 60000) {
                return Math.round(etaMs / 1000) + 's';
            } else if (etaMs < 3600000) {
                return Math.round(etaMs / 60000) + 'm';
            } else {
                return Math.round(etaMs / 3600000) + 'h';
            }
        }

        async function refreshStats() {
            try {
                const response = await fetch('async_sync_handler.php?action=get_stats');
                const data = await response.json();
                
                if (data.success) {
                    // Update the stats cards
                    document.querySelectorAll('.stat-number').forEach((el, index) => {
                        const stats = [data.total_tracks, data.tracks_with_metadata, data.tracks_with_local_files, data.tracks_with_enhanced_metadata];
                        if (stats[index] !== undefined) {
                            el.textContent = stats[index].toLocaleString();
                        }
                    });
                    
                    addLogEntry('Statistics refreshed', 'info');
                }
            } catch (error) {
                addLogEntry('Failed to refresh stats: ' + error.message, 'error');
            }
        }
    </script>
</body>
</html> 

CasperSecurity Mini