From b04c8a6283a196af248646789ecac3e238a28d15 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 11:52:23 +0900 Subject: [PATCH 1/2] feat: support beta channel updates (fixes #60) --- frontend/src/SettingsWindow.tsx | 15 +++++++++ settings.go | 4 +++ updater.go | 58 ++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/frontend/src/SettingsWindow.tsx b/frontend/src/SettingsWindow.tsx index 9233d48..02ddd47 100644 --- a/frontend/src/SettingsWindow.tsx +++ b/frontend/src/SettingsWindow.tsx @@ -18,6 +18,7 @@ function SettingsWindow() { const [watchFolder, setWatchFolder] = useState(""); const [exportFolder, setExportFolder] = useState(""); const [jpegQuality, setJpegQuality] = useState("auto"); + const [enableBetaUpdates, setEnableBetaUpdates] = useState(false); // Frame Settings const [aspectRatioPreset, setAspectRatioPreset] = useState("4300:3618"); @@ -46,6 +47,7 @@ function SettingsWindow() { setWatchFolder(s.watchFolder || ""); setExportFolder(s.exportFolder || ""); setJpegQuality(s.jpegQuality || "auto"); + setEnableBetaUpdates(s.enableBetaUpdates ?? false); setAspectRatioPreset(s.aspectRatioPreset || "4300:3618"); setCustomRatioW(s.customRatioW || 4300); @@ -102,6 +104,7 @@ function SettingsWindow() { s.watchFolder = watchFolder; s.exportFolder = exportFolder; s.jpegQuality = jpegQuality; + s.enableBetaUpdates = enableBetaUpdates; s.aspectRatioPreset = aspectRatioPreset; s.customRatioW = customRatioW; s.customRatioH = customRatioH; @@ -222,6 +225,18 @@ function SettingsWindow() { Auto calculates the optimal quality based on the original image compression to prevent file size bloat. +
+ + Receive pre-release (beta) versions of ExifFrame automatically. +
)} {activeTab === 'frame' && ( diff --git a/settings.go b/settings.go index 492c283..2bfe1c7 100644 --- a/settings.go +++ b/settings.go @@ -52,6 +52,9 @@ type Settings struct { VisibilityDilution bool `json:"visibilityDilution"` VisibilityTemperature bool `json:"visibilityTemperature"` VisibilityTime bool `json:"visibilityTime"` + + // Updater settings + EnableBetaUpdates bool `json:"enableBetaUpdates"` } var ( @@ -97,6 +100,7 @@ func init() { VisibilityDilution: true, VisibilityTemperature: true, VisibilityTime: true, + EnableBetaUpdates: false, } loadSettings() } diff --git a/updater.go b/updater.go index ab85446..827e968 100644 --- a/updater.go +++ b/updater.go @@ -2,6 +2,7 @@ package main import ( "context" + "io" "log" "strings" "time" @@ -17,27 +18,74 @@ const ( updateCheckInterval = 4 * time.Hour ) +// dynamicGithubProvider routes updater requests to either a stable or beta +// GitHub provider depending on the user's settings. +type dynamicGithubProvider struct { + stableProvider updater.Provider + betaProvider updater.Provider +} + +func (p *dynamicGithubProvider) Name() string { + return "github" +} + +func (p *dynamicGithubProvider) Check(ctx context.Context, req updater.CheckRequest) (*updater.Release, error) { + settingsMu.RLock() + betaEnabled := currentSettings.EnableBetaUpdates + settingsMu.RUnlock() + + if betaEnabled { + return p.betaProvider.Check(ctx, req) + } + return p.stableProvider.Check(ctx, req) +} + +func (p *dynamicGithubProvider) Download(ctx context.Context, r *updater.Release, dst io.Writer, onProgress func(written, total int64)) error { + settingsMu.RLock() + betaEnabled := currentSettings.EnableBetaUpdates + settingsMu.RUnlock() + + if betaEnabled { + return p.betaProvider.Download(ctx, r, dst, onProgress) + } + return p.stableProvider.Download(ctx, r, dst, onProgress) +} + // InitUpdater initialises the Wails v3 built-in updater on the given app // instance. It configures a GitHub provider pointed at the ExifFrame // repository and enables periodic background checks. func InitUpdater(app *application.App) { - ghProvider, err := github.New(github.Config{ + stableProvider, err := github.New(github.Config{ + Repository: updateOwner + "/" + updateRepo, + ChecksumAsset: "SHA256SUMS", + Prerelease: false, + }) + if err != nil { + log.Printf("GitHub stable provider creation failed: %v", err) + return + } + + betaProvider, err := github.New(github.Config{ Repository: updateOwner + "/" + updateRepo, ChecksumAsset: "SHA256SUMS", + Prerelease: true, }) if err != nil { - // Non-fatal: if the provider can't be constructed the app still works, - // just without auto-update. - log.Printf("GitHub provider creation failed: %v", err) + log.Printf("GitHub beta provider creation failed: %v", err) return } + dynProvider := &dynamicGithubProvider{ + stableProvider: stableProvider, + betaProvider: betaProvider, + } + // The Wails updater expects versions without the "v" prefix. ver := strings.TrimPrefix(Version, "v") err = app.Updater.Init(updater.Config{ CurrentVersion: ver, - Providers: []updater.Provider{ghProvider}, + Providers: []updater.Provider{dynProvider}, CheckInterval: updateCheckInterval, }) if err != nil { From 85887c8f92bb3e7e84f1d578254c76d295aa57c4 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 11:56:29 +0900 Subject: [PATCH 2/2] fix: embed updater.Provider in dynamic provider for interface compatibility --- updater.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/updater.go b/updater.go index 827e968..0413380 100644 --- a/updater.go +++ b/updater.go @@ -21,13 +21,12 @@ const ( // dynamicGithubProvider routes updater requests to either a stable or beta // GitHub provider depending on the user's settings. type dynamicGithubProvider struct { - stableProvider updater.Provider - betaProvider updater.Provider + updater.Provider // Embedded default provider for future-proofing interface additions + betaProvider updater.Provider } -func (p *dynamicGithubProvider) Name() string { - return "github" -} +// We let the embedded Provider handle Name(), which will correctly return "github" +// or whatever the underlying github provider returns. func (p *dynamicGithubProvider) Check(ctx context.Context, req updater.CheckRequest) (*updater.Release, error) { settingsMu.RLock() @@ -37,7 +36,7 @@ func (p *dynamicGithubProvider) Check(ctx context.Context, req updater.CheckRequ if betaEnabled { return p.betaProvider.Check(ctx, req) } - return p.stableProvider.Check(ctx, req) + return p.Provider.Check(ctx, req) } func (p *dynamicGithubProvider) Download(ctx context.Context, r *updater.Release, dst io.Writer, onProgress func(written, total int64)) error { @@ -48,7 +47,7 @@ func (p *dynamicGithubProvider) Download(ctx context.Context, r *updater.Release if betaEnabled { return p.betaProvider.Download(ctx, r, dst, onProgress) } - return p.stableProvider.Download(ctx, r, dst, onProgress) + return p.Provider.Download(ctx, r, dst, onProgress) } // InitUpdater initialises the Wails v3 built-in updater on the given app @@ -76,8 +75,8 @@ func InitUpdater(app *application.App) { } dynProvider := &dynamicGithubProvider{ - stableProvider: stableProvider, - betaProvider: betaProvider, + Provider: stableProvider, + betaProvider: betaProvider, } // The Wails updater expects versions without the "v" prefix.