diff --git a/js/app.js b/js/app.js index 2ff1c20..bc95f36 100644 --- a/js/app.js +++ b/js/app.js @@ -7,7 +7,8 @@ import { REPEAT_MODE, SVG_PLAY, SVG_PAUSE, SVG_VOLUME, SVG_MUTE, formatTime, trackDataStore, buildTrackFilename, RATE_LIMIT_ERROR_MESSAGE, debounce, - sanitizeForFilename + sanitizeForFilename, + getTrackTitle } from './utils.js'; const downloadTasks = new Map(); @@ -38,13 +39,15 @@ function addDownloadTask(trackId, track, filename, api) { const taskEl = document.createElement('div'); taskEl.className = 'download-task'; taskEl.dataset.trackId = trackId; + + const trackTitle = getTrackTitle(track); taskEl.innerHTML = `
-
${track.title}
+
${trackTitle}
${track.artist?.name || 'Unknown'}
@@ -184,8 +187,9 @@ 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, track.title); + updateBulkDownloadProgress(notification, i, tracks.length, trackTitle); const blob = await downloadTrackBlob(track, quality, api); zip.file(`${folderName}/${filename}`, blob); @@ -735,7 +739,7 @@ document.addEventListener('DOMContentLoaded', async () => { const html = currentQueue.map((track, index) => { const isPlaying = index === player.currentQueueIndex; - const trackTitle = track?.version ? `${track.title} (${track.version})` : track?.title; + const trackTitle = getTrackTitle(track); return `
diff --git a/js/player.js b/js/player.js index b888be0..410ef1c 100644 --- a/js/player.js +++ b/js/player.js @@ -1,5 +1,5 @@ //player.js -import { REPEAT_MODE, formatTime } from './utils.js'; +import { REPEAT_MODE, formatTime, getTrackTitle } from './utils.js'; export class Player { constructor(audioElement, api, quality = 'LOSSLESS') { @@ -99,6 +99,7 @@ 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); @@ -113,7 +114,7 @@ export class Player { } catch (error) { if (error.name !== 'AbortError') { - console.debug('Failed to get stream URL for preload:', track.title); + console.debug('Failed to get stream URL for preload:', trackTitle); } } } @@ -128,7 +129,7 @@ async playTrackFromQueue() { const track = currentQueue[this.currentQueueIndex]; this.currentTrack = track; - const trackTitle = track?.version ? `${track.title} (${track.version})` : track?.title; + const trackTitle = getTrackTitle(track); document.querySelector('.now-playing-bar .cover').src = this.api.getCoverUrl(track.album?.cover, '1280'); @@ -183,8 +184,8 @@ async playTrackFromQueue() { this.setupCrossfadeListener(); } catch (error) { - console.error(`Could not play track: ${track.title}`, error); - document.querySelector('.now-playing-bar .title').textContent = `Error: ${track.title}`; + console.error(`Could not play track: ${trackTitle}`, error); + document.querySelector('.now-playing-bar .title').textContent = `Error: ${trackTitle}`; document.querySelector('.now-playing-bar .artist').textContent = error.message || 'Could not load track'; } } @@ -412,6 +413,7 @@ async playTrackFromQueue() { const artwork = []; const sizes = ['1280']; const coverId = track.album?.cover; + const trackTitle = getTrackTitle(track); if (coverId) { sizes.forEach(size => { @@ -424,7 +426,7 @@ async playTrackFromQueue() { } navigator.mediaSession.metadata = new MediaMetadata({ - title: track.title || 'Unknown Title', + title: trackTitle, artist: track.artist?.name || 'Unknown Artist', album: track.album?.title || 'Unknown Album', artwork: artwork.length > 0 ? artwork : undefined diff --git a/js/ui.js b/js/ui.js index ccf23e1..80126d5 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1,5 +1,5 @@ //ui.js -import { formatTime, createPlaceholder, trackDataStore, hasExplicitContent } from './utils.js'; +import { formatTime, createPlaceholder, trackDataStore, hasExplicitContent, getTrackTitle } from './utils.js'; import { recentActivityManager } from './storage.js'; export class UIRenderer { @@ -26,7 +26,7 @@ export class UIRenderer { const playIconSmall = ''; const trackNumberHTML = `
${showCover ? playIconSmall : index + 1}
`; const explicitBadge = !hasExplicitContent(track) ? this.createExplicitBadge() : ''; - const trackTitle = track?.version ? `${track.title} (${track.version})` : track?.title; + const trackTitle = getTrackTitle(track); return `
diff --git a/js/utils.js b/js/utils.js index 05754a2..460e19e 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(track.title); + const trackTitle = sanitizeForFilename(getTrackTitle(track)); return `${artistName} - ${albumTitle} - ${padded} ${trackTitle}.${extension}`; }; @@ -155,4 +155,9 @@ export const debounce = (func, wait) => { clearTimeout(timeout); timeout = setTimeout(later, wait); }; -}; \ No newline at end of file +}; + +export const getTrackTitle = (track, { fallback = 'Unknown Title' } = {}) => { + if (!track?.title) return fallback; + return track?.version ? `${track.title} (${track.version})` : track.title; +};