diff --git a/src/renderer/api/jellyfin/jellyfin-controller.ts b/src/renderer/api/jellyfin/jellyfin-controller.ts index 1a77a7f7d..956713e5c 100644 --- a/src/renderer/api/jellyfin/jellyfin-controller.ts +++ b/src/renderer/api/jellyfin/jellyfin-controller.ts @@ -531,12 +531,7 @@ export const JellyfinController: InternalControllerEndpoint = { const albumIdSet = new Set([query.id]); const songs = songsRes.body.Items.filter((item) => albumIdSet.has(item.AlbumId!)); - return jfNormalize.album( - { ...res.body, Songs: songs }, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ); + return jfNormalize.album({ ...res.body, Songs: songs }, apiClientProps.server); }, getAlbumList: async (args) => { const { apiClientProps, query } = args; @@ -630,14 +625,7 @@ export const JellyfinController: InternalControllerEndpoint = { throw new Error('Failed to get album radio songs'); } - return res.body.Items.map((song) => - jfNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + return res.body.Items.map((song) => jfNormalize.song(song, apiClientProps.server)); }, getArtistList: async (args) => { const { apiClientProps, query } = args; @@ -693,14 +681,7 @@ export const JellyfinController: InternalControllerEndpoint = { throw new Error('Failed to get artist radio songs'); } - return res.body.Items.map((song) => - jfNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + return res.body.Items.map((song) => jfNormalize.song(song, apiClientProps.server)); }, getDownloadUrl: (args) => { const { apiClientProps, query } = args; @@ -870,8 +851,6 @@ export const JellyfinController: InternalControllerEndpoint = { jfNormalize.song( item as unknown as z.infer, apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, ), ); @@ -1100,14 +1079,7 @@ export const JellyfinController: InternalControllerEndpoint = { } return { - items: res.body.Items.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server)), startIndex: 0, totalRecordCount: res.body.TotalRecordCount, }; @@ -1160,14 +1132,7 @@ export const JellyfinController: InternalControllerEndpoint = { } return { - items: res.body.Items.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server)), startIndex: 0, totalRecordCount: res.body.Items.length || 0, }; @@ -1219,14 +1184,7 @@ export const JellyfinController: InternalControllerEndpoint = { if (res.status === 200 && res.body.Items.length) { const results = res.body.Items.reduce((acc, song) => { if (song.Id !== query.songId) { - acc.push( - jfNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + acc.push(jfNormalize.song(song, apiClientProps.server)); } return acc; @@ -1255,14 +1213,7 @@ export const JellyfinController: InternalControllerEndpoint = { return mix.body.Items.reduce((acc, song) => { if (song.Id !== query.songId) { - acc.push( - jfNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + acc.push(jfNormalize.song(song, apiClientProps.server)); } return acc; @@ -1282,12 +1233,7 @@ export const JellyfinController: InternalControllerEndpoint = { throw new Error('Failed to get song detail'); } - return jfNormalize.song( - res.body, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ); + return jfNormalize.song(res.body, apiClientProps.server); }, getSongList: async (args) => { const { apiClientProps, query } = args; @@ -1399,14 +1345,7 @@ export const JellyfinController: InternalControllerEndpoint = { } return { - items: items.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + items: items.map((item) => jfNormalize.song(item, apiClientProps.server)), startIndex: query.startIndex, totalRecordCount, }; @@ -1538,14 +1477,7 @@ export const JellyfinController: InternalControllerEndpoint = { throw new Error('Failed to get top song list'); } - const items = res.body.Items.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + const items = res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server)); if (type === 'personal') { const sorted = orderBy( @@ -1647,12 +1579,7 @@ export const JellyfinController: InternalControllerEndpoint = { } const existingSongs = existingSongsRes.body.Items.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + jfNormalize.song(item, apiClientProps.server), ); // 2. Get playlist detail to get the name @@ -1903,14 +1830,7 @@ export const JellyfinController: InternalControllerEndpoint = { jfNormalize.albumArtist(item, apiClientProps.server), ), albums: albums.map((item) => jfNormalize.album(item, apiClientProps.server)), - songs: songs.map((item) => - jfNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + songs: songs.map((item) => jfNormalize.song(item, apiClientProps.server)), }; }, setPlaylistSongs: async (args) => { diff --git a/src/renderer/api/navidrome/navidrome-controller.ts b/src/renderer/api/navidrome/navidrome-controller.ts index 0c8416f75..7d38afe09 100644 --- a/src/renderer/api/navidrome/navidrome-controller.ts +++ b/src/renderer/api/navidrome/navidrome-controller.ts @@ -367,7 +367,7 @@ export const NavidromeController: InternalControllerEndpoint = { query: { ...query, limit: 1, startIndex: 0 }, }).then((result) => result!.totalRecordCount!), getAlbumDetail: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const albumRes = await ndApiClient(apiClientProps).getAlbumDetail({ params: { @@ -393,8 +393,6 @@ export const NavidromeController: InternalControllerEndpoint = { return ndNormalize.album( { ...albumRes.body.data, songs: songsData.body.data }, apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, ); }, getAlbumInfo: async (args) => { @@ -418,7 +416,7 @@ export const NavidromeController: InternalControllerEndpoint = { }; }, getAlbumList: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const genres = hasFeature(apiClientProps.server, ServerFeature.BFR) ? query.genreIds @@ -453,14 +451,7 @@ export const NavidromeController: InternalControllerEndpoint = { } return { - items: res.body.data.map((album) => - ndNormalize.album( - album, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ), + items: res.body.data.map((album) => ndNormalize.album(album, apiClientProps.server)), startIndex: query?.startIndex || 0, totalRecordCount: Number(res.body.headers.get('x-total-count') || 0), }; @@ -493,12 +484,7 @@ export const NavidromeController: InternalControllerEndpoint = { } return res.body.similarSongs.song.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ); }, getArtistList: async (args) => { @@ -568,12 +554,7 @@ export const NavidromeController: InternalControllerEndpoint = { } return res.body.similarSongs2.song.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ); }, getDownloadUrl: SubsonicController.getDownloadUrl, @@ -723,14 +704,7 @@ export const NavidromeController: InternalControllerEndpoint = { } return { - items: res.body.data.map((item) => - ndNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + items: res.body.data.map((item) => ndNormalize.song(item, apiClientProps.server)), startIndex: 0, totalRecordCount: Number(res.body.headers.get('x-total-count') || 0), }; @@ -747,14 +721,7 @@ export const NavidromeController: InternalControllerEndpoint = { const { changedBy, current, items = [], position, updatedAt } = res.body.data; // if there is no queue saved, items is undefined - const entries = items.map((song) => - ndNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + const entries = items.map((song) => ndNormalize.song(song, apiClientProps.server)); return { changed: updatedAt, @@ -830,14 +797,7 @@ export const NavidromeController: InternalControllerEndpoint = { return ( (res.body.similarSongs?.song || []) .filter((song) => song.id !== query.songId) - .map((song) => - ssNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ) || [] + .map((song) => ssNormalize.song(song, apiClientProps.server)) || [] ); }, getSongDetail: async (args) => { @@ -853,12 +813,7 @@ export const NavidromeController: InternalControllerEndpoint = { throw new Error('Failed to get song detail'); } - return ndNormalize.song( - res.body.data, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ); + return ndNormalize.song(res.body.data, apiClientProps.server); }, getSongList: async (args) => { const { apiClientProps, query } = args; @@ -898,14 +853,7 @@ export const NavidromeController: InternalControllerEndpoint = { } return { - items: res.body.data.map((song) => - ndNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + items: res.body.data.map((song) => ndNormalize.song(song, apiClientProps.server)), totalRecordCount: Number(res.body.headers.get('x-total-count') || 0), }; }; @@ -1022,12 +970,7 @@ export const NavidromeController: InternalControllerEndpoint = { return { items: (res.body.topSongs?.song || []).map((song) => - ssNormalize.song( - song, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ), startIndex: 0, totalRecordCount: res.body.topSongs?.song?.length || 0, @@ -1036,7 +979,6 @@ export const NavidromeController: InternalControllerEndpoint = { const res = await NavidromeController.getSongList({ apiClientProps, - context: args.context, query: { artistIds: [query.artistId], sortBy: SongListSort.PLAY_COUNT, @@ -1138,12 +1080,7 @@ export const NavidromeController: InternalControllerEndpoint = { } const existingSongs = existingSongsRes.body.data.map((item) => - ndNormalize.song( - item, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ndNormalize.song(item, apiClientProps.server), ); // 2. Get playlist detail to get the name diff --git a/src/renderer/api/subsonic/subsonic-controller.ts b/src/renderer/api/subsonic/subsonic-controller.ts index f468e439e..ae90fa10d 100644 --- a/src/renderer/api/subsonic/subsonic-controller.ts +++ b/src/renderer/api/subsonic/subsonic-controller.ts @@ -482,14 +482,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { ...ssNormalize.albumArtist(artist, apiClientProps.server), - albums: artist.album?.map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ), + albums: artist.album?.map((album) => ssNormalize.album(album, apiClientProps.server)), similarArtists: null, }; }, @@ -564,7 +557,6 @@ export const SubsonicController: InternalControllerEndpoint = { getAlbumArtistListCount: (args) => SubsonicController.getAlbumArtistList({ ...args, - context: args.context, query: { ...args.query, startIndex: 0 }, }).then((res) => res!.totalRecordCount!), getAlbumDetail: async (args) => { @@ -580,12 +572,7 @@ export const SubsonicController: InternalControllerEndpoint = { throw new Error('Failed to get album detail'); } - return ssNormalize.album( - res.body.album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ); + return ssNormalize.album(res.body.album, apiClientProps.server); }, getAlbumList: async (args) => { const { apiClientProps, query } = args; @@ -610,12 +597,7 @@ export const SubsonicController: InternalControllerEndpoint = { const results = res.body.searchResult3?.album?.map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.album(album, apiClientProps.server), ) || []; return { @@ -650,14 +632,7 @@ export const SubsonicController: InternalControllerEndpoint = { return artist.body.artist.album ?? []; }); - const items = albums.map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), - ); + const items = albums.map((album) => ssNormalize.album(album, apiClientProps.server)); return { items: sortAlbumList(items, query.sortBy, query.sortOrder), @@ -679,12 +654,7 @@ export const SubsonicController: InternalControllerEndpoint = { const allResults = res.body.starred?.album?.map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.album(album, apiClientProps.server), ) || []; return sortAndPaginate(allResults, { @@ -749,12 +719,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { items: res.body.albumList2.album?.map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.album(album, apiClientProps.server), ) || [], startIndex: query.startIndex, totalRecordCount: null, @@ -905,7 +870,7 @@ export const SubsonicController: InternalControllerEndpoint = { return totalRecordCount; }, getAlbumRadio: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).getSimilarSongs({ query: { @@ -923,12 +888,7 @@ export const SubsonicController: InternalControllerEndpoint = { } return res.body.similarSongs.song.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ); }, getArtistList: async (args) => { @@ -974,11 +934,10 @@ export const SubsonicController: InternalControllerEndpoint = { getArtistListCount: async (args) => SubsonicController.getArtistList({ ...args, - context: args.context, query: { ...args.query, startIndex: 0 }, }).then((res) => res!.totalRecordCount!), getArtistRadio: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).getSimilarSongs2({ query: { @@ -996,12 +955,7 @@ export const SubsonicController: InternalControllerEndpoint = { } return res.body.similarSongs2.song.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ); }, getDownloadUrl: (args) => { @@ -1015,7 +969,7 @@ export const SubsonicController: InternalControllerEndpoint = { '&c=Feishin' ); }, - getFolder: async ({ apiClientProps, context, query }) => { + getFolder: async ({ apiClientProps, query }) => { const sortOrder = (query.sortOrder?.toLowerCase() ?? 'asc') as 'asc' | 'desc'; const isRootFolderId = query.id === '0'; @@ -1048,14 +1002,7 @@ export const SubsonicController: InternalControllerEndpoint = { }); } - let folders = items.map((item) => - ssNormalize.folder( - item, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ); + let folders = items.map((item) => ssNormalize.folder(item, apiClientProps.server)); folders = orderBy(folders, [(v) => v.name.toLowerCase()], [sortOrder]); @@ -1083,12 +1030,7 @@ export const SubsonicController: InternalControllerEndpoint = { throw new Error('Failed to get folder'); } - const folder = ssNormalize.folder( - directoryRes.body.directory, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ); + const folder = ssNormalize.folder(directoryRes.body.directory, apiClientProps.server); let filteredFolders = folder.children?.folders || []; let filteredSongs = folder.children?.songs || []; @@ -1281,7 +1223,7 @@ export const SubsonicController: InternalControllerEndpoint = { return results.length; }, - getPlaylistSongList: async ({ apiClientProps, context, query }) => { + getPlaylistSongList: async ({ apiClientProps, query }) => { const res = await ssApiClient(apiClientProps).getPlaylist({ query: { id: query.id, @@ -1294,13 +1236,7 @@ export const SubsonicController: InternalControllerEndpoint = { const items = res.body.playlist.entry?.map((song, index) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - index, - ), + ssNormalize.song(song, apiClientProps.server, index), ) || []; return { @@ -1309,7 +1245,7 @@ export const SubsonicController: InternalControllerEndpoint = { totalRecordCount: items.length, }; }, - getPlayQueue: async ({ apiClientProps, context }) => { + getPlayQueue: async ({ apiClientProps }) => { if (hasFeature(apiClientProps.server, ServerFeature.SERVER_PLAY_QUEUE)) { const res = await ssApiClient(apiClientProps).getPlayQueueByIndex(); @@ -1324,15 +1260,7 @@ export const SubsonicController: InternalControllerEndpoint = { changed: changed ?? '', changedBy: changedBy ?? '', currentIndex: currentIndex ?? 0, - entry: - entry?.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ) || [], + entry: entry?.map((song) => ssNormalize.song(song, apiClientProps.server)) || [], positionMs: position ?? 0, username: username ?? '', }; @@ -1349,22 +1277,14 @@ export const SubsonicController: InternalControllerEndpoint = { changed, changedBy, currentIndex: current ? entry.findIndex((item) => item.id === current) : 0, - entry: - entry?.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ) || [], + entry: entry?.map((song) => ssNormalize.song(song, apiClientProps.server)) || [], positionMs: position ?? 0, username, }; } }, getRandomSongList: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).getRandomSongList({ query: { @@ -1382,12 +1302,7 @@ export const SubsonicController: InternalControllerEndpoint = { const results = res.body.randomSongs?.song || []; const normalizedResults = results.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ); return { @@ -1473,7 +1388,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { features, id: apiClientProps.server?.id, version: ping.body.serverVersion }; }, getSimilarSongs: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).getSimilarSongs({ query: { @@ -1492,21 +1407,14 @@ export const SubsonicController: InternalControllerEndpoint = { return res.body.similarSongs.song.reduce((acc, song) => { if (song.id !== query.songId) { - acc.push( - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ); + acc.push(ssNormalize.song(song, apiClientProps.server)); } return acc; }, []); }, getSongDetail: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).getSong({ query: { @@ -1518,14 +1426,9 @@ export const SubsonicController: InternalControllerEndpoint = { throw new Error('Failed to get song detail'); } - return ssNormalize.song( - res.body.song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ); + return ssNormalize.song(res.body.song, apiClientProps.server); }, - getSongList: async ({ apiClientProps, context, query }) => { + getSongList: async ({ apiClientProps, query }) => { const fromAlbumPromises: Promise>[] = []; const artistDetailPromises: Promise>[] = []; @@ -1550,12 +1453,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { items: res.body.searchResult3?.song?.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ) || [], startIndex: query.startIndex, totalRecordCount: null, @@ -1579,15 +1477,7 @@ export const SubsonicController: InternalControllerEndpoint = { const results = res.body.songsByGenre?.song || []; return { - items: - results.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ) || [], + items: results.map((song) => ssNormalize.song(song, apiClientProps.server)) || [], startIndex: 0, totalRecordCount: null, }; @@ -1606,12 +1496,7 @@ export const SubsonicController: InternalControllerEndpoint = { let allResults = (res.body.starred?.song || []).map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ) || []; const filterArtistIds = query.albumArtistIds || query.artistIds; @@ -1696,15 +1581,7 @@ export const SubsonicController: InternalControllerEndpoint = { } return { - items: - results.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), - ) || [], + items: results.map((song) => ssNormalize.song(song, apiClientProps.server)) || [], startIndex: 0, totalRecordCount: results.length, }; @@ -1730,12 +1607,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { items: res.body.searchResult3?.song?.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ) || [], startIndex: 0, totalRecordCount: null, @@ -2103,7 +1975,7 @@ export const SubsonicController: InternalControllerEndpoint = { }); }, getTopSongs: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const type = query.type === 'personal' ? 'personal' : 'community'; @@ -2121,12 +1993,7 @@ export const SubsonicController: InternalControllerEndpoint = { return { items: (res.body.topSongs?.song || []).map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ), startIndex: 0, totalRecordCount: res.body.topSongs?.song?.length || 0, @@ -2135,7 +2002,6 @@ export const SubsonicController: InternalControllerEndpoint = { const res = await SubsonicController.getSongList({ apiClientProps, - context, query: { artistIds: [query.artistId], sortBy: SongListSort.PLAY_COUNT, @@ -2190,7 +2056,7 @@ export const SubsonicController: InternalControllerEndpoint = { return null; }, replacePlaylist: async (args) => { - const { apiClientProps, body, context, query } = args; + const { apiClientProps, body, query } = args; // 1. Fetch existing songs from the playlist const existingSongsRes = await ssApiClient(apiClientProps).getPlaylist({ @@ -2205,12 +2071,7 @@ export const SubsonicController: InternalControllerEndpoint = { const existingSongs = existingSongsRes.body.playlist.entry?.map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ) || []; // 2. Get playlist detail to get the name @@ -2388,7 +2249,7 @@ export const SubsonicController: InternalControllerEndpoint = { return null; }, search: async (args) => { - const { apiClientProps, context, query } = args; + const { apiClientProps, query } = args; const res = await ssApiClient(apiClientProps).search3({ query: { @@ -2412,20 +2273,10 @@ export const SubsonicController: InternalControllerEndpoint = { ssNormalize.albumArtist(artist, apiClientProps.server), ), albums: (res.body.searchResult3?.album || []).map((album) => - ssNormalize.album( - album, - apiClientProps.server, - args.context?.pathReplace, - args.context?.pathReplaceWith, - ), + ssNormalize.album(album, apiClientProps.server), ), songs: (res.body.searchResult3?.song || []).map((song) => - ssNormalize.song( - song, - apiClientProps.server, - context?.pathReplace, - context?.pathReplaceWith, - ), + ssNormalize.song(song, apiClientProps.server), ), }; }, diff --git a/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx b/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx index df244597d..eb43ba975 100644 --- a/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx +++ b/src/renderer/components/item-list/item-detail-list/columns/path-column.tsx @@ -1,3 +1,5 @@ import { ItemDetailListCellProps } from './types'; +import { resolveSongPath } from '/@/renderer/utils/resolve-song-path'; -export const PathColumn = ({ song }: ItemDetailListCellProps) => song.path ?? <> ; +export const PathColumn = ({ song }: ItemDetailListCellProps) => + resolveSongPath(song.path) ?? <> ; diff --git a/src/renderer/components/item-list/item-table-list/columns/path-column.tsx b/src/renderer/components/item-list/item-table-list/columns/path-column.tsx index 52f5ef289..a48f759a2 100644 --- a/src/renderer/components/item-list/item-table-list/columns/path-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/path-column.tsx @@ -4,15 +4,17 @@ import { ItemTableListInnerColumn, TableColumnTextContainer, } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { resolveSongPath } from '/@/renderer/utils/resolve-song-path'; export const PathColumn = (props: ItemTableListInnerColumn) => { const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex]; const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id]; + const resolvedPath = typeof row === 'string' ? resolveSongPath(row) : null; - if (typeof row === 'string' && row) { + if (resolvedPath) { return ( - {row} + {resolvedPath} ); } diff --git a/src/renderer/features/context-menu/actions/show-in-file-explorer-action.tsx b/src/renderer/features/context-menu/actions/show-in-file-explorer-action.tsx index aaf80fcec..3c060c08b 100644 --- a/src/renderer/features/context-menu/actions/show-in-file-explorer-action.tsx +++ b/src/renderer/features/context-menu/actions/show-in-file-explorer-action.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import { ContextMenu } from '/@/shared/components/context-menu/context-menu'; import { toast } from '/@/shared/components/toast/toast'; +import { resolveSongPath } from '/@/renderer/utils/resolve-song-path'; import { QueueSong, Song } from '/@/shared/types/domain-types'; interface ShowInFileExplorerActionProps { @@ -21,12 +22,13 @@ export const ShowInFileExplorerAction = ({ items }: ShowInFileExplorerActionProp } const firstItem = items[0]; - if (!firstItem?.path) { + const resolvedPath = resolveSongPath(firstItem?.path); + if (!resolvedPath) { return; } try { - await utils.openItem(firstItem.path); + await utils.openItem(resolvedPath); } catch (error) { toast.error({ message: (error as Error).message, diff --git a/src/renderer/features/item-details/components/song-path.tsx b/src/renderer/features/item-details/components/song-path.tsx index 68bfc9c45..436a2b9c4 100644 --- a/src/renderer/features/item-details/components/song-path.tsx +++ b/src/renderer/features/item-details/components/song-path.tsx @@ -1,6 +1,7 @@ import isElectron from 'is-electron'; import { useTranslation } from 'react-i18next'; +import { useResolvedSongPath } from '/@/renderer/utils/resolve-song-path'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { CopyButton } from '/@/shared/components/copy-button/copy-button'; import { Group } from '/@/shared/components/group/group'; @@ -17,12 +18,13 @@ export type SongPathProps = { export const SongPath = ({ path }: SongPathProps) => { const { t } = useTranslation(); + const resolvedPath = useResolvedSongPath(path); - if (!path) return null; + if (!resolvedPath) return null; return ( - + {({ copied, copy }) => ( { { - util.openItem(path).catch((error) => { + util.openItem(resolvedPath).catch((error) => { toast.error({ message: (error as Error).message, title: t('error.openError'), @@ -53,7 +55,7 @@ export const SongPath = ({ path }: SongPathProps) => { /> )} - {path} + {resolvedPath} ); }; diff --git a/src/renderer/features/player/utils.ts b/src/renderer/features/player/utils.ts index 3119bf704..cfbc3c978 100644 --- a/src/renderer/features/player/utils.ts +++ b/src/renderer/features/player/utils.ts @@ -6,6 +6,7 @@ import { folderQueries } from '/@/renderer/features/folders/api/folder-api'; import { PlayerFilter, useSettingsStore } from '/@/renderer/store'; import { LogCategory, logFn } from '/@/renderer/utils/logger'; import { logMsg } from '/@/renderer/utils/logger-message'; +import { resolveSongPath } from '/@/renderer/utils/resolve-song-path'; import { sortSongList } from '/@/shared/api/utils'; import { PlaylistSongListQuery, @@ -351,7 +352,7 @@ const getSongFieldValue = (song: Song, field: string): boolean | null | number | case 'note': return song.comment || ''; case 'path': - return song.path || ''; + return resolveSongPath(song.path) || ''; case 'playCount': return song.playCount; case 'rating': diff --git a/src/renderer/features/settings/components/general/path-settings.tsx b/src/renderer/features/settings/components/general/path-settings.tsx index cf65728db..84170447d 100644 --- a/src/renderer/features/settings/components/general/path-settings.tsx +++ b/src/renderer/features/settings/components/general/path-settings.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import { songsQueries } from '/@/renderer/features/songs/api/songs-api'; import { useCurrentServerId, useGeneralSettings, useSettingsStoreActions } from '/@/renderer/store'; +import { useResolvedSongPath } from '/@/renderer/utils/resolve-song-path'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Code } from '/@/shared/components/code/code'; import { Group } from '/@/shared/components/group/group'; @@ -27,6 +28,7 @@ export const PathSettings = memo(() => { const { pathReplace, pathReplaceWith } = useGeneralSettings(); const { setSettings } = useSettingsStoreActions(); + const resolvedPreviewPath = useResolvedSongPath(randomSong.data?.items[0]?.path); const [localPathReplace, setLocalPathReplace] = useState(pathReplace); const [localPathReplaceWith, setLocalPathReplaceWith] = useState(pathReplaceWith); @@ -45,8 +47,6 @@ export const PathSettings = memo(() => { pathReplace: value, }, }); - - randomSong.refetch(); }, 500); const debouncedSetPathReplaceWith = useDebouncedCallback((value: string) => { @@ -55,8 +55,6 @@ export const PathSettings = memo(() => { pathReplaceWith: value, }, }); - - randomSong.refetch(); }, 500); return ( @@ -73,7 +71,7 @@ export const PathSettings = memo(() => { - {randomSong.data?.items[0]?.path || ''} + {resolvedPreviewPath || ''} diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index f68b655dd..051adcaa8 100644 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -4,6 +4,7 @@ export * from './get-header-color'; export * from './normalize-server-url'; export * from './parse-search-params'; export * from './random-string'; +export * from './resolve-song-path'; export * from './rgb-to-rgba'; export * from './sentence-case'; export * from './set-local-storage-setttings'; diff --git a/src/renderer/utils/resolve-song-path.ts b/src/renderer/utils/resolve-song-path.ts new file mode 100644 index 000000000..1766acd9d --- /dev/null +++ b/src/renderer/utils/resolve-song-path.ts @@ -0,0 +1,26 @@ +import { useMemo } from 'react'; + +import { usePathReplace, useSettingsStore } from '/@/renderer/store/settings.store'; +import { replacePathPrefix } from '/@/shared/api/utils'; + +export const resolveSongPath = (path: null | string | undefined): null | string => { + if (!path) { + return null; + } + + const { pathReplace, pathReplaceWith } = useSettingsStore.getState().general; + + return replacePathPrefix(path, pathReplace, pathReplaceWith); +}; + +export const useResolvedSongPath = (path: null | string | undefined): null | string => { + const { pathReplace, pathReplaceWith } = usePathReplace(); + + return useMemo(() => { + if (!path) { + return null; + } + + return replacePathPrefix(path, pathReplace, pathReplaceWith); + }, [path, pathReplace, pathReplaceWith]); +}; diff --git a/src/shared/api/jellyfin/jellyfin-normalize.ts b/src/shared/api/jellyfin/jellyfin-normalize.ts index e10f85506..bfa827869 100644 --- a/src/shared/api/jellyfin/jellyfin-normalize.ts +++ b/src/shared/api/jellyfin/jellyfin-normalize.ts @@ -2,7 +2,6 @@ import { z } from 'zod'; import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; import { coerceYear, parsePartialIsoDateFromApi } from '/@/shared/api/partial-iso-date'; -import { replacePathPrefix } from '/@/shared/api/utils'; import { Album, AlbumArtist, @@ -156,8 +155,6 @@ const jellyfinPremiereFields = (item: { const normalizeSong = ( item: z.infer, server: null | ServerListItem, - pathReplace?: string, - pathReplaceWith?: string, ): Song => { let bitDepth: null | number = null; let bitRate = 0; @@ -257,7 +254,7 @@ const normalizeSong = ( mbzTrackId: item.ProviderIds?.MusicBrainzTrack || null, name: item.Name, participants, - path: replacePathPrefix(path || '', pathReplace, pathReplaceWith), + path: path || '', peak: null, playCount: (item.UserData && item.UserData.PlayCount) || 0, playlistItemId: item.PlaylistItemId, @@ -278,8 +275,6 @@ const normalizeSong = ( const normalizeAlbum = ( item: z.infer, server: null | ServerListItem, - pathReplace?: string, - pathReplaceWith?: string, ): Album => { const { originalYear, releaseDate, releaseYear } = jellyfinPremiereFields(item); @@ -342,7 +337,7 @@ const normalizeAlbum = ( releaseYear, size: null, songCount: item?.ChildCount || null, - songs: item.Songs?.map((song) => normalizeSong(song, server, pathReplace, pathReplaceWith)), + songs: item.Songs?.map((song) => normalizeSong(song, server)), sortName: item.SortName || item.Name, tags: getTags(item), updatedAt: item?.DateLastMediaAdded || item.DateCreated, diff --git a/src/shared/api/navidrome/navidrome-normalize.ts b/src/shared/api/navidrome/navidrome-normalize.ts index 2a45227e8..ad9b93bf8 100644 --- a/src/shared/api/navidrome/navidrome-normalize.ts +++ b/src/shared/api/navidrome/navidrome-normalize.ts @@ -3,7 +3,6 @@ import z from 'zod'; import { ndType } from '/@/shared/api/navidrome/navidrome-types'; import { coerceYear, parsePartialIsoDate } from '/@/shared/api/partial-iso-date'; import { ssType } from '/@/shared/api/subsonic/subsonic-types'; -import { replacePathPrefix } from '/@/shared/api/utils'; import { Album, AlbumArtist, @@ -199,8 +198,6 @@ const getArtists = ( const normalizeSong = ( item: z.infer | z.infer, server?: null | ServerListItem, - pathReplace?: string, - pathReplaceWith?: string, ): Song => { let id; let playlistItemId; @@ -270,7 +267,7 @@ const normalizeSong = ( name: item.title, // Thankfully, Windows is merciful and allows a mix of separators. So, we can use the // POSIX separator here instead - path: item.path ? replacePathPrefix(item.path, pathReplace, pathReplaceWith) : null, + path: item.path ? `${item.libraryPath}/${item.path}` : null, peak: item.rgAlbumPeak || item.rgTrackPeak ? { album: item.rgAlbumPeak, track: item.rgTrackPeak } @@ -337,8 +334,6 @@ const normalizeAlbum = ( songs?: z.infer; }, server?: null | ServerListItem, - pathReplace?: string, - pathReplaceWith?: string, ): Album => { const releaseDate = normalizeNavidromeReleaseDate(item); const originalDate = normalizeNavidromeOriginalDate(item); @@ -386,9 +381,7 @@ const normalizeAlbum = ( releaseYear: releaseDate.year > 0 ? releaseDate.year : null, size: item.size, songCount: item.songCount, - songs: item.songs - ? item.songs.map((song) => normalizeSong(song, server, pathReplace, pathReplaceWith)) - : undefined, + songs: item.songs ? item.songs.map((song) => normalizeSong(song, server)) : undefined, sortName: item.orderAlbumName, tags: item.tags || null, updatedAt: item.updatedAt, diff --git a/src/shared/api/subsonic/subsonic-normalize.ts b/src/shared/api/subsonic/subsonic-normalize.ts index dbc8ebcfd..e852a55fe 100644 --- a/src/shared/api/subsonic/subsonic-normalize.ts +++ b/src/shared/api/subsonic/subsonic-normalize.ts @@ -2,7 +2,6 @@ import { z } from 'zod'; import { coerceYear, parsePartialIsoDate } from '/@/shared/api/partial-iso-date'; import { ssType } from '/@/shared/api/subsonic/subsonic-types'; -import { replacePathPrefix } from '/@/shared/api/utils'; import { Album, AlbumArtist, @@ -163,8 +162,6 @@ const subsonicReleaseFields = (item: { const normalizeSong = ( item: z.infer, server?: null | ServerListItemWithCredential, - pathReplace?: string, - pathReplaceWith?: string, playlistIndex?: number, discTitleMap?: Map, ): Song => { @@ -221,7 +218,7 @@ const normalizeSong = ( mbzTrackId: null, name: item.title, participants, - path: replacePathPrefix(item.path || '', pathReplace, pathReplaceWith), + path: item.path || '', peak: item.replayGain && (item.replayGain.albumPeak || item.replayGain.trackPeak) ? { @@ -305,8 +302,6 @@ const getReleaseType = ( const normalizeAlbum = ( item: z.infer | z.infer, server?: null | ServerListItemWithCredential, - pathReplace?: string, - pathReplaceWith?: string, ): Album => { const discTitleMap = new Map(); @@ -354,7 +349,7 @@ const normalizeAlbum = ( songCount: item.songCount, songs: (item as z.infer).song?.map((song) => - normalizeSong(song, server, pathReplace, pathReplaceWith, undefined, discTitleMap), + normalizeSong(song, server, undefined, discTitleMap), ) || [], sortName: item.title, tags: null, @@ -410,8 +405,6 @@ const normalizeGenre = ( const normalizeFolder = ( item: z.infer, server?: null | ServerListItemWithCredential, - pathReplace?: string, - pathReplaceWith?: string, ): Folder => { const results = item.child?.reduce( (acc: { folders: Folder[]; songs: Song[] }, item) => { @@ -421,7 +414,7 @@ const normalizeFolder = ( const folder = normalizeFolder(item, server); acc.folders.push(folder); } else { - const song = normalizeSong(item, server, pathReplace, pathReplaceWith); + const song = normalizeSong(item, server); acc.songs.push(song); } diff --git a/src/shared/types/domain-types.ts b/src/shared/types/domain-types.ts index 30e8446e9..dbf2d1e1e 100644 --- a/src/shared/types/domain-types.ts +++ b/src/shared/types/domain-types.ts @@ -414,10 +414,8 @@ export type Song = { userRating: null | number; }; -type ApiContext = { - pathReplace?: string; - pathReplaceWith?: string; -}; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +type ApiContext = {}; type BaseEndpointArgs = { apiClientProps: {