Compare commits

...

5 Commits

Author SHA1 Message Date
Nova
be2c45cbdd
Merge bbe8fe164df8ba915d1cba17da9871c2fe435a53 into 64a9260174cd7c7c27f2b82c9ebaa4657afaeea6 2025-11-29 18:06:35 +00:00
floatlesss
64a9260174
fix(ui): allow scrolling in shareplayer queue by adding delay #4748
fix(shareplayer): allow-scrolling-in-shareplayer - #4747
2025-11-29 12:54:46 -05:00
Deluan
6a7381aa5a test: prevent environment variables from overriding config file values in tests
Added a loadEnvVars parameter to InitConfig to control whether environment
variables should be loaded via viper.AutomaticEnv(). In tests, environment
variables (like ND_MUSICFOLDER) were overriding values from config test files,
causing tests to fail when these variables were set in the developer's
environment. Now tests can pass loadEnvVars=false to isolate from the
environment while production code continues to use loadEnvVars=true.

Signed-off-by: Deluan <deluan@navidrome.org>
2025-11-29 11:45:07 -05:00
Nova
bbe8fe164d
Fix typos
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-28 20:43:02 +00:00
zero
72969711d2 Refactor selectTranscodingOptions and add findTargetTranscodingOptions 2025-10-28 21:34:46 +01:00
5 changed files with 90 additions and 46 deletions

View File

@ -346,7 +346,7 @@ func startPluginManager(ctx context.Context) func() error {
// TODO: Implement some struct tags to map flags to viper
func init() {
cobra.OnInitialize(func() {
conf.InitConfig(cfgFile)
conf.InitConfig(cfgFile, true)
})
rootCmd.PersistentFlags().StringVarP(&cfgFile, "configfile", "c", "", `config file (default "./navidrome.toml")`)

View File

@ -617,7 +617,7 @@ func init() {
setViperDefaults()
}
func InitConfig(cfgFile string) {
func InitConfig(cfgFile string, loadEnvVars bool) {
codecRegistry := viper.NewCodecRegistry()
_ = codecRegistry.RegisterCodec("ini", ini.Codec{
LoadOptions: ini.LoadOptions{
@ -638,10 +638,12 @@ func InitConfig(cfgFile string) {
}
_ = viper.BindEnv("port")
viper.SetEnvPrefix("ND")
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv()
if loadEnvVars {
viper.SetEnvPrefix("ND")
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv()
}
err := viper.ReadInConfig()
if viper.ConfigFileUsed() != "" && err != nil {

View File

@ -31,7 +31,7 @@ var _ = Describe("Configuration", func() {
filename := filepath.Join("testdata", "cfg."+format)
// Initialize config with the test file
conf.InitConfig(filename)
conf.InitConfig(filename, false)
// Load the configuration (with noConfigDump=true)
conf.Load(true)

View File

@ -130,58 +130,99 @@ func (s *Stream) EstimatedContentLength() int {
return int(s.mf.Duration * float32(s.bitRate) / 8 * 1024)
}
// TODO This function deserves some love (refactoring)
func selectTranscodingOptions(ctx context.Context, ds model.DataStore, mf *model.MediaFile, reqFormat string, reqBitRate int) (format string, bitRate int) {
// Default case
format = "raw"
bitRate = 0
// If the client explicitly requests "raw"
// then always serve the original
if reqFormat == "raw" {
return format, bitRate
}
// If requested format matches the files suffix and
// no bitrate reduction is requested then
// stream the file without transcoding
if reqFormat == mf.Suffix && reqBitRate == 0 {
return format, mf.BitRate
}
targetFormat, targetBitRate := findTargetTranscodingOptions(ctx, mf, reqFormat, reqBitRate)
// If nothing was found then stream raw
if targetFormat == "" && targetBitRate == 0 {
return format, 0
}
if reqFormat == mf.Suffix && reqBitRate == 0 {
bitRate = mf.BitRate
return format, bitRate
t, err := ds.Transcoding(ctx).FindByFormat(targetFormat)
if err != nil {
// TODO: log error?
return format, 0
}
trc, hasDefault := request.TranscodingFrom(ctx)
var cFormat string
var cBitRate int
if reqFormat != "" {
cFormat = reqFormat
format = t.TargetFormat
// If no target bitrate was specified
// fall back to the transcodings configuration
// default bitrate
if targetBitRate == 0 {
bitRate = t.DefaultBitRate
} else {
if hasDefault {
cFormat = trc.TargetFormat
cBitRate = trc.DefaultBitRate
if p, ok := request.PlayerFrom(ctx); ok {
cBitRate = p.MaxBitRate
}
} else if reqBitRate > 0 && reqBitRate < mf.BitRate && conf.Server.DefaultDownsamplingFormat != "" {
// If no format is specified and no transcoding associated to the player, but a bitrate is specified,
// and there is no transcoding set for the player, we use the default downsampling format.
// But only if the requested bitRate is lower than the original bitRate.
log.Debug("Default Downsampling", "Using default downsampling format", conf.Server.DefaultDownsamplingFormat)
cFormat = conf.Server.DefaultDownsamplingFormat
}
}
if reqBitRate > 0 {
cBitRate = reqBitRate
}
if cBitRate == 0 && cFormat == "" {
return format, bitRate
}
t, err := ds.Transcoding(ctx).FindByFormat(cFormat)
if err == nil {
format = t.TargetFormat
if cBitRate != 0 {
bitRate = cBitRate
} else {
bitRate = t.DefaultBitRate
}
bitRate = targetBitRate
}
// If the final format is the same as the original
// and does not reduce bitrate
// theres no reason to transcode
if format == mf.Suffix && bitRate >= mf.BitRate {
format = "raw"
bitRate = 0
return "raw", 0
}
return format, bitRate
}
func findTargetTranscodingOptions(ctx context.Context, mf *model.MediaFile, reqFormat string, reqBitRate int) (string, int) {
// If a format is requested use that
if reqFormat != "" {
return reqFormat, reqBitRate
}
// If a default transcoding configuration exists for this context
if trc, ok := request.TranscodingFrom(ctx); ok {
targetFormat := trc.TargetFormat
targetBitRate := trc.DefaultBitRate
// If a player is configured adjust bitrate based on
// user request or player limits
if p, hasPlayer := request.PlayerFrom(ctx); hasPlayer {
if reqBitRate > 0 {
targetBitRate = reqBitRate
} else if p.MaxBitRate > 0 {
targetBitRate = p.MaxBitRate
}
} else if reqBitRate > 0 {
targetBitRate = reqBitRate
}
return targetFormat, targetBitRate
}
// Use the default downsampling format the server is configured to but
// only if the requested bitrate is reduced
isBitrateReduced := reqBitRate > 0 && reqBitRate < mf.BitRate
hasDefaultDownsamplingFormat := conf.Server.DefaultDownsamplingFormat != ""
if isBitrateReduced && hasDefaultDownsamplingFormat {
log.Debug("Default Downsampling",
"Using default downsampling format",
conf.Server.DefaultDownsamplingFormat)
return conf.Server.DefaultDownsamplingFormat, reqBitRate
}
return "", 0
}
var (
onceTranscodingCache sync.Once
instanceTranscodingCache TranscodingCache

View File

@ -53,6 +53,7 @@ const SharePlayer = () => {
remove: false,
spaceBar: true,
volumeFade: { fadeIn: 200, fadeOut: 200 },
sortableOptions: { delay: 200, delayOnTouchOnly: true },
}
return (
<ReactJkMusicPlayer