From 349fab7a1db920cfa31424d71dd7bd573c8c4704 Mon Sep 17 00:00:00 2001 From: ChekeredList71 <66330496+ChekeredList71@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:47:02 +0200 Subject: [PATCH 1/4] No longer prints invalid clip mode when wrong tagmode is set --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 673be99..6ab75d2 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func main() { } if !slices.Contains([]string{"s", "d", "i"}, *tagMode) { - fmt.Printf("Invalid clip mode: %s", *tagMode) + fmt.Printf("Invalid tagmode: %s", *tagMode) os.Exit(2) } command = append(command, "-s", *tagMode) From b476940a6140557b7fc3f57e31b5ccb926d686df Mon Sep 17 00:00:00 2001 From: ChekeredList71 Date: Mon, 15 Sep 2025 14:01:17 +0200 Subject: [PATCH 2/4] supposedly streaming logs now needs testing --- main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.go b/main.go index 6ab75d2..575cfbd 100644 --- a/main.go +++ b/main.go @@ -129,6 +129,10 @@ func walker(root string) error { defer func() { <-rsgainSemaphore }() cmd := exec.Command("rsgain", append(command, audioFiles...)...) + + // Stream output to console + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { From 3626ac6529400ca11bbc9f95eea496db8b63c48d Mon Sep 17 00:00:00 2001 From: ChekeredList71 Date: Sun, 21 Sep 2025 14:43:51 +0200 Subject: [PATCH 3/4] README.MD typo fixed --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 2af4e70..d9f3c4c 100644 --- a/README.MD +++ b/README.MD @@ -21,7 +21,7 @@ There isn't really any requirement for track based REPLAYGAIN. The script will f As for album based REPLAYGAIN: the script considers audio files, that are in the same directory to belong into the same album. So, rsgain will calculate REPLAYGAIN_ALBUM_GAIN for those, as if they are in one album. -This isn't an issue at all, if you have your albums grouped into fodlers, +This isn't an issue at all, if you have your albums grouped into folders, you don't make rsgain calculate album REPLAYGAIN or just don't use that. ## Dependencies From 8e543a7a4c302e757dacc3fa25fe4ad3ab46c174 Mon Sep 17 00:00:00 2001 From: ChekeredList71 Date: Sun, 21 Sep 2025 14:49:39 +0200 Subject: [PATCH 4/4] works perfectly --- .gitignore | 1 + main.go | 124 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 72 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 8e0bc29..021f85c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build/ /lib/ +/testing_files/ diff --git a/main.go b/main.go index 575cfbd..852f988 100644 --- a/main.go +++ b/main.go @@ -19,91 +19,103 @@ var command = []string{"custom"} var rsgainSemaphore chan int func main() { - albumMode := flag.Bool("a", false, "Calculate album gain and peak.") - skipExisting := flag.Bool("S", false, "Don't scan files with existing ReplayGain information.") - tagMode := flag.String("s", "s", "Tagmode:\ns: scan only\ni: write tags\nd: delete tags") - targetLoudness := flag.Int("l", -18, "Use n LUFS as target loudness (-30 ≤ n ≤ -5), default: -18") - clipMode := flag.String("c", "n", "n: no clipping protection (default),\np: clipping protection enabled for positive gain values only,\na: Use max peak level n dB for clipping protection") - quiet := flag.Bool("q", false, "(rsgain) Don't print scanning status messages.") - rsgainLimit := flag.Int("r", 100, "Limit, how many rsgain instances can run at a time.") + albumMode := *flag.Bool("a", false, "Calculate album gain and peak.") + skipExisting := *flag.Bool("S", false, "Don't scan files with existing ReplayGain information.") + tagMode := *flag.String("s", "s", "Tagmode:\ns: scan only\ni: write tags\nd: delete tags") + targetLoudness := *flag.Int("l", -18, "Use n LUFS as target loudness (-30 ≤ n ≤ -5), default: -18") + clipMode := *flag.String("c", "n", "n: no clipping protection (default),\np: clipping protection enabled for positive gain values only,\na: Use max peak level n dB for clipping protection") + quiet := *flag.Bool("q", false, "(rsgain) Don't print scanning status messages.") + rsgainLimit := *flag.Int("r", 100, "Limit, how many rsgain instances can run at a time.") flag.Parse() libraryRoot := flag.Arg(0) // build the rsgain custom command and check values - if *albumMode { + if albumMode { command = append(command, "-a") } - if *skipExisting { + if skipExisting { command = append(command, "-S") } - if !slices.Contains([]string{"s", "d", "i"}, *tagMode) { - fmt.Printf("Invalid tagmode: %s", *tagMode) + if !slices.Contains([]string{"s", "d", "i"}, tagMode) { + fmt.Printf("Invalid tagmode: %s", tagMode) os.Exit(2) } - command = append(command, "-s", *tagMode) + command = append(command, "-s", tagMode) - if !(-30 <= *targetLoudness && *targetLoudness <= -5) { + if !(-30 <= targetLoudness && targetLoudness <= -5) { fmt.Println("Target loudness n needs to be -30 ≤ n ≤ -5") os.Exit(2) } - command = append(command, "-l", strconv.Itoa(*targetLoudness)) + command = append(command, "-l", strconv.Itoa(targetLoudness)) - if !slices.Contains([]string{"n", "p", "a"}, *clipMode) { - fmt.Printf("Invalid clip mode: %s", *clipMode) + if !slices.Contains([]string{"n", "p", "a"}, clipMode) { + fmt.Printf("Invalid clip mode: %s", clipMode) os.Exit(2) } - command = append(command, "-c", *clipMode) + command = append(command, "-c", clipMode) if libraryRoot == "" { fmt.Println("No library path specified.") os.Exit(2) } - if *quiet { + if quiet { command = append(command, "-q") } - rsgainSemaphore = make(chan int, *rsgainLimit) + rsgainSemaphore = make(chan int, rsgainLimit) /* Used for debugging ctx, cancel := context.WithCancel(context.Background()) go monitorRsgainProcesses(ctx, 500*time.Millisecond) */ - // scan for album folders - wg.Add(1) - err := walker(libraryRoot) + // if root is just a file + if isSupportedMusicFile(libraryRoot) { + err := runRSGain([]string{libraryRoot}, quiet) + if err != nil { + errLog.Printf("Something went wrong scanning %s: '%s\n'", libraryRoot, err) + } + } else { // if we have a folder, scan them with WalkDir + wg.Add(1) + err := walker(libraryRoot, quiet) - if err != nil { - errLog.Printf("Error walking library folder: %s\n", err) - } + if err != nil { + errLog.Printf("Error walking library folder: %s\n", err) + } - wg.Wait() + wg.Wait() + } /*cancel()*/ } -func walker(root string) error { +func walker(root string, isQuiet bool) error { defer wg.Done() return filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } - // skip creating walkers on the initial directory (it would create infinite threads lol) - if d.IsDir() && path != root { - // when walked into a directory, launch a new walker on that - wg.Add(1) - go func() { - err := walker(path) - if err != nil { - errLog.Printf("Error walking %s: %s\n", path, err) - } - }() + if d.IsDir() { + // skip creating walkers on the initial directory (it would create infinite threads lol) + if path != root { + // when walked into a directory, launch a new walker on that + wg.Add(1) + go func() { + err := walker(path, isQuiet) + if err != nil { + errLog.Printf("Error walking %s: %s\n", path, err) + } + }() + + // skip the current directory (the newly summoned walker is dealing with it) + return fs.SkipDir + } // process supported files (separate thread) wg.Add(1) @@ -128,29 +140,35 @@ func walker(root string) error { rsgainSemaphore <- 0 //add a slot to the semaphore defer func() { <-rsgainSemaphore }() - cmd := exec.Command("rsgain", append(command, audioFiles...)...) - - // Stream output to console - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - - if err != nil { - errLog.Printf("Error calling rsgain on these files: '%v'\n", audioFiles) - errLog.Printf("Command failed: %s\nError: %v\n", cmd.String(), err) - - } + err = runRSGain(audioFiles, isQuiet) } }() - - // skip the current directory (the newly summoned walker is dealing with it) - return fs.SkipDir } - return nil + return err }) } +func runRSGain(audioFiles []string, isQuiet bool) error { + cmd := exec.Command("rsgain", append(command, audioFiles...)...) + + // Stream output to console if set + if !isQuiet { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + } + + err := cmd.Run() + + if err != nil { + errLog.Printf("Error calling rsgain on these files: '%v'\n", audioFiles) + errLog.Printf("Command failed: %s\nError: %v\n", cmd.String(), err) + + } + + return err +} + func isSupportedMusicFile(path string) bool { supportedFiles := []string{ ".aiff", ".flac", ".flac",