![]() 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/artist_includes/ |
<?php
// Include translation system
require_once __DIR__ . '/../includes/translations.php';
// Include audio token system for signed URLs
require_once __DIR__ . '/../utils/audio_token.php';
// Pagination setup
$page = max(1, intval($_GET['page'] ?? 1));
$per_page = 20;
$offset = ($page - 1) * $per_page;
// Get user's tracks with detailed stats (with pagination)
$tracks_query = $pdo->prepare("
SELECT
mt.*,
COALESCE(like_count.count, 0) as likes,
COALESCE(play_count.count, 0) as plays,
COALESCE(comment_count.count, 0) as comments,
COALESCE(sales_count.count, 0) as sales,
COALESCE(sales_revenue.revenue, 0) as revenue
FROM music_tracks mt
LEFT JOIN (
SELECT track_id, COUNT(*) as count
FROM track_likes
GROUP BY track_id
) like_count ON mt.id = like_count.track_id
LEFT JOIN (
SELECT track_id, COUNT(*) as count
FROM track_plays
GROUP BY track_id
) play_count ON mt.id = play_count.track_id
LEFT JOIN (
SELECT track_id, COUNT(*) as count
FROM track_comments
GROUP BY track_id
) comment_count ON mt.id = comment_count.track_id
LEFT JOIN (
SELECT track_id, COUNT(*) as count
FROM sales
GROUP BY track_id
) sales_count ON mt.id = sales_count.track_id
LEFT JOIN (
SELECT track_id, SUM(amount) as revenue
FROM sales
GROUP BY track_id
) sales_revenue ON mt.id = sales_revenue.track_id
WHERE mt.user_id = ?
ORDER BY mt.created_at DESC
LIMIT ? OFFSET ?
");
$tracks_query->execute([$user_id, $per_page, $offset]);
$user_tracks = $tracks_query->fetchAll();
// Get total count for pagination
$count_query = $pdo->prepare("
SELECT COUNT(*) as total
FROM music_tracks mt
WHERE mt.user_id = ?
");
$count_query->execute([$user_id]);
$total_tracks = $count_query->fetch()['total'];
$total_pages = ceil($total_tracks / $per_page);
?>
<div class="content-section">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;">
<h2><i class="fas fa-music"></i> <?= t('tracks.my_tracks') ?> (<?= number_format($total_tracks) ?>)</h2>
<a href="index.php" class="btn btn-primary">
<i class="fas fa-plus"></i> <?= t('tracks.create_new_track') ?>
</a>
</div>
<?php if (empty($user_tracks)): ?>
<div style="text-align: center; padding: 3rem; color: #a0aec0;">
<i class="fas fa-music" style="font-size: 4rem; margin-bottom: 1rem; opacity: 0.3;"></i>
<h3><?= t('tracks.no_tracks_yet') ?></h3>
<p><?= t('tracks.create_first_track') ?></p>
<a href="index.php" class="btn btn-primary" style="margin-top: 1rem;">
<i class="fas fa-plus"></i> <?= t('tracks.create_track') ?>
</a>
</div>
<?php else: ?>
<div class="tracks-grid">
<?php foreach ($user_tracks as $track): ?>
<div class="track-item">
<!-- Track Thumbnail -->
<div class="track-thumbnail">
<?php if (!empty($track['cover_image'])): ?>
<img src="<?= htmlspecialchars($track['cover_image']) ?>" alt="Cover" style="width: 100%; height: 100%; object-fit: cover; border-radius: 12px;">
<?php else: ?>
<i class="fas fa-music"></i>
<?php endif; ?>
</div>
<!-- Track Info -->
<div class="track-info">
<div class="track-title"><?= htmlspecialchars($track['title'] ?: t('tracks.untitled_track')) ?></div>
<div class="track-meta">
<div><?= t('tracks.status') ?>:
<span style="color: <?= $track['status'] === 'complete' ? '#48bb78' : '#ed8936' ?>;">
<?= t('tracks.status_' . $track['status']) ?>
</span>
</div>
<div><?= t('tracks.created') ?>: <?= date('M j, Y', strtotime($track['created_at'])) ?></div>
<?php if ($track['price'] > 0): ?>
<div><?= t('tracks.price') ?>: $<?= number_format($track['price'], 2) ?></div>
<?php else: ?>
<div style="color: #4299e1;"><?= t('tracks.free_track') ?></div>
<?php endif; ?>
</div>
<div class="track-stats">
<span><i class="fas fa-play"></i> <?= number_format($track['plays']) ?></span>
<span><i class="fas fa-heart"></i> <?= number_format($track['likes']) ?></span>
<span><i class="fas fa-comment"></i> <?= number_format($track['comments']) ?></span>
<span><i class="fas fa-shopping-cart"></i> <?= number_format($track['sales']) ?></span>
</div>
</div>
<!-- Track Revenue -->
<div style="text-align: center;">
<div style="font-size: 1.5rem; font-weight: bold; color: #48bb78;">
$<?= number_format($track['revenue'] * (1 - $commission_rate), 2) ?>
</div>
<div style="font-size: 0.9rem; color: #a0aec0;"><?= t('tracks.your_earnings') ?></div>
<?php if ($track['revenue'] > 0): ?>
<div style="font-size: 0.8rem; color: #cbd5e0; margin-top: 0.25rem;">
<?= t('tracks.total') ?>: $<?= number_format($track['revenue'], 2) ?>
</div>
<?php endif; ?>
</div>
<!-- Track Actions -->
<div class="track-actions">
<?php if ($track['status'] === 'complete' && !empty($track['audio_url'])): ?>
<button class="btn btn-success play-track-btn"
data-audio-url="<?= htmlspecialchars(getSignedAudioUrl($track['id'])) ?>"
data-title="<?= htmlspecialchars($track['title']) ?>"
data-artist="<?= htmlspecialchars($user['name']) ?>">
<i class="fas fa-play"></i> <?= t('btn.play') ?>
</button>
<?php endif; ?>
<button class="btn btn-primary edit-track-btn"
data-track-id="<?= $track['id'] ?>"
data-track-title="<?= htmlspecialchars($track['title'] ?: t('tracks.untitled_track'), ENT_QUOTES) ?>"
data-track-description="<?= htmlspecialchars($track['prompt'] ?? '', ENT_QUOTES) ?>"
data-track-price="<?= $track['price'] ?? 0 ?>"
data-track-public="<?= $track['is_public'] ?? 0 ?>">
<i class="fas fa-edit"></i> <?= t('btn.edit') ?>
</button>
<button class="btn btn-warning" onclick="duplicateTrack(<?= $track['id'] ?>)">
<i class="fas fa-copy"></i> <?= t('tracks.duplicate') ?>
</button>
<?php if ($track['status'] === 'complete'): ?>
<button class="btn" onclick="toggleVisibility(<?= $track['id'] ?>, <?= $track['is_public'] ?? 0 ?>)">
<i class="fas fa-eye<?= ($track['is_public'] ?? 0) ? '' : '-slash' ?>"></i>
<?= ($track['is_public'] ?? 0) ? t('tracks.public') : t('tracks.private') ?>
</button>
<?php endif; ?>
<?php if (isset($_SESSION['is_admin']) && $_SESSION['is_admin']): ?>
<button class="btn btn-danger" onclick="deleteTrack(<?= $track['id'] ?>, '<?= htmlspecialchars($track['title'], ENT_QUOTES) ?>')">
<i class="fas fa-trash"></i> <?= t('btn.delete') ?>
</button>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- Pagination Controls -->
<?php if ($total_pages > 1): ?>
<div class="pagination-container" style="margin-top: 3rem; text-align: center;">
<div class="pagination-info" style="margin-bottom: 1rem; color: #a0aec0;">
<?= t('tracks.showing', ['start' => $offset + 1, 'end' => min($offset + $per_page, $total_tracks), 'total' => number_format($total_tracks)]) ?>
</div>
<div class="pagination-controls" style="display: flex; justify-content: center; gap: 0.5rem; flex-wrap: wrap;">
<?php if ($page > 1): ?>
<a href="?tab=tracks&page=1" class="btn btn-secondary">
<i class="fas fa-angle-double-left"></i> <?= t('tracks.first') ?>
</a>
<a href="?tab=tracks&page=<?= $page - 1 ?>" class="btn btn-secondary">
<i class="fas fa-angle-left"></i> <?= t('tracks.previous') ?>
</a>
<?php endif; ?>
<?php
$start_page = max(1, $page - 2);
$end_page = min($total_pages, $page + 2);
for ($i = $start_page; $i <= $end_page; $i++):
?>
<a href="?tab=tracks&page=<?= $i ?>"
class="btn <?= $i == $page ? 'btn-primary' : 'btn-secondary' ?>">
<?= $i ?>
</a>
<?php endfor; ?>
<?php if ($page < $total_pages): ?>
<a href="?tab=tracks&page=<?= $page + 1 ?>" class="btn btn-secondary">
<?= t('tracks.next') ?> <i class="fas fa-angle-right"></i>
</a>
<a href="?tab=tracks&page=<?= $total_pages ?>" class="btn btn-secondary">
<?= t('tracks.last') ?> <i class="fas fa-angle-double-right"></i>
</a>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<script>
// Enhanced track management functions
function duplicateTrack(trackId) {
if (confirm(<?= json_encode(t('tracks.confirm_duplicate')) ?>)) {
fetch('api_track_management.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'duplicate', track_id: trackId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(<?= json_encode(t('tracks.duplicate_failed')) ?> + ': ' + (data.message || <?= json_encode(t('tracks.unknown_error')) ?>));
}
})
.catch(error => {
console.error('Duplicate error:', error);
alert(<?= json_encode(t('tracks.duplicate_failed')) ?>);
});
}
}
function toggleVisibility(trackId, currentVisibility) {
const newVisibility = currentVisibility ? 0 : 1;
const action = newVisibility ? <?= json_encode(t('tracks.make_public')) ?> : <?= json_encode(t('tracks.make_private')) ?>;
if (confirm(<?= json_encode(t('tracks.confirm_visibility')) ?> + ' ' + action + '?')) {
fetch('api_track_management.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'toggle_visibility',
track_id: trackId,
visibility: newVisibility
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(<?= json_encode(t('tracks.visibility_failed')) ?> + ': ' + (data.message || <?= json_encode(t('tracks.unknown_error')) ?>));
}
})
.catch(error => {
console.error('Visibility error:', error);
alert(<?= json_encode(t('tracks.visibility_failed')) ?>);
});
}
}
function deleteTrack(trackId, trackTitle) {
if (confirm(<?= json_encode(t('tracks.confirm_delete')) ?> + ' "' + trackTitle + '"?\n\n' + <?= json_encode(t('tracks.delete_warning')) ?>)) {
fetch('api_track_management.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'delete',
track_id: trackId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Show success message
alert(<?= json_encode(t('tracks.delete_success')) ?>);
location.reload();
} else {
alert(<?= json_encode(t('tracks.delete_failed')) ?> + ': ' + (data.message || <?= json_encode(t('tracks.unknown_error')) ?>));
}
})
.catch(error => {
console.error('Delete error:', error);
alert(<?= json_encode(t('tracks.delete_failed')) ?>);
});
}
}
// Enhanced play button functionality for artist dashboard
function initPlayButtons() {
// Play button handlers
const playButtons = document.querySelectorAll('.play-track-btn');
playButtons.forEach(button => {
// Remove existing listeners to avoid duplicates
const newButton = button.cloneNode(true);
button.parentNode.replaceChild(newButton, button);
newButton.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const audioUrl = this.getAttribute('data-audio-url');
const title = this.getAttribute('data-title');
const artist = this.getAttribute('data-artist');
if (!audioUrl || audioUrl === '' || audioUrl === 'NULL' || audioUrl === 'null') {
alert(<?= json_encode(t('tracks.audio_not_available')) ?>);
return;
}
// Ensure audio URL is absolute if it's relative
let finalAudioUrl = audioUrl;
if (audioUrl && !audioUrl.startsWith('http') && !audioUrl.startsWith('//')) {
if (audioUrl.startsWith('/')) {
finalAudioUrl = window.location.origin + audioUrl;
} else {
finalAudioUrl = window.location.origin + '/' + audioUrl;
}
}
// Check if this track is currently playing (button has 'playing' class)
const isCurrentlyPlaying = this.classList.contains('playing');
const globalPlayer = window.enhancedGlobalPlayer;
// If button shows playing state, pause it
if (isCurrentlyPlaying && globalPlayer && typeof globalPlayer.togglePlayPause === 'function') {
console.log('🎵 Dashboard: Button shows playing, pausing track');
// Pause the track using togglePlayPause
globalPlayer.togglePlayPause();
// Update button state
this.classList.remove('playing');
this.innerHTML = '<i class="fas fa-play"></i> ' + <?= json_encode(t('btn.play')) ?>;
// Clear playing state from all buttons
document.querySelectorAll('.play-track-btn').forEach(btn => {
if (btn !== this) {
btn.classList.remove('playing');
const icon = btn.querySelector('i');
if (icon && icon.classList.contains('fa-pause')) {
btn.innerHTML = '<i class="fas fa-play"></i> ' + <?= json_encode(t('btn.play')) ?>;
}
}
});
return;
}
// Check if this is the same track that's already loaded but paused - resume it instead
const audioElement = document.getElementById('globalAudioElement');
if (audioElement && audioElement.src) {
// Compare by track ID instead of URL (signed URLs have unique tokens)
const getTrackIdFromUrl = (url) => {
if (!url) return null;
const match = url.match(/[?&]id=(\d+)/);
return match ? match[1] : null;
};
const currentTrackId = getTrackIdFromUrl(audioElement.src);
const buttonTrackId = trackId || getTrackIdFromUrl(finalAudioUrl);
const isSameTrack = currentTrackId && buttonTrackId && currentTrackId === buttonTrackId;
const isPaused = audioElement.paused;
if (isSameTrack && isPaused) {
console.log('🎵 Dashboard: Resuming paused track instead of restarting');
// Resume playback using togglePlayPause (which will resume if paused)
if (globalPlayer && typeof globalPlayer.togglePlayPause === 'function') {
globalPlayer.togglePlayPause();
} else {
// Fallback: directly play the audio element
audioElement.play();
}
// Update button state
document.querySelectorAll('.play-track-btn').forEach(btn => {
btn.classList.remove('playing');
const icon = btn.querySelector('i');
if (icon) {
btn.innerHTML = '<i class="fas fa-play"></i> ' + <?= json_encode(t('btn.play')) ?>;
}
});
this.classList.add('playing');
this.innerHTML = '<i class="fas fa-pause"></i> ' + <?= json_encode(t('tracks.playing')) ?>;
return;
}
}
// Clear other playing states
document.querySelectorAll('.play-track-btn').forEach(btn => {
btn.classList.remove('playing');
const icon = btn.querySelector('i');
if (icon) {
btn.innerHTML = '<i class="fas fa-play"></i> ' + <?= json_encode(t('btn.play')) ?>;
}
});
// Set this button as playing
this.classList.add('playing');
this.innerHTML = '<i class="fas fa-pause"></i> ' + <?= json_encode(t('tracks.playing')) ?>;
// Function to try playing
function tryPlay() {
if (typeof window.enhancedGlobalPlayer !== 'undefined' && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
try {
const success = window.enhancedGlobalPlayer.playTrack(finalAudioUrl, title, artist);
if (!success) {
throw new Error('Play failed');
}
return true;
} catch (error) {
console.error('Play error:', error);
return false;
}
} else if (typeof window.playTrack === 'function') {
try {
window.playTrack(null, finalAudioUrl, title, artist);
return true;
} catch (error) {
console.error('Play error:', error);
return false;
}
}
return false;
}
// Try to play immediately
if (!tryPlay()) {
// Wait for global player to load (retry up to 3 times)
let retries = 0;
const retryInterval = setInterval(() => {
retries++;
if (tryPlay() || retries >= 3) {
clearInterval(retryInterval);
if (retries >= 3 && !tryPlay()) {
alert(<?= json_encode(t('tracks.player_not_available')) ?>);
this.classList.remove('playing');
this.innerHTML = '<i class="fas fa-play"></i> ' + <?= json_encode(t('btn.play')) ?>;
}
}
}, 300);
}
});
});
}
// Initialize on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPlayButtons);
} else {
initPlayButtons();
}
// Re-initialize after AJAX loads (for pagination)
document.addEventListener('click', function(e) {
if (e.target.closest('.pagination-controls a, .pagination-controls .btn')) {
setTimeout(initPlayButtons, 500);
}
});
// Initialize edit buttons on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
initEditButtons();
});
} else {
initEditButtons();
}
function initEditButtons() {
// Edit button handlers
const editButtons = document.querySelectorAll('.edit-track-btn');
editButtons.forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault();
const trackId = this.getAttribute('data-track-id');
const title = this.getAttribute('data-track-title') || <?= json_encode(t('tracks.untitled_track')) ?>;
const description = this.getAttribute('data-track-description') || '';
const price = parseFloat(this.getAttribute('data-track-price')) || 0;
const isPublic = parseInt(this.getAttribute('data-track-public')) || 0;
// Call editTrack function if it exists
if (typeof window.editTrack === 'function') {
window.editTrack(trackId, title, description, price, isPublic);
} else {
console.error('editTrack function not found');
alert(<?= json_encode(t('tracks.edit_not_available')) ?>);
}
});
});
}
// Re-initialize edit buttons after pagination
document.addEventListener('click', function(e) {
if (e.target.closest('.pagination-controls a, .pagination-controls .btn')) {
setTimeout(initEditButtons, 500);
}
});
</script>