mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
commit
2f679e943c
12 changed files with 132 additions and 52 deletions
|
|
@ -5,6 +5,8 @@ using System.Collections.Generic;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -16,6 +18,11 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
|
||||
private List<UserPlugin> plugins = new();
|
||||
|
||||
private static JsonSerializerOptions PluginStoreItemSerializationOption = new JsonSerializerOptions()
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Fetch and deserialize the contents of a plugins.json file found at <see cref="ManifestFileUrl"/>.
|
||||
/// We use conditional http requests to keep repeat requests fast.
|
||||
|
|
@ -32,12 +39,15 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
|
||||
request.Headers.Add("If-None-Match", latestEtag);
|
||||
|
||||
using var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);
|
||||
using var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
this.plugins = await response.Content.ReadFromJsonAsync<List<UserPlugin>>(cancellationToken: token).ConfigureAwait(false);
|
||||
this.latestEtag = response.Headers.ETag.Tag;
|
||||
this.plugins = await response.Content
|
||||
.ReadFromJsonAsync<List<UserPlugin>>(PluginStoreItemSerializationOption, cancellationToken: token)
|
||||
.ConfigureAwait(false);
|
||||
this.latestEtag = response.Headers.ETag?.Tag;
|
||||
|
||||
Log.Info(nameof(CommunityPluginSource), $"Loaded {this.plugins.Count} plugins from {ManifestFileUrl}");
|
||||
return this.plugins;
|
||||
|
|
@ -49,7 +59,8 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
}
|
||||
else
|
||||
{
|
||||
Log.Warn(nameof(CommunityPluginSource), $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
|
||||
Log.Warn(nameof(CommunityPluginSource),
|
||||
$"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
|
||||
throw new Exception($"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
public string UrlDownload { get; set; }
|
||||
public string UrlSourceCode { get; set; }
|
||||
public string IcoPath { get; set; }
|
||||
public DateTime LatestReleaseDate { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public DateTime? LatestReleaseDate { get; set; }
|
||||
public DateTime? DateAdded { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Droplex" Version="1.7.0" />
|
||||
<PackageReference Include="FSharp.Core" Version="7.0.401" />
|
||||
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.2.1" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
|
||||
<PackageReference Include="StreamJsonRpc" Version="2.17.8" />
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
_storage = new JsonStorage<ConcurrentDictionary<string, object>>(SettingPath);
|
||||
Settings = await _storage.LoadAsync();
|
||||
|
||||
if (Settings != null || Configuration == null)
|
||||
if (Configuration == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,20 +28,21 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
protected override Task<Stream> RequestAsync(JsonRPCRequestModel request, CancellationToken token = default)
|
||||
{
|
||||
_startInfo.ArgumentList[1] = JsonSerializer.Serialize(request);
|
||||
_startInfo.ArgumentList[1] = JsonSerializer.Serialize(request, RequestSerializeOption);
|
||||
return ExecuteAsync(_startInfo, token);
|
||||
}
|
||||
|
||||
protected override string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default)
|
||||
{
|
||||
// since this is not static, request strings will build up in ArgumentList if index is not specified
|
||||
_startInfo.ArgumentList[1] = JsonSerializer.Serialize(rpcRequest);
|
||||
_startInfo.ArgumentList[1] = JsonSerializer.Serialize(rpcRequest, RequestSerializeOption);
|
||||
return Execute(_startInfo);
|
||||
}
|
||||
|
||||
public override async Task InitAsync(PluginInitContext context)
|
||||
{
|
||||
_startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
||||
_startInfo.ArgumentList.Add(string.Empty);
|
||||
_startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
||||
await base.InitAsync(context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,24 @@ using System.IO.Pipelines;
|
|||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Meziantou.Framework.Win32;
|
||||
using Nerdbank.Streams;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
internal abstract class ProcessStreamPluginV2 : JsonRPCPluginV2
|
||||
{
|
||||
private static JobObject _jobObject = new JobObject();
|
||||
|
||||
static ProcessStreamPluginV2()
|
||||
{
|
||||
_jobObject.SetLimits(new JobObjectLimits()
|
||||
{
|
||||
Flags = JobObjectLimitFlags.KillOnJobClose | JobObjectLimitFlags.DieOnUnhandledException
|
||||
});
|
||||
|
||||
_jobObject.AssignProcess(Process.GetCurrentProcess());
|
||||
}
|
||||
|
||||
public override string SupportedLanguage { get; set; }
|
||||
protected sealed override IDuplexPipe ClientPipe { get; set; }
|
||||
|
|
@ -30,22 +42,22 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
ClientProcess = Process.Start(StartInfo);
|
||||
ArgumentNullException.ThrowIfNull(ClientProcess);
|
||||
|
||||
|
||||
SetupPipe(ClientProcess);
|
||||
|
||||
ErrorStream = ClientProcess.StandardError;
|
||||
|
||||
await base.InitAsync(context);
|
||||
}
|
||||
|
||||
|
||||
private void SetupPipe(Process process)
|
||||
{
|
||||
var (reader, writer) = (PipeReader.Create(process.StandardOutput.BaseStream),
|
||||
PipeWriter.Create(process.StandardInput.BaseStream));
|
||||
ClientPipe = new DuplexPipe(reader, writer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override async Task ReloadDataAsync()
|
||||
{
|
||||
var oldProcess = ClientProcess;
|
||||
|
|
@ -57,8 +69,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
await oldProcess.WaitForExitAsync();
|
||||
oldProcess.Dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
ClientProcess.Kill(true);
|
||||
|
|
|
|||
|
|
@ -5,57 +5,57 @@
|
|||
<system:String x:Key="flowlauncher_plugin_sys_command">Befehl</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_desc">Beschreibung</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_sys_shutdown_computer_cmd">Shutdown</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_computer_cmd">Restart</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_advanced_cmd">Restart With Advanced Boot Options</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_log_off_cmd">Log Off/Sign Out</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_lock_cmd">Lock</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_sleep_cmd">Sleep</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_hibernate_cmd">Hibernate</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_indexoption_cmd">Index Option</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_emptyrecyclebin_cmd">Empty Recycle Bin</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_openrecyclebin_cmd">Open Recycle Bin</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_shutdown_computer_cmd">Herunterfahren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_computer_cmd">Neu starten</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_advanced_cmd">Neustart mit erweiterten Startoptionen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_log_off_cmd">Abmelden</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_lock_cmd">Sperren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_sleep_cmd">Energie sparen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_hibernate_cmd">Ruhezustand</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_indexoption_cmd">Indizierungsoptionen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_emptyrecyclebin_cmd">Papierkorb leeren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_openrecyclebin_cmd">Papierkorb öffnen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_exit_cmd">Schließen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_save_all_settings_cmd">Save Settings</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_cmd">Restart Flow Launcher"</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_save_all_settings_cmd">Einstellungen speichern</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_cmd">Flow Launcher neu starten</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_setting_cmd">Einstellungen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_reload_plugin_data_cmd">Plugin-Daten neu laden</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_check_for_update_cmd">Check For Update</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_log_location_cmd">Open Log Location</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips_cmd">Flow Launcher Tips</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location_cmd">Flow Launcher UserData Folder</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_check_for_update_cmd">Auf Updates prüfen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_log_location_cmd">Log-Speicherort öffnen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips_cmd">Flow Launcher Tipps</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location_cmd">Flow Launcher Benutzerdaten-Ordner</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_toggle_game_mode_cmd">Gott Modus</system:String>
|
||||
|
||||
<!-- Command Descriptions -->
|
||||
<system:String x:Key="flowlauncher_plugin_sys_shutdown_computer">Computer herunterfahren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_computer">Computer neu starten</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_advanced">Restart the computer with Advanced Boot Options for Safe and Debugging modes, as well as other options</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart_advanced">Startet den Computer mit erweiterten Startoptionen für den abgesicherten Modus neu</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_log_off">Abmelden</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_lock">Computer sperren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_exit">Flow Launcher schließen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_restart">Flow Launcher neu starten</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_setting">Tweak Flow Launcher's settings</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_setting">Einstellungen des Flow Launchers anpassen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_sleep">Computer in Schlafmodus versetzen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_emptyrecyclebin">Papierkorb leeren</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_openrecyclebin">Open recycle bin</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_indexoption">Indexierungsoptionen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_hibernate">Hibernate computer</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_save_all_settings">Save all Flow Launcher settings</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_reload_plugin_data">Refreshes plugin data with new content</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_log_location">Open Flow Launcher's log location</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_check_for_update">Check for new Flow Launcher update</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips">Visit Flow Launcher's documentation for more help and how to use tips</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location">Open the location where Flow Launcher's settings are stored</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_openrecyclebin">Papierkorb öffnen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_indexoption">Indizierungsoptionen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_hibernate">Computer in den Ruhezustand versetzen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_save_all_settings">Alle Flow Launcher Einstellungen speichern</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_reload_plugin_data">Aktualisiert Plugin-Daten mit neuen Inhalten</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_log_location">Öffnet den Speicherort der Flow Launcher Logs</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_check_for_update">Prüft auf neue Flow Launcher Updates</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips">Öffnet die Dokumentation von Flow Launcher für Hilfe und Tipps</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location">Öffnet den Ort an dem Flow Laucher Einstellungen speichert</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_toggle_game_mode">Gott Modus</system:String>
|
||||
|
||||
<!-- Dialogs -->
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtitle_success">Erfolgreich</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_settings_saved">All Flow Launcher settings saved</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded">Reloaded all applicable plugin data</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_shutdown_computer">Are you sure you want to shut the computer down?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_restart_computer">Are you sure you want to restart the computer?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_restart_computer_advanced">Are you sure you want to restart the computer with Advanced Boot Options?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_logoff_computer">Are you sure you want to log off?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_settings_saved">Alle Flow Launcher Einstellungen wurden gespeichert</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded">Alle betroffenen Plugin-Daten wurden neu geladen</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_shutdown_computer">Soll der Computer wirklich heruntergefahren werden?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_restart_computer">Soll der Computer wirklich neu gestartet werden?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_restart_computer_advanced">Soll der Computer wirklich mit erweiterten Startoptionen neu gestartet werden?</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_logoff_computer">Soll der aktuelle Benutzer wirklich abgemeldet werden?</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_sys_plugin_name">Systembefehle</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_plugin_description">Stellt Systemrelevante Befehle bereit. z.B. herunterfahren, sperren, Einstellungen, usw.</system:String>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "System Commands",
|
||||
"Description": "Provide System related commands. e.g. shutdown,lock, setting etc.",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.1.0",
|
||||
"Version": "3.1.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll",
|
||||
|
|
|
|||
|
|
@ -197,7 +197,8 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
public SuggestionSource[] Suggestions { get; set; } = {
|
||||
new Google(),
|
||||
new Baidu(),
|
||||
new Bing()
|
||||
new Bing(),
|
||||
new DuckDuckGo()
|
||||
};
|
||||
|
||||
[JsonIgnore]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Infrastructure.Http;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
|
||||
{
|
||||
public class DuckDuckGo : SuggestionSource
|
||||
{
|
||||
public override async Task<List<string>> SuggestionsAsync(string query, CancellationToken token)
|
||||
{
|
||||
// When the search query is empty, DuckDuckGo returns `[]`. When it's not empty, it returns data
|
||||
// in the following format: `["query", ["suggestion1", "suggestion2", ...]]`.
|
||||
if (string.IsNullOrEmpty(query))
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const string api = "https://duckduckgo.com/ac/?type=list&q=";
|
||||
|
||||
await using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeDataString(query), token: token).ConfigureAwait(false);
|
||||
|
||||
using var json = await JsonDocument.ParseAsync(resultStream, cancellationToken: token);
|
||||
|
||||
var results = json.RootElement.EnumerateArray().ElementAt(1);
|
||||
|
||||
return results.EnumerateArray().Select(o => o.GetString()).ToList();
|
||||
|
||||
}
|
||||
catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException})
|
||||
{
|
||||
Log.Exception("|DuckDuckGo.Suggestions|Can't get suggestion from DuckDuckGo", e);
|
||||
return null;
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Log.Exception("|DuckDuckGo.Suggestions|can't parse suggestions", e);
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "DuckDuckGo";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
"Name": "Web Searches",
|
||||
"Description": "Provide the web search ability",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.0.6",
|
||||
"Version": "3.0.7",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version: '1.17.1.{build}'
|
||||
version: '1.17.2.{build}'
|
||||
|
||||
init:
|
||||
- ps: |
|
||||
|
|
|
|||
Loading…
Reference in a new issue