![]() 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
// Orphaned Tracks Management Tab
// This file handles tracks that have no associated user
// Get orphaned tracks (tracks with no user_id or user_id is NULL)
try {
$stmt = $pdo->prepare("
SELECT
mt.*,
'Orphaned' as user_name,
'orphaned@system.com' as user_email
FROM music_tracks mt
WHERE mt.user_id IS NULL OR mt.user_id = 0
ORDER BY mt.created_at DESC
LIMIT 100
");
$stmt->execute();
$orphaned_tracks = $stmt->fetchAll();
} catch (Exception $e) {
$orphaned_tracks = [];
}
// Get orphaned track statistics
$orphaned_stats = $pdo->query("
SELECT
COUNT(*) as total_orphaned,
COUNT(CASE WHEN status = 'complete' THEN 1 END) as completed_orphaned,
COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing_orphaned,
COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed_orphaned,
COUNT(CASE WHEN audio_url IS NOT NULL AND audio_url != '' THEN 1 END) as with_audio,
COUNT(CASE WHEN audio_url LIKE '%apiboxfiles.erweima.ai%' THEN 1 END) as cdn_tracks
FROM music_tracks
WHERE user_id IS NULL OR user_id = 0
")->fetch();
// Get all users for assignment
$users = $pdo->query("
SELECT id, name, email, plan, credits
FROM users
WHERE is_admin = 0
ORDER BY name ASC
")->fetchAll();
?>
<!-- Orphaned Tracks Management -->
<div class="section-header">
<h2><i class="fas fa-exclamation-triangle"></i> Orphaned Tracks Management</h2>
<p>Manage tracks that have no associated user and organize them properly</p>
<div style="margin-top: 10px; display: flex; gap: 1rem; flex-wrap: wrap;">
<button class="btn btn-primary" onclick="assignAllOrphanedTracks()">
<i class="fas fa-users"></i> Assign All to Admin
</button>
<button class="btn btn-warning" onclick="showOrphanedTracksAnalysis()">
<i class="fas fa-chart-bar"></i> Orphaned Tracks Analysis
</button>
<button class="btn btn-info" onclick="exportOrphanedTracks()">
<i class="fas fa-download"></i> Export Orphaned Tracks
</button>
</div>
</div>
<!-- Orphaned Track Statistics Cards -->
<div class="stats-grid" style="margin-bottom: 3rem;">
<div class="stat-card">
<div class="stat-number"><?= number_format($orphaned_stats['total_orphaned']) ?></div>
<div class="stat-label">Total Orphaned</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= number_format($orphaned_stats['completed_orphaned']) ?></div>
<div class="stat-label">Completed</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= number_format($orphaned_stats['with_audio']) ?></div>
<div class="stat-label">With Audio</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= number_format($orphaned_stats['cdn_tracks']) ?></div>
<div class="stat-label">CDN Tracks</div>
</div>
</div>
<!-- Orphaned Tracks Table -->
<div class="section-header">
<h3><i class="fas fa-list"></i> Orphaned Tracks List</h3>
<p>These tracks have no associated user and need to be organized</p>
</div>
<input type="text" id="orphanedTrackSearch" placeholder="Search orphaned tracks..." class="search-input">
<table class="data-table">
<thead>
<tr>
<th>Track</th>
<th>Status</th>
<th>Audio</th>
<th>Created</th>
<th>Assign To</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($orphaned_tracks as $track): ?>
<tr data-track-id="<?= $track['id'] ?>">
<td>
<div style="display: flex; align-items: center; gap: 1rem;">
<div style="width: 50px; height: 50px; background: linear-gradient(135deg, #f56565, #e53e3e); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white;">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div>
<div style="font-weight: 600; color: white;"><?= htmlspecialchars($track['title'] ?? 'Untitled') ?></div>
<div style="font-size: 1.2rem; color: #a0aec0;">ID: <?= $track['id'] ?></div>
<?php if (!empty($track['prompt'])): ?>
<div style="font-size: 1.2rem; color: #a0aec0;"><?= htmlspecialchars(substr($track['prompt'], 0, 50)) ?>...</div>
<?php endif; ?>
</div>
</div>
</td>
<td>
<span class="status-badge status-<?= $track['status'] ?>">
<?= ucfirst($track['status']) ?>
</span>
</td>
<td>
<?php if ($track['audio_url']): ?>
<div style="display: flex; align-items: center; gap: 0.5rem;">
<i class="fas fa-music" style="color: #48bb78;"></i>
<span style="color: #48bb78;">Available</span>
<?php if (strpos($track['audio_url'], 'apiboxfiles.erweima.ai') !== false): ?>
<i class="fas fa-cloud" style="color: #667eea;" title="CDN Track"></i>
<?php endif; ?>
</div>
<?php else: ?>
<span style="color: #f56565;">No Audio</span>
<?php endif; ?>
</td>
<td><?= date('M j, Y H:i', strtotime($track['created_at'])) ?></td>
<td>
<select class="user-assignment" data-track-id="<?= $track['id'] ?>" style="background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); color: white; padding: 0.5rem; border-radius: 4px;">
<option value="">Select User...</option>
<?php foreach ($users as $user): ?>
<option value="<?= $user['id'] ?>"><?= htmlspecialchars($user['name']) ?> (<?= $user['plan'] ?>)</option>
<?php endforeach; ?>
</select>
</td>
<td>
<div style="display: flex; gap: 0.5rem;">
<?php if ($track['audio_url']): ?>
<button class="btn btn-sm btn-secondary" onclick="playOrphanedTrack('<?= htmlspecialchars($track['audio_url']) ?>', '<?= htmlspecialchars($track['title'] ?? 'Untitled') ?>')">
<i class="fas fa-play"></i>
</button>
<?php endif; ?>
<button class="btn btn-sm btn-primary" onclick="assignTrackToUser(<?= $track['id'] ?>, this)">
<i class="fas fa-user-plus"></i> Assign
</button>
<button class="btn btn-sm btn-danger" onclick="deleteOrphanedTrack(<?= $track['id'] ?>)">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (empty($orphaned_tracks)): ?>
<div style="text-align: center; padding: 3rem; color: #a0aec0;">
<i class="fas fa-check-circle" style="font-size: 3rem; color: #48bb78; margin-bottom: 1rem;"></i>
<h3>No Orphaned Tracks</h3>
<p>All tracks are properly assigned to users!</p>
</div>
<?php endif; ?>
<script>
// Assign track to selected user
function assignTrackToUser(trackId, button) {
const row = button.closest('tr');
const select = row.querySelector('.user-assignment');
const userId = select.value;
if (!userId) {
alert('Please select a user first');
return;
}
// Show loading state
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Assigning...';
button.disabled = true;
fetch('/admin_api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'assign_orphaned_track',
track_id: trackId,
user_id: userId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove the row from the table
row.style.background = 'rgba(72, 187, 120, 0.1)';
setTimeout(() => {
row.remove();
updateOrphanedStats();
}, 1000);
} else {
alert('Error: ' + data.message);
button.innerHTML = '<i class="fas fa-user-plus"></i> Assign';
button.disabled = false;
}
})
.catch(error => {
console.error('Error:', error);
alert('Failed to assign track');
button.innerHTML = '<i class="fas fa-user-plus"></i> Assign';
button.disabled = false;
});
}
// Assign all orphaned tracks to admin
function assignAllOrphanedTracks() {
if (!confirm('Assign all orphaned tracks to admin user? This will organize all tracks properly.')) {
return;
}
fetch('/admin_api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'assign_all_orphaned_tracks'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(`Successfully assigned ${data.assigned_count} tracks to admin`);
location.reload();
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Failed to assign tracks');
});
}
// Play orphaned track in global player
function playOrphanedTrack(audioUrl, title) {
if (typeof window.playTrackWithGlobalPlayer === 'function') {
window.playTrackWithGlobalPlayer(audioUrl, title, 'Orphaned Track');
} else if (typeof window.globalPlayer !== 'undefined' && window.globalPlayer.playTrack) {
window.globalPlayer.playTrack(audioUrl, title, 'Orphaned Track');
} else {
alert('Global player not available');
}
}
// Delete orphaned track
function deleteOrphanedTrack(trackId) {
if (!confirm('Are you sure you want to delete this orphaned track? This action cannot be undone.')) {
return;
}
fetch('/admin_api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'delete_orphaned_track',
track_id: trackId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
const row = document.querySelector(`[data-track-id="${trackId}"]`);
row.style.background = 'rgba(245, 101, 101, 0.1)';
setTimeout(() => {
row.remove();
updateOrphanedStats();
}, 1000);
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Failed to delete track');
});
}
// Update orphaned stats
function updateOrphanedStats() {
// This would update the statistics cards
// For now, just reload the page
setTimeout(() => {
location.reload();
}, 2000);
}
// Search functionality
document.getElementById('orphanedTrackSearch').addEventListener('input', function(e) {
const searchTerm = e.target.value.toLowerCase();
const rows = document.querySelectorAll('.data-table tbody tr');
rows.forEach(row => {
const title = row.querySelector('td:first-child').textContent.toLowerCase();
const prompt = row.querySelector('td:first-child div:last-child')?.textContent.toLowerCase() || '';
if (title.includes(searchTerm) || prompt.includes(searchTerm)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
// Auto-assign when user is selected
document.querySelectorAll('.user-assignment').forEach(select => {
select.addEventListener('change', function() {
if (this.value) {
const trackId = this.getAttribute('data-track-id');
const button = this.closest('tr').querySelector('.btn-primary');
assignTrackToUser(trackId, button);
}
});
});
</script>