update installer to use git releases
This commit is contained in:
@@ -9,16 +9,22 @@
|
|||||||
<ApplicationIcon>bb.ico</ApplicationIcon>
|
<ApplicationIcon>bb.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||||
|
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||||
|
|
||||||
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
|
<DebuggerSupport>false</DebuggerSupport>
|
||||||
|
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="bb.ico">
|
<Content Include="bb.ico">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Include="AppPayload.zip">
|
|
||||||
<Visible>false</Visible>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Windows.Media.Protection.PlayReady;
|
||||||
|
|
||||||
namespace BlueberryUpdater
|
namespace BlueberryUpdater
|
||||||
{
|
{
|
||||||
@@ -65,7 +68,23 @@ namespace BlueberryUpdater
|
|||||||
{
|
{
|
||||||
try
|
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<JsonElement>(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}...");
|
Console.WriteLine($"Installing to {installPath}...");
|
||||||
|
|
||||||
@@ -76,56 +95,9 @@ namespace BlueberryUpdater
|
|||||||
}
|
}
|
||||||
Directory.CreateDirectory(installPath);
|
Directory.CreateDirectory(installPath);
|
||||||
|
|
||||||
// 2. Extract Embedded Resource
|
ExtractWithProgress(stream);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveUpdater();
|
MoveUpdater();
|
||||||
|
|
||||||
DrawProgressBar(100, "Done");
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("Installation Complete!");
|
Console.WriteLine("Installation Complete!");
|
||||||
|
|
||||||
@@ -181,7 +153,7 @@ namespace BlueberryUpdater
|
|||||||
string shortName = filename.Length > 20 ? filename.Substring(0, 17) + "..." : filename.PadRight(20);
|
string shortName = filename.Length > 20 ? filename.Substring(0, 17) + "..." : filename.PadRight(20);
|
||||||
|
|
||||||
Console.Write("[");
|
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);
|
int progress = (int)((percent / 100.0) * width);
|
||||||
|
|
||||||
// Draw filled part
|
// Draw filled part
|
||||||
@@ -191,5 +163,72 @@ namespace BlueberryUpdater
|
|||||||
|
|
||||||
Console.Write($"] {percent}% {shortName}");
|
Console.Write($"] {percent}% {shortName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async Task<MemoryStream> 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user