support secondary public server URL

This commit is contained in:
jeffvli
2025-12-30 21:05:38 -08:00
parent 7aeadb531f
commit 72d0fca28b
16 changed files with 244 additions and 68 deletions
+3 -1
View File
@@ -9,6 +9,7 @@ import packageJson from '../../../../package.json';
import i18n from '/@/i18n/i18n';
import { authenticationFailure } from '/@/renderer/api/utils';
import { useAuthStore } from '/@/renderer/store';
import { getServerUrl } from '/@/renderer/utils/normalize-server-url';
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
import { getClientType } from '/@/shared/api/utils';
import { ServerListItemWithCredential } from '/@/shared/types/domain-types';
@@ -408,7 +409,8 @@ export const jfApiClient = (args: {
const { params, path: api } = parsePath(path);
if (server) {
baseUrl = `${server?.url}`;
const serverUrl = getServerUrl(server);
baseUrl = serverUrl;
token = server?.credential;
} else {
baseUrl = url;
@@ -6,6 +6,7 @@ import { z } from 'zod';
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
import { useRadioStore } from '/@/renderer/features/radio/store/radio-store';
import { getServerUrl } from '/@/renderer/utils/normalize-server-url';
import { jfNormalize } from '/@/shared/api/jellyfin/jellyfin-normalize';
import { JFSongListSort, JFSortOrder, jfType } from '/@/shared/api/jellyfin/jellyfin-types';
import { getFeatures, hasFeature, sortSongList, VersionInfo } from '/@/shared/api/utils';
@@ -691,21 +692,22 @@ export const JellyfinController: InternalControllerEndpoint = {
totalRecordCount: res.body?.TotalRecordCount || 0,
};
},
getImageUrl: ({ apiClientProps: { server }, query }) => {
getImageUrl: ({ apiClientProps: { server }, baseUrl, query }) => {
const { id, size } = query;
const imageSize = size;
const url = baseUrl || getServerUrl(server);
if (!server?.url) {
if (!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}` : ''}`;
const imageUrl = `${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;
return imageUrl;
},
getInternetRadioStations: async (args) => {
const { apiClientProps } = args;
+3 -1
View File
@@ -8,6 +8,7 @@ import qs from 'qs';
import i18n from '/@/i18n/i18n';
import { authenticationFailure } from '/@/renderer/api/utils';
import { useAuthStore } from '/@/renderer/store';
import { getServerUrl } from '/@/renderer/utils/normalize-server-url';
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
import { resultWithHeaders } from '/@/shared/api/utils';
import { toast } from '/@/shared/components/toast/toast';
@@ -411,7 +412,8 @@ export const ndApiClient = (args: {
const { params, path: api } = parsePath(path);
if (server) {
baseUrl = `${server?.url}/api`;
const serverUrl = getServerUrl(server);
baseUrl = serverUrl ? `${serverUrl}/api` : undefined;
token = server?.ndCredential;
} else {
baseUrl = url;
+3 -1
View File
@@ -5,6 +5,7 @@ import qs from 'qs';
import { z } from 'zod';
import i18n from '/@/i18n/i18n';
import { getServerUrl } from '/@/renderer/utils/normalize-server-url';
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
import { hasFeature } from '/@/shared/api/utils';
import { toast } from '/@/shared/components/toast/toast';
@@ -398,7 +399,8 @@ export const ssApiClient = (args: {
const { params, path: api } = parsePath(path);
if (server) {
baseUrl = `${server.url}/rest`;
const serverUrl = getServerUrl(server);
baseUrl = serverUrl ? `${serverUrl}/rest` : undefined;
const token = server.credential;
const params = token.split(/&?\w=/gm);
@@ -9,6 +9,7 @@ import { z } from 'zod';
import { contract, ssApiClient } from '/@/renderer/api/subsonic/subsonic-api';
import { randomString } from '/@/renderer/utils';
import { getServerUrl } from '/@/renderer/utils/normalize-server-url';
import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize';
import {
AlbumListSortType,
@@ -851,11 +852,12 @@ export const SubsonicController: InternalControllerEndpoint = {
startIndex: query.startIndex,
});
},
getImageUrl: ({ apiClientProps: { server }, query }) => {
getImageUrl: ({ apiClientProps: { server }, baseUrl, query }) => {
const { id, size } = query;
const imageSize = size;
const url = baseUrl || getServerUrl(server);
if (!server?.url || !server?.credential) {
if (!url || !server?.credential) {
return null;
}
@@ -865,7 +867,7 @@ export const SubsonicController: InternalControllerEndpoint = {
}
return (
`${server.url}/rest/getCoverArt.view` +
`${url}/rest/getCoverArt.view` +
`?id=${id}` +
`&${server.credential}` +
'&v=1.13.0' +