@@ -187,9 +185,8 @@ async function downloadAlbumAsZip(album, tracks, api, quality) {
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
const filename = buildTrackFilename(track, quality);
- const trackTitle = getTrackTitle(track);
- updateBulkDownloadProgress(notification, i, tracks.length, trackTitle);
+ updateBulkDownloadProgress(notification, i, tracks.length, track.title);
const blob = await downloadTrackBlob(track, quality, api);
zip.file(`${folderName}/${filename}`, blob);
@@ -399,6 +396,7 @@ document.addEventListener('DOMContentLoaded', async () => {
const lastfmToggleSetting = document.getElementById('lastfm-toggle-setting');
window.loadHomeFeed = loadHomeFeed;
+
function positionContextMenu(menu, x, y, preferLeft = false) {
menu.style.display = 'block';
menu.style.visibility = 'hidden';
@@ -781,7 +779,9 @@ document.addEventListener('DOMContentLoaded', async () => {
const html = currentQueue.map((track, index) => {
const isPlaying = index === player.currentQueueIndex;
- const trackTitle = getTrackTitle(track);
+ const trackArtists = getTrackArtists(track, {
+ fallback: "Unknown"
+ });
return `
@@ -795,8 +795,8 @@ document.addEventListener('DOMContentLoaded', async () => {
-
${trackTitle}
-
${track.artist?.name || 'Unknown'}
+
${track.title}
+
${trackArtists}
${formatTime(track.duration)}
@@ -855,11 +855,11 @@ document.addEventListener('DOMContentLoaded', async () => {
function showQueueTrackMenu(e, trackIndex) {
const menu = document.getElementById('queue-track-menu');
+ menu.style.top = `${e.pageY}px`;
+ menu.style.left = `${e.pageX}px`;
menu.classList.add('show');
menu.dataset.trackIndex = trackIndex;
-
positionContextMenu(menu, e.pageX, e.pageY, true);
-
document.addEventListener('click', hideQueueTrackMenu);
}
@@ -892,7 +892,9 @@ document.addEventListener('DOMContentLoaded', async () => {
contextTrack = trackDataStore.get(trackItem);
if (contextTrack) {
const rect = menuBtn.getBoundingClientRect();
- positionContextMenu(contextMenu, rect.left, rect.bottom + 5, true);
+ contextMenu.style.top = `${rect.bottom + 5}px`;
+ contextMenu.style.left = `${rect.left}px`;
+ contextMenu.style.display = 'block';
}
}
return;
@@ -922,7 +924,9 @@ document.addEventListener('DOMContentLoaded', async () => {
contextTrack = trackDataStore.get(trackItem);
if (contextTrack) {
- positionContextMenu(contextMenu, e.pageX, e.pageY, true);
+ contextMenu.style.top = `${e.pageY}px`;
+ contextMenu.style.left = `${e.pageX}px`;
+ contextMenu.style.display = 'block';
}
}
});
diff --git a/js/player.js b/js/player.js
index 410ef1c..ba43204 100644
--- a/js/player.js
+++ b/js/player.js
@@ -1,5 +1,5 @@
//player.js
-import { REPEAT_MODE, formatTime, getTrackTitle } from './utils.js';
+import { REPEAT_MODE, formatTime, getTrackArtists } from './utils.js';
export class Player {
constructor(audioElement, api, quality = 'LOSSLESS') {
@@ -99,7 +99,6 @@ export class Player {
for (const { track, index } of tracksToPreload) {
if (this.preloadCache.has(track.id)) continue;
- const trackTitle = getTrackTitle(track);
try {
const streamUrl = await this.api.getStreamUrl(track.id, this.quality);
@@ -114,7 +113,7 @@ export class Player {
} catch (error) {
if (error.name !== 'AbortError') {
- console.debug('Failed to get stream URL for preload:', trackTitle);
+ console.debug('Failed to get stream URL for preload:', track.title);
}
}
}
@@ -129,13 +128,13 @@ async playTrackFromQueue() {
const track = currentQueue[this.currentQueueIndex];
this.currentTrack = track;
- const trackTitle = getTrackTitle(track);
+ const trackArtists = getTrackArtists(track);
document.querySelector('.now-playing-bar .cover').src =
this.api.getCoverUrl(track.album?.cover, '1280');
- document.querySelector('.now-playing-bar .title').textContent = trackTitle;
- document.querySelector('.now-playing-bar .artist').textContent = track.artist?.name || 'Unknown Artist';
- document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
+ document.querySelector('.now-playing-bar .title').textContent = track.title;
+ document.querySelector('.now-playing-bar .artist').textContent = trackArtists;
+ document.title = `${track.title} • ${track.artist?.name || 'Unknown'}`;
this.updatePlayingTrackIndicator();
this.updateMediaSession(track);
@@ -184,8 +183,8 @@ async playTrackFromQueue() {
this.setupCrossfadeListener();
} catch (error) {
- console.error(`Could not play track: ${trackTitle}`, error);
- document.querySelector('.now-playing-bar .title').textContent = `Error: ${trackTitle}`;
+ console.error(`Could not play track: ${track.title}`, error);
+ document.querySelector('.now-playing-bar .title').textContent = `Error: ${track.title}`;
document.querySelector('.now-playing-bar .artist').textContent = error.message || 'Could not load track';
}
}
@@ -413,7 +412,6 @@ async playTrackFromQueue() {
const artwork = [];
const sizes = ['1280'];
const coverId = track.album?.cover;
- const trackTitle = getTrackTitle(track);
if (coverId) {
sizes.forEach(size => {
@@ -426,7 +424,7 @@ async playTrackFromQueue() {
}
navigator.mediaSession.metadata = new MediaMetadata({
- title: trackTitle,
+ title: track.title || 'Unknown Title',
artist: track.artist?.name || 'Unknown Artist',
album: track.album?.title || 'Unknown Album',
artwork: artwork.length > 0 ? artwork : undefined
@@ -471,4 +469,4 @@ applyNormalization() {
console.debug('Failed to update Media Session position:', error);
}
}
-}
+}
\ No newline at end of file
diff --git a/js/ui.js b/js/ui.js
index 4d62417..2aab374 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -1,5 +1,5 @@
//ui.js
-import { formatTime, createPlaceholder, trackDataStore, hasExplicitContent, getTrackTitle } from './utils.js';
+import { formatTime, createPlaceholder, trackDataStore, hasExplicitContent, getTrackArtists } from './utils.js';
import { recentActivityManager } from './storage.js';
export class UIRenderer {
@@ -25,8 +25,8 @@ export class UIRenderer {
createTrackItemHTML(track, index, showCover = false) {
const playIconSmall = '
';
const trackNumberHTML = `
${showCover ? playIconSmall : index + 1}
`;
- const explicitBadge = !hasExplicitContent(track) ? this.createExplicitBadge() : '';
- const trackTitle = getTrackTitle(track);
+ const explicitBadge = hasExplicitContent(track) ? this.createExplicitBadge() : '';
+ const trackArtists = getTrackArtists(track);
return `
@@ -35,7 +35,7 @@ export class UIRenderer {
${showCover ? `
})
` : ''}
- ${trackTitle}
+ ${track.title}
${explicitBadge}
${trackArtists}
@@ -419,4 +419,4 @@ async renderHomePage() {
}
});
}
-}
+}
\ No newline at end of file
diff --git a/js/utils.js b/js/utils.js
index 460e19e..6b4095e 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -70,7 +70,7 @@ export const buildTrackFilename = (track, quality) => {
const artistName = sanitizeForFilename(track.artist?.name);
const albumTitle = sanitizeForFilename(track.album?.title);
- const trackTitle = sanitizeForFilename(getTrackTitle(track));
+ const trackTitle = sanitizeForFilename(track.title);
return `${artistName} - ${albumTitle} - ${padded} ${trackTitle}.${extension}`;
};
@@ -157,7 +157,10 @@ export const debounce = (func, wait) => {
};
};
-export const getTrackTitle = (track, { fallback = 'Unknown Title' } = {}) => {
- if (!track?.title) return fallback;
- return track?.version ? `${track.title} (${track.version})` : track.title;
-};
+export const getTrackArtists = (track = {}, { fallback = 'Unknown Artist' } = {}) => {
+ if (track?.artists?.length) {
+ return track.artists.map(artist => artist?.name).join(', ');
+ }
+
+ return fallback;
+}
\ No newline at end of file