IMP: mixes using new API
This commit is contained in:
parent
4fc36f63e4
commit
6ee3c57bc5
4 changed files with 29 additions and 56 deletions
30
js/api.js
30
js/api.js
|
|
@ -487,27 +487,23 @@ export class LosslessAPI {
|
||||||
const response = await this.fetchWithRetry(`/mix/?id=${id}`, { type: 'api' });
|
const response = await this.fetchWithRetry(`/mix/?id=${id}`, { type: 'api' });
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
let mix = null;
|
const mixData = data.mix;
|
||||||
let tracks = [];
|
const items = data.items || [];
|
||||||
|
|
||||||
// Mix response structure might vary, handle likely cases
|
if (!mixData) {
|
||||||
const items = data.items || data.tracks || (Array.isArray(data) ? data : []);
|
throw new Error('Mix metadata not found');
|
||||||
|
|
||||||
// If data has mix info, use it. Otherwise, fabricate one or look for it.
|
|
||||||
if (data.mix) {
|
|
||||||
mix = data.mix;
|
|
||||||
} else if (!Array.isArray(data) && data.id) {
|
|
||||||
mix = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mix) {
|
const tracks = items.map(i => this.prepareTrack(i.item || i));
|
||||||
// Basic placeholder if mix metadata isn't explicitly separated
|
|
||||||
mix = { id, title: 'Mix', description: 'Generated Mix' };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.length > 0) {
|
const mix = {
|
||||||
tracks = items.map(i => this.prepareTrack(i.item || i));
|
id: mixData.id,
|
||||||
}
|
title: mixData.title,
|
||||||
|
subTitle: mixData.subTitle,
|
||||||
|
description: mixData.description,
|
||||||
|
mixType: mixData.mixType,
|
||||||
|
cover: mixData.images?.LARGE?.url || mixData.images?.MEDIUM?.url || mixData.images?.SMALL?.url || null
|
||||||
|
};
|
||||||
|
|
||||||
const result = { mix, tracks };
|
const result = { mix, tracks };
|
||||||
await this.cache.set('mix', id, result);
|
await this.cache.set('mix', id, result);
|
||||||
|
|
|
||||||
|
|
@ -329,9 +329,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const btn = e.target.closest('#download-mix-btn');
|
const btn = e.target.closest('#download-mix-btn');
|
||||||
if (btn.disabled) return;
|
if (btn.disabled) return;
|
||||||
|
|
||||||
const param = window.location.hash.split('#mix/')[1];
|
const mixId = window.location.hash.split('#mix/')[1];
|
||||||
if (!param) return;
|
if (!mixId) return;
|
||||||
const [mixId] = param.split('?');
|
|
||||||
|
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
const originalHTML = btn.innerHTML;
|
const originalHTML = btn.innerHTML;
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,7 @@ export async function handleTrackAction(action, item, player, api, lyricsManager
|
||||||
showNotification(`Playing next: ${item.title}`);
|
showNotification(`Playing next: ${item.title}`);
|
||||||
} else if (action === 'track-mix') {
|
} else if (action === 'track-mix') {
|
||||||
if (item.mixes && item.mixes.TRACK_MIX) {
|
if (item.mixes && item.mixes.TRACK_MIX) {
|
||||||
window.location.hash = `#mix/${item.mixes.TRACK_MIX}?type=track&name=${encodeURIComponent(item.title)}`;
|
window.location.hash = `#mix/${item.mixes.TRACK_MIX}`;
|
||||||
}
|
}
|
||||||
} else if (action === 'play-card') {
|
} else if (action === 'play-card') {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
42
js/ui.js
42
js/ui.js
|
|
@ -933,7 +933,7 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
const mixBtn = document.getElementById('album-mix-btn');
|
const mixBtn = document.getElementById('album-mix-btn');
|
||||||
if (mixBtn && artistData.mixes && artistData.mixes.ARTIST_MIX) {
|
if (mixBtn && artistData.mixes && artistData.mixes.ARTIST_MIX) {
|
||||||
mixBtn.style.display = 'flex';
|
mixBtn.style.display = 'flex';
|
||||||
mixBtn.onclick = () => window.location.hash = `#mix/${artistData.mixes.ARTIST_MIX}?type=artist&name=${encodeURIComponent(artistData.name)}`;
|
mixBtn.onclick = () => window.location.hash = `#mix/${artistData.mixes.ARTIST_MIX}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderSection = (items, container, section, titleEl, titleText) => {
|
const renderSection = (items, container, section, titleEl, titleText) => {
|
||||||
|
|
@ -1171,12 +1171,8 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderMixPage(param) {
|
async renderMixPage(mixId) {
|
||||||
this.showPage('mix');
|
this.showPage('mix');
|
||||||
const [mixId, query] = param.split('?');
|
|
||||||
const urlParams = new URLSearchParams(query);
|
|
||||||
const type = urlParams.get('type');
|
|
||||||
const name = urlParams.get('name');
|
|
||||||
|
|
||||||
const imageEl = document.getElementById('mix-detail-image');
|
const imageEl = document.getElementById('mix-detail-image');
|
||||||
const titleEl = document.getElementById('mix-detail-title');
|
const titleEl = document.getElementById('mix-detail-title');
|
||||||
|
|
@ -1206,16 +1202,10 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
try {
|
try {
|
||||||
const { mix, tracks } = await this.api.getMix(mixId);
|
const { mix, tracks } = await this.api.getMix(mixId);
|
||||||
|
|
||||||
// Mixes usually have covers from Tidal resources, similar to playlists
|
if (mix.cover) {
|
||||||
const imageId = mix.images?.medium?.source || mix.image || mix.id;
|
imageEl.src = mix.cover;
|
||||||
// Fallback for cover: if mix.id matches a pattern or we can just try generic mix cover
|
this.setPageBackground(mix.cover);
|
||||||
// Often mix ID isn't directly an image ID.
|
this.extractAndApplyColor(mix.cover);
|
||||||
// If API returns explicit image URL/ID use it.
|
|
||||||
// For now assume standard playlist-like cover or placeholder.
|
|
||||||
if (imageId && imageId !== mix.id) {
|
|
||||||
imageEl.src = this.api.getCoverUrl(imageId);
|
|
||||||
this.setPageBackground(imageEl.src);
|
|
||||||
this.extractAndApplyColor(this.api.getCoverUrl(imageId, '160'));
|
|
||||||
} else {
|
} else {
|
||||||
// Try to get cover from first track album
|
// Try to get cover from first track album
|
||||||
if (tracks.length > 0 && tracks[0].album?.cover) {
|
if (tracks.length > 0 && tracks[0].album?.cover) {
|
||||||
|
|
@ -1231,26 +1221,14 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
|
|
||||||
imageEl.style.backgroundColor = '';
|
imageEl.style.backgroundColor = '';
|
||||||
|
|
||||||
let displayTitle;
|
// Use title and subtitle from API directly
|
||||||
if (type === 'artist' && name) {
|
const displayTitle = mix.title || 'Mix';
|
||||||
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) {
|
|
||||||
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 {
|
|
||||||
const firstTrackArtist = tracks.length > 0 ? tracks[0].artist?.name : '';
|
|
||||||
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);
|
||||||
|
|
||||||
metaEl.textContent = `${tracks.length} tracks • ${formatDuration(totalDuration)}`;
|
metaEl.textContent = `${tracks.length} tracks • ${formatDuration(totalDuration)}`;
|
||||||
descEl.textContent = mix.subTitle || mix.description || '';
|
descEl.innerHTML = `${mix.subTitle}`;
|
||||||
|
|
||||||
tracklistContainer.innerHTML = `
|
tracklistContainer.innerHTML = `
|
||||||
<div class="track-list-header">
|
<div class="track-list-header">
|
||||||
|
|
@ -1309,7 +1287,7 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
|
||||||
if (mixBtn) {
|
if (mixBtn) {
|
||||||
if (artist.mixes && artist.mixes.ARTIST_MIX) {
|
if (artist.mixes && artist.mixes.ARTIST_MIX) {
|
||||||
mixBtn.style.display = 'flex';
|
mixBtn.style.display = 'flex';
|
||||||
mixBtn.onclick = () => window.location.hash = `#mix/${artist.mixes.ARTIST_MIX}?type=artist&name=${encodeURIComponent(artist.name)}`;
|
mixBtn.onclick = () => window.location.hash = `#mix/${artist.mixes.ARTIST_MIX}`;
|
||||||
} else {
|
} else {
|
||||||
mixBtn.style.display = 'none';
|
mixBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue