![]() 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/-24d6c3ee/ |
<?php
// Simple Playlist Management - REDESIGNED
// Clean, working interface for managing playlists
if (!isset($pdo)) {
echo '<div style="color: red; padding: 20px;">Database connection not available.</div>';
return;
}
// Get playlist filter
$playlist_tab = $_GET['playlist_tab'] ?? 'all';
// Get tracks for playlist management
$playlist_where = "mt.status = 'complete' AND mt.audio_url IS NOT NULL";
$playlist_params = [];
if ($playlist_tab === 'featured') {
$playlist_where .= " AND mt.is_featured = 1";
} elseif ($playlist_tab === 'vip') {
$playlist_where .= " AND mt.is_vip_sample = 1";
}
$playlist_tracks = $pdo->prepare("
SELECT mt.*, u.name as artist_name,
(SELECT COUNT(*) FROM track_plays WHERE track_id = mt.id) as play_count,
(SELECT COUNT(*) FROM track_likes WHERE track_id = mt.id) as like_count
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
WHERE $playlist_where
ORDER BY mt.playlist_order ASC, mt.created_at DESC
LIMIT 100
");
$playlist_tracks->execute($playlist_params);
$tracks = $playlist_tracks->fetchAll();
// Get playlist stats
$playlist_stats = [
'total' => $pdo->query("SELECT COUNT(*) FROM music_tracks mt WHERE mt.status = 'complete' AND mt.audio_url IS NOT NULL")->fetchColumn(),
'featured' => $pdo->query("SELECT COUNT(*) FROM music_tracks mt WHERE mt.status = 'complete' AND mt.audio_url IS NOT NULL AND mt.is_featured = 1")->fetchColumn(),
'vip' => $pdo->query("SELECT COUNT(*) FROM music_tracks mt WHERE mt.status = 'complete' AND mt.audio_url IS NOT NULL AND mt.is_vip_sample = 1")->fetchColumn()
];
?>
<!-- REDESIGNED Playlist Management -->
<div class="section-header">
<h2><i class="fas fa-list-music"></i> Playlist Management</h2>
<p>Manage Featured and VIP tracks. Changes are saved automatically.</p>
</div>
<style>
.playlist-container {
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.playlist-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1.5rem;
}
.playlist-filters {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.filter-btn {
padding: 10px 20px;
border: 2px solid #e5e7eb;
background: white;
color: #374151;
text-decoration: none;
border-radius: 8px;
transition: all 0.2s ease;
font-weight: 500;
}
.filter-btn:hover {
border-color: #667eea;
background: #f8fafc;
}
.filter-btn.active {
background: #667eea;
border-color: #667eea;
color: white;
}
.track-grid {
display: grid;
gap: 1rem;
padding: 1.5rem;
}
.track-item {
background: white;
border: 2px solid #e5e7eb;
border-radius: 12px;
padding: 1.5rem;
display: flex;
align-items: center;
gap: 1rem;
transition: all 0.2s ease;
}
.track-item:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
}
.track-info {
flex: 1;
}
.track-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 0.25rem;
color: #1f2937;
}
.track-artist {
color: #6b7280;
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.track-stats {
color: #9ca3af;
font-size: 0.8rem;
}
.track-controls {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: center;
}
.control-label {
font-size: 0.8rem;
color: #6b7280;
font-weight: 500;
}
.checkbox-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
border-radius: 6px;
transition: all 0.2s ease;
}
.checkbox-wrapper:hover {
background: #f9fafb;
}
.checkbox-wrapper input[type="checkbox"] {
width: 18px;
height: 18px;
accent-color: #667eea;
}
.checkbox-wrapper.featured {
color: #f59e0b;
}
.checkbox-wrapper.vip {
color: #8b5cf6;
}
.order-input {
width: 80px;
padding: 0.5rem;
border: 2px solid #e5e7eb;
border-radius: 6px;
text-align: center;
font-size: 0.9rem;
}
.order-input:focus {
outline: none;
border-color: #667eea;
}
.save-btn {
background: #10b981;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 6px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s ease;
}
.save-btn:hover {
background: #059669;
}
.save-btn:disabled {
background: #9ca3af;
cursor: not-allowed;
}
.status-message {
padding: 0.5rem;
border-radius: 6px;
font-size: 0.9rem;
margin-top: 0.5rem;
}
.status-success {
background: #d1fae5;
color: #065f46;
border: 1px solid #a7f3d0;
}
.status-error {
background: #fee2e2;
color: #991b1b;
border: 1px solid #fecaca;
}
.loading {
opacity: 0.6;
pointer-events: none;
}
</style>
<!-- Playlist Statistics -->
<div class="playlist-container">
<div class="playlist-header">
<h3 style="margin: 0 0 1rem 0;">📊 Playlist Statistics</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem;">
<div>
<div style="font-size: 2rem; font-weight: bold;"><?= number_format($playlist_stats['total']) ?></div>
<div style="opacity: 0.9;">Total Tracks</div>
</div>
<div>
<div style="font-size: 2rem; font-weight: bold;"><?= number_format($playlist_stats['featured']) ?></div>
<div style="opacity: 0.9;">Featured</div>
</div>
<div>
<div style="font-size: 2rem; font-weight: bold;"><?= number_format($playlist_stats['vip']) ?></div>
<div style="opacity: 0.9;">VIP Samples</div>
</div>
</div>
</div>
<!-- Playlist Filters -->
<div style="padding: 1.5rem 1.5rem 0 1.5rem;">
<div class="playlist-filters">
<a href="?tab=playlists&playlist_tab=all" class="filter-btn <?= $playlist_tab === 'all' ? 'active' : '' ?>">
<i class="fas fa-list"></i> All Tracks (<?= number_format($playlist_stats['total']) ?>)
</a>
<a href="?tab=playlists&playlist_tab=featured" class="filter-btn <?= $playlist_tab === 'featured' ? 'active' : '' ?>">
<i class="fas fa-star"></i> Featured (<?= number_format($playlist_stats['featured']) ?>)
</a>
<a href="?tab=playlists&playlist_tab=vip" class="filter-btn <?= $playlist_tab === 'vip' ? 'active' : '' ?>">
<i class="fas fa-crown"></i> VIP Samples (<?= number_format($playlist_stats['vip']) ?>)
</a>
</div>
</div>
</div>
<!-- Track Grid -->
<div class="track-grid">
<?php if (empty($tracks)): ?>
<div style="text-align: center; padding: 3rem; color: #6b7280; background: white; border-radius: 12px; border: 2px dashed #e5e7eb;">
<i class="fas fa-music" style="font-size: 48px; margin-bottom: 1rem; opacity: 0.5;"></i>
<h3>No tracks found</h3>
<p>No tracks match the current filter criteria.</p>
</div>
<?php else: ?>
<?php foreach ($tracks as $track): ?>
<div class="track-item" data-track-id="<?= $track['id'] ?>">
<div class="track-info">
<div class="track-title"><?= htmlspecialchars($track['title']) ?></div>
<div class="track-artist">by <?= htmlspecialchars($track['artist_name']) ?></div>
<div class="track-stats"><?= $track['play_count'] ?> plays • <?= $track['like_count'] ?> likes</div>
</div>
<div class="track-controls">
<!-- Featured Toggle -->
<div class="control-group">
<div class="control-label">Featured</div>
<div class="checkbox-wrapper featured">
<input type="checkbox"
id="featured_<?= $track['id'] ?>"
<?= $track['is_featured'] ? 'checked' : '' ?>
onchange="updateTrackSetting(<?= $track['id'] ?>, 'featured', this.checked)">
<label for="featured_<?= $track['id'] ?>">
<i class="fas fa-star"></i>
</label>
</div>
</div>
<!-- VIP Toggle -->
<div class="control-group">
<div class="control-label">VIP</div>
<div class="checkbox-wrapper vip">
<input type="checkbox"
id="vip_<?= $track['id'] ?>"
<?= $track['is_vip_sample'] ? 'checked' : '' ?>
onchange="updateTrackSetting(<?= $track['id'] ?>, 'vip', this.checked)">
<label for="vip_<?= $track['id'] ?>">
<i class="fas fa-crown"></i>
</label>
</div>
</div>
<!-- Order Input -->
<div class="control-group">
<div class="control-label">Order</div>
<input type="number"
value="<?= $track['playlist_order'] ?>"
class="order-input" min="0" max="999"
onchange="updateTrackOrder(<?= $track['id'] ?>, this.value)"
onblur="updateTrackOrder(<?= $track['id'] ?>, this.value)">
</div>
<!-- Save Button -->
<div class="control-group">
<button class="save-btn" onclick="saveTrackChanges(<?= $track['id'] ?>)">
<i class="fas fa-save"></i> Save
</button>
</div>
</div>
<!-- Status Message -->
<div id="status_<?= $track['id'] ?>" class="status-message" style="display: none;"></div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<script>
// Simple, working playlist management functions
function updateTrackSetting(trackId, setting, value) {
console.log('Updating track setting:', { trackId, setting, value });
// Show loading state
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
trackItem.classList.add('loading');
// Prepare form data
const formData = new FormData();
formData.append('playlist_action', setting === 'featured' ? 'toggle_featured' : 'toggle_vip');
formData.append('track_id', trackId);
formData.append(setting === 'featured' ? 'is_featured' : 'is_vip', value ? '1' : '0');
// Send AJAX request
fetch('admin.php?tab=playlists&ajax=1', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
trackItem.classList.remove('loading');
const statusDiv = document.getElementById(`status_${trackId}`);
if (data.success) {
statusDiv.className = 'status-message status-success';
statusDiv.textContent = '✅ Saved successfully';
} else {
statusDiv.className = 'status-message status-error';
statusDiv.textContent = '❌ Failed to save: ' + (data.error || 'Unknown error');
}
statusDiv.style.display = 'block';
// Hide status after 3 seconds
setTimeout(() => {
statusDiv.style.display = 'none';
}, 3000);
})
.catch(error => {
trackItem.classList.remove('loading');
console.error('Error updating track setting:', error);
const statusDiv = document.getElementById(`status_${trackId}`);
statusDiv.className = 'status-message status-error';
statusDiv.textContent = '❌ Network error';
statusDiv.style.display = 'block';
setTimeout(() => {
statusDiv.style.display = 'none';
}, 3000);
});
}
function updateTrackOrder(trackId, order) {
console.log('Updating track order:', { trackId, order });
// Validate order value
const orderNum = parseInt(order);
if (isNaN(orderNum) || orderNum < 0 || orderNum > 999) {
console.error('Invalid order value:', order);
return;
}
// Show loading state
const trackItem = document.querySelector(`[data-track-id="${trackId}"]`);
trackItem.classList.add('loading');
// Prepare form data
const formData = new FormData();
formData.append('playlist_action', 'update_order');
formData.append('track_id', trackId);
formData.append('order', orderNum);
// Send AJAX request
fetch('admin.php?tab=playlists&ajax=1', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
trackItem.classList.remove('loading');
const statusDiv = document.getElementById(`status_${trackId}`);
if (data.success) {
statusDiv.className = 'status-message status-success';
statusDiv.textContent = '✅ Order updated';
} else {
statusDiv.className = 'status-message status-error';
statusDiv.textContent = '❌ Failed to update order: ' + (data.error || 'Unknown error');
}
statusDiv.style.display = 'block';
setTimeout(() => {
statusDiv.style.display = 'none';
}, 3000);
})
.catch(error => {
trackItem.classList.remove('loading');
console.error('Error updating track order:', error);
const statusDiv = document.getElementById(`status_${trackId}`);
statusDiv.className = 'status-message status-error';
statusDiv.textContent = '❌ Network error';
statusDiv.style.display = 'block';
setTimeout(() => {
statusDiv.style.display = 'none';
}, 3000);
});
}
function saveTrackChanges(trackId) {
console.log('Saving all changes for track:', trackId);
// Get current values
const featuredCheckbox = document.getElementById(`featured_${trackId}`);
const vipCheckbox = document.getElementById(`vip_${trackId}`);
const orderInput = featuredCheckbox.closest('.track-item').querySelector('.order-input');
// Update featured status
if (featuredCheckbox) {
updateTrackSetting(trackId, 'featured', featuredCheckbox.checked);
}
// Update VIP status
if (vipCheckbox) {
updateTrackSetting(trackId, 'vip', vipCheckbox.checked);
}
// Update order
if (orderInput) {
updateTrackOrder(trackId, orderInput.value);
}
}
function refreshPlaylistData() {
console.log('Refreshing playlist data...');
location.reload();
}
function exportPlaylistData() {
console.log('Exporting playlist data...');
const tracks = <?= json_encode($tracks) ?>;
let csv = 'Track ID,Title,Artist,Featured,VIP,Order,Play Count,Like Count\n';
tracks.forEach(track => {
csv += `${track.id},"${track.title}","${track.artist_name}",${track.is_featured ? 'Yes' : 'No'},${track.is_vip_sample ? 'Yes' : 'No'},${track.playlist_order},${track.play_count},${track.like_count}\n`;
});
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `playlist_data_${new Date().toISOString().split('T')[0]}.csv`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
console.log('✅ Playlist data exported successfully');
}
</script>