fix(jukebox): fix mpv command and template parsing (#4162)
* test(mpv): add unit tests for MPV command generation and execution Signed-off-by: Deluan <deluan@navidrome.org> * fix(mpv): improve command template parsing Signed-off-by: Deluan <deluan@navidrome.org> * fix(mpv): update mock script to output arguments to stdout instead of a file Signed-off-by: Deluan <deluan@navidrome.org> * test(mpv): add test suite for MPV command functionality Signed-off-by: Deluan <deluan@navidrome.org> * fix(mpv): improve MPV command template parsing to handle quoted arguments Signed-off-by: Deluan <deluan@navidrome.org> * fix(mpv): simplify MPV command check by removing unnecessary string containment Signed-off-by: Deluan <deluan@navidrome.org> * fix(mpv): add error handling for empty command arguments and malformed templates Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
+26
-18
@@ -10,11 +10,15 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/kballard/go-shellquote"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
)
|
||||
|
||||
func start(ctx context.Context, args []string) (Executor, error) {
|
||||
if len(args) == 0 {
|
||||
return Executor{}, fmt.Errorf("no command arguments provided")
|
||||
}
|
||||
log.Debug("Executing mpv command", "cmd", args)
|
||||
j := Executor{args: args}
|
||||
j.PipeReader, j.out = io.Pipe()
|
||||
@@ -71,28 +75,32 @@ func (j *Executor) wait() {
|
||||
|
||||
// Path will always be an absolute path
|
||||
func createMPVCommand(deviceName string, filename string, socketName string) []string {
|
||||
split := strings.Split(fixCmd(conf.Server.MPVCmdTemplate), " ")
|
||||
for i, s := range split {
|
||||
s = strings.ReplaceAll(s, "%d", deviceName)
|
||||
s = strings.ReplaceAll(s, "%f", filename)
|
||||
s = strings.ReplaceAll(s, "%s", socketName)
|
||||
split[i] = s
|
||||
// Parse the template structure using shell parsing to handle quoted arguments
|
||||
templateArgs, err := shellquote.Split(conf.Server.MPVCmdTemplate)
|
||||
if err != nil {
|
||||
log.Error("Failed to parse MPV command template", "template", conf.Server.MPVCmdTemplate, err)
|
||||
return nil
|
||||
}
|
||||
return split
|
||||
}
|
||||
|
||||
func fixCmd(cmd string) string {
|
||||
split := strings.Split(cmd, " ")
|
||||
var result []string
|
||||
cmdPath, _ := mpvCommand()
|
||||
for _, s := range split {
|
||||
if s == "mpv" || s == "mpv.exe" {
|
||||
result = append(result, cmdPath)
|
||||
} else {
|
||||
result = append(result, s)
|
||||
// Replace placeholders in each parsed argument to preserve spaces in substituted values
|
||||
for i, arg := range templateArgs {
|
||||
arg = strings.ReplaceAll(arg, "%d", deviceName)
|
||||
arg = strings.ReplaceAll(arg, "%f", filename)
|
||||
arg = strings.ReplaceAll(arg, "%s", socketName)
|
||||
templateArgs[i] = arg
|
||||
}
|
||||
|
||||
// Replace mpv executable references with the configured path
|
||||
if len(templateArgs) > 0 {
|
||||
cmdPath, err := mpvCommand()
|
||||
if err == nil {
|
||||
if templateArgs[0] == "mpv" || templateArgs[0] == "mpv.exe" {
|
||||
templateArgs[0] = cmdPath
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(result, " ")
|
||||
|
||||
return templateArgs
|
||||
}
|
||||
|
||||
// This is a 1:1 copy of the stuff in ffmpeg.go, need to be unified.
|
||||
|
||||
Reference in New Issue
Block a user