mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
Compare commits
5 Commits
42890bc526
...
be2c45cbdd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be2c45cbdd | ||
|
|
64a9260174 | ||
|
|
6a7381aa5a | ||
|
|
bbe8fe164d | ||
|
|
72969711d2 |
@ -346,7 +346,7 @@ func startPluginManager(ctx context.Context) func() error {
|
|||||||
// TODO: Implement some struct tags to map flags to viper
|
// TODO: Implement some struct tags to map flags to viper
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(func() {
|
cobra.OnInitialize(func() {
|
||||||
conf.InitConfig(cfgFile)
|
conf.InitConfig(cfgFile, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&cfgFile, "configfile", "c", "", `config file (default "./navidrome.toml")`)
|
rootCmd.PersistentFlags().StringVarP(&cfgFile, "configfile", "c", "", `config file (default "./navidrome.toml")`)
|
||||||
|
|||||||
@ -617,7 +617,7 @@ func init() {
|
|||||||
setViperDefaults()
|
setViperDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitConfig(cfgFile string) {
|
func InitConfig(cfgFile string, loadEnvVars bool) {
|
||||||
codecRegistry := viper.NewCodecRegistry()
|
codecRegistry := viper.NewCodecRegistry()
|
||||||
_ = codecRegistry.RegisterCodec("ini", ini.Codec{
|
_ = codecRegistry.RegisterCodec("ini", ini.Codec{
|
||||||
LoadOptions: ini.LoadOptions{
|
LoadOptions: ini.LoadOptions{
|
||||||
@ -638,10 +638,12 @@ func InitConfig(cfgFile string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = viper.BindEnv("port")
|
_ = viper.BindEnv("port")
|
||||||
viper.SetEnvPrefix("ND")
|
if loadEnvVars {
|
||||||
replacer := strings.NewReplacer(".", "_")
|
viper.SetEnvPrefix("ND")
|
||||||
viper.SetEnvKeyReplacer(replacer)
|
replacer := strings.NewReplacer(".", "_")
|
||||||
viper.AutomaticEnv()
|
viper.SetEnvKeyReplacer(replacer)
|
||||||
|
viper.AutomaticEnv()
|
||||||
|
}
|
||||||
|
|
||||||
err := viper.ReadInConfig()
|
err := viper.ReadInConfig()
|
||||||
if viper.ConfigFileUsed() != "" && err != nil {
|
if viper.ConfigFileUsed() != "" && err != nil {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ var _ = Describe("Configuration", func() {
|
|||||||
filename := filepath.Join("testdata", "cfg."+format)
|
filename := filepath.Join("testdata", "cfg."+format)
|
||||||
|
|
||||||
// Initialize config with the test file
|
// Initialize config with the test file
|
||||||
conf.InitConfig(filename)
|
conf.InitConfig(filename, false)
|
||||||
// Load the configuration (with noConfigDump=true)
|
// Load the configuration (with noConfigDump=true)
|
||||||
conf.Load(true)
|
conf.Load(true)
|
||||||
|
|
||||||
|
|||||||
@ -130,58 +130,99 @@ func (s *Stream) EstimatedContentLength() int {
|
|||||||
return int(s.mf.Duration * float32(s.bitRate) / 8 * 1024)
|
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) {
|
func selectTranscodingOptions(ctx context.Context, ds model.DataStore, mf *model.MediaFile, reqFormat string, reqBitRate int) (format string, bitRate int) {
|
||||||
|
// Default case
|
||||||
format = "raw"
|
format = "raw"
|
||||||
|
bitRate = 0
|
||||||
|
|
||||||
|
// If the client explicitly requests "raw"
|
||||||
|
// then always serve the original
|
||||||
if reqFormat == "raw" {
|
if reqFormat == "raw" {
|
||||||
|
return format, bitRate
|
||||||
|
}
|
||||||
|
|
||||||
|
// If requested format matches the file’s 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
|
return format, 0
|
||||||
}
|
}
|
||||||
if reqFormat == mf.Suffix && reqBitRate == 0 {
|
|
||||||
bitRate = mf.BitRate
|
t, err := ds.Transcoding(ctx).FindByFormat(targetFormat)
|
||||||
return format, bitRate
|
if err != nil {
|
||||||
|
// TODO: log error?
|
||||||
|
return format, 0
|
||||||
}
|
}
|
||||||
trc, hasDefault := request.TranscodingFrom(ctx)
|
|
||||||
var cFormat string
|
format = t.TargetFormat
|
||||||
var cBitRate int
|
|
||||||
if reqFormat != "" {
|
// If no target bitrate was specified
|
||||||
cFormat = reqFormat
|
// fall back to the transcoding’s configuration
|
||||||
|
// default bitrate
|
||||||
|
if targetBitRate == 0 {
|
||||||
|
bitRate = t.DefaultBitRate
|
||||||
} else {
|
} else {
|
||||||
if hasDefault {
|
bitRate = targetBitRate
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the final format is the same as the original
|
||||||
|
// and does not reduce bitrate
|
||||||
|
// there’s no reason to transcode
|
||||||
if format == mf.Suffix && bitRate >= mf.BitRate {
|
if format == mf.Suffix && bitRate >= mf.BitRate {
|
||||||
format = "raw"
|
return "raw", 0
|
||||||
bitRate = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return format, bitRate
|
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 (
|
var (
|
||||||
onceTranscodingCache sync.Once
|
onceTranscodingCache sync.Once
|
||||||
instanceTranscodingCache TranscodingCache
|
instanceTranscodingCache TranscodingCache
|
||||||
|
|||||||
@ -53,6 +53,7 @@ const SharePlayer = () => {
|
|||||||
remove: false,
|
remove: false,
|
||||||
spaceBar: true,
|
spaceBar: true,
|
||||||
volumeFade: { fadeIn: 200, fadeOut: 200 },
|
volumeFade: { fadeIn: 200, fadeOut: 200 },
|
||||||
|
sortableOptions: { delay: 200, delayOnTouchOnly: true },
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ReactJkMusicPlayer
|
<ReactJkMusicPlayer
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user