faster fetching for artist albums
This commit is contained in:
@@ -150,18 +150,6 @@ export class ArtistDetails extends LitElement {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-message,
|
|
||||||
.empty-message {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
|
||||||
color: var(
|
|
||||||
--yj-text-secondary,
|
|
||||||
#b3b3b3
|
|
||||||
);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
@@ -185,26 +173,76 @@ export class ArtistDetails extends LitElement {
|
|||||||
private async loadAlbums() {
|
private async loadAlbums() {
|
||||||
if (!this.artistId) return;
|
if (!this.artistId) return;
|
||||||
|
|
||||||
try {
|
// Try to populate instantly from the
|
||||||
this.loading = true;
|
// cached all-albums list if available.
|
||||||
|
const cached =
|
||||||
|
this.libraryCtrl.getAlbumsByArtistNameCached(
|
||||||
|
this.artistName,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cached !== null && cached.length > 0) {
|
||||||
|
this.albums = cached;
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always run the authoritative backend
|
||||||
|
// query. If we got a cache hit above,
|
||||||
|
// this serves as a correction pass.
|
||||||
|
try {
|
||||||
const albums =
|
const albums =
|
||||||
await this.libraryCtrl.getAlbumsByArtist(
|
await this.libraryCtrl.getAlbumsByArtist(
|
||||||
this.artistId,
|
this.artistId,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.albums = albums ?? [];
|
const result = albums ?? [];
|
||||||
|
|
||||||
|
// Skip update if the cached result
|
||||||
|
// is identical (same IDs in same
|
||||||
|
// order) to avoid a re-render.
|
||||||
|
if (!this.albumsMatch(result)) {
|
||||||
|
this.albums = result;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
'Error loading artist albums:',
|
'Error loading artist albums:',
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
this.albums = [];
|
|
||||||
|
// Only overwrite if we had no cached
|
||||||
|
// result to fall back on.
|
||||||
|
if (cached === null) {
|
||||||
|
this.albums = [];
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two album lists by ID to avoid
|
||||||
|
* unnecessary re-renders when the backend
|
||||||
|
* result matches the cached approximation.
|
||||||
|
*/
|
||||||
|
private albumsMatch(
|
||||||
|
incoming: library.Album[],
|
||||||
|
): boolean {
|
||||||
|
const current = this.albums;
|
||||||
|
|
||||||
|
if (current.length !== incoming.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < current.length; i++) {
|
||||||
|
if (
|
||||||
|
current[i]!.ID !== incoming[i]!.ID
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
* Navigation
|
* Navigation
|
||||||
* ================================================================ */
|
* ================================================================ */
|
||||||
@@ -277,20 +315,9 @@ export class ArtistDetails extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this.loading
|
<cover-grid
|
||||||
? html`
|
.externalAlbums=${this.albums}
|
||||||
<div
|
></cover-grid>
|
||||||
class="loading-message"
|
|
||||||
>
|
|
||||||
Loading albums...
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<cover-grid
|
|
||||||
.externalAlbums=${this
|
|
||||||
.albums}
|
|
||||||
></cover-grid>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ export class LibraryController implements ReactiveController {
|
|||||||
return libraryStore.getAlbumsByArtist(artistID);
|
return libraryStore.getAlbumsByArtist(artistID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAlbumsByArtistNameCached(
|
||||||
|
artistName: string,
|
||||||
|
): library.Album[] | null {
|
||||||
|
return libraryStore.getAlbumsByArtistNameCached(
|
||||||
|
artistName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
get cachedTracks(): library.Track[] | null {
|
get cachedTracks(): library.Track[] | null {
|
||||||
return libraryStore.getCachedTracks();
|
return libraryStore.getCachedTracks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,24 @@ class LibraryStore {
|
|||||||
return GetAlbumsByArtist(artistID);
|
return GetAlbumsByArtist(artistID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns albums filtered by artist name from
|
||||||
|
* the in-memory cache, or null if the cache is
|
||||||
|
* not populated. This provides an instant
|
||||||
|
* result when the all-albums list has already
|
||||||
|
* been loaded (e.g. the user visited the albums
|
||||||
|
* view first).
|
||||||
|
*/
|
||||||
|
getAlbumsByArtistNameCached(
|
||||||
|
artistName: string,
|
||||||
|
): library.Album[] | null {
|
||||||
|
if (this.albums === null) return null;
|
||||||
|
|
||||||
|
return this.albums.filter(
|
||||||
|
(a) => a.ArtistName === artistName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// STATE ACCESSORS
|
// STATE ACCESSORS
|
||||||
// Synchronous access for controllers that need current cached values.
|
// Synchronous access for controllers that need current cached values.
|
||||||
|
|||||||
Reference in New Issue
Block a user