diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs
index 33963c01a..692fe3ce1 100644
--- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs
+++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs
@@ -277,6 +277,97 @@ public static class PluginInstaller
}
}
+ ///
+ /// Updates the plugin to the latest version available from its source.
+ ///
+ /// If true, do not show any messages when there is no udpate available.
+ /// If true, only use the primary URL for updates.
+ /// Cancellation token to cancel the update operation.
+ ///
+ public static async Task UpdatePluginAsync(bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default)
+ {
+ // Update the plugin manifest
+ await API.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
+
+ // Get all plugins that can be updated
+ var resultsForUpdate = (
+ from existingPlugin in API.GetAllPlugins()
+ join pluginUpdateSource in API.GetPluginManifest()
+ on existingPlugin.Metadata.ID equals pluginUpdateSource.ID
+ where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version,
+ StringComparison.InvariantCulture) <
+ 0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest)
+ && !API.PluginModified(existingPlugin.Metadata.ID)
+ select
+ new
+ {
+ existingPlugin.Metadata.ID,
+ pluginUpdateSource.Name,
+ pluginUpdateSource.Author,
+ CurrentVersion = existingPlugin.Metadata.Version,
+ NewVersion = pluginUpdateSource.Version,
+ existingPlugin.Metadata.IcoPath,
+ PluginExistingMetadata = existingPlugin.Metadata,
+ PluginNewUserPlugin = pluginUpdateSource
+ }).ToList();
+
+ // No updates
+ if (!resultsForUpdate.Any())
+ {
+ if (!silentUpdate)
+ {
+ API.ShowMsg(API.GetTranslation("updateNoResultTitle"), API.GetTranslation("updateNoResultSubtitle"));
+ }
+ return;
+ }
+
+ // If all plugins are modified, just return
+ if (resultsForUpdate.All(x => API.PluginModified(x.ID)))
+ {
+ return;
+ }
+
+ if (API.ShowMsgBox(
+ string.Format(API.GetTranslation("updateAllPluginsSubtitle"),
+ Environment.NewLine, string.Join(", ", resultsForUpdate.Select(x => x.PluginExistingMetadata.Name))),
+ API.GetTranslation("updateAllPluginsTitle"),
+ MessageBoxButton.YesNo) == MessageBoxResult.No)
+ {
+ return;
+ }
+
+ // Update all plugins
+ await Task.WhenAll(resultsForUpdate.Select(async plugin =>
+ {
+ var downloadToFilePath = Path.Combine(Path.GetTempPath(), $"{plugin.Name}-{plugin.NewVersion}.zip");
+
+ try
+ {
+ using var cts = new CancellationTokenSource();
+
+ await DownloadFileAsync(
+ $"{API.GetTranslation("DownloadingPlugin")} {plugin.PluginNewUserPlugin.Name}",
+ plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
+
+ // check if user cancelled download before installing plugin
+ if (cts.IsCancellationRequested)
+ {
+ return;
+ }
+
+ if (!await API.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
+ {
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ API.LogException(ClassName, "Failed to update plugin", e);
+ API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
+ }
+ }));
+ }
+
///
/// Downloads a file from a URL to a local path, optionally showing a progress box and handling cancellation.
///
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index ad7b44f10..6b04f11d9 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -239,6 +239,7 @@ namespace Flow.Launcher
AutoStartup();
AutoUpdates();
+ AutoPluginUpdates();
API.SaveAppAllSettings();
API.LogInfo(ClassName, "End Flow Launcher startup ----------------------------------------------------");
@@ -289,6 +290,23 @@ namespace Flow.Launcher
});
}
+ private static void AutoPluginUpdates()
+ {
+ _ = Task.Run(async () =>
+ {
+ if (_settings.AutoUpdatePlugins)
+ {
+ // check plugin updates every 5 hour
+ var timer = new PeriodicTimer(TimeSpan.FromHours(5));
+ await PluginInstaller.UpdatePluginAsync();
+
+ while (await timer.WaitForNextTickAsync())
+ // check updates on startup
+ await PluginInstaller.UpdatePluginAsync();
+ }
+ });
+ }
+
#endregion
#region Register Events
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 7a5dc0c07..efbb1de3b 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -233,6 +233,10 @@
Zip files
Please select zip file
Install plugin from local path
+ No update available
+ All plugins are up to date
+ Update all plugins
+ Would you like to update these plugins?{0}{0}{1}
Theme