Skip to content

Commit 40d9f19

Browse files
committed
Replaced winget search CLI with API
1 parent f9f4759 commit 40d9f19

File tree

1 file changed

+44
-109
lines changed

1 file changed

+44
-109
lines changed

Main.cs

Lines changed: 44 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
using System.Diagnostics;
88
using System.Globalization;
99
using System.IO;
10+
using System.IO.Packaging;
1011
using System.Linq;
12+
using System.Net;
13+
using System.Net.Http;
14+
using System.Net.Http.Json;
1115
using System.Reflection;
16+
using System.Text.Json;
1217
using System.Text.RegularExpressions;
1318
using System.Threading;
1419
using System.Windows.Controls;
@@ -28,6 +33,8 @@ public partial class Main : IPlugin, IPluginI18n, IContextMenu, ISettingProvider
2833
// Should only be set in Init()
2934
private Action onPluginError;
3035

36+
private static List<WingetPackage> packagesList;
37+
3138
private const string NotGlobalIfUri = nameof(NotGlobalIfUri);
3239

3340
/// <summary>If true, dont show global result on queries that are URIs</summary>
@@ -58,6 +65,7 @@ public partial class Main : IPlugin, IPluginI18n, IContextMenu, ISettingProvider
5865
// constructor
5966
public Main()
6067
{
68+
GetPackages();
6169
LoadInstalledList();
6270
}
6371

@@ -85,6 +93,35 @@ private static void LoadInstalledList()
8593
installed = output;
8694
}
8795

96+
public class WingetPackage
97+
{
98+
public string Name { get; set; }
99+
100+
public string Company { get; set; }
101+
102+
public string Version { get; set; }
103+
}
104+
105+
private static async void GetPackages()
106+
{
107+
// Download packages list
108+
var packages = new List<string>();
109+
HttpClient client = new HttpClient();
110+
HttpResponseMessage response = await client.GetAsync("https://bostrot.github.io/PowerToysRunPluginWinget/pkgs.json");
111+
response.EnsureSuccessStatusCode();
112+
string responseBody = await response.Content.ReadAsStringAsync();
113+
114+
// Allow trailing comma
115+
var options = new JsonSerializerOptions
116+
{
117+
AllowTrailingCommas = true,
118+
PropertyNameCaseInsensitive = true,
119+
};
120+
121+
// Parse response to JSON and ignore use lowercase first letter instead of uppercase
122+
packagesList = JsonSerializer.Deserialize<List<WingetPackage>>(responseBody, options);
123+
}
124+
88125
public List<Result> Query(Query query)
89126
{
90127
if (query is null)
@@ -115,126 +152,24 @@ public List<Result> Query(Query query)
115152
else
116153
{
117154
string searchTerm = query.Search;
118-
119-
Process process = new Process();
120-
121-
process.StartInfo.FileName = "winget";
122-
process.StartInfo.Arguments = $"search \"{searchTerm}\"";
123-
process.StartInfo.UseShellExecute = false;
124-
process.StartInfo.CreateNoWindow = true;
125-
process.StartInfo.RedirectStandardOutput = true;
126-
process.Start();
127-
128-
string output = process.StandardOutput.ReadToEnd();
129-
process.WaitForExit();
130-
131-
// UTF16 to UTF8
132-
output = System.Text.Encoding.UTF8.GetString(
133-
System.Text.Encoding.Convert(
134-
System.Text.Encoding.Unicode,
135-
System.Text.Encoding.UTF8,
136-
System.Text.Encoding.Unicode.GetBytes(output)));
137-
138-
// If there is no error, iterate through the output and add each line as a result
139-
string[] lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
140-
141-
var id = 0;
142-
143-
int nameChars = 0;
144-
int idChars = 0;
145-
int versionChars = 0;
146-
int matchChars = 0;
147-
148-
// Regex for words in header
149-
string v = lines[0];
150-
var matches = Regex.Matches(v, @"\S+");
151-
152-
if (matches != null)
155+
foreach (WingetPackage package in packagesList)
153156
{
154-
// Get chars between Name, ID, Version, Matches, Source length including spaces
155-
if (matches.Count == 5)
157+
var idStr = $"{package.Company}.{package.Name}";
158+
if (package.Name.ToLower().Contains(searchTerm.ToLower()) || package.Company.ToLower().Contains(searchTerm.ToLower()))
156159
{
157-
nameChars = matches[2].Index - matches[1].Index;
158-
idChars = matches[3].Index - 1 - matches[2].Index;
159-
versionChars = matches[4].Index - matches[3].Index;
160-
}
161-
else if (matches.Count == 6)
162-
{
163-
nameChars = matches[2].Index - matches[1].Index;
164-
idChars = matches[3].Index - 1 - matches[2].Index;
165-
versionChars = matches[4].Index - matches[3].Index;
166-
matchChars = matches[5].Index - 1 - matches[4].Index;
167-
}
168-
}
169-
170-
foreach (string line0 in lines)
171-
{
172-
// Skip header
173-
if (id < 2)
174-
{
175-
id++;
176-
continue;
177-
}
178-
179-
// Filter non-text, non-number, non-space and non (-_.,) characters
180-
var line = AllowedCharacters().Replace(line0, string.Empty);
181-
182-
if (line != string.Empty)
183-
{
184-
string name = string.Empty;
185-
string idStr = string.Empty;
186-
string version = string.Empty;
187-
string match = string.Empty;
188-
string source = string.Empty;
189-
try
190-
{
191-
// Divide line into 5 parts by split
192-
name = line.Substring(0, nameChars).Trim();
193-
idStr = line.Substring(nameChars, idChars).Trim();
194-
version = line.Substring(nameChars + idChars, versionChars).Trim();
195-
if (matches.Count == 6)
196-
{
197-
match = line.Substring(versionChars + nameChars + idChars, matchChars).Trim();
198-
source = line.Substring(matchChars + versionChars + nameChars + idChars).Trim();
199-
}
200-
else
201-
{
202-
match = string.Empty;
203-
}
204-
}
205-
catch (Exception e)
206-
{
207-
name = e.ToString();
208-
}
209-
210-
// Check if result is empty
211-
if (name == string.Empty)
212-
{
213-
continue;
214-
}
215-
216-
string title = $"{name} ({idStr})";
217-
string subTitle = $"{Properties.Resources.plugin_result_name} {name} [{version}] ({source}) {match}";
218-
219-
if (source == string.Empty)
220-
{
221-
subTitle = $"{Properties.Resources.plugin_result_name} {name} [{version}]";
222-
}
223-
224160
results.Add(new Result
225161
{
226-
Title = title,
227-
SubTitle = subTitle,
228-
QueryTextDisplay = name,
162+
Title = package.Name,
163+
SubTitle = $"by {package.Company} version: {package.Version}",
164+
QueryTextDisplay = idStr,
229165
IcoPath = _iconPath,
230166
ProgramArguments = idStr,
231167
Action = action =>
232168
{
233-
Winget("install " + idStr + " --wait");
169+
Winget($"install {idStr} --wait");
234170
return true;
235171
},
236172
});
237-
id++;
238173
}
239174
}
240175
}

0 commit comments

Comments
 (0)