@rmdes/indiekit-endpoint-lastfm 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/lastfm-client.js +18 -0
- package/lib/utils.js +30 -9
- package/package.json +1 -1
package/lib/lastfm-client.js
CHANGED
|
@@ -50,10 +50,28 @@ export class LastFmClient {
|
|
|
50
50
|
},
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
+
// Check content type before parsing
|
|
54
|
+
const contentType = response.headers.get("content-type") || "";
|
|
55
|
+
|
|
53
56
|
if (!response.ok) {
|
|
57
|
+
// Handle non-JSON error responses (e.g., HTML error pages)
|
|
58
|
+
if (!contentType.includes("application/json")) {
|
|
59
|
+
const text = await response.text();
|
|
60
|
+
console.error("[Last.fm] Non-JSON error response:", text.slice(0, 200));
|
|
61
|
+
throw new IndiekitError(`Last.fm API returned ${response.status}: ${response.statusText}`, {
|
|
62
|
+
status: response.status,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
54
65
|
throw await IndiekitError.fromFetch(response);
|
|
55
66
|
}
|
|
56
67
|
|
|
68
|
+
// Handle non-JSON success responses (shouldn't happen but be safe)
|
|
69
|
+
if (!contentType.includes("application/json")) {
|
|
70
|
+
const text = await response.text();
|
|
71
|
+
console.error("[Last.fm] Unexpected non-JSON response:", text.slice(0, 200));
|
|
72
|
+
throw new Error("Last.fm API returned non-JSON response");
|
|
73
|
+
}
|
|
74
|
+
|
|
57
75
|
const data = await response.json();
|
|
58
76
|
|
|
59
77
|
// Check for Last.fm API errors
|
package/lib/utils.js
CHANGED
|
@@ -302,12 +302,18 @@ export function formatLovedTrack(track) {
|
|
|
302
302
|
* @returns {object} - Formatted artist
|
|
303
303
|
*/
|
|
304
304
|
export function formatTopArtist(artist, rank) {
|
|
305
|
+
// Handle edge cases where artist data might be malformed
|
|
306
|
+
let name = artist?.name;
|
|
307
|
+
if (typeof name !== "string") {
|
|
308
|
+
name = name?.["#text"] || String(name || "Unknown Artist");
|
|
309
|
+
}
|
|
310
|
+
|
|
305
311
|
return {
|
|
306
312
|
rank,
|
|
307
|
-
name
|
|
308
|
-
playCount: parseInt(artist
|
|
309
|
-
url: artist
|
|
310
|
-
mbid: artist
|
|
313
|
+
name,
|
|
314
|
+
playCount: parseInt(artist?.playcount) || 0,
|
|
315
|
+
url: artist?.url || null,
|
|
316
|
+
mbid: artist?.mbid || null,
|
|
311
317
|
imageUrl: getCoverUrl(artist),
|
|
312
318
|
};
|
|
313
319
|
}
|
|
@@ -319,13 +325,28 @@ export function formatTopArtist(artist, rank) {
|
|
|
319
325
|
* @returns {object} - Formatted album
|
|
320
326
|
*/
|
|
321
327
|
export function formatTopAlbum(album, rank) {
|
|
328
|
+
// Handle edge cases where album data might be malformed
|
|
329
|
+
let title = album?.name;
|
|
330
|
+
if (typeof title !== "string") {
|
|
331
|
+
title = title?.["#text"] || String(title || "Unknown Album");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Extract artist name from various possible formats
|
|
335
|
+
let artist = album?.artist;
|
|
336
|
+
if (typeof artist === "object" && artist !== null) {
|
|
337
|
+
artist = artist.name || artist["#text"] || "Unknown Artist";
|
|
338
|
+
}
|
|
339
|
+
if (typeof artist !== "string") {
|
|
340
|
+
artist = String(artist || "Unknown Artist");
|
|
341
|
+
}
|
|
342
|
+
|
|
322
343
|
return {
|
|
323
344
|
rank,
|
|
324
|
-
title
|
|
325
|
-
artist
|
|
326
|
-
playCount: parseInt(album
|
|
327
|
-
url: album
|
|
328
|
-
mbid: album
|
|
345
|
+
title,
|
|
346
|
+
artist,
|
|
347
|
+
playCount: parseInt(album?.playcount) || 0,
|
|
348
|
+
url: album?.url || null,
|
|
349
|
+
mbid: album?.mbid || null,
|
|
329
350
|
coverUrl: getCoverUrl(album),
|
|
330
351
|
};
|
|
331
352
|
}
|
package/package.json
CHANGED