Add About and Status pages with improved navigation

- Added About page with detailed technical stack, AGPL license info, and community links
- Added Status page for both frameset and non-frameset modes
- Fixed all navigation links to use /asteroid/frameset as home (workaround for Radiance routing)
- Removed broken AJAX loadInFrame() navigation in frameset content pages
- Fixed logout buttons to redirect properly after logout
- Added spectrum analyzer support for live-stream-audio element ID
- Updated all Home links across the site to avoid Radiance welcome page
- Made About and Status pages consistent between frameset and non-frameset modes
- Added proper navigation to all pages with About, Status, and other links
This commit is contained in:
Glenn Thompson 2025-12-07 14:27:54 +03:00
parent d39b155df3
commit 3aa21c8278
16 changed files with 421 additions and 224 deletions

View File

@ -625,12 +625,33 @@
(format t "ERROR in profile-content: ~a~%" e)
(format nil "<html><body><h1>Error loading profile</h1><pre>~a</pre></body></html>" e))))
;; Status page (non-frameset mode)
(define-page status-page #@"/status" ()
"Status page"
(clip:process-to-string
(load-template "status")
:title " Asteroid Radio - Status"))
;; Status content frame (for frameset mode)
(define-page status-content #@"/status-content" ()
"Status page content (displayed in content frame)"
(clip:process-to-string
(load-template "status-content")
:title "📡 Asteroid Radio - Status"))
:title " Asteroid Radio - Status"))
;; About page
(define-page about-page #@"/about" ()
"About Asteroid Radio"
(clip:process-to-string
(load-template "about")
:title "About - Asteroid Radio"))
;; About content (for frameset mode)
(define-page about-content #@"/about-content" ()
"About content (displayed in content frame)"
(clip:process-to-string
(load-template "about-content")
:title "About - Asteroid Radio"))
;; Configure static file serving for other files
;; BUT exclude ParenScript-compiled JS files

View File

@ -45,7 +45,8 @@
;; Try current document first
(setf audio-element (or (ps:chain document (get-element-by-id "live-audio"))
(ps:chain document (get-element-by-id "persistent-audio"))))
(ps:chain document (get-element-by-id "persistent-audio"))
(ps:chain document (get-element-by-id "live-stream-audio"))))
;; If not found and we're in a frame, try parent frame (frameset mode)
(when (and (not audio-element)
@ -253,7 +254,8 @@
;; Try current document first
(setf audio-element (or (ps:chain document (get-element-by-id "live-audio"))
(ps:chain document (get-element-by-id "persistent-audio"))))
(ps:chain document (get-element-by-id "persistent-audio"))
(ps:chain document (get-element-by-id "live-stream-audio"))))
;; If not found and we're in a frame, try parent frame (frameset mode)
(when (and (not audio-element)

107
template/about-content.ctml Normal file
View File

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>About - Asteroid Radio</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
</head>
<body>
<div class="container">
<header>
<h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>ABOUT ASTEROID RADIO</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<nav class="nav">
<a href="/asteroid/content" target="_self">Home</a>
<a href="/asteroid/player-content" target="_self">Player</a>
<a href="/asteroid/about-content" target="_self">About</a>
<a href="/asteroid/status-content" target="_self">Status</a>
<a href="/asteroid/profile-content" target="_self" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin-content" target="_self" data-show-if-admin>Admin</a>
<a href="/asteroid/login-content" target="_self" data-show-if-logged-out>Login</a>
<a href="/asteroid/register-content" target="_self" data-show-if-logged-out>Register</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.reload());">Logout</a>
</nav>
</header>
<main style="max-width: 800px; margin: 0 auto; padding: 20px;">
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🎵 Asteroid Music for Hackers</h2>
<p style="line-height: 1.6;">
Asteroid Radio is a community-driven internet radio station born from the SystemCrafters community.
We celebrate the intersection of music, technology, and hacker culture—broadcasting for those who
appreciate both great code and great music.
</p>
<p style="line-height: 1.6;">
We met through a shared set of technical biases and a love for building systems from first principles.
Asteroid Radio embodies that ethos: <strong>music for hackers, built by hackers</strong>.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🛠️ Built with Common Lisp</h2>
<p style="line-height: 1.6;">
This entire platform is built using <strong>Common Lisp</strong>, demonstrating the power and elegance
of Lisp for modern web applications. We use:
</p>
<ul style="line-height: 1.8; margin-left: 20px;">
<li><strong><a href="https://codeberg.org/shirakumo/radiance" style="color: #00ff00;">Radiance</a></strong> - Web application framework</li>
<li><strong><a href="https://codeberg.org/shinmera/clip" style="color: #00ff00;">Clip</a></strong> - HTML5-compliant template engine</li>
<li><strong><a href="https://codeberg.org/shinmera/LASS" style="color: #00ff00;">LASS</a></strong> - Lisp Augmented Style Sheets</li>
<li><strong><a href="https://gitlab.common-lisp.net/parenscript/parenscript" style="color: #00ff00;">ParenScript</a></strong> - Lisp-to-JavaScript compiler</li>
<li><strong><a href="https://icecast.org/" style="color: #00ff00;">Icecast</a></strong> - Streaming media server</li>
<li><strong><a href="https://www.liquidsoap.info/" style="color: #00ff00;">Liquidsoap</a></strong> - Audio stream generation</li>
</ul>
<p style="line-height: 1.6;">
By building in Common Lisp, we're doubling down on our technical values and creating features
for "our people"—those who appreciate the elegance of Lisp and the power of understanding your tools deeply.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">📖 Open Source & AGPL Licensed</h2>
<p style="line-height: 1.6;">
Asteroid Radio is <strong>free and open source software</strong>, licensed under the
<strong><a href="https://www.gnu.org/licenses/agpl-3.0.en.html" style="color: #00ff00;">GNU Affero General Public License v3.0 (AGPL)</a></strong>.
</p>
<p style="line-height: 1.6;">
The source code is available at:
<a href="https://github.com/Fade/asteroid" style="color: #00ff00; font-weight: bold;">https://github.com/Fade/asteroid</a>
</p>
<p style="line-height: 1.6;">
We believe in transparency, collaboration, and the freedom to study, modify, and share the software we use.
The AGPL ensures that improvements to Asteroid Radio remain free and available to everyone.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🎧 Features</h2>
<ul style="line-height: 1.8; margin-left: 20px;">
<li><strong>Live Streaming</strong> - Multiple quality options (AAC, MP3)</li>
<li><strong>Persistent Player</strong> - Frameset mode for uninterrupted playback while browsing</li>
<li><strong>Spectrum Analyzer</strong> - Real-time audio visualization with customizable themes</li>
<li><strong>Track Library</strong> - Browse and search the music collection</li>
<li><strong>User Profiles</strong> - Track your listening history</li>
<li><strong>Admin Tools</strong> - Manage tracks, users, and playlists</li>
</ul>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🤝 Community</h2>
<p style="line-height: 1.6;">
We're part of the <strong><a href="https://systemcrafters.net/" style="color: #00ff00;">SystemCrafters</a></strong>
community—a group of developers, hackers, and enthusiasts who believe in building systems from first principles,
understanding our tools deeply, and sharing knowledge freely.
</p>
<p style="line-height: 1.6;">
Join us in celebrating the intersection of great music and great code!
</p>
</section>
</main>
</div>
</body>
</html>

102
template/about.ctml Normal file
View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>About - Asteroid Radio</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
</head>
<body>
<div class="container">
<header>
<h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>ABOUT ASTEROID RADIO</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<nav class="nav">
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
</nav>
</header>
<main style="max-width: 800px; margin: 0 auto; padding: 20px;">
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🎵 Asteroid Music for Hackers</h2>
<p style="line-height: 1.6;">
Asteroid Radio is a community-driven internet radio station born from the SystemCrafters community.
We celebrate the intersection of music, technology, and hacker culture—broadcasting for those who
appreciate both great code and great music.
</p>
<p style="line-height: 1.6;">
We met through a shared set of technical biases and a love for building systems from first principles.
Asteroid Radio embodies that ethos: <strong>music for hackers, built by hackers</strong>.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🛠️ Built with Common Lisp</h2>
<p style="line-height: 1.6;">
This entire platform is built using <strong>Common Lisp</strong>, demonstrating the power and elegance
of Lisp for modern web applications. We use:
</p>
<ul style="line-height: 1.8; margin-left: 20px;">
<li><strong><a href="https://codeberg.org/shirakumo/radiance" style="color: #00ff00;">Radiance</a></strong> - Web application framework</li>
<li><strong><a href="https://codeberg.org/shinmera/clip" style="color: #00ff00;">Clip</a></strong> - HTML5-compliant template engine</li>
<li><strong><a href="https://codeberg.org/shinmera/LASS" style="color: #00ff00;">LASS</a></strong> - Lisp Augmented Style Sheets</li>
<li><strong><a href="https://gitlab.common-lisp.net/parenscript/parenscript" style="color: #00ff00;">ParenScript</a></strong> - Lisp-to-JavaScript compiler</li>
<li><strong><a href="https://icecast.org/" style="color: #00ff00;">Icecast</a></strong> - Streaming media server</li>
<li><strong><a href="https://www.liquidsoap.info/" style="color: #00ff00;">Liquidsoap</a></strong> - Audio stream generation</li>
</ul>
<p style="line-height: 1.6;">
By building in Common Lisp, we're doubling down on our technical values and creating features
for "our people"—those who appreciate the elegance of Lisp and the power of understanding your tools deeply.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">📖 Open Source & AGPL Licensed</h2>
<p style="line-height: 1.6;">
Asteroid Radio is <strong>free and open source software</strong>, licensed under the
<strong><a href="https://www.gnu.org/licenses/agpl-3.0.en.html" style="color: #00ff00;">GNU Affero General Public License v3.0 (AGPL)</a></strong>.
</p>
<p style="line-height: 1.6;">
The source code is available at:
<a href="https://github.com/Fade/asteroid" style="color: #00ff00; font-weight: bold;">https://github.com/Fade/asteroid</a>
</p>
<p style="line-height: 1.6;">
We believe in transparency, collaboration, and the freedom to study, modify, and share the software we use.
The AGPL ensures that improvements to Asteroid Radio remain free and available to everyone.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🎧 Features</h2>
<ul style="line-height: 1.8; margin-left: 20px;">
<li><strong>Live Streaming</strong> - Multiple quality options (AAC, MP3)</li>
<li><strong>Persistent Player</strong> - Frameset mode for uninterrupted playback while browsing</li>
<li><strong>Spectrum Analyzer</strong> - Real-time audio visualization with customizable themes</li>
<li><strong>Track Library</strong> - Browse and search the music collection</li>
<li><strong>User Profiles</strong> - Track your listening history</li>
<li><strong>Admin Tools</strong> - Manage tracks, users, and playlists</li>
</ul>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🤝 Community</h2>
<p style="line-height: 1.6;">
We're part of the <strong><a href="https://systemcrafters.net/" style="color: #00ff00;">SystemCrafters</a></strong>
community—a group of developers, hackers, and enthusiasts who believe in building systems from first principles,
understanding our tools deeply, and sharing knowledge freely.
</p>
<p style="line-height: 1.6;">
Join us in celebrating the intersection of great music and great code!
</p>
</section>
</main>
</div>
</body>
</html>

View File

@ -12,11 +12,12 @@
<div class="container">
<h1>🎛️ ADMIN DASHBOARD</h1>
<div class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/profile">Profile</a>
<a href="/asteroid/admin/users">👥 Users</a>
<a href="/asteroid/logout" class="btn-logout">Logout</a>
<a href="/asteroid/logout" class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.href='/asteroid/frameset');">Logout</a>
</div>
<!-- System Status -->

View File

@ -4,6 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/api/asteroid/spectrum-analyzer.js"></script>
</head>
<body class="persistent-player-container">
<div class="persistent-player">
@ -31,6 +32,25 @@
<button onclick="disableFramesetMode()" class="persistent-disable-btn">
✕ Disable
</button>
<!-- Compact Spectrum Analyzer -->
<div style="display: inline-block; margin-left: 15px;">
<canvas id="spectrum-canvas" width="400" height="40" style="border: 1px solid #00ff00; background: #000; border-radius: 3px; vertical-align: middle;"></canvas>
<select id="spectrum-style-selector" onchange="setSpectrumStyle(this.value)" style="margin-left: 5px; padding: 2px; background: #000; color: #00ff00; border: 1px solid #00ff00; font-size: 0.8em; vertical-align: middle;">
<option value="bars">Bars</option>
<option value="wave">Wave</option>
<option value="dots">Dots</option>
</select>
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="margin-left: 3px; padding: 2px; background: #000; color: #00ff00; border: 1px solid #00ff00; font-size: 0.8em; vertical-align: middle;">
<option value="monotone">Monotone</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
<option value="amber">Amber</option>
<option value="rainbow">Rainbow</option>
</select>
</div>
</div>
<script>
@ -186,8 +206,8 @@
function disableFramesetMode() {
// Clear preference
localStorage.removeItem('useFrameset');
// Redirect parent window to regular view
window.parent.location.href = '/asteroid/';
// Redirect parent window to player page (non-frameset)
window.parent.location.href = '/asteroid/player';
}
</script>
</body>

View File

@ -11,7 +11,6 @@
<script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/asteroid/static/js/front-page.js"></script>
<script src="/asteroid/static/js/recently-played.js"></script>
<script src="/api/asteroid/spectrum-analyzer.js"></script>
<script>
// Handle logout without navigation
function handleLogout() {
@ -20,71 +19,15 @@
redirect: 'manual'
})
.then(() => {
// Reload the current page content to show logged-out state
fetch(window.location.href)
.then(response => response.text())
.then(html => {
document.open();
document.write(html);
document.close();
});
// Just reload the current page
window.location.reload();
})
.catch(error => {
console.error('Logout failed:', error);
window.location.reload();
});
}
// Load content via AJAX to prevent audio interruption
function loadInFrame(link) {
const url = link.href;
console.log('Loading via AJAX:', url);
// Clear all intervals to prevent old page scripts from running
const highestId = window.setTimeout(() => {}, 0);
for (let i = 0; i < highestId; i++) {
window.clearInterval(i);
window.clearTimeout(i);
}
fetch(url)
.then(response => response.text())
.then(html => {
// Replace entire document content
document.open();
document.write(html);
document.close();
// Execute scripts in the new content
const scripts = document.querySelectorAll('script');
scripts.forEach(oldScript => {
const newScript = document.createElement('script');
if (oldScript.src) {
newScript.src = oldScript.src;
} else {
newScript.textContent = oldScript.textContent;
}
oldScript.parentNode.replaceChild(newScript, oldScript);
});
// Re-initialize spectrum analyzer after navigation
if (window.initializeSpectrumAnalyzer) {
setTimeout(() => window.initializeSpectrumAnalyzer(), 100);
}
// Update browser history
if (window.history && window.history.pushState) {
window.history.pushState({}, '', url);
}
})
.catch(error => {
console.error('Failed to load content:', error);
// Fallback to normal navigation
return true;
});
// Prevent default navigation
return false;
}
</script>
</head>
<body>
@ -97,41 +40,15 @@
</h1>
<h3 class="page-subtitle">The Station at the End of Time</h3>
<!-- Spectrum Analyzer Canvas -->
<div style="text-align: center; margin: 15px 0;">
<canvas id="spectrum-canvas" width="800" height="100" style="max-width: 100%; border: 1px solid #00ff00; background: #000; border-radius: 4px;"></canvas>
<div style="margin-top: 8px; font-size: 0.9em;">
<label style="margin-right: 10px;">
Style:
<select id="spectrum-style-selector" onchange="setSpectrumStyle(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="bars">Bars</option>
<option value="wave">Wave</option>
<option value="dots">Dots</option>
</select>
</label>
<label>
Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
<option value="amber">Amber</option>
<option value="rainbow">Rainbow</option>
</select>
</label>
</div>
</div>
<nav class="nav">
<a href="/asteroid/content" target="content-frame" onclick="return loadInFrame(this)">Home</a>
<a href="/asteroid/player-content" target="content-frame" onclick="return loadInFrame(this)">Player</a>
<a href="/asteroid/status-content" target="content-frame" onclick="return loadInFrame(this)">Status</a>
<a href="/asteroid/profile-content" target="content-frame" data-show-if-logged-in onclick="return loadInFrame(this)">Profile</a>
<a href="/asteroid/admin-content" target="content-frame" data-show-if-admin onclick="return loadInFrame(this)">Admin</a>
<a href="/asteroid/login-content" target="content-frame" data-show-if-logged-out onclick="return loadInFrame(this)">Login</a>
<a href="/asteroid/register-content" target="content-frame" data-show-if-logged-out onclick="return loadInFrame(this)">Register</a>
<a href="/asteroid/content" target="_self">Home</a>
<a href="/asteroid/player-content" target="_self">Player</a>
<a href="/asteroid/about-content" target="_self">About</a>
<a href="/asteroid/status-content" target="_self">Status</a>
<a href="/asteroid/profile-content" target="_self" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin-content" target="_self" data-show-if-admin>Admin</a>
<a href="/asteroid/login-content" target="_self" data-show-if-logged-out>Login</a>
<a href="/asteroid/register-content" target="_self" data-show-if-logged-out>Register</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="handleLogout(); return false;">Logout</a>
</nav>
</header>

View File

@ -51,8 +51,9 @@
</div>
<nav class="nav">
<a href="/asteroid/">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
<a href="/asteroid/profile" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin" data-show-if-admin>Admin</a>

View File

@ -17,8 +17,9 @@
<span>ASTEROID RADIO - LOGIN</span>
</h1>
<nav class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
<a href="/asteroid/register">Register</a>
</nav>

View File

@ -6,7 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/api/asteroid/spectrum-analyzer.js"></script>
<script>
// Simple Now Playing updater
function updateNowPlaying() {
@ -116,40 +115,14 @@
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<!-- Spectrum Analyzer Canvas -->
<div style="text-align: center; margin: 15px 0;">
<canvas id="spectrum-canvas" width="800" height="100" style="max-width: 100%; border: 1px solid #00ff00; background: #000; border-radius: 4px;"></canvas>
<div style="margin-top: 8px; font-size: 0.9em;">
<label style="margin-right: 10px;">
Style:
<select id="spectrum-style-selector" onchange="setSpectrumStyle(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="bars">Bars</option>
<option value="wave">Wave</option>
<option value="dots">Dots</option>
</select>
</label>
<label>
Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
<option value="amber">Amber</option>
<option value="rainbow">Rainbow</option>
</select>
</label>
</div>
</div>
<div class="nav">
<nav class="nav">
<a href="/asteroid/content" target="content-frame" onclick="return loadInFrame(this)">Home</a>
<a href="/asteroid/profile-content" target="content-frame" data-show-if-logged-in onclick="return loadInFrame(this)">Profile</a>
<a href="/asteroid/admin-content" target="content-frame" data-show-if-admin onclick="return loadInFrame(this)">Admin</a>
<a href="/asteroid/login-content" target="content-frame" data-show-if-logged-out onclick="return loadInFrame(this)">Login</a>
<a href="/asteroid/register-content" target="content-frame" data-show-if-logged-out onclick="return loadInFrame(this)">Register</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="handleLogout(); return false;">Logout</a>
</nav>
</div>
<!-- Live Stream Section - Note about persistent player -->

View File

@ -9,7 +9,9 @@
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/asteroid/static/js/front-page.js"></script>
<script src="/asteroid/static/js/player.js"></script>
<script src="/api/asteroid/spectrum-analyzer.js"></script>
</head>
<body>
<div class="container">
@ -19,8 +21,11 @@
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<div class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/profile">Profile</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
<a href="/asteroid/profile" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin" data-show-if-admin>Admin</a>
<a href="/asteroid/login" data-show-if-logged-out>Login</a>
<a href="/asteroid/register" data-show-if-logged-out>Register</a>
@ -45,10 +50,38 @@
</select>
</div>
<audio id="live-stream-audio" controls style="width: 100%; margin-top: 20px;">
<audio id="live-stream-audio" controls crossorigin="anonymous" style="width: 100%; margin-top: 20px;">
<source id="live-stream-source" lquery="(attr :src default-stream-url)" type="audio/aac">
Your browser does not support the audio element.
</audio>
<!-- Spectrum Analyzer -->
<div style="text-align: center; margin: 20px 0;">
<canvas id="spectrum-canvas" width="800" height="100" style="max-width: 100%; border: 1px solid #00ff00; background: #000; border-radius: 4px;"></canvas>
<div style="margin-top: 8px; font-size: 0.9em;">
<label style="margin-right: 10px;">
Style:
<select id="spectrum-style-selector" onchange="setSpectrumStyle(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="bars">Bars</option>
<option value="wave">Wave</option>
<option value="dots">Dots</option>
</select>
</label>
<label>
Theme:
<select id="spectrum-theme-selector" onchange="setSpectrumTheme(this.value)" style="padding: 3px; background: #000; color: #00ff00; border: 1px solid #00ff00;">
<option value="monotone">Monotone</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
<option value="amber">Amber</option>
<option value="rainbow">Rainbow</option>
</select>
</label>
</div>
</div>
<p><em>Listen to the live Asteroid Radio stream</em></p>
</div>
</div>

View File

@ -12,10 +12,11 @@
<div class="container">
<h1>👤 USER PROFILE</h1>
<div class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/admin" data-show-if-admin>Admin</a>
<a href="/asteroid/logout" class="btn-logout">Logout</a>
<a href="/asteroid/logout" class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.href='/asteroid/frameset');">Logout</a>
</div>
<!-- User Profile Header -->

View File

@ -17,8 +17,9 @@
<span>ASTEROID RADIO - REGISTER</span>
</h1>
<nav class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
<a href="/asteroid/login">Login</a>
</nav>

View File

@ -6,94 +6,52 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
<script>
// Handle logout without navigation
function handleLogout() {
fetch('/asteroid/logout', {
method: 'GET',
redirect: 'manual'
})
.then(() => {
// Reload the current page content to show logged-out state
fetch(window.location.href)
.then(response => response.text())
.then(html => {
document.open();
document.write(html);
document.close();
});
})
.catch(error => {
console.error('Logout failed:', error);
});
}
// Load content via AJAX to prevent audio interruption
function loadInFrame(link) {
const url = link.href;
console.log('Loading via AJAX:', url);
// Clear all intervals to prevent old page scripts from running
const highestId = window.setTimeout(() => {}, 0);
for (let i = 0; i < highestId; i++) {
window.clearInterval(i);
window.clearTimeout(i);
}
fetch(url)
.then(response => response.text())
.then(html => {
document.open();
document.write(html);
document.close();
// Execute scripts in the new content
const scripts = document.querySelectorAll('script');
scripts.forEach(oldScript => {
const newScript = document.createElement('script');
if (oldScript.src) {
newScript.src = oldScript.src;
} else {
newScript.textContent = oldScript.textContent;
}
oldScript.parentNode.replaceChild(newScript, oldScript);
});
// Re-initialize spectrum analyzer after navigation
if (window.initializeSpectrumAnalyzer) {
setTimeout(() => window.initializeSpectrumAnalyzer(), 100);
}
if (window.history && window.history.pushState) {
window.history.pushState({}, '', url);
}
})
.catch(error => {
console.error('Failed to load content:', error);
return true;
});
return false;
}
</script>
</head>
<body>
<div class="container">
<h1>📡 SYSTEM STATUS</h1>
<div class="nav">
<a href="/asteroid/content" target="content-frame" onclick="return loadInFrame(this)">Home</a>
<a href="/asteroid/player-content" target="content-frame" onclick="return loadInFrame(this)">Player</a>
<a href="/asteroid/profile-content" target="content-frame" data-show-if-logged-in onclick="return loadInFrame(this)">Profile</a>
<a href="/asteroid/admin-content" target="content-frame" data-show-if-admin onclick="return loadInFrame(this)">Admin</a>
<a href="/asteroid/login-content" target="content-frame" data-show-if-logged-out onclick="return loadInFrame(this)">Login</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="handleLogout(); return false;">Logout</a>
</div>
<header>
<h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>📡 SYSTEM STATUS</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<nav class="nav">
<a href="/asteroid/content" target="_self">Home</a>
<a href="/asteroid/player-content" target="_self">Player</a>
<a href="/asteroid/about-content" target="_self">About</a>
<a href="/asteroid/status-content" target="_self">Status</a>
<a href="/asteroid/profile-content" target="_self" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin-content" target="_self" data-show-if-admin>Admin</a>
<a href="/asteroid/login-content" target="_self" data-show-if-logged-out>Login</a>
<a href="/asteroid/register-content" target="_self" data-show-if-logged-out>Register</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.reload());">Logout</a>
</nav>
</header>
<div class="admin-section">
<h2>Server Status</h2>
<p>Status page coming soon...</p>
<p>For now, administrators can view detailed status information in the <a href="/asteroid/admin-content" target="content-frame" onclick="return loadInFrame(this)">Admin Dashboard</a>.</p>
</div>
<main style="max-width: 800px; margin: 0 auto; padding: 20px;">
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🟢 Server Status</h2>
<p style="line-height: 1.6;">
Asteroid Radio is currently online and broadcasting.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">📊 Stream Information</h2>
<ul style="line-height: 1.8;">
<li><strong>Status:</strong> 🟢 Live</li>
<li><strong>Formats:</strong> AAC 96kbps, MP3 128kbps, MP3 64kbps</li>
<li><strong>Server:</strong> Icecast</li>
</ul>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;"> Additional Information</h2>
<p style="line-height: 1.6;">
For detailed system status and administration, please visit the <a href="/asteroid/admin" style="color: #00ff00;" data-show-if-admin>Admin Dashboard</a>.
</p>
</section>
</main>
</div>
</body>
</html>

57
template/status.ctml Normal file
View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Asteroid Radio - Status</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script>
</head>
<body>
<div class="container">
<header>
<h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>📡 SYSTEM STATUS</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<nav class="nav">
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/status">Status</a>
<a href="/asteroid/profile" data-show-if-logged-in>Profile</a>
<a href="/asteroid/admin" data-show-if-admin>Admin</a>
<a href="/asteroid/login" data-show-if-logged-out>Login</a>
<a href="/asteroid/register" data-show-if-logged-out>Register</a>
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.href='/asteroid/frameset');">Logout</a>
</nav>
</header>
<main style="max-width: 800px; margin: 0 auto; padding: 20px;">
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">🟢 Server Status</h2>
<p style="line-height: 1.6;">
Asteroid Radio is currently online and broadcasting.
</p>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;">📊 Stream Information</h2>
<ul style="line-height: 1.8;">
<li><strong>Status:</strong> 🟢 Live</li>
<li><strong>Formats:</strong> AAC 96kbps, MP3 128kbps, MP3 64kbps</li>
<li><strong>Server:</strong> Icecast</li>
</ul>
</section>
<section style="margin-bottom: 30px;">
<h2 style="color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px;"> Additional Information</h2>
<p style="line-height: 1.6;">
For detailed system status and administration, please visit the <a href="/asteroid/admin" style="color: #00ff00;" data-show-if-admin>Admin Dashboard</a>.
</p>
</section>
</main>
</div>
</body>
</html>

View File

@ -11,9 +11,11 @@
<div class="container">
<h1>👥 USER MANAGEMENT</h1>
<div class="nav">
<a href="/asteroid">Home</a>
<a href="/asteroid/frameset">Home</a>
<a href="/asteroid/player">Player</a>
<a href="/asteroid/about">About</a>
<a href="/asteroid/admin">Admin</a>
<a href="/asteroid/logout" class="btn-logout">Logout</a>
<a href="/asteroid/logout" class="btn-logout" onclick="event.preventDefault(); fetch('/asteroid/logout').then(() => window.location.href='/asteroid/frameset');">Logout</a>
</div>
<!-- User Statistics -->