Files
silo-server/internal/playback/audio_select.go
T

98 lines
2.6 KiB
Go

package playback
import (
"strings"
"github.com/Silo-Server/silo-server/internal/lang"
"github.com/Silo-Server/silo-server/internal/models"
"github.com/Silo-Server/silo-server/internal/userstore"
)
// OriginalLanguageSentinel is the value stored in audio language preference
// columns to mean "use the media item's original language." It is resolved
// to a concrete language code in the playback handler before reaching
// SelectAudioTrack.
const OriginalLanguageSentinel = "original"
// AudioTrackPreference holds a per-series audio track preference.
type AudioTrackPreference struct {
AudioTrackIndex int
AudioLanguage string
TrackSignature *userstore.AudioTrackSignature
}
func langMatch(a, b string) bool {
if a == "" || b == "" {
return false
}
return lang.Canonical(a) == lang.Canonical(b)
}
// SelectAudioTrack determines which audio track to use based on preferences.
//
// Priority:
// 1. Series preference exact track signature
// 2. Series preference index (if track exists at that index with matching language)
// 3. Series preference language (first track matching that language)
// 4. Profile preferred language (first track matching)
// 5. File's default track (first track with Default: true)
// 6. First track (index 0)
func SelectAudioTrack(tracks []models.AudioTrack, preferredLang string, seriesPref *AudioTrackPreference) int {
if len(tracks) == 0 {
return 0
}
// 1. Series preference: try exact signature match first.
if seriesPref != nil {
if idx := findExactAudioTrack(tracks, seriesPref.TrackSignature); idx >= 0 {
return idx
}
// 2. Series preference: try exact index+language match.
if seriesPref.AudioTrackIndex >= 0 && seriesPref.AudioTrackIndex < len(tracks) {
if langMatch(tracks[seriesPref.AudioTrackIndex].Language, seriesPref.AudioLanguage) {
return seriesPref.AudioTrackIndex
}
}
// 3. Series preference: fall back to language match.
if seriesPref.AudioLanguage != "" {
for i, t := range tracks {
if langMatch(t.Language, seriesPref.AudioLanguage) {
return i
}
}
}
}
// 4. Profile language preference.
if preferredLang != "" {
for i, t := range tracks {
if langMatch(t.Language, preferredLang) {
return i
}
}
}
// 5. File's default track.
for i, t := range tracks {
if t.Default {
return i
}
}
// 6. First track.
return 0
}
// BrowserSupportsAudioCodec returns true if the given audio codec can be
// played natively by web browsers without transcoding.
func BrowserSupportsAudioCodec(codec string) bool {
switch strings.ToLower(codec) {
case "aac", "mp3", "opus", "vorbis", "flac":
return true
default:
return false
}
}