From c96f5b207d3e656e4d89aef910fa7e1ec9335f28 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Thu, 26 Sep 2024 11:14:06 -0700 Subject: [PATCH] Handle subsonic endpoints that potentially return optional response when no items --- .../api/subsonic/subsonic-controller.ts | 50 +++++++-------- src/renderer/api/subsonic/subsonic-types.ts | 64 +++++++++++-------- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/renderer/api/subsonic/subsonic-controller.ts b/src/renderer/api/subsonic/subsonic-controller.ts index 7c294698..c87bb4e6 100644 --- a/src/renderer/api/subsonic/subsonic-controller.ts +++ b/src/renderer/api/subsonic/subsonic-controller.ts @@ -270,7 +270,7 @@ export const SubsonicController: ControllerEndpoint = { } const results = - res.body.searchResult3.album?.map((album) => + res.body.searchResult3?.album?.map((album) => ssNormalize.album(album, apiClientProps.server), ) || []; @@ -325,14 +325,14 @@ export const SubsonicController: ControllerEndpoint = { } const results = - res.body.starred.album?.map((album) => + res.body.starred?.album?.map((album) => ssNormalize.album(album, apiClientProps.server), ) || []; return { items: sortAlbumList(results, query.sortBy, query.sortOrder), startIndex: 0, - totalRecordCount: res.body.starred.album?.length || 0, + totalRecordCount: res.body.starred?.album?.length || 0, }; } @@ -410,7 +410,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get album list count'); } - const albumCount = res.body.searchResult3.album?.length; + const albumCount = (res.body.searchResult3?.album || [])?.length; totalRecordCount += albumCount; startIndex += albumCount; @@ -433,7 +433,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get album list'); } - return res.body.starred.album?.length || 0; + return (res.body.starred?.album || []).length || 0; } let type = ALBUM_LIST_SORT_MAPPING[query.sortBy] ?? AlbumListSortType.ALPHABETICAL_BY_NAME; @@ -523,7 +523,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get genre list'); } - let results = res.body.genres.genre; + let results = res.body.genres?.genre || []; if (query.searchTerm) { const searchResults = filter(results, (genre) => @@ -588,7 +588,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get playlist list'); } - let results = res.body.playlists.playlist; + let results = res.body.playlists?.playlist || []; if (query.searchTerm) { const searchResults = filter(results, (playlist) => { @@ -634,7 +634,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get playlist list'); } - let results = res.body.playlists.playlist; + let results = res.body.playlists?.playlist || []; if (query.searchTerm) { const searchResults = filter(results, (playlist) => { @@ -689,10 +689,10 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get random songs'); } + const results = res.body.randomSongs?.song || []; + return { - items: res.body.randomSongs?.song?.map((song) => - ssNormalize.song(song, apiClientProps.server, ''), - ), + items: results.map((song) => ssNormalize.song(song, apiClientProps.server, '')), startIndex: 0, totalRecordCount: res.body.randomSongs?.song?.length || 0, }; @@ -818,11 +818,11 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list'); } + const results = res.body.songsByGenre?.song || []; + return { items: - res.body.songsByGenre.song?.map((song) => - ssNormalize.song(song, apiClientProps.server, ''), - ) || [], + results.map((song) => ssNormalize.song(song, apiClientProps.server, '')) || [], startIndex: 0, totalRecordCount: null, }; @@ -840,14 +840,14 @@ export const SubsonicController: ControllerEndpoint = { } const results = - res.body.starred.song?.map((song) => + (res.body.starred?.song || []).map((song) => ssNormalize.song(song, apiClientProps.server, ''), ) || []; return { items: sortSongList(results, query.sortBy, query.sortOrder), startIndex: 0, - totalRecordCount: res.body.starred.song?.length || 0, + totalRecordCount: (res.body.starred?.song || []).length || 0, }; } @@ -973,7 +973,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list count'); } - const songCount = res.body.searchResult3.song?.length || 0; + const songCount = (res.body.searchResult3?.song || []).length || 0; totalRecordCount += songCount; startIndex += songCount; @@ -1001,7 +1001,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list count'); } - const numberOfResults = res.body.songsByGenre.song?.length || 0; + const numberOfResults = (res.body.songsByGenre?.song || []).length || 0; if (numberOfResults !== 1) { fetchNextSection = false; @@ -1026,7 +1026,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list count'); } - const numberOfResults = res.body.songsByGenre.song?.length || 0; + const numberOfResults = (res.body.songsByGenre?.song || []).length || 0; totalRecordCount = startIndex + numberOfResults; startIndex += numberOfResults; @@ -1048,7 +1048,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list'); } - return res.body.starred.song?.length || 0; + return (res.body.starred?.song || []).length || 0; } let totalRecordCount = 0; @@ -1070,7 +1070,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list count'); } - const numberOfResults = res.body.searchResult3.song?.length || 0; + const numberOfResults = (res.body.searchResult3?.song || []).length || 0; // Check each batch of 5000 songs to check for data sectionIndex += 5000; @@ -1099,7 +1099,7 @@ export const SubsonicController: ControllerEndpoint = { throw new Error('Failed to get song list count'); } - const numberOfResults = res.body.searchResult3.song?.length || 0; + const numberOfResults = (res.body.searchResult3?.song || []).length || 0; totalRecordCount = startIndex + numberOfResults; startIndex += numberOfResults; @@ -1237,13 +1237,13 @@ export const SubsonicController: ControllerEndpoint = { } return { - albumArtists: res.body.searchResult3?.artist?.map((artist) => + albumArtists: (res.body.searchResult3?.artist || [])?.map((artist) => ssNormalize.albumArtist(artist, apiClientProps.server), ), - albums: res.body.searchResult3?.album?.map((album) => + albums: (res.body.searchResult3?.album || []).map((album) => ssNormalize.album(album, apiClientProps.server), ), - songs: res.body.searchResult3?.song?.map((song) => + songs: (res.body.searchResult3?.song || []).map((song) => ssNormalize.song(song, apiClientProps.server, ''), ), }; diff --git a/src/renderer/api/subsonic/subsonic-types.ts b/src/renderer/api/subsonic/subsonic-types.ts index 7f5ae6c6..3ac3c81e 100644 --- a/src/renderer/api/subsonic/subsonic-types.ts +++ b/src/renderer/api/subsonic/subsonic-types.ts @@ -190,9 +190,11 @@ const topSongsListParameters = z.object({ }); const topSongsList = z.object({ - topSongs: z.object({ - song: z.array(song), - }), + topSongs: z + .object({ + song: z.array(song), + }) + .optional(), }); const scrobbleParameters = z.object({ @@ -204,11 +206,13 @@ const scrobbleParameters = z.object({ const scrobble = z.null(); const search3 = z.object({ - searchResult3: z.object({ - album: z.array(album), - artist: z.array(albumArtist), - song: z.array(song), - }), + searchResult3: z + .object({ + album: z.array(album).optional(), + artist: z.array(albumArtist).optional(), + song: z.array(song).optional(), + }) + .optional(), }); const search3Parameters = z.object({ @@ -231,9 +235,11 @@ const randomSongListParameters = z.object({ }); const randomSongList = z.object({ - randomSongs: z.object({ - song: z.array(song), - }), + randomSongs: z + .object({ + song: z.array(song), + }) + .optional(), }); const ping = z.object({ @@ -310,11 +316,13 @@ const getStarredParameters = z.object({ }); const getStarred = z.object({ - starred: z.object({ - album: z.array(albumListEntry), - artist: z.array(artistListEntry), - song: z.array(song), - }), + starred: z + .object({ + album: z.array(albumListEntry), + artist: z.array(artistListEntry), + song: z.array(song), + }) + .optional(), }); const getSongsByGenreParameters = z.object({ @@ -325,9 +333,11 @@ const getSongsByGenreParameters = z.object({ }); const getSongsByGenre = z.object({ - songsByGenre: z.object({ - song: z.array(song), - }), + songsByGenre: z + .object({ + song: z.array(song), + }) + .optional(), }); const getAlbumParameters = z.object({ @@ -408,9 +418,11 @@ const playlistListEntry = playlist.omit({ }); const getPlaylists = z.object({ - playlists: z.object({ - playlist: z.array(playlistListEntry), - }), + playlists: z + .object({ + playlist: z.array(playlistListEntry), + }) + .optional(), }); const getPlaylistParameters = z.object({ @@ -430,9 +442,11 @@ const genre = z.object({ const getGenresParameters = z.object({}); const getGenres = z.object({ - genres: z.object({ - genre: z.array(genre), - }), + genres: z + .object({ + genre: z.array(genre), + }) + .optional(), }); export enum AlbumListSortType {