feat: show last played songs in web ui
This commit is contained in:
parent
7f16452a99
commit
bcc1bce743
6 changed files with 206 additions and 7 deletions
|
@ -149,9 +149,10 @@ func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// StatusResponse contains the jukebox status
|
||||
type StatusResponse struct {
|
||||
IsPlaying bool `json:"isPlaying"`
|
||||
CurrentSong *subsonic.Song `json:"currentSong"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
IsPlaying bool `json:"isPlaying"`
|
||||
CurrentSong *subsonic.Song `json:"currentSong"`
|
||||
SongHistory []*subsonic.Song `json:"songHistory"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
}
|
||||
|
||||
// handleStatus returns the current jukebox status as JSON
|
||||
|
@ -165,11 +166,13 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
|
|||
// getStatus returns the current status
|
||||
func (s *Server) getStatus() StatusResponse {
|
||||
currentSong := s.jukebox.GetCurrentSong()
|
||||
songHistory := s.jukebox.GetSongHistory()
|
||||
isPlaying := s.bot.IsPlaying()
|
||||
|
||||
return StatusResponse{
|
||||
IsPlaying: isPlaying,
|
||||
CurrentSong: currentSong,
|
||||
SongHistory: songHistory,
|
||||
UpdateTime: time.Now().Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ const statusText = document.getElementById('status-text');
|
|||
const nowPlaying = document.getElementById('now-playing');
|
||||
const notPlaying = document.getElementById('not-playing');
|
||||
const lastUpdate = document.getElementById('last-update');
|
||||
const songHistory = document.getElementById('song-history');
|
||||
const historyList = document.getElementById('history-list');
|
||||
|
||||
// Song info elements
|
||||
const coverArt = document.getElementById('cover-art');
|
||||
|
@ -75,6 +77,15 @@ function updateUI(data) {
|
|||
updateSongInfo(data.currentSong);
|
||||
}
|
||||
|
||||
// Update song history if available
|
||||
if (data.songHistory && data.songHistory.length > 0) {
|
||||
updateSongHistory(data.songHistory, data.currentSong);
|
||||
songHistory.classList.remove('hidden');
|
||||
} else {
|
||||
// No history available
|
||||
songHistory.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Update last update time
|
||||
if (data.updateTime) {
|
||||
const updateDate = new Date(data.updateTime);
|
||||
|
@ -122,4 +133,67 @@ function updateSongInfo(song) {
|
|||
|
||||
function formatDate(date) {
|
||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||
}
|
||||
|
||||
// Update the song history list
|
||||
function updateSongHistory(songs, currentSong) {
|
||||
// Clear the current list
|
||||
historyList.innerHTML = '';
|
||||
|
||||
// Show history even when nothing is playing
|
||||
|
||||
// Start from the first song
|
||||
const startIndex = 0;
|
||||
|
||||
// If no songs are available after filtering current one, show a message
|
||||
if (songs.length === 0) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'history-item history-empty';
|
||||
li.textContent = 'No song history available yet';
|
||||
historyList.appendChild(li);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add each song to the history list
|
||||
for (let i = startIndex; i < songs.length; i++) {
|
||||
const song = songs[i];
|
||||
if (!song) continue;
|
||||
|
||||
// Skip if this song is the same as the currently playing song
|
||||
if (currentSong && song.id === currentSong.id) continue;
|
||||
|
||||
const li = document.createElement('li');
|
||||
li.className = 'history-item';
|
||||
|
||||
// Create cover art
|
||||
const img = document.createElement('img');
|
||||
if (song.coverArt) {
|
||||
img.src = `/cover/${song.coverArt}`;
|
||||
} else {
|
||||
img.src = DEFAULT_COVER_ART;
|
||||
}
|
||||
img.alt = 'Cover';
|
||||
img.className = 'history-cover';
|
||||
|
||||
// Create song details
|
||||
const details = document.createElement('div');
|
||||
details.className = 'history-details';
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'history-title';
|
||||
title.textContent = song.title || 'Unknown Title';
|
||||
|
||||
const artist = document.createElement('div');
|
||||
artist.className = 'history-artist';
|
||||
artist.textContent = song.artist || 'Unknown Artist';
|
||||
|
||||
// Assemble the elements
|
||||
details.appendChild(title);
|
||||
details.appendChild(artist);
|
||||
|
||||
li.appendChild(img);
|
||||
li.appendChild(details);
|
||||
|
||||
historyList.appendChild(li);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Discord Jukebox Status</title>
|
||||
<link rel="stylesheet" href="/static/styles.css">
|
||||
<meta http-equiv="refresh" content="900"> <!-- Refresh page every 15 minutes to prevent memory issues -->
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
@ -35,6 +36,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="song-history" class="hidden">
|
||||
<h2>Recently Played</h2>
|
||||
<div class="history-container">
|
||||
<ul id="history-list" class="history-list">
|
||||
<!-- Song history will be populated here by JavaScript -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="not-playing" class="hidden">
|
||||
<div class="message">
|
||||
<h2>No Song Playing</h2>
|
||||
|
|
|
@ -128,6 +128,65 @@ h3 {
|
|||
margin-right: 15px;
|
||||
}
|
||||
|
||||
/* Song History Section */
|
||||
#song-history {
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.history-container {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.history-empty {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.history-cover {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
margin-right: 15px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.history-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.history-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.history-artist {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* Not Playing Section */
|
||||
#not-playing {
|
||||
text-align: center;
|
||||
|
@ -190,4 +249,18 @@ footer {
|
|||
#cover-art {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.history-cover {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.history-title, .history-artist {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue