fix: prevent home page double refresh and improve artist name extraction in album cards
This commit is contained in:
parent
b62f4144ac
commit
acf64cbc17
2 changed files with 92 additions and 62 deletions
|
|
@ -330,6 +330,17 @@ export class QobuzAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Similar/recommendation methods
|
||||||
|
async getSimilarArtists(artistId) {
|
||||||
|
// Qobuz doesn't have a direct similar artists endpoint in this simplified API
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSimilarAlbums(albumId) {
|
||||||
|
// Qobuz doesn't have a direct similar albums endpoint in this simplified API
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// Unified search - search all types at once
|
// Unified search - search all types at once
|
||||||
async search(query, options = {}) {
|
async search(query, options = {}) {
|
||||||
const offset = options.offset || 0;
|
const offset = options.offset || 0;
|
||||||
|
|
|
||||||
143
js/ui.js
143
js/ui.js
|
|
@ -91,6 +91,7 @@ export class UIRenderer {
|
||||||
this.searchAbortController = null;
|
this.searchAbortController = null;
|
||||||
this.vibrantColorCache = new Map();
|
this.vibrantColorCache = new Map();
|
||||||
this.visualizer = null;
|
this.visualizer = null;
|
||||||
|
this.renderLock = false;
|
||||||
|
|
||||||
// Listen for dynamic color reset events
|
// Listen for dynamic color reset events
|
||||||
window.addEventListener('reset-dynamic-color', () => {
|
window.addEventListener('reset-dynamic-color', () => {
|
||||||
|
|
@ -575,13 +576,19 @@ export class UIRenderer {
|
||||||
else if (album.type === 'SINGLE') typeLabel = ' • Single';
|
else if (album.type === 'SINGLE') typeLabel = ' • Single';
|
||||||
|
|
||||||
const isCompact = cardSettings.isCompactAlbum();
|
const isCompact = cardSettings.isCompactAlbum();
|
||||||
|
let artistName = '';
|
||||||
|
if (album.artist) {
|
||||||
|
artistName = typeof album.artist === 'string' ? album.artist : album.artist.name;
|
||||||
|
} else if (album.artists?.length) {
|
||||||
|
artistName = album.artists.map((a) => a.name).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
return this.createBaseCardHTML({
|
return this.createBaseCardHTML({
|
||||||
type: 'album',
|
type: 'album',
|
||||||
id: album.id,
|
id: album.id,
|
||||||
href: `/album/${album.id}`,
|
href: `/album/${album.id}`,
|
||||||
title: `${escapeHtml(album.title)} ${explicitBadge} ${qualityBadge}`,
|
title: `${escapeHtml(album.title)} ${explicitBadge} ${qualityBadge}`,
|
||||||
subtitle: `${escapeHtml(album.artist?.name ?? '')} • ${yearDisplay}${typeLabel}`,
|
subtitle: `${escapeHtml(artistName)} • ${yearDisplay}${typeLabel}`,
|
||||||
imageHTML: `<img src="${this.api.getCoverUrl(album.cover)}" alt="${escapeHtml(album.title)}" class="card-image" loading="lazy">`,
|
imageHTML: `<img src="${this.api.getCoverUrl(album.cover)}" alt="${escapeHtml(album.title)}" class="card-image" loading="lazy">`,
|
||||||
actionButtonsHTML: `
|
actionButtonsHTML: `
|
||||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
|
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
|
||||||
|
|
@ -1464,66 +1471,78 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderHomePage() {
|
async renderHomePage() {
|
||||||
this.showPage('home');
|
if (this.renderLock) return;
|
||||||
|
this.renderLock = true;
|
||||||
|
|
||||||
const welcomeEl = document.getElementById('home-welcome');
|
try {
|
||||||
const contentEl = document.getElementById('home-content');
|
this.showPage('home');
|
||||||
const editorsPicksSectionEmpty = document.getElementById('home-editors-picks-section-empty');
|
|
||||||
const editorsPicksSection = document.getElementById('home-editors-picks-section');
|
|
||||||
|
|
||||||
const history = await db.getHistory();
|
const welcomeEl = document.getElementById('home-welcome');
|
||||||
const favorites = await db.getFavorites('track');
|
const contentEl = document.getElementById('home-content');
|
||||||
const playlists = await db.getPlaylists(true);
|
const editorsPicksSectionEmpty = document.getElementById('home-editors-picks-section-empty');
|
||||||
|
const editorsPicksSection = document.getElementById('home-editors-picks-section');
|
||||||
|
|
||||||
const hasActivity = history.length > 0 || favorites.length > 0 || playlists.length > 0;
|
const history = await db.getHistory();
|
||||||
|
const favorites = await db.getFavorites('track');
|
||||||
|
const playlists = await db.getPlaylists(true);
|
||||||
|
|
||||||
// Handle Editor's Picks visibility based on settings
|
const hasActivity = history.length > 0 || favorites.length > 0 || playlists.length > 0;
|
||||||
if (!homePageSettings.shouldShowEditorsPicks()) {
|
|
||||||
if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = 'none';
|
// Handle Editor's Picks visibility based on settings
|
||||||
if (editorsPicksSection) editorsPicksSection.style.display = 'none';
|
if (!homePageSettings.shouldShowEditorsPicks()) {
|
||||||
} else {
|
if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = 'none';
|
||||||
// Show empty-state section at top when no activity, hide the bottom one
|
if (editorsPicksSection) editorsPicksSection.style.display = 'none';
|
||||||
if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = hasActivity ? 'none' : '';
|
} else {
|
||||||
// Show bottom section when has activity, render it
|
// Show empty-state section at top when no activity, hide the bottom one
|
||||||
if (editorsPicksSection) editorsPicksSection.style.display = hasActivity ? '' : 'none';
|
if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = hasActivity ? 'none' : '';
|
||||||
|
// Show bottom section when has activity, render it
|
||||||
|
if (editorsPicksSection) editorsPicksSection.style.display = hasActivity ? '' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render editor's picks in the visible container
|
||||||
|
if (hasActivity) {
|
||||||
|
this.renderHomeEditorsPicks(false, 'home-editors-picks');
|
||||||
|
} else {
|
||||||
|
this.renderHomeEditorsPicks(false, 'home-editors-picks-empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasActivity) {
|
||||||
|
if (welcomeEl) welcomeEl.style.display = 'block';
|
||||||
|
if (contentEl) contentEl.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (welcomeEl) welcomeEl.style.display = 'none';
|
||||||
|
if (contentEl) contentEl.style.display = 'block';
|
||||||
|
|
||||||
|
const refreshSongsBtn = document.getElementById('refresh-songs-btn');
|
||||||
|
const refreshAlbumsBtn = document.getElementById('refresh-albums-btn');
|
||||||
|
const refreshArtistsBtn = document.getElementById('refresh-artists-btn');
|
||||||
|
const clearRecentBtn = document.getElementById('clear-recent-btn');
|
||||||
|
|
||||||
|
if (refreshSongsBtn) refreshSongsBtn.onclick = () => this.renderHomeSongs(true);
|
||||||
|
if (refreshAlbumsBtn) refreshAlbumsBtn.onclick = () => this.renderHomeAlbums(true);
|
||||||
|
if (refreshArtistsBtn) refreshArtistsBtn.onclick = () => this.renderHomeArtists(true);
|
||||||
|
if (clearRecentBtn)
|
||||||
|
clearRecentBtn.onclick = () => {
|
||||||
|
if (confirm('Clear recent activity?')) {
|
||||||
|
recentActivityManager.clear();
|
||||||
|
this.renderHomeRecent();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.renderHomeRecent();
|
||||||
|
|
||||||
|
// Load dynamic sections in parallel with pre-fetched seeds
|
||||||
|
const seeds = await this.getSeeds();
|
||||||
|
await Promise.all([
|
||||||
|
this.renderHomeSongs(false, seeds),
|
||||||
|
this.renderHomeAlbums(false, seeds),
|
||||||
|
this.renderHomeArtists(false, seeds),
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
this.renderLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render editor's picks in the visible container
|
|
||||||
if (hasActivity) {
|
|
||||||
this.renderHomeEditorsPicks(false, 'home-editors-picks');
|
|
||||||
} else {
|
|
||||||
this.renderHomeEditorsPicks(false, 'home-editors-picks-empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasActivity) {
|
|
||||||
if (welcomeEl) welcomeEl.style.display = 'block';
|
|
||||||
if (contentEl) contentEl.style.display = 'none';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (welcomeEl) welcomeEl.style.display = 'none';
|
|
||||||
if (contentEl) contentEl.style.display = 'block';
|
|
||||||
|
|
||||||
const refreshSongsBtn = document.getElementById('refresh-songs-btn');
|
|
||||||
const refreshAlbumsBtn = document.getElementById('refresh-albums-btn');
|
|
||||||
const refreshArtistsBtn = document.getElementById('refresh-artists-btn');
|
|
||||||
const clearRecentBtn = document.getElementById('clear-recent-btn');
|
|
||||||
|
|
||||||
if (refreshSongsBtn) refreshSongsBtn.onclick = () => this.renderHomeSongs(true);
|
|
||||||
if (refreshAlbumsBtn) refreshAlbumsBtn.onclick = () => this.renderHomeAlbums(true);
|
|
||||||
if (refreshArtistsBtn) refreshArtistsBtn.onclick = () => this.renderHomeArtists(true);
|
|
||||||
if (clearRecentBtn)
|
|
||||||
clearRecentBtn.onclick = () => {
|
|
||||||
if (confirm('Clear recent activity?')) {
|
|
||||||
recentActivityManager.clear();
|
|
||||||
this.renderHomeRecent();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.renderHomeSongs();
|
|
||||||
this.renderHomeAlbums();
|
|
||||||
this.renderHomeArtists();
|
|
||||||
this.renderHomeRecent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSeeds() {
|
async getSeeds() {
|
||||||
|
|
@ -1545,7 +1564,7 @@ export class UIRenderer {
|
||||||
return shuffle(seeds);
|
return shuffle(seeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderHomeSongs(forceRefresh = false) {
|
async renderHomeSongs(forceRefresh = false, providedSeeds = null) {
|
||||||
const songsContainer = document.getElementById('home-recommended-songs');
|
const songsContainer = document.getElementById('home-recommended-songs');
|
||||||
const section = songsContainer?.closest('.content-section');
|
const section = songsContainer?.closest('.content-section');
|
||||||
|
|
||||||
|
|
@ -1564,7 +1583,7 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const seeds = await this.getSeeds();
|
const seeds = providedSeeds || (await this.getSeeds());
|
||||||
const trackSeeds = seeds.slice(0, 5);
|
const trackSeeds = seeds.slice(0, 5);
|
||||||
const recommendedTracks = await this.api.getRecommendedTracksForPlaylist(trackSeeds, 20, {
|
const recommendedTracks = await this.api.getRecommendedTracksForPlaylist(trackSeeds, 20, {
|
||||||
skipCache: forceRefresh,
|
skipCache: forceRefresh,
|
||||||
|
|
@ -1584,7 +1603,7 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderHomeAlbums(forceRefresh = false) {
|
async renderHomeAlbums(forceRefresh = false, providedSeeds = null) {
|
||||||
const albumsContainer = document.getElementById('home-recommended-albums');
|
const albumsContainer = document.getElementById('home-recommended-albums');
|
||||||
const section = albumsContainer?.closest('.content-section');
|
const section = albumsContainer?.closest('.content-section');
|
||||||
|
|
||||||
|
|
@ -1603,7 +1622,7 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const seeds = await this.getSeeds();
|
const seeds = providedSeeds || (await this.getSeeds());
|
||||||
const albumSeed = seeds.find((t) => t.album && t.album.id);
|
const albumSeed = seeds.find((t) => t.album && t.album.id);
|
||||||
if (albumSeed) {
|
if (albumSeed) {
|
||||||
const similarAlbums = await this.api.getSimilarAlbums(albumSeed.album.id);
|
const similarAlbums = await this.api.getSimilarAlbums(albumSeed.album.id);
|
||||||
|
|
@ -1790,7 +1809,7 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderHomeArtists(forceRefresh = false) {
|
async renderHomeArtists(forceRefresh = false, providedSeeds = null) {
|
||||||
const artistsContainer = document.getElementById('home-recommended-artists');
|
const artistsContainer = document.getElementById('home-recommended-artists');
|
||||||
const section = artistsContainer?.closest('.content-section');
|
const section = artistsContainer?.closest('.content-section');
|
||||||
|
|
||||||
|
|
@ -1809,7 +1828,7 @@ export class UIRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const seeds = await this.getSeeds();
|
const seeds = providedSeeds || (await this.getSeeds());
|
||||||
const artistSeed = seeds.find((t) => (t.artist && t.artist.id) || (t.artists && t.artists.length > 0));
|
const artistSeed = seeds.find((t) => (t.artist && t.artist.id) || (t.artists && t.artists.length > 0));
|
||||||
const artistId = artistSeed ? artistSeed.artist?.id || artistSeed.artists?.[0]?.id : null;
|
const artistId = artistSeed ? artistSeed.artist?.id || artistSeed.artists?.[0]?.id : null;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue