mirror of
https://github.com/ApfelTeeSaft/EasyInstallerV2-Legacy-AI-Generated.git
synced 2026-08-26 19:23:25 +00:00
initial release
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32616.157
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyInstallerV2", "EasyInstallerV2\EasyInstallerV2.csproj", "{0A977DC7-8EB0-4840-A1B7-791156F00F9D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Debug|x64.Build.0 = Debug|x64
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Release|x64.ActiveCfg = Release|x64
|
||||
{0A977DC7-8EB0-4840-A1B7-791156F00F9D}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {97F708CC-110B-4CC6-BAEE-59E698ADB840}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<ApplicationIcon>Icon1.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Program.cs~RFa8656f.TMP" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Icon1.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_LastSelectedProfileId>C:\Users\Ender\source\repos\EasyInstallerV2\EasyInstallerV2\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,171 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
|
||||
namespace EasyInstallerV2
|
||||
{
|
||||
class Program
|
||||
{
|
||||
public const string BASE_URL = "https://manifest.fnbuilds.services";
|
||||
private const int CHUNK_SIZE = 536870912 / 8;
|
||||
|
||||
class ChunkedFile
|
||||
{
|
||||
public List<int> ChunksIds = new();
|
||||
public String File = String.Empty;
|
||||
public long FileSize = 0;
|
||||
}
|
||||
|
||||
class ManifestFile
|
||||
{
|
||||
public String Name = String.Empty;
|
||||
public List<ChunkedFile> Chunks = new();
|
||||
public long Size = 0;
|
||||
}
|
||||
|
||||
static string FormatBytesWithSuffix(long bytes)
|
||||
{
|
||||
string[] Suffix = { "B", "KB", "MB", "GB", "TB" };
|
||||
int i;
|
||||
double dblSByte = bytes;
|
||||
for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024)
|
||||
{
|
||||
dblSByte = bytes / 1024.0;
|
||||
}
|
||||
|
||||
return String.Format("{0:0.##} {1}", dblSByte, Suffix[i]);
|
||||
}
|
||||
|
||||
static async Task Download(ManifestFile manifest, string version, string resultPath)
|
||||
{
|
||||
long totalBytes = manifest.Size;
|
||||
long completedBytes = 0;
|
||||
int progressLength = 0;
|
||||
|
||||
if (!Directory.Exists(resultPath))
|
||||
Directory.CreateDirectory(resultPath);
|
||||
|
||||
SemaphoreSlim semaphore = new SemaphoreSlim(12);
|
||||
|
||||
await Task.WhenAll(manifest.Chunks.Select(async chunkedFile =>
|
||||
{
|
||||
await semaphore.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
WebClient httpClient = new WebClient();
|
||||
|
||||
string outputFilePath = Path.Combine(resultPath, chunkedFile.File);
|
||||
var fileInfo = new FileInfo(outputFilePath);
|
||||
|
||||
if (File.Exists(outputFilePath) && fileInfo.Length == chunkedFile.FileSize)
|
||||
{
|
||||
completedBytes += chunkedFile.FileSize;
|
||||
semaphore.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath));
|
||||
|
||||
using (FileStream outputStream = File.OpenWrite(outputFilePath))
|
||||
{
|
||||
foreach (int chunkId in chunkedFile.ChunksIds)
|
||||
{
|
||||
retry:
|
||||
|
||||
try
|
||||
{
|
||||
string chunkUrl = BASE_URL + $"/{version}/" + chunkId + ".chunk";
|
||||
var chunkData = await httpClient.DownloadDataTaskAsync(chunkUrl);
|
||||
|
||||
byte[] chunkDecompData = new byte[CHUNK_SIZE + 1];
|
||||
int bytesRead;
|
||||
long chunkCompletedBytes = 0;
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream(chunkData);
|
||||
GZipStream decompressionStream = new GZipStream(memoryStream, CompressionMode.Decompress);
|
||||
|
||||
while ((bytesRead = await decompressionStream.ReadAsync(chunkDecompData, 0, chunkDecompData.Length)) > 0)
|
||||
{
|
||||
await outputStream.WriteAsync(chunkDecompData, 0, bytesRead);
|
||||
Interlocked.Add(ref completedBytes, bytesRead);
|
||||
Interlocked.Add(ref chunkCompletedBytes, bytesRead);
|
||||
|
||||
double progress = (double)completedBytes / totalBytes * 100;
|
||||
string progressMessage = $"\rDownloaded: {FormatBytesWithSuffix(completedBytes)} / {FormatBytesWithSuffix(totalBytes)} ({progress:F2}%)";
|
||||
|
||||
int padding = progressLength - progressMessage.Length;
|
||||
if (padding > 0)
|
||||
progressMessage += new string(' ', padding);
|
||||
|
||||
Console.Write(progressMessage);
|
||||
progressLength = progressMessage.Length;
|
||||
}
|
||||
|
||||
memoryStream.Close();
|
||||
decompressionStream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
}));
|
||||
|
||||
Console.WriteLine("\n\nFinished Downloading.\nPress any key to exit!");
|
||||
Thread.Sleep(100);
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var httpClient = new WebClient();
|
||||
|
||||
List<string> versions = JsonConvert.DeserializeObject<List<string>>(httpClient.DownloadString(BASE_URL + "/versions.json"));
|
||||
|
||||
Console.Clear();
|
||||
|
||||
Console.Title = "EasyInstaller V2 made by Ender & blk";
|
||||
Console.Write("\n\nEasyInstaller V2 made by Ender & blk\n\n");
|
||||
Console.WriteLine("\nAvailable manifests:");
|
||||
|
||||
for (int i = 0; i < versions.Count; i++)
|
||||
{
|
||||
Console.WriteLine($" * [{i}] {versions[i]}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"\nTotal: {versions.Count}");
|
||||
|
||||
Console.Write("Please enter the number before the Build Version to select it: ");
|
||||
var targetVersionStr = Console.ReadLine();
|
||||
var targetVersionIndex = 0;
|
||||
|
||||
try
|
||||
{
|
||||
targetVersionIndex = int.Parse(targetVersionStr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main(args);
|
||||
}
|
||||
|
||||
if (!(targetVersionIndex >= 0 && targetVersionIndex < versions.Count))
|
||||
Main(args);
|
||||
|
||||
var targetVersion = versions[targetVersionIndex].Split("-")[1];
|
||||
var manifest = JsonConvert.DeserializeObject<ManifestFile>(httpClient.DownloadString(BASE_URL + $"/{targetVersion}/{targetVersion}.manifest"));
|
||||
|
||||
Console.Write("Please enter a game folder location: ");
|
||||
var targetPath = Console.ReadLine();
|
||||
Console.Write("\n");
|
||||
|
||||
Download(manifest, targetVersion, targetPath).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
<PublishDir>bin\Release\net6.0-windows\publish\win-x64\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<History>True|2023-06-04T05:06:49.9843864Z;True|2023-06-04T01:01:13.4649588-04:00;True|2023-06-04T00:53:14.8161177-04:00;False|2023-06-04T00:49:47.5760062-04:00;False|2023-06-04T00:48:08.4918082-04:00;True|2023-06-04T00:47:35.6382492-04:00;True|2023-06-04T00:45:41.3367378-04:00;True|2023-06-04T00:43:34.9416852-04:00;True|2023-06-04T00:43:11.2497253-04:00;True|2023-06-04T00:42:40.5978756-04:00;</History>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user