diff --git a/index.html b/index.html
index ef3f00f..1478e8e 100644
--- a/index.html
+++ b/index.html
@@ -226,6 +226,10 @@
diff --git a/js/api.js b/js/api.js
index ab66413..4ba9fa3 100644
--- a/js/api.js
+++ b/js/api.js
@@ -484,15 +484,42 @@ export class LosslessAPI {
entries.forEach(entry => scan(entry));
- const albums = Array.from(albumMap.values()).sort((a, b) =>
+ // Attempt to find more albums/EPs via search since the direct feed might be limited
+ try {
+ const searchResults = await this.searchAlbums(artist.name);
+ if (searchResults && searchResults.items) {
+ const numericArtistId = Number(artistId);
+
+ for (const item of searchResults.items) {
+ const itemArtistId = item.artist?.id;
+ const matchesArtist = itemArtistId === numericArtistId ||
+ (Array.isArray(item.artists) && item.artists.some(a => a.id === numericArtistId));
+
+ if (matchesArtist && !albumMap.has(item.id)) {
+ albumMap.set(item.id, item);
+ }
+ }
+ }
+ } catch (e) {
+ console.warn('Failed to fetch additional albums via search:', e);
+ }
+
+ const allReleases = Array.from(albumMap.values()).sort((a, b) =>
new Date(b.releaseDate || 0) - new Date(a.releaseDate || 0)
);
+ const eps = allReleases.filter(a =>
+ a.type === 'EP' ||
+ a.type === 'SINGLE' ||
+ (a.numberOfTracks < 7 && !a.type)
+ );
+ const albums = allReleases.filter(a => !eps.includes(a));
+
const tracks = Array.from(trackMap.values())
.sort((a, b) => (b.popularity || 0) - (a.popularity || 0))
- .slice(0, 10);
+ .slice(0, 15);
- const result = { ...artist, albums, tracks };
+ const result = { ...artist, albums, eps, tracks };
await this.cache.set('artist', artistId, result);
return result;
diff --git a/js/app.js b/js/app.js
index e577baf..e086e50 100644
--- a/js/app.js
+++ b/js/app.js
@@ -418,8 +418,9 @@ document.addEventListener('DOMContentLoaded', async () => {
try {
const artist = await api.getArtist(artistId);
- if (!artist.albums || artist.albums.length === 0) {
- throw new Error("No albums found for this artist");
+ const allReleases = [...(artist.albums || []), ...(artist.eps || [])];
+ if (allReleases.length === 0) {
+ throw new Error("No albums or EPs found for this artist");
}
const trackSet = new Set();
@@ -427,7 +428,7 @@ document.addEventListener('DOMContentLoaded', async () => {
const chunks = [];
const chunkSize = 3;
- const albums = artist.albums;
+ const albums = allReleases;
for (let i = 0; i < albums.length; i += chunkSize) {
chunks.push(albums.slice(i, i + chunkSize));
diff --git a/js/downloads.js b/js/downloads.js
index c652c33..46a0041 100644
--- a/js/downloads.js
+++ b/js/downloads.js
@@ -387,12 +387,13 @@ export async function downloadDiscography(artist, api, quality, lyricsManager =
const template = localStorage.getItem('zip-folder-template') || '{albumTitle} - {albumArtist} - monochrome.tf';
const rootFolder = `${sanitizeForFilename(artist.name)} discography - monochrome.tf`;
- const totalAlbums = artist.albums.length;
+ const allReleases = [...(artist.albums || []), ...(artist.eps || [])];
+ const totalAlbums = allReleases.length;
const notification = createBulkDownloadNotification('discography', artist.name, totalAlbums);
try {
- for (let albumIndex = 0; albumIndex < artist.albums.length; albumIndex++) {
- const album = artist.albums[albumIndex];
+ for (let albumIndex = 0; albumIndex < allReleases.length; albumIndex++) {
+ const album = allReleases[albumIndex];
updateBulkDownloadProgress(notification, albumIndex, totalAlbums, album.title);
diff --git a/js/ui.js b/js/ui.js
index f5ae910..e39e7e6 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -140,6 +140,17 @@ export class UIRenderer {
yearDisplay = `${date.getFullYear()}`;
}
}
+
+ let typeLabel = '';
+ if (album.type === 'EP') {
+ typeLabel = ' • EP';
+ } else if (album.type === 'SINGLE') {
+ typeLabel = ' • Single';
+ } else if (!album.type && album.numberOfTracks) {
+ if (album.numberOfTracks <= 3) typeLabel = ' • Single';
+ else if (album.numberOfTracks <= 6) typeLabel = ' • EP';
+ }
+
return `
@@ -147,7 +158,7 @@ export class UIRenderer {
${album.title} ${explicitBadge}
${album.artist?.name ?? ''}
- ${yearDisplay}
+ ${yearDisplay}${typeLabel}
`;
}
@@ -557,43 +568,57 @@ export class UIRenderer {
document.title = `${album.title} - ${album.artist.name} - Monochrome`;
- // "More from Artist" Section
+ // "More from Artist" Sections
try {
- // Remove any existing "More from" section if re-rendering
- const existingMoreSection = document.getElementById('album-more-from-artist');
- if (existingMoreSection) existingMoreSection.remove();
+ // Remove any existing "More from" sections if re-rendering
+ document.querySelectorAll('.album-more-section').forEach(el => el.remove());
+ document.getElementById('album-more-from-artist')?.remove(); // Legacy cleanup
- const moreSection = document.createElement('section');
- moreSection.id = 'album-more-from-artist';
- moreSection.className = 'content-section';
- moreSection.style.marginTop = '3rem';
- moreSection.innerHTML = `
+ // Create placeholder section while loading
+ const placeholderSection = document.createElement('section');
+ placeholderSection.className = 'content-section album-more-section';
+ placeholderSection.style.marginTop = '3rem';
+ placeholderSection.innerHTML = `
More from ${album.artist.name}
-
+
${this.createSkeletonCards(6, false)}
`;
- document.getElementById('page-album').appendChild(moreSection);
+ document.getElementById('page-album').appendChild(placeholderSection);
const artistData = await this.api.getArtist(album.artist.id);
- // Filter out current album and duplicates
- const otherAlbums = artistData.albums
- .filter(a => a.id != album.id)
- .filter((a, index, self) =>
- index === self.findIndex((t) => t.title === a.title) // Dedup by title
- )
- .slice(0, 12); // Limit to 12
-
- const moreContainer = document.getElementById('album-more-albums');
- if (otherAlbums.length > 0) {
- moreContainer.innerHTML = otherAlbums.map(a => this.createAlbumCardHTML(a)).join('');
- } else {
- moreSection.remove(); // Remove section if no other albums
- }
+ // Remove placeholder
+ placeholderSection.remove();
+
+ const renderSection = (title, items) => {
+ const filtered = (items || [])
+ .filter(a => a.id != album.id)
+ .filter((a, index, self) =>
+ index === self.findIndex((t) => t.title === a.title) // Dedup by title
+ )
+ .slice(0, 12);
+
+ if (filtered.length === 0) return;
+
+ const section = document.createElement('section');
+ section.className = 'content-section album-more-section';
+ section.style.marginTop = '3rem';
+ section.innerHTML = `
+
${title}
+
+ ${filtered.map(a => this.createAlbumCardHTML(a)).join('')}
+
+ `;
+ document.getElementById('page-album').appendChild(section);
+ };
+
+ renderSection(`More albums from ${album.artist.name}`, artistData.albums);
+ renderSection(`EPs and Singles from ${album.artist.name}`, artistData.eps);
+
} catch (err) {
console.warn('Failed to load "More from artist":', err);
- document.getElementById('album-more-from-artist')?.remove();
+ document.querySelectorAll('.album-more-section').forEach(el => el.remove());
}
} catch (error) {
@@ -672,6 +697,8 @@ async renderPlaylistPage(playlistId) {
const metaEl = document.getElementById('artist-detail-meta');
const tracksContainer = document.getElementById('artist-detail-tracks');
const albumsContainer = document.getElementById('artist-detail-albums');
+ const epsContainer = document.getElementById('artist-detail-eps');
+ const epsSection = document.getElementById('artist-section-eps');
const dlBtn = document.getElementById('download-discography-btn');
if (dlBtn) dlBtn.innerHTML = `${SVG_DOWNLOAD}
Download Discography`;
@@ -681,6 +708,8 @@ async renderPlaylistPage(playlistId) {
metaEl.innerHTML = '
';
tracksContainer.innerHTML = this.createSkeletonTracks(5, true);
albumsContainer.innerHTML = this.createSkeletonCards(6, false);
+ if (epsContainer) epsContainer.innerHTML = this.createSkeletonCards(6, false);
+ if (epsSection) epsSection.style.display = 'none';
try {
const artist = await this.api.getArtist(artistId);
@@ -702,9 +731,21 @@ async renderPlaylistPage(playlistId) {
`;
this.renderListWithTracks(tracksContainer, artist.tracks, true);
- albumsContainer.innerHTML = artist.albums.map(album =>
- this.createAlbumCardHTML(album)
- ).join('');
+
+ // Render Albums
+ albumsContainer.innerHTML = artist.albums.length
+ ? artist.albums.map(album => this.createAlbumCardHTML(album)).join('')
+ : createPlaceholder('No albums found.');
+
+ // Render EPs and Singles
+ if (epsContainer && epsSection) {
+ if (artist.eps && artist.eps.length > 0) {
+ epsContainer.innerHTML = artist.eps.map(album => this.createAlbumCardHTML(album)).join('');
+ epsSection.style.display = 'block';
+ } else {
+ epsSection.style.display = 'none';
+ }
+ }
recentActivityManager.addArtist(artist);