![]() 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/ |
<?php
session_start();
require_once 'config/database.php';
header('Content-Type: application/json');
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
exit;
}
$user_id = $_SESSION['user_id'];
$input = json_decode(file_get_contents('php://input'), true);
$action = $input['action'] ?? '';
// Get database connection
$pdo = getDBConnection();
if (!$pdo) {
echo json_encode(['success' => false, 'message' => 'Database connection failed']);
exit;
}
try {
switch ($action) {
case 'duplicate':
$track_id = $input['track_id'] ?? 0;
// Verify track ownership
$stmt = $pdo->prepare("SELECT * FROM music_tracks WHERE id = ? AND user_id = ?");
$stmt->execute([$track_id, $user_id]);
$original_track = $stmt->fetch();
if (!$original_track) {
echo json_encode(['success' => false, 'message' => 'Track not found or access denied']);
break;
}
// Create duplicate track
$stmt = $pdo->prepare("
INSERT INTO music_tracks (
user_id, title, prompt, model_name, status, price,
duration, metadata, is_public, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
");
$duplicate_title = $original_track['title'] . ' (Copy)';
$stmt->execute([
$user_id,
$duplicate_title,
$original_track['prompt'],
$original_track['model_name'],
'pending', // New duplicate starts as pending
$original_track['price'],
$original_track['duration'],
$original_track['metadata'],
0 // Start as private
]);
echo json_encode([
'success' => true,
'message' => 'Track duplicated successfully',
'new_track_id' => $pdo->lastInsertId()
]);
break;
case 'toggle_visibility':
$track_id = $input['track_id'] ?? 0;
$visibility = $input['visibility'] ?? 0;
error_log("Toggle visibility request: track_id=$track_id, visibility=$visibility, user_id=$user_id");
// Verify track ownership and get current state
$stmt = $pdo->prepare("SELECT id, is_public, published_at FROM music_tracks WHERE id = ? AND user_id = ?");
$stmt->execute([$track_id, $user_id]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
error_log("Track not found or access denied: track_id=$track_id, user_id=$user_id");
echo json_encode(['success' => false, 'message' => 'Track not found or access denied']);
break;
}
// Determine if we need to set published_at (first time going public)
$set_published_at = false;
if ($visibility == 1 && $track['is_public'] == 0 && empty($track['published_at'])) {
$set_published_at = true;
}
// Update visibility
if ($set_published_at) {
// First time publishing - set permanent published_at timestamp
$stmt = $pdo->prepare("UPDATE music_tracks SET is_public = ?, published_at = NOW(), updated_at = NOW() WHERE id = ? AND user_id = ?");
$result = $stmt->execute([$visibility, $track_id, $user_id]);
} else {
// Not first publish - don't touch published_at
$stmt = $pdo->prepare("UPDATE music_tracks SET is_public = ?, updated_at = NOW() WHERE id = ? AND user_id = ?");
$result = $stmt->execute([$visibility, $track_id, $user_id]);
}
if (!$result) {
error_log("Failed to update track visibility: " . implode(", ", $stmt->errorInfo()));
echo json_encode(['success' => false, 'message' => 'Database update failed']);
break;
}
$status = $visibility ? 'public' : 'private';
error_log("Successfully updated track visibility: track_id=$track_id, new_status=$status, published_at_set=" . ($set_published_at ? 'yes' : 'no'));
echo json_encode([
'success' => true,
'message' => "Track is now $status"
]);
break;
case 'delete':
$track_id = $input['track_id'] ?? 0;
// Check if user is admin
if (!isset($_SESSION['is_admin']) || !$_SESSION['is_admin']) {
echo json_encode(['success' => false, 'message' => 'Admin access required to delete tracks']);
break;
}
// Verify track exists (admins can delete any track)
$stmt = $pdo->prepare("SELECT audio_url, user_id FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
$track = $stmt->fetch();
if (!$track) {
echo json_encode(['success' => false, 'message' => 'Track not found']);
break;
}
// Delete related data first (foreign key constraints)
$pdo->prepare("DELETE FROM track_likes WHERE track_id = ?")->execute([$track_id]);
$pdo->prepare("DELETE FROM track_comments WHERE track_id = ?")->execute([$track_id]);
$pdo->prepare("DELETE FROM track_plays WHERE track_id = ?")->execute([$track_id]);
$pdo->prepare("DELETE FROM track_views WHERE track_id = ?")->execute([$track_id]);
$pdo->prepare("DELETE FROM sales WHERE track_id = ?")->execute([$track_id]);
// Delete the track (admins can delete any track)
$stmt = $pdo->prepare("DELETE FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
// Optionally delete audio file (be careful with this)
if (!empty($track['audio_url']) && file_exists($track['audio_url'])) {
// unlink($track['audio_url']); // Uncomment if you want to delete files
}
echo json_encode([
'success' => true,
'message' => 'Track deleted successfully by admin'
]);
break;
case 'bulk_action':
$track_ids = $input['track_ids'] ?? [];
$bulk_action = $input['bulk_action'] ?? '';
if (empty($track_ids) || !is_array($track_ids)) {
echo json_encode(['success' => false, 'message' => 'No tracks selected']);
break;
}
// Verify all tracks belong to user
$placeholders = str_repeat('?,', count($track_ids) - 1) . '?';
$stmt = $pdo->prepare("SELECT COUNT(*) FROM music_tracks WHERE id IN ($placeholders) AND user_id = ?");
$params = array_merge($track_ids, [$user_id]);
$stmt->execute($params);
if ($stmt->fetchColumn() != count($track_ids)) {
echo json_encode(['success' => false, 'message' => 'Some tracks not found or access denied']);
break;
}
switch ($bulk_action) {
case 'make_public':
// First, set published_at for tracks that don't have it yet (first time going public)
$stmt = $pdo->prepare("UPDATE music_tracks SET is_public = 1, published_at = NOW(), updated_at = NOW() WHERE id IN ($placeholders) AND user_id = ? AND (is_public = 0 OR published_at IS NULL)");
$stmt->execute($params);
// Then, update tracks that are already public but might need is_public set
$stmt = $pdo->prepare("UPDATE music_tracks SET is_public = 1, updated_at = NOW() WHERE id IN ($placeholders) AND user_id = ? AND is_public = 0 AND published_at IS NOT NULL");
$stmt->execute($params);
echo json_encode(['success' => true, 'message' => 'Tracks made public']);
break;
case 'make_private':
$stmt = $pdo->prepare("UPDATE music_tracks SET is_public = 0 WHERE id IN ($placeholders) AND user_id = ?");
$stmt->execute($params);
echo json_encode(['success' => true, 'message' => 'Tracks made private']);
break;
case 'update_price':
$new_price = floatval($input['new_price'] ?? 0);
$stmt = $pdo->prepare("UPDATE music_tracks SET price = ? WHERE id IN ($placeholders) AND user_id = ?");
$params = array_merge([$new_price], $track_ids, [$user_id]);
$stmt->execute($params);
echo json_encode(['success' => true, 'message' => "Price updated to $" . number_format($new_price, 2)]);
break;
default:
echo json_encode(['success' => false, 'message' => 'Invalid bulk action']);
}
break;
case 'update_metadata':
$track_id = $input['track_id'] ?? 0;
$metadata = $input['metadata'] ?? [];
// Verify track ownership
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ? AND user_id = ?");
$stmt->execute([$track_id, $user_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'Track not found or access denied']);
break;
}
// Update metadata
$stmt = $pdo->prepare("UPDATE music_tracks SET metadata = ? WHERE id = ? AND user_id = ?");
$stmt->execute([json_encode($metadata), $track_id, $user_id]);
echo json_encode([
'success' => true,
'message' => 'Track metadata updated successfully'
]);
break;
case 'generate_share_token':
require_once __DIR__ . '/utils/share_token.php';
$track_id = $input['track_id'] ?? 0;
$expires_in = $input['expires_in'] ?? SHARE_TOKEN_DEFAULT_EXPIRY; // Default 1 hour
// Verify track ownership
$stmt = $pdo->prepare("SELECT id, is_public FROM music_tracks WHERE id = ? AND user_id = ?");
$stmt->execute([$track_id, $user_id]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
echo json_encode(['success' => false, 'message' => 'Track not found or access denied']);
break;
}
// If track is public, return regular URL (no token needed)
if ($track['is_public'] == 1) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'soundstudiopro.com';
$baseUrl = $protocol . '://' . $host;
$share_url = $baseUrl . '/track.php?id=' . $track_id;
echo json_encode([
'success' => true,
'share_url' => $share_url,
'is_public' => 1,
'message' => 'Track is public - using regular link'
]);
break;
}
// Generate or retrieve share token for private tracks
$tokenData = getOrCreateShareToken($track_id, $user_id, $expires_in);
if (!$tokenData) {
echo json_encode(['success' => false, 'message' => 'Failed to generate share token']);
break;
}
// Generate shareable URL
$share_url = getShareableUrl($track_id, $tokenData['token']);
echo json_encode([
'success' => true,
'share_token' => $tokenData['token'],
'share_url' => $share_url,
'expires' => $tokenData['expires'],
'expires_in' => $expires_in,
'is_public' => 0
]);
break;
case 'revoke_share_token':
require_once __DIR__ . '/utils/share_token.php';
$track_id = $input['track_id'] ?? 0;
// Verify track ownership
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ? AND user_id = ?");
$stmt->execute([$track_id, $user_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'Track not found or access denied']);
break;
}
// Revoke share token
$result = revokeShareToken($track_id, $user_id);
echo json_encode([
'success' => $result,
'message' => $result ? 'Share link revoked successfully' : 'Failed to revoke share link'
]);
break;
default:
echo json_encode(['success' => false, 'message' => 'Invalid action']);
}
} catch (Exception $e) {
error_log("Track management API error: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => 'An error occurred while processing your request'
]);
}
?>