diff --git a/BlueberryUpdater/BlueberryUpdater.csproj b/BlueberryUpdater/BlueberryUpdater.csproj
index 82ce019..e76b315 100644
--- a/BlueberryUpdater/BlueberryUpdater.csproj
+++ b/BlueberryUpdater/BlueberryUpdater.csproj
@@ -9,16 +9,22 @@
bb.ico
+
+ true
+
+ true
+ true
+ true
+
+ true
+ false
+ false
+
+
PreserveNewest
-
-
- false
-
-
-
diff --git a/BlueberryUpdater/Program.cs b/BlueberryUpdater/Program.cs
index 4672b43..d7c3b95 100644
--- a/BlueberryUpdater/Program.cs
+++ b/BlueberryUpdater/Program.cs
@@ -1,6 +1,9 @@
using System.Diagnostics;
using System.IO.Compression;
+using System.Net.Http.Json;
using System.Reflection;
+using System.Text.Json;
+using Windows.Media.Protection.PlayReady;
namespace BlueberryUpdater
{
@@ -65,7 +68,23 @@ namespace BlueberryUpdater
{
try
{
- string resourceName = "BlueberryUpdater.AppPayload.zip"; // Format: Namespace.Filename
+ var client = new HttpClient();
+ client.DefaultRequestHeaders.UserAgent.ParseAdd("BlueberryUpdater");
+
+ string releaseUrl = "https://git.technopunk.space/api/v1/repos/tomi/Blueberry/releases/latest";
+
+ // 1. Fetch JSON
+ var root = client.GetFromJsonAsync(releaseUrl).ConfigureAwait(false).GetAwaiter().GetResult();
+
+ // 2. Find URL for "payload.zip"
+ string downloadUrl = root.GetProperty("assets")
+ .EnumerateArray()
+ .First(x => x.GetProperty("name").GetString() == "payload.zip")
+ .GetProperty("browser_download_url")
+ .GetString() ?? throw new NullReferenceException();
+
+ Console.WriteLine("Downloading Blueberry...");
+ var stream = DownloadFileWithProgressAsync(client, downloadUrl).GetAwaiter().GetResult();
Console.WriteLine($"Installing to {installPath}...");
@@ -76,56 +95,9 @@ namespace BlueberryUpdater
}
Directory.CreateDirectory(installPath);
- // 2. Extract Embedded Resource
- var assembly = Assembly.GetExecutingAssembly();
-
- using (Stream stream = assembly.GetManifestResourceStream(resourceName))
- {
- if (stream == null)
- {
- throw new Exception($"Resource '{resourceName}' not found. Check Embedded Resource settings.");
- }
-
- using (ZipArchive archive = new(stream))
- {
- int totalEntries = archive.Entries.Count;
- int currentEntry = 0;
-
- foreach (ZipArchiveEntry entry in archive.Entries)
- {
- currentEntry++;
-
- // Calculate percentage
- int percent = (int)((double)currentEntry / totalEntries * 100);
-
- // Draw Progress Bar
- DrawProgressBar(percent, entry.Name);
-
- // Create the full path
- string destinationPath = Path.GetFullPath(Path.Combine(installPath, entry.FullName));
-
- // Security check: prevent ZipSlip (writing outside target folder)
- if (!destinationPath.StartsWith(installPath, StringComparison.OrdinalIgnoreCase))
- continue;
-
- // Handle folders vs files
- if (string.IsNullOrEmpty(entry.Name)) // It's a directory
- {
- Directory.CreateDirectory(destinationPath);
- }
- else // It's a file
- {
- // Ensure the directory exists (zipped files might not list their dir first)
- Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
- entry.ExtractToFile(destinationPath, overwrite: true);
- }
- }
- }
- }
-
+ ExtractWithProgress(stream);
MoveUpdater();
- DrawProgressBar(100, "Done");
Console.WriteLine();
Console.WriteLine("Installation Complete!");
@@ -181,7 +153,7 @@ namespace BlueberryUpdater
string shortName = filename.Length > 20 ? filename.Substring(0, 17) + "..." : filename.PadRight(20);
Console.Write("[");
- int width = Console.WindowWidth - 1; // Width of the bar
+ int width = Console.WindowWidth - 21; // Width of the bar
int progress = (int)((percent / 100.0) * width);
// Draw filled part
@@ -191,5 +163,72 @@ namespace BlueberryUpdater
Console.Write($"] {percent}% {shortName}");
}
+
+ static async Task DownloadFileWithProgressAsync(HttpClient client, string url)
+ {
+ // 1. Get headers only first to check size
+ using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ response.EnsureSuccessStatusCode();
+
+ var totalBytes = response.Content.Headers.ContentLength ?? -1L;
+ var canReportProgress = totalBytes != -1;
+
+ using var contentStream = await response.Content.ReadAsStreamAsync();
+ using var memoryStream = new MemoryStream();
+
+ var buffer = new byte[8192];
+ long totalRead = 0;
+ int bytesRead;
+
+ while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
+ {
+ await memoryStream.WriteAsync(buffer, 0, bytesRead);
+ totalRead += bytesRead;
+
+ if (canReportProgress)
+ DrawProgressBar((int)((double)totalRead / totalBytes * 100), "Downloading...");
+ }
+ DrawProgressBar(100, "Done");
+ return memoryStream;
+ }
+ static void ExtractWithProgress(MemoryStream stream)
+ {
+ using (ZipArchive archive = new(stream))
+ {
+ int totalEntries = archive.Entries.Count;
+ int currentEntry = 0;
+
+ foreach (ZipArchiveEntry entry in archive.Entries)
+ {
+ currentEntry++;
+
+ // Calculate percentage
+ int percent = (int)((double)currentEntry / totalEntries * 100);
+
+ // Draw Progress Bar
+ DrawProgressBar(percent, entry.Name);
+
+ // Create the full path
+ string destinationPath = Path.GetFullPath(Path.Combine(installPath, entry.FullName));
+
+ // Security check: prevent ZipSlip (writing outside target folder)
+ if (!destinationPath.StartsWith(installPath, StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ // Handle folders vs files
+ if (string.IsNullOrEmpty(entry.Name)) // It's a directory
+ {
+ Directory.CreateDirectory(destinationPath);
+ }
+ else // It's a file
+ {
+ // Ensure the directory exists (zipped files might not list their dir first)
+ Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
+ entry.ExtractToFile(destinationPath, overwrite: true);
+ }
+ }
+ }
+ DrawProgressBar(100, "Done");
+ }
}
}