diff --git a/src/internal/browserlauncher/browserlauncher.go b/src/internal/browserlauncher/browserlauncher.go
new file mode 100644
index 0000000..bc14a7d
--- /dev/null
+++ b/src/internal/browserlauncher/browserlauncher.go
@@ -0,0 +1,75 @@
+package browserlauncher
+
+import (
+ "fmt"
+ "os/exec"
+ "runtime"
+
+ "git.weirdcat.su/weirdcat/auto-attendance/internal/config"
+ "git.weirdcat.su/weirdcat/auto-attendance/internal/logger"
+)
+
+type BrowserLauncher interface {
+ OpenDefault(url string) error
+ OpenCustom(url string) error
+ OpenAuto(url string) error
+}
+
+type browserLauncherImpl struct {
+ config *config.Config
+ log *logger.Logger
+ useCustomCommand bool
+ customCommand string
+}
+
+// OpenAuto implements BrowserLauncher.
+func (b *browserLauncherImpl) OpenAuto(url string) error {
+ if (b.useCustomCommand) {
+ return b.OpenCustom(url)
+ } else {
+ return b.OpenDefault(url)
+ }
+}
+
+// OpenCustom implements BrowserLauncher.
+func (b *browserLauncherImpl) OpenCustom(url string) error {
+ command := fmt.Sprintf(b.customCommand, url)
+
+ b.log.Debug("opening link with custom command", "command", command, "url", url)
+ err := exec.Command(command).Start()
+
+ if err != nil {
+ b.log.Error("failed to open link with custom command", "command", command, "url", url, "error", err)
+ }
+
+ return err
+}
+
+// OpenDefault implements BrowserLauncher.
+func (b *browserLauncherImpl) OpenDefault(url string) (err error) {
+ b.log.Debug("opening link with default browser", "url", url)
+ switch runtime.GOOS {
+ case "windows":
+ err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
+ default:
+ err = exec.Command("xdg-open", url).Start()
+ }
+
+ if err != nil {
+ b.log.Error("failed to open link with default browser", "url", url, "error", err)
+ }
+
+ return err
+}
+
+func NewBrowserLauncher(config *config.Config, log *logger.Logger) BrowserLauncher {
+
+ useCustomCommand := config.App.UseCustomBrowserCommand
+ customCommand := config.App.BrowserOpenCommand
+ return &browserLauncherImpl{
+ config: config,
+ log: log,
+ useCustomCommand: useCustomCommand,
+ customCommand: customCommand,
+ }
+}
diff --git a/src/internal/browserlauncher/chrome.go b/src/internal/browserlauncher/chrome.go
deleted file mode 100644
index 2639813..0000000
--- a/src/internal/browserlauncher/chrome.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2025 Nikolai Papin
-//
-// This file is part of the Auto Attendance app that looks for
-// self-attend QR-codes during lectures and opens their URLs in your
-// browser.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-// the GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package browserlauncher
diff --git a/src/internal/browserlauncher/firefox.go b/src/internal/browserlauncher/firefox.go
deleted file mode 100644
index 2639813..0000000
--- a/src/internal/browserlauncher/firefox.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2025 Nikolai Papin
-//
-// This file is part of the Auto Attendance app that looks for
-// self-attend QR-codes during lectures and opens their URLs in your
-// browser.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-// the GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package browserlauncher
diff --git a/src/internal/config/config.go b/src/internal/config/config.go
index baf4bd3..2cae791 100644
--- a/src/internal/config/config.go
+++ b/src/internal/config/config.go
@@ -41,7 +41,8 @@ type AppConfig struct {
EnableAlarm bool `mapstructure:"enable_alarm"`
EnableLinkOpening bool `mapstructure:"enable_link_opening"`
UseAttendanceJounralApi bool `mapstructure:"use_attendance_journal_api"`
- Browser string `mapstructure:"browser"`
+ UseCustomBrowserCommand bool `mapstructure:"use_custom_browser_command"`
+ BrowserOpenCommand string `mapstructure:"browser_open_command"`
EnableCheckingUpdates bool `mapstructure:"enable_checking_updates"`
}
@@ -79,7 +80,8 @@ func getDefaultConfig() Config {
EnableAlarm: false,
EnableLinkOpening: true,
UseAttendanceJounralApi: false,
- Browser: "firefox",
+ UseCustomBrowserCommand: false,
+ BrowserOpenCommand: "firefox %s",
EnableCheckingUpdates: true,
},
Screenshot: ScreenshotConfig{
@@ -132,7 +134,8 @@ func initializeViper(appName string) (*viper.Viper, string, error) {
v.SetDefault("app.enable_alarm", defaults.App.EnableAlarm)
v.SetDefault("app.enable_link_opening", defaults.App.EnableLinkOpening)
v.SetDefault("app.use_attendance_journal_api", defaults.App.UseAttendanceJounralApi)
- v.SetDefault("app.browser", defaults.App.Browser)
+ v.SetDefault("app.use_custom_browser_command", defaults.App.UseCustomBrowserCommand)
+ v.SetDefault("app.browser_open_command", defaults.App.BrowserOpenCommand)
v.SetDefault("app.enable_checking_updates", defaults.App.EnableCheckingUpdates)
v.SetDefault("screenshot.screen_index", defaults.Screenshot.ScreenIndex)
@@ -159,7 +162,8 @@ func (c *Config) Save() error {
v.Set("app.enable_alarm", c.App.EnableAlarm)
v.Set("app.enable_link_opening", c.App.EnableLinkOpening)
v.Set("app.use_attendance_journal_api", c.App.UseAttendanceJounralApi)
- v.Set("app.browser", c.App.Browser)
+ v.Set("app.use_custom_browser_command", c.App.UseCustomBrowserCommand)
+ v.Set("app.browser_open_command", c.App.BrowserOpenCommand)
v.Set("app.enable_checking_updates", c.App.EnableCheckingUpdates)
v.Set("screenshot.screen_index", c.Screenshot.ScreenIndex)