![]() 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/ |
<?php
session_start();
// Check if user is admin
if (!isset($_SESSION['user_id']) || !isset($_SESSION['is_admin']) || !$_SESSION['is_admin']) {
header('Location: ../auth/login.php');
exit;
}
require_once '../config/database.php';
$pdo = getDBConnection();
$API_KEY = '63edba40620216c5aa2c04240ac41dbd';
$API_URL = 'https://api.api.box';
// Function to fetch all tracks from API
function fetchAllTracksFromAPI($apiKey, $apiUrl) {
$allTracks = [];
$page = 1;
$perPage = 50; // API usually returns 50 per page
while (true) {
$url = $apiUrl . "/api/v1/tracks?page=$page&per_page=$perPage";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL Error: $error");
}
if ($httpCode !== 200) {
throw new Exception("API Error: HTTP $httpCode - $response");
}
$data = json_decode($response, true);
if (!$data || !isset($data['data']) || empty($data['data'])) {
break; // No more tracks
}
$allTracks = array_merge($allTracks, $data['data']);
// Check if we have more pages
if (count($data['data']) < $perPage) {
break;
}
$page++;
// Safety check to prevent infinite loops
if ($page > 20) {
break;
}
}
return $allTracks;
}
// Function to create track in database
function createTrackInDatabase($pdo, $trackData) {
try {
// Extract track information
$taskId = $trackData['id'] ?? $trackData['task_id'] ?? null;
$title = $trackData['title'] ?? 'Untitled Track';
$prompt = $trackData['prompt'] ?? '';
$status = $trackData['status'] ?? 'processing';
$audioUrl = $trackData['audio_url'] ?? $trackData['source_audio_url'] ?? null;
$duration = $trackData['duration'] ?? null;
if (!$taskId) {
return ['success' => false, 'error' => 'No task_id found in track data'];
}
// Check if track already exists
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE task_id = ?");
$stmt->execute([$taskId]);
if ($stmt->fetch()) {
return ['success' => false, 'error' => 'Track already exists in database'];
}
// Create the track
$stmt = $pdo->prepare("
INSERT INTO music_tracks
(user_id, task_id, title, prompt, music_type, model_version, duration, status, audio_url, metadata, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
");
$metadata = json_encode($trackData);
$userId = 1; // Default admin user ID
$stmt->execute([
$userId,
$taskId,
$title,
$prompt,
'music',
'v3',
$duration,
$status,
$audioUrl,
$metadata
]);
return ['success' => true, 'track_id' => $taskId, 'title' => $title];
} catch (Exception $e) {
return ['success' => false, 'error' => $e->getMessage()];
}
}
// Handle form submission
$message = '';
$stats = [
'total_fetched' => 0,
'created' => 0,
'already_exists' => 0,
'errors' => 0
];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['sync_missing'])) {
try {
// Fetch all tracks from API
$apiTracks = fetchAllTracksFromAPI($API_KEY, $API_URL);
$stats['total_fetched'] = count($apiTracks);
// Process each track
foreach ($apiTracks as $track) {
$result = createTrackInDatabase($pdo, $track);
if ($result['success']) {
$stats['created']++;
} elseif (strpos($result['error'], 'already exists') !== false) {
$stats['already_exists']++;
} else {
$stats['errors']++;
}
}
$message = "Sync completed! Fetched {$stats['total_fetched']} tracks, created {$stats['created']} new tracks, {$stats['already_exists']} already existed, {$stats['errors']} errors.";
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
}
}
// Get current database stats
$dbStats = [];
$stmt = $pdo->query("SELECT COUNT(*) as total FROM music_tracks");
$dbStats['total'] = $stmt->fetch()['total'];
$stmt = $pdo->query("SELECT COUNT(*) as complete FROM music_tracks WHERE status = 'complete'");
$dbStats['complete'] = $stmt->fetch()['complete'];
$stmt = $pdo->query("SELECT COUNT(*) as failed FROM music_tracks WHERE status = 'failed'");
$dbStats['failed'] = $stmt->fetch()['failed'];
$stmt = $pdo->query("SELECT COUNT(*) as processing FROM music_tracks WHERE status = 'processing'");
$dbStats['processing'] = $stmt->fetch()['processing'];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sync Missing Tracks - Admin Dashboard</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: #f093fb;
--success: #48bb78;
--error: #f56565;
--warning: #ed8936;
--bg-dark: #1a202c;
--bg-card: #2d3748;
--text-primary: #f7fafc;
--text-secondary: #a0aec0;
--border-light: rgba(255, 255, 255, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, var(--bg-dark), #2d3748);
color: var(--text-primary);
min-height: 100vh;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.header {
text-align: center;
margin-bottom: 3rem;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
background: linear-gradient(135deg, var(--primary), var(--accent));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header p {
color: var(--text-secondary);
font-size: 1.1rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-bottom: 3rem;
}
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}
.stat-number {
font-size: 2.5rem;
font-weight: bold;
color: var(--accent);
margin-bottom: 0.5rem;
}
.stat-label {
color: var(--text-secondary);
font-size: 1rem;
font-weight: 600;
}
.sync-section {
background: var(--bg-card);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 2rem;
margin-bottom: 2rem;
}
.sync-section h2 {
color: var(--text-primary);
margin-bottom: 1rem;
font-size: 1.5rem;
}
.sync-info {
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.sync-info h3 {
color: var(--accent);
margin-bottom: 1rem;
}
.sync-info ul {
list-style: none;
padding: 0;
}
.sync-info li {
padding: 0.5rem 0;
border-bottom: 1px solid var(--border-light);
color: var(--text-secondary);
}
.sync-info li:last-child {
border-bottom: none;
}
.sync-info li:before {
content: "✅ ";
color: var(--success);
}
.sync-button {
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.sync-button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.message {
padding: 1rem;
border-radius: 8px;
margin-bottom: 1.5rem;
font-weight: 600;
}
.message.success {
background: rgba(72, 187, 120, 0.2);
border: 1px solid var(--success);
color: var(--success);
}
.message.error {
background: rgba(245, 101, 101, 0.2);
border: 1px solid var(--error);
color: var(--error);
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--accent);
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
.back-link:hover {
color: var(--primary);
}
@media (max-width: 768px) {
.container {
padding: 1rem;
}
.header h1 {
font-size: 2rem;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1><i class="fas fa-sync-alt"></i> Sync Missing Tracks</h1>
<p>Fetch all your tracks from the API and sync them to your database</p>
</div>
<?php if ($message): ?>
<div class="message <?= strpos($message, 'Error') !== false ? 'error' : 'success' ?>">
<?= htmlspecialchars($message) ?>
</div>
<?php endif; ?>
<!-- Current Database Stats -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number"><?= $dbStats['total'] ?></div>
<div class="stat-label">Total Tracks in Database</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $dbStats['complete'] ?></div>
<div class="stat-label">Complete Tracks</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $dbStats['failed'] ?></div>
<div class="stat-label">Failed Tracks</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $dbStats['processing'] ?></div>
<div class="stat-label">Processing Tracks</div>
</div>
</div>
<!-- Sync Section -->
<div class="sync-section">
<h2><i class="fas fa-download"></i> Sync Missing Tracks</h2>
<div class="sync-info">
<h3>What This Will Do:</h3>
<ul>
<li>Connect to your API.box account using your API key</li>
<li>Fetch ALL tracks from your API dashboard (81 tracks)</li>
<li>Compare with your database (46 tracks)</li>
<li>Create missing tracks in your database</li>
<li>Preserve all metadata and audio URLs</li>
<li>Set proper status (complete/failed/processing)</li>
</ul>
</div>
<form method="POST">
<button type="submit" name="sync_missing" class="sync-button">
<i class="fas fa-sync-alt"></i>
Sync Missing Tracks from API
</button>
</form>
</div>
<!-- Sync Results -->
<?php if ($stats['total_fetched'] > 0): ?>
<div class="sync-section">
<h2><i class="fas fa-chart-bar"></i> Sync Results</h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number"><?= $stats['total_fetched'] ?></div>
<div class="stat-label">Tracks Fetched from API</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['created'] ?></div>
<div class="stat-label">New Tracks Created</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['already_exists'] ?></div>
<div class="stat-label">Already Existed</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['errors'] ?></div>
<div class="stat-label">Errors</div>
</div>
</div>
</div>
<?php endif; ?>
<div style="text-align: center; margin-top: 3rem;">
<a href="index.php" class="back-link">
<i class="fas fa-arrow-left"></i>
Back to Admin Dashboard
</a>
</div>
</div>
</body>
</html>