refactor: implement cross-platform abstraction for process management, media control, and startup configuration (TESTING)

This commit is contained in:
jahruz67
2026-04-09 21:31:02 -07:00
parent cc644e3059
commit ba0e75c503
25 changed files with 458 additions and 48 deletions
+42
View File
@@ -0,0 +1,42 @@
//go:build linux
package linux
import (
"os/exec"
"wis-free-v3/internal/logger"
)
// IsPlaying checks if media is currently playing using playerctl
func IsPlaying() bool {
cmd := exec.Command("playerctl", "status")
out, err := cmd.Output()
if err != nil {
return false
}
return string(out) == "Playing\n"
}
// TogglePlayPause sends the play-pause command via playerctl
func TogglePlayPause() {
cmd := exec.Command("playerctl", "play-pause")
err := cmd.Run()
if err != nil {
logger.Error("Failed to toggle media on Linux: %v", err)
}
}
// PauseMedia checks if playing, pauses if so, returns whether we paused
func PauseMedia() bool {
wasPlaying := IsPlaying()
if wasPlaying {
TogglePlayPause()
}
return wasPlaying
}
// ResumeMedia resumes only if we paused it
func ResumeMedia(wasPaused bool) {
if wasPaused {
TogglePlayPause()
}
}
+15
View File
@@ -0,0 +1,15 @@
//go:build linux
package linux
// linuxOverlay provides a simple dummy implementation for Linux.
// It relies on tray icon status updates for visual feedback instead of raw drawing.
type linuxOverlay struct{}
func NewOverlay() *linuxOverlay {
return &linuxOverlay{}
}
func (o *linuxOverlay) Show(message string) {}
func (o *linuxOverlay) Hide() {}
func (o *linuxOverlay) SetVolume(level float64) {}
func (o *linuxOverlay) Close() {}
+11
View File
@@ -0,0 +1,11 @@
//go:build linux
package linux
import "syscall"
// IsProcessRunning checks if a process with the given PID exists on Linux.
func IsProcessRunning(pid int) bool {
// sending signal 0 checks if the process exists and we have permission
err := syscall.Kill(pid, 0)
return err == nil
}
+91
View File
@@ -0,0 +1,91 @@
//go:build linux
package linux
import (
"fmt"
"os"
"path/filepath"
)
const (
appName = "wis-free-v3"
desktopFileContent = `[Desktop Entry]
Type=Application
Name=WIS Free V3
Exec="%s"
Terminal=false
Categories=Utility;
X-GNOME-Autostart-enabled=true
`
)
func getAutostartPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
configDir := os.Getenv("XDG_CONFIG_HOME")
if configDir == "" {
configDir = filepath.Join(home, ".config")
}
autostartDir := filepath.Join(configDir, "autostart")
if err := os.MkdirAll(autostartDir, 0755); err != nil {
return "", err
}
return filepath.Join(autostartDir, appName+".desktop"), nil
}
func getExecutablePath() (string, error) {
exe, err := os.Executable()
if err != nil {
return "", err
}
return filepath.Abs(exe)
}
func AddToStartup() error {
autostartPath, err := getAutostartPath()
if err != nil {
return fmt.Errorf("failed to determine autostart path: %w", err)
}
exePath, err := getExecutablePath()
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
content := fmt.Sprintf(desktopFileContent, exePath)
if err := os.WriteFile(autostartPath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write autostart file: %w", err)
}
return nil
}
func RemoveFromStartup() error {
autostartPath, err := getAutostartPath()
if err != nil {
return fmt.Errorf("failed to determine autostart path: %w", err)
}
if err := os.Remove(autostartPath); err != nil {
if !os.IsNotExist(err) {
return fmt.Errorf("failed to remove autostart file: %w", err)
}
}
return nil
}
func IsInStartup() bool {
autostartPath, err := getAutostartPath()
if err != nil {
return false
}
_, err = os.Stat(autostartPath)
return err == nil
}