mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
* fix: update codec MIME types to support multiple variants for better compatibility Signed-off-by: Deluan <deluan@navidrome.org> * fix: limit Safari transcoding to mp3 Signed-off-by: Deluan <deluan@navidrome.org> * style: format browserProfile test file with prettier * fix: comment Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
81 lines
2.6 KiB
JavaScript
81 lines
2.6 KiB
JavaScript
// Each entry: { codec name for the server, container, mime: [MIME probe strings] }
|
|
export const CODEC_PROBES = [
|
|
{ codec: 'mp3', container: 'mp3', mime: ['audio/mpeg; codecs="mp3"'] },
|
|
{ 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', 'audio/flac; codecs="flac"'],
|
|
},
|
|
{ codec: 'wav', container: 'wav', mime: ['audio/wav; codecs="1"'] },
|
|
{ codec: 'alac', container: 'mp4', mime: ['audio/mp4; codecs="alac"'] },
|
|
{ codec: 'aac', container: 'mp4', mime: ['audio/mp4; codecs="mp4a.40.2"'] },
|
|
]
|
|
|
|
// Transcoding targets in preference order (lossless first, then lossy).
|
|
// Derived from CODEC_PROBES to avoid duplicating MIME strings.
|
|
// MP3 is always included as a universal fallback.
|
|
const TRANSCODE_CODECS = ['flac', 'opus', 'mp3']
|
|
|
|
// Safari transcoding is limited to mp3 only. Safari cannot reliably stream
|
|
// Ogg containers (reports canPlayType support but fails on non-seekable
|
|
// transcoded streams), and FLAC transcoding also fails in practice.
|
|
const SAFARI_TRANSCODE_CODECS = ['mp3']
|
|
|
|
function canPlay(audio, mimeList) {
|
|
return mimeList.some((m) => {
|
|
const result = audio.canPlayType(m)
|
|
return result === 'probably' || result === 'maybe'
|
|
})
|
|
}
|
|
|
|
function probeSupported(audio, probes) {
|
|
return probes.filter(({ mime }) => canPlay(audio, mime))
|
|
}
|
|
|
|
function isSafari() {
|
|
const ua = navigator.userAgent
|
|
return (
|
|
ua.includes('Safari') && !ua.includes('Chrome') && !ua.includes('Chromium')
|
|
)
|
|
}
|
|
|
|
export function detectBrowserProfile() {
|
|
const audio = new Audio()
|
|
|
|
const directPlayProfiles = probeSupported(audio, CODEC_PROBES).map(
|
|
({ codec, container }) => ({
|
|
containers: [container],
|
|
audioCodecs: [codec],
|
|
protocols: ['http'],
|
|
}),
|
|
)
|
|
|
|
// Build transcoding profiles from supported codecs, always keeping mp3 as fallback.
|
|
// Safari is limited to mp3 transcoding only.
|
|
const transcodeCodecs = isSafari()
|
|
? SAFARI_TRANSCODE_CODECS
|
|
: TRANSCODE_CODECS
|
|
const transcodingProfiles = transcodeCodecs.reduce((profiles, codec) => {
|
|
const probe = CODEC_PROBES.find((p) => p.codec === codec)
|
|
if (!probe) return profiles
|
|
if (canPlay(audio, probe.mime) || codec === 'mp3') {
|
|
profiles.push({
|
|
container: probe.container,
|
|
audioCodec: codec,
|
|
protocol: 'http',
|
|
})
|
|
}
|
|
return profiles
|
|
}, [])
|
|
|
|
return {
|
|
name: 'NavidromeUI',
|
|
platform: navigator.userAgent,
|
|
directPlayProfiles,
|
|
transcodingProfiles,
|
|
codecProfiles: [],
|
|
}
|
|
}
|