mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 12:30:12 +02:00
Add image URL generation at runtime to allow for dynamic image sizes (#1439)
* add getImageUrl to domain endpoints * add new ItemImage component and hooks to generate image url * add configuration for image resolution based on types
This commit is contained in:
@@ -370,6 +370,20 @@ export const controller: GeneralController = {
|
||||
query: mergeMusicFolderId(args.query, server),
|
||||
});
|
||||
},
|
||||
getImageUrl(args) {
|
||||
const server = getServerById(args.apiClientProps.serverId);
|
||||
|
||||
if (!server) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
apiController(
|
||||
'getImageUrl',
|
||||
server.type,
|
||||
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } }) || null
|
||||
);
|
||||
},
|
||||
getInternetRadioStations(args) {
|
||||
const server = getServerById(args.apiClientProps.serverId);
|
||||
|
||||
|
||||
@@ -670,6 +670,22 @@ export const JellyfinController: InternalControllerEndpoint = {
|
||||
totalRecordCount: res.body?.TotalRecordCount || 0,
|
||||
};
|
||||
},
|
||||
getImageUrl: ({ apiClientProps: { server }, query }) => {
|
||||
const { id, size } = query;
|
||||
const imageSize = size;
|
||||
|
||||
if (!server?.url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// For Jellyfin, we construct the URL pattern
|
||||
// The server will return a 404 or placeholder if no image exists
|
||||
const baseUrl = `${server.url}/Items/${id}/Images/Primary?quality=96${imageSize ? `&width=${imageSize}` : ''}`;
|
||||
|
||||
// For songs, we might want to fall back to album art, but we don't have albumId here
|
||||
// The caller can handle this if needed
|
||||
return baseUrl;
|
||||
},
|
||||
getInternetRadioStations: async (args) => {
|
||||
const { apiClientProps } = args;
|
||||
|
||||
@@ -1077,9 +1093,7 @@ export const JellyfinController: InternalControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: items.map((item) =>
|
||||
jfNormalize.song(item, apiClientProps.server, query.imageSize),
|
||||
),
|
||||
items: items.map((item) => jfNormalize.song(item, apiClientProps.server)),
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount,
|
||||
};
|
||||
|
||||
@@ -461,6 +461,7 @@ export const NavidromeController: InternalControllerEndpoint = {
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getImageUrl: SubsonicController.getImageUrl,
|
||||
getInternetRadioStations: SubsonicController.getInternetRadioStations,
|
||||
getLyrics: SubsonicController.getLyrics,
|
||||
getMusicFolderList: SubsonicController.getMusicFolderList,
|
||||
@@ -664,9 +665,7 @@ export const NavidromeController: InternalControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: res.body.data.map((song) =>
|
||||
ndNormalize.song(song, apiClientProps.server, query.imageSize),
|
||||
),
|
||||
items: res.body.data.map((song) => ndNormalize.song(song, apiClientProps.server)),
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
|
||||
@@ -827,6 +827,28 @@ export const SubsonicController: InternalControllerEndpoint = {
|
||||
startIndex: query.startIndex,
|
||||
});
|
||||
},
|
||||
getImageUrl: ({ apiClientProps: { server }, query }) => {
|
||||
const { id, size } = query;
|
||||
const imageSize = size;
|
||||
|
||||
if (!server?.url || !server?.credential) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for default placeholder image ID
|
||||
if (id.match('2a96cbd8b46e442fc41c2b86b821562f')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
`${server.url}/rest/getCoverArt.view` +
|
||||
`?id=${id}` +
|
||||
`&${server.credential}` +
|
||||
'&v=1.13.0' +
|
||||
'&c=Feishin' +
|
||||
(imageSize ? `&size=${imageSize}` : '')
|
||||
);
|
||||
},
|
||||
getInternetRadioStations: async (args) => {
|
||||
const { apiClientProps } = args;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user