Skip to content

Commit

Permalink
style: progress bar and QoL visuals
Browse files Browse the repository at this point in the history
  • Loading branch information
ChecksumDev committed Aug 27, 2023
1 parent bf20839 commit 7994e60
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 63 deletions.
125 changes: 84 additions & 41 deletions GenericStripper/Modules/BeatSaber/BeatSaber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Spectre.Console;

namespace GenericStripper.Modules.BeatSaber;

Expand All @@ -21,6 +22,61 @@ public BeatSaber(string gamePath)
public string GameName => "Beat Saber";
public string GamePath { get; }


private async Task InstallBsipa()
{
if (File.Exists(Path.Combine(GamePath, "IPA.exe")))
{
AnsiConsole.MarkupLine("[green]BSIPA already installed, skipping...[/]");
return;
}

await AnsiConsole.Status()
.StartAsync("Installing BSIPA...", async ctx =>
{
var res = await _client.GetAsync(
"https://api.github.com/repos/nike4613/BeatSaber-IPA-Reloaded/releases/latest");
if (res.StatusCode != HttpStatusCode.OK) throw new Exception("Failed to get latest BSIPA release!");
var latestRelease =
JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(await res.Content.ReadAsStringAsync());
if (latestRelease == null) throw new Exception("Failed to parse BSIPA release!");
var assets = latestRelease["assets"] as JArray;
var arch = RuntimeInformation.OSArchitecture.ToString().ToLower();
var asset = assets?.FirstOrDefault(x => x["name"]?.ToString().Contains(arch) ?? false);
if (asset == null) throw new Exception("Failed to find a BSIPA asset for this system!");
var assetRes = await _client.GetAsync(asset["browser_download_url"]?.ToString());
if (assetRes.StatusCode != HttpStatusCode.OK) throw new Exception("Failed to download BSIPA asset!");
await using var assetStream = await assetRes.Content.ReadAsStreamAsync();
using var archive = new ZipArchive(assetStream);
archive.ExtractToDirectory(GamePath);
if (!File.Exists(Path.Combine(GamePath, "IPA.exe")))
throw new Exception("Failed to extract BSIPA asset!");
// todo: prevent BSIPA from outputting to stdout
var bsipa = new Process
{
StartInfo =
{
FileName = Path.Combine(GamePath, "IPA.exe"),
WorkingDirectory = GamePath,
Arguments = "--nowait",
}
};
bsipa.Start();
await bsipa.WaitForExitAsync();
if (bsipa.ExitCode != 0) throw new Exception("Failed to install BSIPA!");
ctx.Status("[green]BSIPA installed![/]");
});
}

public void StripDll(string file, string outDir, params string[] resolveDirs)
{
if (!File.Exists(file)) throw new FileNotFoundException("Failed to find assembly to strip!", file);
Expand All @@ -30,52 +86,39 @@ public void StripDll(string file, string outDir, params string[] resolveDirs)
bsAssemblyModule.Virtualize();
bsAssemblyModule.Strip();

Console.WriteLine($"Stripped {fileInf.Name}!");

Directory.CreateDirectory(Path.Combine(outDir, Path.GetRelativePath(GamePath, fileInf.Directory!.ToString())));
var outFile = Path.Combine(outDir, Path.GetRelativePath(GamePath, fileInf.FullName));
bsAssemblyModule.Write(outFile);
}

public async Task InstallBsipa()
public async Task StripAllDlls(string outDir)
{
if (File.Exists(Path.Combine(GamePath, "IPA.exe"))) return;
Console.WriteLine("Installing BSIPA...");

var res = await _client.GetAsync(
"https://api.github.com/repos/nike4613/BeatSaber-IPA-Reloaded/releases/latest");
if (res.StatusCode != HttpStatusCode.OK) throw new Exception("Failed to get latest BSIPA release!");

var latestRelease =
JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(await res.Content.ReadAsStringAsync());
if (latestRelease == null) throw new Exception("Failed to parse BSIPA release!");

var assets = latestRelease["assets"] as JArray;
var arch = RuntimeInformation.OSArchitecture.ToString().ToLower();
var asset = assets?.FirstOrDefault(x => x["name"]?.ToString().Contains(arch) ?? false);

if (asset == null) throw new Exception("Failed to find a BSIPA asset for this system!");

var assetRes = await _client.GetAsync(asset["browser_download_url"]?.ToString());
if (assetRes.StatusCode != HttpStatusCode.OK) throw new Exception("Failed to download BSIPA asset!");

await using var assetStream = await assetRes.Content.ReadAsStreamAsync();
using var archive = new ZipArchive(assetStream);
archive.ExtractToDirectory(GamePath);

if (!File.Exists(Path.Combine(GamePath, "IPA.exe"))) throw new Exception("Failed to extract BSIPA asset!");

var bsipa = new Process
{
StartInfo =
{
FileName = Path.Combine(GamePath, "IPA.exe"),
WorkingDirectory = GamePath,
Arguments = "--nowait"
}
};

bsipa.Start();
await bsipa.WaitForExitAsync();
await InstallBsipa();

var bsLibsDir = Path.Combine(GamePath, "Libs");
var bsManagedDir = Path.Combine(GamePath, "Beat Saber_Data", "Managed");

var outputDir = Path.Combine(GamePath, outDir);
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);

var libAssemblies = Directory.GetFiles(bsLibsDir, "*.dll", SearchOption.AllDirectories);
var managedAssemblies = Directory.GetFiles(bsManagedDir, "*.dll", SearchOption.AllDirectories);

AnsiConsole.Progress()
.Start(ctx =>
{
var task = ctx.AddTask("[salmon1]Stripping assemblies...[/]", new ProgressTaskSettings
{
MaxValue = libAssemblies.Length + managedAssemblies.Length
});
foreach (var assembly in libAssemblies.Concat(managedAssemblies))
{
StripDll(assembly, outputDir, bsLibsDir, bsManagedDir);
task.Increment(1);
AnsiConsole.MarkupLine($"[teal]Stripped {assembly}[/]");
}
}
);
}
}
4 changes: 3 additions & 1 deletion GenericStripper/Modules/IModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public interface IModule

public string GamePath { get; }

public void StripDll(string file, string outDir, params string[] resolveDirs);
protected void StripDll(string file, string outDir, params string[] resolveDirs);

public Task StripAllDlls(string outDir);
}
44 changes: 23 additions & 21 deletions GenericStripper/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using GenericStripper.Modules.BeatSaber;
using System.Diagnostics.CodeAnalysis;
using GenericStripper.Modules;
using GenericStripper.Modules.BeatSaber;
using Spectre.Console;
using Spectre.Console.Cli;

namespace GenericStripper;

[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
internal abstract class Program
{
public static int Main(string[] args)
Expand All @@ -12,9 +15,9 @@ public static int Main(string[] args)
return app.Run(args);
}

internal sealed class MainCommand : Command<MainCommand.Settings>
internal sealed class MainCommand : AsyncCommand<MainCommand.Settings>
{
public override int Execute(CommandContext context, Settings settings)
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{
if (settings.Module == null)
{
Expand All @@ -34,24 +37,23 @@ public override int Execute(CommandContext context, Settings settings)
return 1;
}


var bs = new BeatSaber(settings.Path);
bs.InstallBsipa().Wait();

var bsLibsDir = Path.Combine(bs.GamePath, "Libs");
var bsManagedDir = Path.Combine(bs.GamePath, "Beat Saber_Data", "Managed");

var outputDir = Path.Combine(bs.GamePath, settings.Out);
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);

var libAssemblies = Directory.GetFiles(bsLibsDir, "*.dll", SearchOption.AllDirectories);
var managedAssemblies = Directory.GetFiles(bsManagedDir, "*.dll", SearchOption.AllDirectories);

foreach (var assembly in libAssemblies.Concat(managedAssemblies))
bs.StripDll(assembly, outputDir, bsLibsDir, bsManagedDir);

Console.WriteLine("Done!");

var module = settings.Module.ToLower();
var path = settings.Path;
var outDir = settings.Out;

IModule? mod = module switch
{
"beatsaber" => new BeatSaber(path),
_ => null
};

if (mod == null)
{
AnsiConsole.MarkupLine("[red]Invalid module specified![/]");
return 1;
}

await mod.StripAllDlls(outDir);
return 0;
}

Expand Down

0 comments on commit 7994e60

Please sign in to comment.