FEAT: add track mix button to player bar and display release year
This commit is contained in:
parent
0791c59f15
commit
3e228a0d46
5 changed files with 54 additions and 7 deletions
|
|
@ -711,6 +711,11 @@
|
||||||
<div class="player-actions-row">
|
<div class="player-actions-row">
|
||||||
<button id="now-playing-like-btn" class="like-btn" data-action="toggle-like" title="Save to Favorites" style="display: none;">
|
<button id="now-playing-like-btn" class="like-btn" data-action="toggle-like" title="Save to Favorites" style="display: none;">
|
||||||
</button>
|
</button>
|
||||||
|
<button id="now-playing-mix-btn" class="mix-btn" data-action="track-mix" title="Track Mix" style="display: none;">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button id="toggle-lyrics-btn" title="Lyrics">
|
<button id="toggle-lyrics-btn" title="Lyrics">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mic"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/><line x1="8" y1="22" x2="16" y2="22"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mic"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/><line x1="8" y1="22" x2="16" y2="22"/></svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
10
js/events.js
10
js/events.js
|
|
@ -667,6 +667,16 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nowPlayingMixBtn = document.getElementById('now-playing-mix-btn');
|
||||||
|
if (nowPlayingMixBtn) {
|
||||||
|
nowPlayingMixBtn.addEventListener('click', async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (player.currentTrack) {
|
||||||
|
await handleTrackAction('track-mix', player.currentTrack, player, api, lyricsManager, 'track', ui, scrobbler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderQueue(player) {
|
function renderQueue(player) {
|
||||||
|
|
|
||||||
32
js/player.js
32
js/player.js
|
|
@ -45,13 +45,27 @@ export class Player {
|
||||||
const trackTitle = getTrackTitle(track);
|
const trackTitle = getTrackTitle(track);
|
||||||
const trackArtistsHTML = getTrackArtistsHTML(track);
|
const trackArtistsHTML = getTrackArtistsHTML(track);
|
||||||
|
|
||||||
|
let yearDisplay = '';
|
||||||
|
const releaseDate = track.album?.releaseDate || track.streamStartDate;
|
||||||
|
if (releaseDate) {
|
||||||
|
const date = new Date(releaseDate);
|
||||||
|
if (!isNaN(date.getTime())) {
|
||||||
|
yearDisplay = ` • ${date.getFullYear()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const coverEl = document.querySelector('.now-playing-bar .cover');
|
const coverEl = document.querySelector('.now-playing-bar .cover');
|
||||||
const titleEl = document.querySelector('.now-playing-bar .title');
|
const titleEl = document.querySelector('.now-playing-bar .title');
|
||||||
const artistEl = document.querySelector('.now-playing-bar .artist');
|
const artistEl = document.querySelector('.now-playing-bar .artist');
|
||||||
|
|
||||||
if (coverEl) coverEl.src = this.api.getCoverUrl(track.album?.cover, '1280');
|
if (coverEl) coverEl.src = this.api.getCoverUrl(track.album?.cover, '1280');
|
||||||
if (titleEl) titleEl.textContent = trackTitle;
|
if (titleEl) titleEl.textContent = trackTitle;
|
||||||
if (artistEl) artistEl.innerHTML = trackArtistsHTML;
|
if (artistEl) artistEl.innerHTML = trackArtistsHTML + yearDisplay;
|
||||||
|
|
||||||
|
const mixBtn = document.getElementById('now-playing-mix-btn');
|
||||||
|
if (mixBtn) {
|
||||||
|
mixBtn.style.display = (track.mixes && track.mixes.TRACK_MIX) ? 'flex' : 'none';
|
||||||
|
}
|
||||||
const totalDurationEl = document.getElementById('total-duration');
|
const totalDurationEl = document.getElementById('total-duration');
|
||||||
if (totalDurationEl) totalDurationEl.textContent = formatTime(track.duration);
|
if (totalDurationEl) totalDurationEl.textContent = formatTime(track.duration);
|
||||||
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
|
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
|
||||||
|
|
@ -170,10 +184,24 @@ export class Player {
|
||||||
const trackTitle = getTrackTitle(track);
|
const trackTitle = getTrackTitle(track);
|
||||||
const trackArtistsHTML = getTrackArtistsHTML(track);
|
const trackArtistsHTML = getTrackArtistsHTML(track);
|
||||||
|
|
||||||
|
let yearDisplay = '';
|
||||||
|
const releaseDate = track.album?.releaseDate || track.streamStartDate;
|
||||||
|
if (releaseDate) {
|
||||||
|
const date = new Date(releaseDate);
|
||||||
|
if (!isNaN(date.getTime())) {
|
||||||
|
yearDisplay = ` • ${date.getFullYear()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelector('.now-playing-bar .cover').src =
|
document.querySelector('.now-playing-bar .cover').src =
|
||||||
this.api.getCoverUrl(track.album?.cover, '1280');
|
this.api.getCoverUrl(track.album?.cover, '1280');
|
||||||
document.querySelector('.now-playing-bar .title').textContent = trackTitle;
|
document.querySelector('.now-playing-bar .title').textContent = trackTitle;
|
||||||
document.querySelector('.now-playing-bar .artist').innerHTML = trackArtistsHTML;
|
document.querySelector('.now-playing-bar .artist').innerHTML = trackArtistsHTML + yearDisplay;
|
||||||
|
|
||||||
|
const mixBtn = document.getElementById('now-playing-mix-btn');
|
||||||
|
if (mixBtn) {
|
||||||
|
mixBtn.style.display = (track.mixes && track.mixes.TRACK_MIX) ? 'flex' : 'none';
|
||||||
|
}
|
||||||
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
|
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
|
||||||
|
|
||||||
this.updatePlayingTrackIndicator();
|
this.updatePlayingTrackIndicator();
|
||||||
|
|
|
||||||
11
js/ui.js
11
js/ui.js
|
|
@ -1189,16 +1189,19 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
|
|
||||||
let displayTitle;
|
let displayTitle;
|
||||||
if (type === 'artist' && name) {
|
if (type === 'artist' && name) {
|
||||||
displayTitle = `Mix for artist ${decodeURIComponent(name)}`;
|
const decodedName = decodeURIComponent(name);
|
||||||
|
titleEl.innerHTML = `<span style="color: var(--muted-foreground)">Mix for artist</span> ${decodedName}`;
|
||||||
|
this.adjustTitleFontSize(titleEl, `Mix for artist ${decodedName}`);
|
||||||
} else if (type === 'track' && name) {
|
} else if (type === 'track' && name) {
|
||||||
displayTitle = `Mix for track ${decodeURIComponent(name)}`;
|
const decodedName = decodeURIComponent(name);
|
||||||
|
titleEl.innerHTML = `<span style="color: var(--muted-foreground)">Mix for track</span> ${decodedName}`;
|
||||||
|
this.adjustTitleFontSize(titleEl, `Mix for track ${decodedName}`);
|
||||||
} else {
|
} else {
|
||||||
const firstTrackArtist = tracks.length > 0 ? tracks[0].artist?.name : '';
|
const firstTrackArtist = tracks.length > 0 ? tracks[0].artist?.name : '';
|
||||||
displayTitle = mix.title || (firstTrackArtist ? `${firstTrackArtist} Mix` : 'Mix');
|
displayTitle = mix.title || (firstTrackArtist ? `${firstTrackArtist} Mix` : 'Mix');
|
||||||
}
|
|
||||||
|
|
||||||
titleEl.textContent = displayTitle;
|
titleEl.textContent = displayTitle;
|
||||||
this.adjustTitleFontSize(titleEl, displayTitle);
|
this.adjustTitleFontSize(titleEl, displayTitle);
|
||||||
|
}
|
||||||
|
|
||||||
const totalDuration = calculateTotalDuration(tracks);
|
const totalDuration = calculateTotalDuration(tracks);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ export const SVG_MENU = '<svg xmlns="http://www.w3.org/2000/svg" width="24" heig
|
||||||
export const SVG_HEART = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="heart-icon"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>';
|
export const SVG_HEART = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="heart-icon"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>';
|
||||||
export const SVG_CLOSE = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
|
export const SVG_CLOSE = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
|
||||||
export const SVG_BIN = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>';
|
export const SVG_BIN = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>';
|
||||||
|
export const SVG_MIX = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>';
|
||||||
|
|
||||||
export const formatTime = (seconds) => {
|
export const formatTime = (seconds) => {
|
||||||
if (isNaN(seconds)) return '0:00';
|
if (isNaN(seconds)) return '0:00';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue