Files
Psychotoxical-psysonic/src/cover/integrations/discord.ts
T
Psychotoxical 4fd558fa28 fix(discord): use the public server address for Rich Presence cover art
The Discord cover URL was built via the connect endpoint, which prefers the
LAN address — but Discord fetches the image from its own servers, so a LAN
address is unreachable and the cover falls back to the app icon. This is a
dual-address regression: before a second (public) address could be added,
the only configured URL was the public one.

Build the Discord large-image URL via serverShareBaseUrl (public preferred,
like share links / Orbit invites) instead of the connect URL. Adds a test.

(cherry picked from commit 5f15784b7d)
2026-06-17 01:29:07 +03:00

55 lines
2.0 KiB
TypeScript

import { buildCoverArtUrlForServer } from '../../api/subsonicStreamUrl';
import { serverShareBaseUrl } from '../../utils/server/serverEndpoint';
import { getPlaybackServerId } from '../../utils/playback/playbackServer';
import { useAuthStore } from '../../store/authStore';
import type { CoverArtRef, CoverServerScope } from '../types';
/** The saved profile id that a cover scope resolves to (active/playback/server). */
function serverIdForScope(scope: CoverServerScope): string | null {
if (scope.kind === 'server') return scope.serverId;
if (scope.kind === 'playback') {
return getPlaybackServerId() ?? useAuthStore.getState().activeServerId ?? null;
}
return useAuthStore.getState().activeServerId ?? null;
}
/**
* Discord large image — an https:// URL Discord's own servers can reach.
*
* Unlike every other cover fetch we must NOT use the connect URL: that prefers
* the LAN address (fast for the app itself), but Discord fetches the image
* remotely, so a `http://192.168.x.x` address is unreachable and falls back to
* the app icon. Discord is an external consumer just like a share link, so use
* `serverShareBaseUrl` (public address preferred when both are set).
*/
export async function coverArtUrlForDiscord(ref: CoverArtRef): Promise<string | null> {
const { serverScope, fetchCoverArtId } = ref;
const serverId = serverIdForScope(serverScope);
const profile = serverId
? useAuthStore.getState().servers.find(s => s.id === serverId)
: undefined;
if (profile) {
return buildCoverArtUrlForServer(
serverShareBaseUrl(profile),
profile.username,
profile.password,
fetchCoverArtId,
800,
) || null;
}
// Server scope carries its own URL/creds even when not a saved profile.
if (serverScope.kind === 'server') {
return buildCoverArtUrlForServer(
serverShareBaseUrl({ url: serverScope.url }),
serverScope.username,
serverScope.password,
fetchCoverArtId,
800,
) || null;
}
return null;
}