98 lines
2.6 KiB
Go
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
|
|
}
|
|
}
|