Skip to content

Commit

Permalink
Merge pull request #22 from dpolakovics/15-better-error-messages
Browse files Browse the repository at this point in the history
15 better error messages
dpolakovics authored Dec 16, 2024
2 parents ebf4410 + 7149358 commit 40ada38
Showing 3 changed files with 71 additions and 33 deletions.
41 changes: 20 additions & 21 deletions internal/logic/sync.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package logic

import (
"io"
"bufio"
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
@@ -15,7 +15,6 @@ import (

"fyne.io/fyne/v2/widget"
"github.com/dhowden/tag"

ff "github.com/dpolakovics/soundscape-sync/internal/ffmpeg"
)

@@ -40,23 +39,20 @@ func getAudioFiles(folder string) ([]string, error) {
return audioFiles, nil
}

// Add a statusCallback parameter to allow updates on what is happening
func CombineFiles(folder1 string, folder2 string, outputFolder string, progress *widget.ProgressBar, soundscapeVolume float64, statusCallback func(string)) error {
// Adjust volume to range [0.5, 1.0]
func CombineFiles(folder1 string, folder2 string, outputFolder string, progress *widget.ProgressBar, soundscapeVolume float64, debug bool, statusCallback func(string)) error {
soundscapeVolume = 0.5 + (soundscapeVolume / 100.0 * 0.5)

// Get list of audio files from both folders
files1, err := getAudioFiles(folder1)
if err != nil {
return err
return fmt.Errorf("failed to read audio files from folder1 (%s): %w. Check folder permissions or file formats and try again.", folder1, err)
}
files2, err := getAudioFiles(folder2)
if err != nil {
return err
return fmt.Errorf("failed to read audio files from folder2 (%s): %w. Check folder permissions or file formats and try again.", folder2, err)
}

if len(files1) != len(files2) {
return fmt.Errorf("the number of audio files in the two folders must be the same")
return fmt.Errorf("the number of audio files in the two folders does not match: folder1 has %d files, folder2 has %d files. Please ensure both folders contain the same number of audio files and that they are in the correct order before retrying.", len(files1), len(files2))
}

ffmpeg := ff.FFmpegPath()
@@ -65,7 +61,7 @@ func CombineFiles(folder1 string, folder2 string, outputFolder string, progress
for index, file := range files1 {
statusCallback(fmt.Sprintf("Preparing to combine file %d of %d: %s", index+1, total, filepath.Base(file)))

channel , err := getChannelAmount(file)
channel, err := getChannelAmount(file)
if err != nil {
return err
}
@@ -79,12 +75,10 @@ func CombineFiles(folder1 string, folder2 string, outputFolder string, progress
return err
}

// Get output file name
ext := filepath.Ext(file)
newFileName := outputFolder + "/" + filepath.Base(files2[index])
newFileName = newFileName[:len(newFileName)-4] + "_synced" + ext

// Construct FFmpeg command
ctx, _ := context.WithCancel(context.Background())
arguments := []string{
"-i", file,
@@ -95,28 +89,33 @@ func CombineFiles(folder1 string, folder2 string, outputFolder string, progress
if ext == ".mp3" || ext == ".flac" {
arguments = append(arguments, getCoverArtArguments(file, files2[index])...)
}

// If debug mode is enabled, add verbose logging arguments
if debug {
arguments = append(arguments, "-loglevel", "verbose")
}

arguments = append(arguments, newFileName)

cmd := exec.CommandContext(ctx, ffmpeg, arguments...)
cmd.SysProcAttr = getSysProcAttr()
stdout, err := cmd.StdoutPipe()
if err != nil {
// prepend error with text
err = fmt.Errorf("error creating ffmpeg command: %w", err)
err = fmt.Errorf("error creating FFmpeg command pipeline (arguments: %v): %w. Consider running with more detailed logging or contacting the developer if the problem persists.", cmd.Args, err)
return err
}

statusCallback(fmt.Sprintf("Combining file %d of %d...", index+1, total))

// Execute FFmpeg command
if err := cmd.Start(); err != nil {
err = fmt.Errorf("error at ffmpeg command start: %w", err)
err = fmt.Errorf("error starting FFmpeg command with arguments %v: %w. Check that the input files are accessible and not corrupted. If the issue persists, contact the developer.", cmd.Args, err)
return err
}

parseProgress(index, total, progress, stdout, duration)

if err := cmd.Wait(); err != nil {
err = fmt.Errorf("error at ffmpeg command wait: %w", err)
err = fmt.Errorf("FFmpeg encountered an error while processing file %q with arguments %v: %w. Check the input files for issues or consider contacting the developer for further assistance.", newFileName, cmd.Args, err)
return err
}

@@ -133,11 +132,11 @@ func getChannelAmount(file string) (int, error) {
cmd := exec.Command(ffprobe, "-v", "error", "-select_streams", "a:0", "-count_packets", "-show_entries", "stream=channels", "-of", "csv=p=0", file)
out, err := cmd.Output()
if err != nil {
return 0, err
return 0, fmt.Errorf("failed to determine channel amount for file %q: %w. The file might be corrupted or unsupported.", file, err)
}
channels, err := strconv.Atoi(strings.TrimSuffix(strings.TrimSpace(string(out)), ","))
if err != nil {
return 0, err
return 0, fmt.Errorf("invalid channel information retrieved for file %q: %w. Please ensure the file is a valid audio file and consider reporting this issue if it persists.", file, err)
}
return channels, nil
}
@@ -148,7 +147,7 @@ func getDuration(filename string) (float64, error) {
cmd := exec.Command(ffprobe, "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", filename)
out, err := cmd.Output()
if err != nil {
return 0, err
return 0, fmt.Errorf("failed to determine duration for file %q: %w. The file might be corrupted or unsupported. If issues persist, consider contacting the developer.", filename, err)
}
return strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
}
@@ -186,7 +185,7 @@ func getChannelArguments(channels int, volume float64) ([]string, error) {
case 12:
return get7_1_4Arguments(volume), nil
}
return nil, fmt.Errorf("Currently only stereo, 5.1, 7.1.2 and 7.1.4 Soundscapes are supported")
return nil, fmt.Errorf("unsupported soundscape format with %d channels. Currently only stereo (2 channels), 5.1 (6 channels), 7.1.2 (10 channels), and 7.1.4 (12 channels) are supported. Please convert your files or contact the developer for assistance.", channels)
}

func getCoverArtArguments(file1 string, file2 string) []string {
31 changes: 26 additions & 5 deletions internal/ui/windows.go
Original file line number Diff line number Diff line change
@@ -95,7 +95,7 @@ func showFolderSelection(win fyne.Window, callback func(string)) {

dialog.ShowFolderOpen(func(uri fyne.ListableURI, err error) {
if err != nil {
dialog.ShowError(err, win)
showErrorDialog(win, fmt.Errorf("Failed to open folder selection dialog: %w. If this issue persists, please contact the developer.", err))
return
}
if uri == nil {
@@ -180,17 +180,18 @@ func CreateMainContent(app fyne.App, window fyne.Window) fyne.CanvasObject {

statusLabel := widget.NewLabel("Idle")

// Add a checkbox for debug mode
debugCheck := widget.NewCheck("Debug Mode", func(checked bool) {})

startButton.OnTapped = func() {
startButton.Disable()
progressBar.Show()
// Run CombineFiles synchronously on the main goroutine
err := logic.CombineFiles(folder1, folder2, folderOutput, progressBar, volumeSlider.Value, func(msg string) {
// Safe to call directly because we're on the main goroutine
err := logic.CombineFiles(folder1, folder2, folderOutput, progressBar, volumeSlider.Value, debugCheck.Checked, func(msg string) {
statusLabel.SetText(msg)
})
progressBar.Hide()
if err != nil {
dialog.ShowError(err, window)
showErrorDialog(window, fmt.Errorf("An error occurred while combining the audio files: %w. Check that the input files are valid and supported. If you continue to encounter this issue, consider seeking help from the developer and providing the details above.", err))
statusLabel.SetText("Error during combination")
} else {
dialog.ShowInformation("Success", "Audio files combined successfully", window)
@@ -204,6 +205,7 @@ func CreateMainContent(app fyne.App, window fyne.Window) fyne.CanvasObject {
"",
container.NewVBox(
statusLabel,
debugCheck,
startButton,
progressBar,
),
@@ -250,3 +252,22 @@ func updateStartButton(label1, label2, folderOutputLabel *widget.Label, button *
button.Disable()
}
}

func showErrorDialog(win fyne.Window, err error) {
if err == nil {
return
}

errorStr := err.Error()
copyButton := widget.NewButton("Copy Error", func() {
win.Clipboard().SetContent(errorStr)
})

errorLabel := widget.NewLabel(errorStr)
errorLabel.Wrapping = fyne.TextWrapWord

content := container.NewVBox(errorLabel, copyButton)
d := dialog.NewCustom("Error", "Close", content, win)
d.Resize(fyne.NewSize(700, 500))
d.Show()
}
32 changes: 25 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
@@ -2,7 +2,11 @@ package main

import (
"context"
"fmt"
"net/url"
"strconv"
"strings"

"github.com/dpolakovics/soundscape-sync/internal/ui"

"fyne.io/fyne/v2"
@@ -12,9 +16,6 @@ import (
"fyne.io/fyne/v2/widget"

"github.com/google/go-github/v39/github"
"fmt"
"strings"
"strconv"
)

const (
@@ -40,7 +41,7 @@ func checkForUpdates(a fyne.App, w fyne.Window) {
client := github.NewClient(nil)
release, _, err := client.Repositories.GetLatestRelease(context.Background(), owner, repo)
if err != nil {
dialog.ShowError(err, w)
showErrorDialog(w, fmt.Errorf("Failed to check for the latest release: %w. Please ensure you have an internet connection, and if the issue persists, reach out to the developer.", err))
return
}

@@ -61,7 +62,6 @@ func checkForUpdates(a fyne.App, w fyne.Window) {
}

func isNewerVersion(oldVer, newVer string) bool {
// Strip leading 'v'
oldVer = strings.TrimPrefix(oldVer, "v")
newVer = strings.TrimPrefix(newVer, "v")

@@ -78,6 +78,24 @@ func isNewerVersion(oldVer, newVer string) bool {
}
}

// If all matched so far, then a longer new version means it's newer
return len(newParts) > len(oldParts)
}
}

func showErrorDialog(win fyne.Window, err error) {
if err == nil {
return
}

errorStr := err.Error()
copyButton := widget.NewButton("Copy Error", func() {
win.Clipboard().SetContent(errorStr)
})

errorLabel := widget.NewLabel(errorStr)
errorLabel.Wrapping = fyne.TextWrapWord

content := container.NewVBox(errorLabel, copyButton)
d := dialog.NewCustom("Error", "Close", content, win)
d.Resize(fyne.NewSize(700, 500))
d.Show()
}

0 comments on commit 40ada38

Please sign in to comment.