From ee33720fcd9ec3bda1935d06ec2e8e0f75f8c88e Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 31 Mar 2026 20:41:36 -0700 Subject: [PATCH] shamelessly copy transcoding config from NavidromeUI --- .../api/subsonic/subsonic-controller.ts | 96 +++++++++---------- .../player/components/audio-players.tsx | 51 ++++++++++ 2 files changed, 97 insertions(+), 50 deletions(-) diff --git a/src/renderer/api/subsonic/subsonic-controller.ts b/src/renderer/api/subsonic/subsonic-controller.ts index 62f86f5cc..901f948f3 100644 --- a/src/renderer/api/subsonic/subsonic-controller.ts +++ b/src/renderer/api/subsonic/subsonic-controller.ts @@ -8,6 +8,10 @@ import md5 from 'md5'; import { z } from 'zod'; import { contract, ssApiClient } from '/@/renderer/api/subsonic/subsonic-api'; +import { + getDefaultTranscodingProfiles, + getDirectPlayProfiles, +} from '/@/renderer/features/player/components/audio-players'; import { randomString } from '/@/renderer/utils'; import { logFn } from '/@/renderer/utils/logger'; import { getServerUrl } from '/@/renderer/utils/normalize-server-url'; @@ -88,44 +92,44 @@ const ALBUM_LIST_SORT_MAPPING: Record { - const trimmedFormat = f.trim(); - - return { - audioCodec: trimmedFormat, - container: trimmedFormat, - maxAudioChannels: 2, - protocol: 'http', - }; - }); + const directPlayProfiles = getDirectPlayProfiles(); + const transcodingProfiles = getDefaultTranscodingProfiles(); const transcodeDecision = await ssApiClient(apiClientProps).getTranscodeDecision({ body: { codecProfiles: [], - directPlayProfiles: TRANSCODE_DIRECT_PLAY_PROFILES, + directPlayProfiles, maxAudioBitrate: 0, maxTranscodingAudioBitrate, name: 'Feishin', - platform: 'Web', + platform: navigator.userAgent, transcodingProfiles, }, query: { diff --git a/src/renderer/features/player/components/audio-players.tsx b/src/renderer/features/player/components/audio-players.tsx index d4d667a50..fb30fbd7b 100644 --- a/src/renderer/features/player/components/audio-players.tsx +++ b/src/renderer/features/player/components/audio-players.tsx @@ -37,6 +37,52 @@ import { toast } from '/@/shared/components/toast/toast'; import { LibraryItem } from '/@/shared/types/domain-types'; import { PlayerType } from '/@/shared/types/types'; +const CODEC_PROBES = [ + { codec: 'mp3', container: 'mp3', mime: 'audio/mpeg' }, + { codec: 'aac', container: 'mp4', mime: 'audio/mp4; codecs="mp4a.40.2"' }, + { codec: 'opus', container: 'ogg', mime: 'audio/ogg; codecs="opus"' }, + { codec: 'vorbis', container: 'ogg', mime: 'audio/ogg; codecs="vorbis"' }, + { codec: 'flac', container: 'flac', mime: 'audio/flac' }, + { codec: 'wav', container: 'wav', mime: 'audio/wav' }, + { codec: 'alac', container: 'mp4', mime: 'audio/mp4; codecs="alac"' }, +]; + +const DEFAULT_TRANSCODING_PROFILES = [ + { audioCodec: 'opus', container: 'ogg', protocol: 'http' }, + { audioCodec: 'mp3', container: 'mp3', protocol: 'http' }, +]; + +const DIRECT_PLAY_PROFILES: { + audioCodecs: string[]; + containers: string[]; + protocols: string[]; +}[] = []; + +export function getDefaultTranscodingProfiles() { + return DEFAULT_TRANSCODING_PROFILES; +} + +export function getDirectPlayProfiles() { + return DIRECT_PLAY_PROFILES; +} + +// Shamelessly taken from NavidromeUI +function detectBrowserProfile() { + const audio = new Audio(); + + for (const { codec, container, mime } of CODEC_PROBES) { + if (audio.canPlayType(mime) === 'probably') { + DIRECT_PLAY_PROFILES.push({ + audioCodecs: [codec], + containers: [container], + protocols: ['http'], + }); + } + } + + return DIRECT_PLAY_PROFILES; +} + export const AudioPlayers = () => { const playbackType = usePlaybackType(); const serverId = useCurrentServerId(); @@ -49,6 +95,11 @@ export const AudioPlayers = () => { } = usePlaybackSettings(); const { setWebAudio, webAudio: audioContext } = useWebAudio(); + useEffect(() => { + console.log('getDirectPlayProfiles'); + detectBrowserProfile(); + }, []); + return ( <>