feat: added web server with currently playing song

This commit is contained in:
Felipe M 2025-05-13 12:27:01 +02:00
parent 1a4986f294
commit 7f16452a99
Signed by: fmartingr
GPG key ID: CCFBC5637D4000A8
12 changed files with 847 additions and 9 deletions

125
pkg/web/static/app.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
I can't create or include binary content like PNG files directly in my response, as this would require binary data that can't be represented as text.
For the default-cover.png file, you'll need to:
1. Generate a simple placeholder image using an image editor
2. Save it as "default-cover.png" in the "discord-jukebox-bot/pkg/web/static/" directory
Alternatively, you could:
1. Use a base64-encoded data URL in your JavaScript to represent a default image
2. Update the app.js file to include a fallback image directly in the code
Would you like me to update the JavaScript to include a base64-encoded default image instead? This would eliminate the need for a separate PNG file.

54
pkg/web/static/index.html Normal file
View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Discord Jukebox Status</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<div class="container">
<header>
<h1>Discord Jukebox</h1>
<div id="status-indicator" class="status-indicator">
<span class="status-dot"></span>
<span id="status-text">Checking status...</span>
</div>
</header>
<div id="now-playing" class="hidden">
<h2>Now Playing</h2>
<div class="song-info">
<div id="cover-art-container">
<img id="cover-art" src="/static/default-cover.png" alt="Album Cover">
</div>
<div class="song-details">
<h3 id="song-title">Loading...</h3>
<p><strong>Artist:</strong> <span id="song-artist">--</span></p>
<p><strong>Album:</strong> <span id="song-album">--</span></p>
<div class="additional-info">
<p><strong>Duration:</strong> <span id="song-duration">--</span></p>
<p><strong>Genre:</strong> <span id="song-genre">--</span></p>
<p><strong>Year:</strong> <span id="song-year">--</span></p>
</div>
</div>
</div>
</div>
<div id="not-playing" class="hidden">
<div class="message">
<h2>No Song Playing</h2>
<p>The jukebox is currently inactive.</p>
<p>Use <code>/jukebox play</code> in Discord to start the music!</p>
</div>
</div>
<footer>
<p>Last updated: <span id="last-update">never</span></p>
<p class="bot-info">Discord Jukebox Bot</p>
</footer>
</div>
<script src="/static/app.js"></script>
</body>
</html>

193
pkg/web/static/styles.css Normal file
View file

@ -0,0 +1,193 @@
/* Main styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
min-height: calc(100vh - 40px);
margin-top: 20px;
margin-bottom: 20px;
display: flex;
flex-direction: column;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
flex-wrap: wrap;
}
h1 {
font-size: 28px;
color: #5865F2; /* Discord blue */
}
.status-indicator {
display: flex;
align-items: center;
font-size: 14px;
color: #666;
}
.status-dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: gray;
margin-right: 6px;
}
.status-dot.online {
background-color: #43b581; /* Discord green */
box-shadow: 0 0 5px rgba(67, 181, 129, 0.5);
}
.status-dot.offline {
background-color: #f04747; /* Discord red */
}
/* Now Playing Section */
#now-playing {
padding: 20px;
background-color: #f9f9f9;
border-radius: 8px;
margin-bottom: 20px;
flex-grow: 1;
}
h2 {
font-size: 22px;
margin-bottom: 15px;
color: #5865F2;
}
.song-info {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
#cover-art-container {
flex: 0 0 200px;
}
#cover-art {
width: 100%;
max-width: 200px;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.song-details {
flex: 1;
min-width: 250px;
}
h3 {
font-size: 20px;
margin-bottom: 10px;
color: #333;
}
.song-details p {
margin-bottom: 8px;
}
.additional-info {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 15px;
border-top: 1px solid #eee;
padding-top: 15px;
}
.additional-info p {
margin-right: 15px;
}
/* Not Playing Section */
#not-playing {
text-align: center;
padding: 40px 20px;
background-color: #f9f9f9;
border-radius: 8px;
margin-bottom: 20px;
flex-grow: 1;
}
.message {
max-width: 400px;
margin: 0 auto;
}
code {
font-family: monospace;
background-color: #eee;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.9em;
}
footer {
margin-top: auto;
padding-top: 20px;
border-top: 1px solid #eee;
color: #888;
font-size: 14px;
text-align: center;
}
.bot-info {
margin-top: 5px;
font-size: 12px;
}
/* Helper classes */
.hidden {
display: none;
}
/* Responsive adjustments */
@media (max-width: 600px) {
header {
flex-direction: column;
align-items: flex-start;
}
.status-indicator {
margin-top: 10px;
}
#cover-art-container {
flex: 0 0 100%;
text-align: center;
margin-bottom: 15px;
}
#cover-art {
max-width: 150px;
}
}