![]() 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/radio/dashboard/ |
<?php
/**
* Live Stream Management Dashboard
*/
session_start();
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../includes/functions.php';
// Check if station is logged in
if (!isset($_SESSION['radio_station_id'])) {
header('Location: /radio/login.php');
exit;
}
$station_id = $_SESSION['radio_station_id'];
$station = getRadioStation($station_id);
if (!$station) {
session_destroy();
header('Location: /radio/login.php');
exit;
}
$pdo = getDBConnection();
// Get stream status
$stmt = $pdo->prepare("
SELECT rs.*,
(SELECT COUNT(*) FROM radio_listeners WHERE stream_id = rs.id AND disconnected_at IS NULL) as current_listeners
FROM radio_streams rs
WHERE rs.station_id = ?
ORDER BY rs.started_at DESC
LIMIT 1
");
$stmt->execute([$station_id]);
$stream = $stmt->fetch();
// Get current track
$now_playing = null;
if ($stream) {
$stmt = $pdo->prepare("
SELECT np.*, mt.title, mt.audio_url, mt.image_url, mt.duration,
u.name as artist_name
FROM radio_now_playing np
JOIN music_tracks mt ON np.track_id = mt.id
LEFT JOIN users u ON mt.user_id = u.id
WHERE np.stream_id = ? AND np.ended_at IS NULL
ORDER BY np.started_at DESC
LIMIT 1
");
$stmt->execute([$stream['id']]);
$now_playing = $stmt->fetch();
}
// Get queue
$queue = [];
if ($stream) {
$stmt = $pdo->prepare("
SELECT q.*, mt.title, mt.audio_url, mt.image_url,
u.name as artist_name
FROM radio_stream_queue q
JOIN music_tracks mt ON q.track_id = mt.id
LEFT JOIN users u ON mt.user_id = u.id
WHERE q.stream_id = ? AND q.played_at IS NULL
ORDER BY q.priority DESC, q.vote_count DESC, q.queued_at ASC
LIMIT 20
");
$stmt->execute([$stream['id']]);
$queue = $stmt->fetchAll();
}
$page_title = 'Live Stream Management - ' . htmlspecialchars($station['station_name']);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $page_title ?></title>
<link rel="stylesheet" href="/assets/css/main.css">
<style>
.live-stream-dashboard {
max-width: 1400px;
margin: 2rem auto;
padding: 2rem;
}
.stream-controls {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 2rem;
}
.stream-status {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1.5rem;
}
.status-indicator {
width: 16px;
height: 16px;
border-radius: 50%;
background: #ef4444;
animation: pulse 2s ease-in-out infinite;
}
.status-indicator.offline {
background: #9ca3af;
animation: none;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.control-buttons {
display: flex;
gap: 1rem;
margin-top: 1.5rem;
}
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover {
background: #5568d3;
}
.btn-danger {
background: #ef4444;
color: white;
}
.btn-danger:hover {
background: #dc2626;
}
.btn-secondary {
background: #6b7280;
color: white;
}
.now-playing-section {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 2rem;
}
.now-playing-card {
display: flex;
align-items: center;
gap: 2rem;
}
.track-artwork {
width: 150px;
height: 150px;
border-radius: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
overflow: hidden;
}
.track-artwork img {
width: 100%;
height: 100%;
object-fit: cover;
}
.queue-section {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.queue-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
border-bottom: 1px solid #eee;
}
.queue-item:last-child {
border-bottom: none;
}
.queue-item-artwork {
width: 60px;
height: 60px;
border-radius: 8px;
background: #f3f4f6;
overflow: hidden;
}
.queue-item-artwork img {
width: 100%;
height: 100%;
object-fit: cover;
}
.queue-item-info {
flex: 1;
}
.queue-item-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.queue-item-artist {
font-size: 0.9rem;
color: #6b7280;
}
.queue-item-votes {
color: #667eea;
font-weight: 600;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
}
.form-group input {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 1rem;
}
</style>
</head>
<body>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<div class="live-stream-dashboard">
<div style="margin-bottom: 2rem;">
<a href="/radio/dashboard/" style="color: #667eea; text-decoration: none;">← Back to Dashboard</a>
</div>
<h1 style="margin-bottom: 2rem;">Live Stream Management</h1>
<div class="stream-controls">
<div class="stream-status">
<div class="status-indicator <?= ($stream && $stream['is_live']) ? '' : 'offline' ?>"></div>
<div>
<h2 style="margin: 0;">
<?= ($stream && $stream['is_live']) ? 'Stream is LIVE' : 'Stream is OFFLINE' ?>
</h2>
<?php if ($stream && $stream['is_live']): ?>
<p style="margin: 0.5rem 0 0 0; color: #6b7280;">
<?= number_format($stream['current_listeners']) ?> listeners
<?php if ($stream['started_at']): ?>
• Started <?= date('M j, Y g:i A', strtotime($stream['started_at'])) ?>
<?php endif; ?>
</p>
<?php endif; ?>
</div>
</div>
<?php if (!$stream || !$stream['is_live']): ?>
<form id="start-stream-form">
<div class="form-group">
<label>Stream Name</label>
<input type="text" name="stream_name" value="<?= htmlspecialchars($station['station_name']) ?> Live Stream" required>
</div>
<div class="form-group">
<label>Stream URL (optional)</label>
<input type="url" name="stream_url" placeholder="https://your-stream-server.com/stream">
</div>
<div class="control-buttons">
<button type="submit" class="btn btn-primary">Start Stream</button>
</div>
</form>
<?php else: ?>
<div class="control-buttons">
<button onclick="stopStream()" class="btn btn-danger">Stop Stream</button>
<a href="/radio/live.php?station=<?= $station_id ?>" target="_blank" class="btn btn-secondary">View Live Player</a>
</div>
<?php endif; ?>
</div>
<?php if ($stream && $stream['is_live'] && $now_playing): ?>
<div class="now-playing-section">
<h2>Now Playing</h2>
<div class="now-playing-card">
<div class="track-artwork">
<?php if ($now_playing['image_url']): ?>
<img src="<?= htmlspecialchars($now_playing['image_url']) ?>" alt="<?= htmlspecialchars($now_playing['title']) ?>">
<?php else: ?>
<div style="display: flex; align-items: center; justify-content: center; height: 100%; font-size: 3rem;">🎵</div>
<?php endif; ?>
</div>
<div style="flex: 1;">
<h3 style="margin: 0 0 0.5rem 0;"><?= htmlspecialchars($now_playing['title']) ?></h3>
<p style="margin: 0; color: #6b7280;"><?= htmlspecialchars($now_playing['artist_name'] ?? 'Unknown Artist') ?></p>
<p style="margin: 0.5rem 0 0 0; color: #6b7280; font-size: 0.9rem;">
Started <?= date('g:i A', strtotime($now_playing['started_at'])) ?>
</p>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($stream && $stream['is_live'] && count($queue) > 0): ?>
<div class="queue-section">
<h2>Queue (<?= count($queue) ?> tracks)</h2>
<?php foreach ($queue as $item): ?>
<div class="queue-item">
<div class="queue-item-artwork">
<?php if ($item['image_url']): ?>
<img src="<?= htmlspecialchars($item['image_url']) ?>" alt="<?= htmlspecialchars($item['title']) ?>">
<?php else: ?>
<div style="display: flex; align-items: center; justify-content: center; height: 100%;">🎵</div>
<?php endif; ?>
</div>
<div class="queue-item-info">
<div class="queue-item-title"><?= htmlspecialchars($item['title']) ?></div>
<div class="queue-item-artist"><?= htmlspecialchars($item['artist_name'] ?? 'Unknown Artist') ?></div>
</div>
<div class="queue-item-votes"><?= $item['vote_count'] ?> votes</div>
<button onclick="playTrack(<?= $item['track_id'] ?>)" class="btn btn-primary" style="padding: 0.5rem 1rem;">Play Now</button>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<script>
const apiKey = '<?= htmlspecialchars($station['api_key'] ?? '') ?>';
const apiSecret = '<?= htmlspecialchars($station['api_secret'] ?? '') ?>';
// Start stream
document.getElementById('start-stream-form')?.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
try {
const response = await fetch('/radio/api/v1/stream/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
location.reload();
} else {
alert(result.error || 'Failed to start stream');
}
} catch (error) {
console.error('Error:', error);
alert('Failed to start stream');
}
});
// Stop stream
async function stopStream() {
if (!confirm('Are you sure you want to stop the stream?')) return;
try {
const response = await fetch('/radio/api/v1/stream/stop', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
}
});
const result = await response.json();
if (result.success) {
location.reload();
} else {
alert(result.error || 'Failed to stop stream');
}
} catch (error) {
console.error('Error:', error);
alert('Failed to stop stream');
}
}
// Play track now
async function playTrack(trackId) {
try {
const response = await fetch('/radio/api/v1/stream/now_playing', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
},
body: JSON.stringify({ track_id: trackId })
});
const result = await response.json();
if (result.success) {
location.reload();
} else {
alert(result.error || 'Failed to play track');
}
} catch (error) {
console.error('Error:', error);
alert('Failed to play track');
}
}
</script>
<?php include __DIR__ . '/../../includes/footer.php'; ?>
</body>
</html>