diff --git a/.vscode/launch.json b/.vscode/launch.json
index e29b25a7..bf70844b 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
- "program": "${workspaceFolder}/bin/Debug/net6.0/pupdate.dll",
+ "program": "${workspaceFolder}/bin/Debug/net7.0/pupdate.dll",
"args": ["-p", "/Users/mattpannella/pocket-test"],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
diff --git a/pupdate.csproj b/pupdate.csproj
index ffda5684..d82cfc10 100644
--- a/pupdate.csproj
+++ b/pupdate.csproj
@@ -3,15 +3,16 @@
true
Exe
true
- net6.0
+ net7.0
enable
- enable
+ disable
3.2.1
Keep your Analogue Pocket up to date
2024 Matt Pannella
Matt Pannella
Pupdate
https://github.com/mattpannella/pocket-updater-utility
+ Pannella
diff --git a/src/Factory.cs b/src/Factory.cs
deleted file mode 100644
index ddcba8c7..00000000
--- a/src/Factory.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace pannella.analoguepocket;
-
-public class Factory
-{
- public static HttpHelper GetHttpHelper()
- {
- return HttpHelper.Instance;
- }
-
- public static GlobalHelper GetGlobals()
- {
- return GlobalHelper.Instance;
- }
-}
\ No newline at end of file
diff --git a/src/PocketCoreUpdater.cs b/src/PocketCoreUpdater.cs
new file mode 100644
index 00000000..b8d7a92a
--- /dev/null
+++ b/src/PocketCoreUpdater.cs
@@ -0,0 +1,546 @@
+using System.Diagnostics.CodeAnalysis;
+using System.IO.Compression;
+using System.Text.Json;
+using Pannella.Helpers;
+using Pannella.Models;
+using Pannella.Services;
+using File = System.IO.File;
+using AnalogueCore = Pannella.Models.Analogue.Core.Core;
+using GithubFile = Pannella.Models.Github.File;
+
+namespace Pannella;
+
+[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")]
+public class PocketCoreUpdater : Base
+{
+ private const string FIRMWARE_FILENAME_PATTERN = "pocket_firmware_*.bin";
+
+ private bool _downloadAssets;
+ private bool _preservePlatformsFolder;
+ private bool _downloadFirmware = true;
+ private bool _deleteSkippedCores = true;
+ private bool _renameJotegoCores = true;
+ private bool _jtBeta;
+ private bool _backupSaves;
+ private string _backupSavesLocation;
+ private Dictionary _platformFiles = new();
+
+ public PocketCoreUpdater()
+ {
+ Directory.CreateDirectory(Path.Combine(GlobalHelper.UpdateDirectory, "Cores"));
+
+ foreach (Core core in GlobalHelper.Cores)
+ {
+ core.StatusUpdated += updater_StatusUpdated; // attach handler to bubble event up
+ }
+ }
+
+ #region Settings
+
+ ///
+ /// Turn on/off renaming the Jotego cores
+ ///
+ /// Set to true to rename the Jotego cores
+ public void RenameJotegoCores(bool set)
+ {
+ _renameJotegoCores = set;
+ }
+
+ ///
+ /// Turn on/off the automatic BIOS downloader
+ ///
+ /// Set to true to enable automatic BIOS downloading
+ public void DownloadAssets(bool set)
+ {
+ _downloadAssets = set;
+ }
+
+ ///
+ /// Turn on/off preserving customizations to /Platforms
+ ///
+ /// Set to true to enable preserving custom /Platforms changes
+ public void PreservePlatformsFolder(bool set)
+ {
+ _preservePlatformsFolder = set;
+ }
+
+ ///
+ /// Turn on/off downloading the Analogue Pocket firmware
+ ///
+ /// Set to true to download the latest Analogue Pocket firmware
+ public void DownloadFirmware(bool set)
+ {
+ _downloadFirmware = set;
+ }
+
+ ///
+ /// Turn on/off compressing and backing up the /Saves directory
+ ///
+ /// Set to true to compress and backup the /Saves directory
+ /// The absolute path to the backup location
+ public void BackupSaves(bool set, string location)
+ {
+ _backupSaves = set;
+ _backupSavesLocation = location;
+ }
+
+ ///
+ /// Turn on/off the deletion of skipped cores
+ ///
+ /// Set to true to delete the skipped cores
+ public void DeleteSkippedCores(bool set)
+ {
+ _deleteSkippedCores = set;
+ }
+
+ #endregion
+
+ public void BuildInstanceJson(bool overwrite = false, string coreName = null)
+ {
+ foreach (Core core in GlobalHelper.Cores)
+ {
+ if (core.CheckInstancePackager() && (coreName == null || coreName == core.identifier))
+ {
+ WriteMessage(core.identifier);
+ core.BuildInstanceJSONs(overwrite);
+ Divide();
+ }
+ }
+ }
+
+ ///
+ /// Run the full openFPGA core download and update process
+ ///
+ public async Task RunUpdates(string id = null, bool clean = false)
+ {
+ List> installed = new List>();
+ List installedAssets = new List();
+ List skippedAssets = new List();
+ List missingBetaKeys = new List();
+ string firmwareDownloaded = string.Empty;
+
+ if (GlobalHelper.Cores == null)
+ {
+ throw new Exception("Must initialize updater before running update process");
+ }
+
+ if (_backupSaves)
+ {
+ AssetsService.BackupSaves(GlobalHelper.UpdateDirectory, _backupSavesLocation);
+ }
+
+ if (_downloadFirmware && id == null)
+ {
+ firmwareDownloaded = await UpdateFirmware();
+ }
+
+ ExtractBetaKey();
+
+ foreach (var core in GlobalHelper.Cores.Where(core => id == null || core.identifier == id))
+ {
+ core.download_assets = _downloadAssets && id == null;
+ core.build_instances = GlobalHelper.SettingsManager.GetConfig().build_instance_jsons && id == null;
+
+ try
+ {
+ if (GlobalHelper.SettingsManager.GetCoreSettings(core.identifier).skip)
+ {
+ DeleteCore(core);
+ continue;
+ }
+
+ if (core.requires_license && !_jtBeta)
+ {
+ continue; //skip if you don't have the key
+ }
+
+ string name = core.identifier;
+
+ if (name == null)
+ {
+ WriteMessage("Core Name is required. Skipping.");
+ continue;
+ }
+
+ WriteMessage("Checking Core: " + name);
+ var mostRecentRelease = core.version;
+
+ Dictionary results;
+
+ if (mostRecentRelease == null)
+ {
+ WriteMessage("No releases found. Skipping");
+
+ CopyBetaKey(core);
+
+ results = await core.DownloadAssets();
+ installedAssets.AddRange(results["installed"] as List);
+ skippedAssets.AddRange(results["skipped"] as List);
+
+ if ((bool)results["missingBetaKey"])
+ {
+ missingBetaKeys.Add(core.identifier);
+ }
+
+ await JotegoRename(core);
+ Divide();
+ continue;
+ }
+
+ WriteMessage(mostRecentRelease + " is the most recent release, checking local core...");
+
+ if (core.IsInstalled())
+ {
+ AnalogueCore localCore = core.GetConfig();
+ string localVersion = localCore.metadata.version;
+
+ if (localVersion != null)
+ {
+ WriteMessage("local core found: " + localVersion);
+ }
+
+ if (mostRecentRelease != localVersion || clean)
+ {
+ WriteMessage("Updating core");
+ }
+ else
+ {
+ CopyBetaKey(core);
+ results = await core.DownloadAssets();
+ await JotegoRename(core);
+
+ installedAssets.AddRange(results["installed"] as List);
+ skippedAssets.AddRange(results["skipped"] as List);
+
+ if ((bool)results["missingBetaKey"])
+ {
+ missingBetaKeys.Add(core.identifier);
+ }
+
+ WriteMessage("Up to date. Skipping core");
+ Divide();
+ continue;
+ }
+ }
+ else
+ {
+ WriteMessage("Downloading core");
+ }
+
+ if (await core.Install(_preservePlatformsFolder, clean))
+ {
+ Dictionary summary = new Dictionary
+ {
+ { "version", mostRecentRelease },
+ { "core", core.identifier },
+ { "platform", core.platform.name }
+ };
+
+ installed.Add(summary);
+ }
+
+ await JotegoRename(core);
+ CopyBetaKey(core);
+
+ results = await core.DownloadAssets();
+ installedAssets.AddRange(results["installed"] as List);
+ skippedAssets.AddRange(results["skipped"] as List);
+
+ if ((bool)results["missingBetaKey"])
+ {
+ missingBetaKeys.Add(core.identifier);
+ }
+
+ WriteMessage("Installation complete.");
+ Divide();
+
+ }
+ catch (Exception e)
+ {
+ WriteMessage("Uh oh something went wrong.");
+ WriteMessage(e.Message);
+ }
+ }
+
+ UpdateProcessCompleteEventArgs args = new UpdateProcessCompleteEventArgs
+ {
+ Message = "Update Process Complete",
+ InstalledCores = installed,
+ InstalledAssets = installedAssets,
+ SkippedAssets = skippedAssets,
+ MissingBetaKeys = missingBetaKeys,
+ FirmwareUpdated = firmwareDownloaded
+ };
+
+ GlobalHelper.RefreshInstalledCores();
+ OnUpdateProcessComplete(args);
+ }
+
+ private async Task LoadPlatformFiles()
+ {
+ try
+ {
+ List files = await GithubApiService.GetFiles(
+ "dyreschlock",
+ "pocket-platform-images",
+ "arcade/Platforms");
+ Dictionary platformFiles = new();
+
+ foreach (GithubFile file in files)
+ {
+ string url = file.download_url;
+ string filename = file.name;
+
+ if (filename.EndsWith(".json"))
+ {
+ string platform = Path.GetFileNameWithoutExtension(filename);
+
+ platformFiles.Add(platform, url);
+ }
+ }
+
+ _platformFiles = platformFiles;
+ }
+ catch (Exception)
+ {
+ WriteMessage("Unable to retrieve archive contents. Asset download may not work.");
+ _platformFiles = new Dictionary();
+ }
+ }
+
+ private async Task JotegoRename(Core core)
+ {
+ if (_renameJotegoCores &&
+ GlobalHelper.SettingsManager.GetCoreSettings(core.identifier).platform_rename &&
+ core.identifier.Contains("jotego"))
+ {
+ await LoadPlatformFiles();
+
+ core.platform_id = core.identifier.Split('.')[1]; //whatever
+
+ string path = Path.Combine(GlobalHelper.UpdateDirectory, "Platforms", core.platform_id + ".json");
+ string json = await File.ReadAllTextAsync(path);
+ Dictionary data = JsonSerializer.Deserialize>(json);
+ Platform platform = data["platform"];
+
+ if (_platformFiles.TryGetValue(core.platform_id, out string value) && platform.name == core.platform_id)
+ {
+ WriteMessage("Updating JT Platform Name...");
+ await HttpHelper.Instance.DownloadFileAsync(value, path);
+ WriteMessage("Complete");
+ }
+ }
+ }
+
+ private void CopyBetaKey(Core core)
+ {
+ if (core.JTBetaCheck())
+ {
+ AnalogueCore info = core.GetConfig();
+ string path = Path.Combine(
+ GlobalHelper.UpdateDirectory,
+ "Assets",
+ info.metadata.platform_ids[core.beta_slot_platform_id_index],
+ "common");
+
+ if (!Directory.Exists(path))
+ {
+ Directory.CreateDirectory(path);
+ }
+
+ string keyPath = Path.Combine(GlobalHelper.UpdateDirectory, "betakeys");
+
+ if (Directory.Exists(keyPath) && Directory.Exists(path))
+ {
+ Util.CopyDirectory(keyPath, path, false, true);
+ WriteMessage("Beta key copied to common directory.");
+ }
+ }
+ }
+
+ private void ExtractBetaKey()
+ {
+ string keyPath = Path.Combine(GlobalHelper.UpdateDirectory, "betakeys");
+ string file = Path.Combine(GlobalHelper.UpdateDirectory, "jtbeta.zip");
+
+ if (File.Exists(file))
+ {
+ _jtBeta = true;
+ WriteMessage("Extracting JT beta key...");
+ ZipFile.ExtractToDirectory(file, keyPath, true);
+ }
+ }
+
+ public async Task RunAssetDownloader(string id = null)
+ {
+ List installedAssets = new List();
+ List skippedAssets = new List();
+ List missingBetaKeys = new List();
+
+ if (GlobalHelper.Cores == null)
+ {
+ throw new Exception("Must initialize updater before running update process");
+ }
+
+ foreach (var core in GlobalHelper.Cores.Where(core => id == null || core.identifier == id)
+ .Where(core => !GlobalHelper.SettingsManager.GetCoreSettings(core.identifier).skip))
+ {
+ core.download_assets = true;
+
+ try
+ {
+ string name = core.identifier;
+
+ if (name == null)
+ {
+ WriteMessage("Core Name is required. Skipping.");
+ continue;
+ }
+
+ WriteMessage(core.identifier);
+
+ var results = await core.DownloadAssets();
+
+ installedAssets.AddRange(results["installed"] as List);
+ skippedAssets.AddRange(results["skipped"] as List);
+
+ if ((bool)results["missingBetaKey"])
+ {
+ missingBetaKeys.Add(core.identifier);
+ }
+
+ Divide();
+ }
+ catch (Exception e)
+ {
+ WriteMessage("Uh oh something went wrong.");
+ WriteMessage(e.Message);
+ }
+ }
+
+ UpdateProcessCompleteEventArgs args = new UpdateProcessCompleteEventArgs
+ {
+ Message = "All Done",
+ InstalledAssets = installedAssets,
+ SkippedAssets = skippedAssets,
+ MissingBetaKeys = missingBetaKeys
+ };
+
+ OnUpdateProcessComplete(args);
+ }
+
+ public void ForceDisplayModes(string id = null)
+ {
+ if (GlobalHelper.Cores == null)
+ {
+ throw new Exception("Must initialize updater before running update process");
+ }
+
+ foreach (var core in GlobalHelper.Cores.Where(core => id == null || core.identifier == id)
+ .Where(core => !GlobalHelper.SettingsManager.GetCoreSettings(core.identifier).skip))
+ {
+ core.download_assets = true;
+
+ try
+ {
+ string name = core.identifier;
+
+ if (name == null)
+ {
+ WriteMessage("Core Name is required. Skipping.");
+ continue;
+ }
+
+ WriteMessage("Updating " + core.identifier);
+ core.AddDisplayModes();
+ Divide();
+ }
+ catch (Exception e)
+ {
+ WriteMessage("Uh oh something went wrong.");
+ WriteMessage(e.Message);
+ }
+ }
+
+ WriteMessage("Finished.");
+ }
+
+ private void OnUpdateProcessComplete(UpdateProcessCompleteEventArgs e)
+ {
+ EventHandler handler = UpdateProcessComplete;
+
+ handler?.Invoke(this, e);
+
+ GlobalHelper.RefreshInstalledCores();
+ }
+
+ public async Task UpdateFirmware()
+ {
+ string version = string.Empty;
+
+ WriteMessage("Checking for firmware updates...");
+
+ var details = await AnalogueFirmwareService.GetDetails();
+ string[] parts = details.download_url.Split("/");
+ string filename = parts[parts.Length - 1];
+ string filepath = Path.Combine(GlobalHelper.UpdateDirectory, filename);
+
+ if (!File.Exists(filepath) || !Util.CompareChecksum(filepath, details.md5, Util.HashTypes.MD5))
+ {
+ version = filename;
+
+ var oldFiles = Directory.GetFiles(GlobalHelper.UpdateDirectory, FIRMWARE_FILENAME_PATTERN);
+
+ WriteMessage("Firmware update found. Downloading...");
+
+ await HttpHelper.Instance.DownloadFileAsync(details.download_url, Path.Combine(GlobalHelper.UpdateDirectory, filename));
+
+ WriteMessage("Download Complete");
+ WriteMessage(Path.Combine(GlobalHelper.UpdateDirectory, filename));
+
+ foreach (string oldFile in oldFiles)
+ {
+ if (File.Exists(oldFile) && Path.GetFileName(oldFile) != filename)
+ {
+ WriteMessage("Deleting old firmware file...");
+ File.Delete(oldFile);
+ }
+ }
+
+ WriteMessage("To install firmware, restart your Pocket.");
+ }
+ else
+ {
+ WriteMessage("Firmware up to date.");
+ }
+
+ Divide();
+
+ return version;
+ }
+
+ public void DeleteCore(Core core, bool force = false, bool nuke = false)
+ {
+ if (_deleteSkippedCores || force)
+ {
+ core.Uninstall(nuke);
+ }
+ }
+
+ private void updater_StatusUpdated(object sender, StatusUpdatedEventArgs e)
+ {
+ this.OnStatusUpdated(e);
+ }
+
+ public event EventHandler UpdateProcessComplete;
+}
+
+public class UpdateProcessCompleteEventArgs : EventArgs
+{
+ public string Message { get; set; }
+ public List> InstalledCores { get; set; }
+ public List InstalledAssets { get; set; }
+ public List SkippedAssets { get; set; }
+ public string FirmwareUpdated { get; set; } = string.Empty;
+ public List MissingBetaKeys { get; set; }
+}
diff --git a/src/Program.cs b/src/Program.cs
index 3569c3e5..5e453d73 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -1,189 +1,218 @@
using System.Diagnostics;
-using System.IO.Compression;
-using System.Reflection;
-using System.Runtime.InteropServices;
using CommandLine;
-using pannella.analoguepocket;
-using ConsoleTools;
+using Pannella.Helpers;
+using Pannella.Models;
+using Pannella.Options;
+using Pannella.Services;
+namespace Pannella;
-internal class Program
+internal partial class Program
{
- private static string version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
- private const string USER = "mattpannella";
- private const string REPOSITORY = "pocket-updater-utility";
- private const string RELEASE_URL = "https://github.com/mattpannella/pocket-updater-utility/releases/download/{0}/pupdate_{1}.zip";
- private static SettingsManager settings;
+ private static bool CLI_MODE;
- private static PocketCoreUpdater updater;
-
- private static bool cliMode = false;
private static async Task Main(string[] args)
{
- try {
- string location = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
- string? path = Path.GetDirectoryName(location);
+ try
+ {
+ string location = Process.GetCurrentProcess().MainModule.FileName;
+ string path = Path.GetDirectoryName(location);
bool preservePlatformsFolder = false;
bool forceUpdate = false;
bool forceInstanceGenerator = false;
- string? downloadAssets = null;
- string? coreName = null;
- string? imagePackOwner = null;
- string? imagePackRepo = null;
- string? imagePackVariant = null;
+ string downloadAssets = null;
+ string coreName = null;
+ string imagePackOwner = null;
+ string imagePackRepo = null;
+ string imagePackVariant = null;
bool downloadFirmware = false;
bool selfUpdate = false;
bool nuke = false;
bool cleanInstall = false;
- string backupSaves_Path = null!;
+ string backupSaves_Path = null;
bool backupSaves_SaveConfig = false;
- ConsoleKey response;
-
string verb = "menu";
- Dictionary data = new Dictionary();
+ Dictionary data = new Dictionary();
+
+ #region Command Line Arguments
+
Parser.Default.ParseArguments(args)
- .WithParsed(o => {
- selfUpdate = true;
- })
- .WithParsed(async o =>
- {
- verb = "fund";
- data.Add("core", null);
- if(o.Core != null && o.Core != "") {
- data["core"] = o.Core;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "update";
- cliMode = true;
- forceUpdate = true;
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- if(o.PreservePlatformsFolder) {
- preservePlatformsFolder = true;
- }
- if(o.CleanInstall) {
- cleanInstall = true;
- }
- if(o.CoreName != null && o.CoreName != "") {
+ AssetsOptions, FirmwareOptions, ImagesOptions, InstanceGeneratorOptions,
+ UpdateSelfOptions, UninstallOptions, BackupSavesOptions>(args)
+ .WithParsed(_ => { selfUpdate = true; })
+ .WithParsed(o =>
+ {
+ verb = "fund";
+ data.Add("core", null);
+
+ if (!string.IsNullOrEmpty(o.Core))
+ {
+ data["core"] = o.Core;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "update";
+ CLI_MODE = true;
+ forceUpdate = true;
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+
+ if (o.PreservePlatformsFolder)
+ {
+ preservePlatformsFolder = true;
+ }
+
+ if (o.CleanInstall)
+ {
+ cleanInstall = true;
+ }
+
+ if (!string.IsNullOrEmpty(o.CoreName))
+ {
+ coreName = o.CoreName;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "uninstall";
+ CLI_MODE = true;
coreName = o.CoreName;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "uninstall";
- cliMode = true;
- coreName = o.CoreName;
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- if(o.DeleteAssets) {
- nuke = true;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "assets";
- cliMode = true;
- downloadAssets = "all";
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- if(o.CoreName != null) {
- downloadAssets = o.CoreName;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "firmware";
- cliMode = true;
- downloadFirmware = true;
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "images";
- cliMode = true;
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- if(o.ImagePackOwner != null) {
- imagePackOwner = o.ImagePackOwner;
- imagePackRepo = o.ImagePackRepo;
- imagePackVariant = o.ImagePackVariant;
- }
- }
- )
- .WithParsed(async o =>
- {
- verb = "instancegenerator";
- forceInstanceGenerator = true;
- cliMode = true;
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- }
- )
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+
+ if (o.DeleteAssets)
+ {
+ nuke = true;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "assets";
+ CLI_MODE = true;
+ downloadAssets = "all";
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+
+ if (o.CoreName != null)
+ {
+ downloadAssets = o.CoreName;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "firmware";
+ CLI_MODE = true;
+ downloadFirmware = true;
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "images";
+ CLI_MODE = true;
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+
+ if (o.ImagePackOwner != null)
+ {
+ imagePackOwner = o.ImagePackOwner;
+ imagePackRepo = o.ImagePackRepo;
+ imagePackVariant = o.ImagePackVariant;
+ }
+ })
+ .WithParsed(o =>
+ {
+ verb = "instancegenerator";
+ CLI_MODE = true;
+ forceInstanceGenerator = true;
+
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+ })
.WithParsed(o =>
- {
- if(o.InstallPath != null && o.InstallPath != "") {
- path = o.InstallPath;
- }
- if(o.SkipUpdate) {
- cliMode = true;
- }
- }
- )
+ {
+ if (!string.IsNullOrEmpty(o.InstallPath))
+ {
+ path = o.InstallPath;
+ }
+
+ if (o.SkipUpdate)
+ {
+ CLI_MODE = true;
+ }
+ })
.WithParsed(o =>
- {
- verb = "backup-saves";
- cliMode = true;
- path = o.InstallPath;
- backupSaves_Path = o.BackupPath;
- backupSaves_SaveConfig = o.Save;
- }
- )
+ {
+ verb = "backup-saves";
+ CLI_MODE = true;
+ path = o.InstallPath;
+ backupSaves_Path = o.BackupPath;
+ backupSaves_SaveConfig = o.Save;
+ })
.WithNotParsed(o =>
- {
- if(o.IsHelp()) {
- Environment.Exit(1);
- }
- if(o.IsVersion()) {
- Environment.Exit(1);
- }
- }
- );
+ {
+ if (o.IsHelp())
+ {
+ Environment.Exit(1);
+ }
+
+ if (o.IsVersion())
+ {
+ Environment.Exit(1);
+ }
+ });
+
+ #endregion
- if (!cliMode) {
- Console.WriteLine("Pupdate v" + version);
+ GlobalHelper.Initialize(path);
+
+ if (!CLI_MODE)
+ {
+ Console.WriteLine("Pupdate v" + VERSION);
Console.WriteLine("Checking for updates...");
- if(await CheckVersion(path) && !selfUpdate) {
- string platform = GetPlatform();
- ConsoleKey[] acceptedInputs = new[] { ConsoleKey.I, ConsoleKey.C, ConsoleKey.Q };
- do {
- if (platform == "win" || platform == "linux" || platform == "mac") {
+ if (await CheckVersion(path) && !selfUpdate)
+ {
+ ConsoleKey[] acceptedInputs = { ConsoleKey.I, ConsoleKey.C, ConsoleKey.Q };
+ ConsoleKey response;
+
+ do
+ {
+ if (SYSTEM_OS_PLATFORM is "win" or "linux" or "mac")
+ {
Console.Write("Would you like to [i]nstall the update, [c]ontinue with the current version, or [q]uit? [i/c/q]: ");
- } else {
+ }
+ else
+ {
Console.Write("Update downloaded. Would you like to [c]ontinue with the current version, or [q]uit? [c/q]: ");
}
+
response = Console.ReadKey(false).Key;
Console.WriteLine();
- } while(!acceptedInputs.Contains(response));
+ }
+ while (!acceptedInputs.Contains(response));
- switch(response) {
+ switch (response)
+ {
case ConsoleKey.I:
int result = UpdateSelfAndRun(path, args);
Environment.Exit(result);
@@ -198,971 +227,306 @@ private static async Task Main(string[] args)
break;
}
}
- if(selfUpdate) {
+
+ if (selfUpdate)
+ {
Environment.Exit(0);
}
}
- updater = new PocketCoreUpdater(path);
- settings = new SettingsManager(path);
+ PocketCoreUpdater coreUpdater = new PocketCoreUpdater();
- switch(verb) {
+ switch (verb)
+ {
case "fund":
- await Funding((string)data["core"]);
+ Funding((string)data["core"]);
Environment.Exit(1);
break;
- default:
- break;
}
- if(preservePlatformsFolder || settings.GetConfig().preserve_platforms_folder) {
- updater.PreservePlatformsFolder(true);
+ // how should the logic work here? what takes priority, the command line parameter or the config setting?
+ // currently this well preserve the platforms folder if either is set to true
+ if (preservePlatformsFolder || GlobalHelper.SettingsManager.GetConfig().preserve_platforms_folder)
+ {
+ coreUpdater.PreservePlatformsFolder(true);
}
- updater.DeleteSkippedCores(settings.GetConfig().delete_skipped_cores);
- updater.SetGithubApiKey(settings.GetConfig().github_token);
- updater.DownloadFirmware(settings.GetConfig().download_firmware);
- updater.RenameJotegoCores(settings.GetConfig().fix_jt_names);
- updater.StatusUpdated += updater_StatusUpdated;
- updater.UpdateProcessComplete += updater_UpdateProcessComplete;
- updater.DownloadAssets(settings.GetConfig().download_assets);
- updater.BackupSaves(settings.GetConfig().backup_saves, settings.GetConfig().backup_saves_location);
- await updater.Initialize();
- settings = GlobalHelper.Instance.SettingsManager;
+ coreUpdater.DeleteSkippedCores(GlobalHelper.SettingsManager.GetConfig().delete_skipped_cores);
+ coreUpdater.DownloadFirmware(GlobalHelper.SettingsManager.GetConfig().download_firmware);
+ coreUpdater.RenameJotegoCores(GlobalHelper.SettingsManager.GetConfig().fix_jt_names);
+ coreUpdater.StatusUpdated += coreUpdater_StatusUpdated;
+ coreUpdater.UpdateProcessComplete += coreUpdater_UpdateProcessComplete;
+ coreUpdater.DownloadAssets(GlobalHelper.SettingsManager.GetConfig().download_assets);
+ coreUpdater.BackupSaves(GlobalHelper.SettingsManager.GetConfig().backup_saves, GlobalHelper.SettingsManager.GetConfig().backup_saves_location);
+
+ //await coreUpdater.Initialize();
// If we have any missing cores, handle them.
- if(updater.GetMissingCores().Any()) {
+ if (GlobalHelper.SettingsManager.GetMissingCores().Any())
+ {
Console.WriteLine("\nNew cores found since the last run.");
AskAboutNewCores();
- string? download_new_cores = settings.GetConfig().download_new_cores?.ToLowerInvariant();
- switch(download_new_cores) {
+ string downloadNewCores = GlobalHelper.SettingsManager.GetConfig().download_new_cores?.ToLowerInvariant();
+
+ switch (downloadNewCores)
+ {
case "yes":
Console.WriteLine("The following cores have been enabled:");
- foreach(Core core in updater.GetMissingCores())
+
+ foreach (Core core in GlobalHelper.SettingsManager.GetMissingCores())
+ {
Console.WriteLine($"- {core.identifier}");
+ }
- settings.EnableMissingCores(updater.GetMissingCores());
- settings.SaveSettings();
+ GlobalHelper.SettingsManager.EnableMissingCores(GlobalHelper.SettingsManager.GetMissingCores());
+ GlobalHelper.SettingsManager.SaveSettings();
break;
+
case "no":
Console.WriteLine("The following cores have been disabled:");
- foreach(Core core in updater.GetMissingCores())
+
+ foreach (Core core in GlobalHelper.SettingsManager.GetMissingCores())
+ {
Console.WriteLine($"- {core.identifier}");
+ }
- settings.DisableMissingCores(updater.GetMissingCores());
- settings.SaveSettings();
+ GlobalHelper.SettingsManager.DisableMissingCores(GlobalHelper.SettingsManager.GetMissingCores());
+ GlobalHelper.SettingsManager.SaveSettings();
break;
+
default:
- case "ask":
- var newones = updater.GetMissingCores();
- settings.EnableMissingCores(newones);
- if (cliMode) {
- settings.SaveSettings();
- } else {
- await RunCoreSelector(newones, "New cores are available!");
+ var newOnes = GlobalHelper.SettingsManager.GetMissingCores();
+
+ GlobalHelper.SettingsManager.EnableMissingCores(newOnes);
+
+ if (CLI_MODE)
+ {
+ GlobalHelper.SettingsManager.SaveSettings();
+ }
+ else
+ {
+ RunCoreSelector(newOnes, "New cores are available!");
}
+
break;
}
- updater.LoadSettings();
+ // Is reloading the settings file necessary?
+ GlobalHelper.ReloadSettings();
}
- if(forceUpdate) {
+
+ if (forceUpdate)
+ {
Console.WriteLine("Starting update process...");
- await updater.RunUpdates(coreName, cleanInstall);
+ await coreUpdater.RunUpdates(coreName, cleanInstall);
Pause();
- } else if(downloadFirmware) {
- await updater.UpdateFirmware();
- } else if(forceInstanceGenerator) {
- await RunInstanceGenerator(updater, true);
- } else if(downloadAssets != null) {
- if (downloadAssets == "all") {
- await updater.RunAssetDownloader();
- } else {
- await updater.RunAssetDownloader(downloadAssets);
+ }
+ else if (downloadFirmware)
+ {
+ await coreUpdater.UpdateFirmware();
+ }
+ else if (forceInstanceGenerator)
+ {
+ RunInstanceGenerator(coreUpdater, true);
+ }
+ else if (downloadAssets != null)
+ {
+ if (downloadAssets == "all")
+ {
+ await coreUpdater.RunAssetDownloader();
+ }
+ else
+ {
+ await coreUpdater.RunAssetDownloader(downloadAssets);
}
- } else if (imagePackOwner != null) {
- ImagePack pack = new ImagePack() {
+ }
+ else if (imagePackOwner != null)
+ {
+ ImagePack pack = new ImagePack
+ {
owner = imagePackOwner,
repository = imagePackRepo,
variant = imagePackVariant
};
- await InstallImagePack(path, pack);
- } else if (verb == "uninstall") {
- if (GlobalHelper.Instance.GetCore(coreName) == null) {
+
+ await pack.Install(path);
+ }
+ else if (verb == "uninstall")
+ {
+ if (GlobalHelper.GetCore(coreName) == null)
+ {
Console.WriteLine("Unknown core");
- } else {
- await updater.DeleteCore(GlobalHelper.Instance.GetCore(coreName), true, nuke);
}
- } else if (verb == "backup-saves") {
+ else
+ {
+ coreUpdater.DeleteCore(GlobalHelper.GetCore(coreName), true, nuke);
+ }
+ }
+ else if (verb == "backup-saves")
+ {
AssetsService.BackupSaves(path, backupSaves_Path);
-
+
if (backupSaves_SaveConfig)
{
- var config = settings.GetConfig();
-
+ var config = GlobalHelper.SettingsManager.GetConfig();
+
config.backup_saves = true;
config.backup_saves_location = backupSaves_Path;
-
- settings.SaveSettings();
+
+ GlobalHelper.SettingsManager.SaveSettings();
}
- } else {
+ }
+ else
+ {
bool flag = true;
- while(flag) {
+
+ while (flag)
+ {
int choice = DisplayMenuNew();
- switch(choice) {
+ switch (choice)
+ {
case 1:
- await updater.UpdateFirmware();
+ await coreUpdater.UpdateFirmware();
Pause();
break;
+
case 2:
Console.WriteLine("Checking for required files...");
- await updater.RunAssetDownloader();
+ await coreUpdater.RunAssetDownloader();
Pause();
break;
+
case 3:
List cores = await CoresService.GetCores();
AskAboutNewCores(true);
- await RunCoreSelector(cores);
- updater.LoadSettings();
+ RunCoreSelector(cores);
+ // Is reloading the settings file necessary?
+ GlobalHelper.ReloadSettings();
break;
+
case 4:
await ImagePackSelector(path);
break;
+
case 5:
- await RunInstanceGenerator(updater);
+ RunInstanceGenerator(coreUpdater);
Pause();
break;
+
case 6:
- await BuildGameandWatchROMS(path);
+ await BuildGameAndWatchRoms(path);
Pause();
break;
+
case 7:
- await updater.ForceDisplayModes();
+ coreUpdater.ForceDisplayModes();
Pause();
break;
+
case 8:
- AssetsService.BackupSaves(path, settings.GetConfig().backup_saves_location);
+ AssetsService.BackupSaves(path, GlobalHelper.SettingsManager.GetConfig().backup_saves_location);
Pause();
break;
+
case 9:
SettingsMenu();
- SetUpdaterFlags();
+
+ coreUpdater.DeleteSkippedCores(GlobalHelper.SettingsManager.GetConfig().delete_skipped_cores);
+ coreUpdater.DownloadFirmware(GlobalHelper.SettingsManager.GetConfig().download_firmware);
+ coreUpdater.DownloadAssets(GlobalHelper.SettingsManager.GetConfig().download_assets);
+ coreUpdater.RenameJotegoCores(GlobalHelper.SettingsManager.GetConfig().fix_jt_names);
+ coreUpdater.BackupSaves(GlobalHelper.SettingsManager.GetConfig().backup_saves, GlobalHelper.SettingsManager.GetConfig().backup_saves_location);
+ // Is reloading the settings file necessary?
+ GlobalHelper.ReloadSettings();
break;
+
case 10:
flag = false;
break;
- case 0:
+
default:
Console.WriteLine("Starting update process...");
- await updater.RunUpdates();
+ await coreUpdater.RunUpdates();
Pause();
break;
}
}
}
- } catch(Exception e) {
- Console.WriteLine("Well, something went wrong. Sorry about that.");
- Console.WriteLine(e.Message);
- Pause();
}
- }
-
- private static int UpdateSelfAndRun(string directory, string[] updaterArgs)
- {
- string execName = "pupdate";
- if(GetPlatform() == "win") {
- execName += ".exe";
- }
- string execLocation = Path.Combine(directory, execName);
- string backupName = $"{execName}.backup";
- string backupLocation = Path.Combine(directory, backupName);
- string updateName = "pupdate.zip";
- string updateLocation = Path.Combine(directory, updateName);
-
- int exitcode = int.MinValue;
-
- try {
- // Load System.IO.Compression now
- Assembly.Load("System.IO.Compression");
- if(GetPlatform() != "win") {
- Assembly.Load("System.IO.Pipes");
- }
-
- // Move current process file
- Console.WriteLine($"Renaming {execLocation} to {backupLocation}");
- File.Move(execLocation, backupLocation, true);
-
- // Extract update
- Console.WriteLine($"Extracting {updateLocation} to {directory}");
- ZipFile.ExtractToDirectory(updateLocation, directory, true);
-
- // Execute
- Console.WriteLine($"Executing {execLocation}");
- ProcessStartInfo pInfo = new ProcessStartInfo(execLocation) {
- Arguments = string.Join(' ', updaterArgs),
- UseShellExecute = false
- };
-
- Process p = Process.Start(pInfo);
- p.WaitForExit();
- exitcode = p.ExitCode;
- } catch(Exception e) {
- Console.Error.WriteLine($"An error occurred: {e.GetType().Name}:{e.ToString()}");
- }
-
- return exitcode;
- }
-
- private async static Task BuildGameandWatchROMS(string directory)
- {
- Github.Release release = await GithubApi.GetLatestRelease("agg23", "fpga-gameandwatch");
- foreach(Github.Asset asset in release.assets) {
- if (asset.name.EndsWith("Tools.zip")) {
- string downloadPath = Path.Combine(directory, "tools", "gameandwatch");
- string filename = Path.Combine(downloadPath, asset.name);
- if(!File.Exists(filename)) {
- Directory.CreateDirectory(downloadPath);
- await HttpHelper.Instance.DownloadFileAsync(asset.browser_download_url, filename);
- ZipFile.ExtractToDirectory(filename, downloadPath, true);
- }
- break;
- }
- }
- string execName = "fpga-gnw-romgenerator";
- string execLocation = Path.Combine(directory, "tools", "gameandwatch");
- string manifestPath = Path.Combine(directory, "tools", "gameandwatch");
- switch(GetPlatform()) {
- case "win":
- execName += ".exe";
- execLocation = Path.Combine(execLocation, "windows", execName);
- manifestPath = Path.Combine(manifestPath, "windows", "manifest.json");
- break;
- case "mac":
- execLocation = Path.Combine(execLocation, "mac", execName);
- manifestPath = Path.Combine(manifestPath, "mac", "manifest.json");
- Exec($"chmod +x {execLocation}");
- break;
- default:
- execLocation = Path.Combine(execLocation, "linux", execName);
- manifestPath = Path.Combine(manifestPath, "linux", "manifest.json");
- Exec($"chmod +x {execLocation}");
- break;
- }
-
- string romLocation = Path.Combine(directory, "Assets", "gameandwatch", "agg23.GameAndWatch");
- string outputLocation = Path.Combine(directory, "Assets", "gameandwatch", "common");
-
- try {
- // Execute
- Console.WriteLine($"Executing {execLocation}");
- ProcessStartInfo pInfo = new ProcessStartInfo(execLocation) {
- Arguments = $"--mame-path \"{romLocation}\" --output-path \"{outputLocation}\" --manifest-path \"{manifestPath}\" supported",
- UseShellExecute = false
- };
-
- Process p = Process.Start(pInfo);
- p.WaitForExit();
- } catch(Exception e) {
- Console.Error.WriteLine($"An error occurred: {e.GetType().Name}:{e.ToString()}");
- }
- }
-
- static void SetUpdaterFlags()
- {
- updater.DeleteSkippedCores(settings.GetConfig().delete_skipped_cores);
- updater.SetGithubApiKey(settings.GetConfig().github_token);
- updater.DownloadFirmware(settings.GetConfig().download_firmware);
- updater.DownloadAssets(settings.GetConfig().download_assets);
- updater.RenameJotegoCores(settings.GetConfig().fix_jt_names);
- updater.BackupSaves(settings.GetConfig().backup_saves, settings.GetConfig().backup_saves_location);
- updater.LoadSettings();
- }
-
- static async Task RunInstanceGenerator(PocketCoreUpdater updater, bool force = false)
- {
- if(!force) {
- ConsoleKey response;
- Console.Write("Do you want to overwrite existing json files? [y/N] ");
- Console.WriteLine("");
- response = Console.ReadKey(false).Key;
- if(response == ConsoleKey.Y) {
- force = true;
- }
- }
- await updater.BuildInstanceJSON(force);
- }
-
- public static void Exec(string cmd)
- {
- var escapedArgs = cmd.Replace("\"", "\\\"");
-
- using var process = new Process
+ catch (Exception e)
{
- StartInfo = new ProcessStartInfo
- {
- RedirectStandardOutput = true,
- UseShellExecute = false,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = "/bin/bash",
- Arguments = $"-c \"{escapedArgs}\""
- }
- };
-
- process.Start();
- process.WaitForExit();
- }
-
- static async Task RunCoreSelector(List cores, string message = "Select your cores.")
- {
- if(settings.GetConfig().download_new_cores?.ToLowerInvariant() == "yes") {
- foreach(Core core in cores)
- settings.EnableCore(core.identifier);
- } else {
- var pageSize = 15;
- var offset = 0;
- bool next = false;
- bool previous = false;
- bool more = true;
- while(more) {
- var menu = new ConsoleMenu()
- .Configure(config =>
- {
- config.Selector = "=>";
- config.EnableWriteTitle = false;
- config.WriteHeaderAction = () => Console.WriteLine($"{message} Use enter to check/uncheck your choices.");
- config.SelectedItemBackgroundColor = Console.ForegroundColor;
- config.SelectedItemForegroundColor = Console.BackgroundColor;
- config.WriteItemAction = item => Console.Write("{1}", item.Index, item.Name);
- });
- var current = -1;
- if((offset + pageSize) <= cores.Count) {
- menu.Add("Next Page", (thisMenu) => { offset += pageSize; thisMenu.CloseMenu();});
- }
- foreach(Core core in cores) {
- current++;
- if ((current <= (offset + pageSize)) && (current >= offset)) {
- var coreSettings = settings.GetCoreSettings(core.identifier);
- var selected = !coreSettings.skip;
- var name = core.identifier;
- if (core.requires_license) {
- name += " (Requires beta access)";
- }
- var title = settingsMenuItem(name, selected);
- menu.Add(title, (thisMenu) => {
- selected = !selected;
- if (!selected) {
- settings.DisableCore(core.identifier);
- } else {
- settings.EnableCore(core.identifier);
- }
-
- thisMenu.CurrentItem.Name = settingsMenuItem(core.identifier, selected);
- });
- }
- }
- if((offset + pageSize) <= cores.Count) {
- menu.Add("Next Page", (thisMenu) => { offset += pageSize; thisMenu.CloseMenu();});
- }
- menu.Add("Save Choices", (thisMenu) => {thisMenu.CloseMenu(); more = false;});
- menu.Show();
- }
+ Console.WriteLine("Well, something went wrong. Sorry about that.");
+ Console.WriteLine(e);
+ Pause();
}
- settings.GetConfig().core_selector = false;
- settings.SaveSettings();
}
- static void updater_StatusUpdated(object sender, StatusUpdatedEventArgs e)
+ private static void coreUpdater_StatusUpdated(object sender, StatusUpdatedEventArgs e)
{
Console.WriteLine(e.Message);
}
- static void updater_UpdateProcessComplete(object sender, UpdateProcessCompleteEventArgs e)
+ static void coreUpdater_UpdateProcessComplete(object sender, UpdateProcessCompleteEventArgs e)
{
Console.WriteLine("-------------");
Console.WriteLine(e.Message);
- if(e.InstalledCores != null && e.InstalledCores.Count > 0) {
+
+ if (e.InstalledCores != null && e.InstalledCores.Count > 0)
+ {
Console.WriteLine("Cores Updated:");
- foreach(Dictionary core in e.InstalledCores) {
+
+ foreach (Dictionary core in e.InstalledCores)
+ {
Console.WriteLine(core["core"] + " " + core["version"]);
}
+
Console.WriteLine("");
}
- if(e.InstalledAssets.Count > 0) {
+
+ if (e.InstalledAssets.Count > 0)
+ {
Console.WriteLine("Assets Installed:");
- foreach(string asset in e.InstalledAssets) {
+
+ foreach (string asset in e.InstalledAssets)
+ {
Console.WriteLine(asset);
}
+
Console.WriteLine("");
}
- if(e.SkippedAssets.Count > 0) {
+
+ if (e.SkippedAssets.Count > 0)
+ {
Console.WriteLine("Assets Not Found:");
- foreach(string asset in e.SkippedAssets) {
+ foreach (string asset in e.SkippedAssets)
+ {
Console.WriteLine(asset);
}
+
Console.WriteLine("");
}
- if(e.FirmwareUpdated != "") {
+
+ if (e.FirmwareUpdated != "")
+ {
Console.WriteLine("New Firmware was downloaded. Restart your Pocket to install");
Console.WriteLine(e.FirmwareUpdated);
Console.WriteLine("");
}
- if(e.MissingBetaKeys.Count > 0) {
+
+ if (e.MissingBetaKeys.Count > 0)
+ {
Console.WriteLine("Missing or incorrect Beta Key for the following cores:");
- foreach(string core in e.MissingBetaKeys) {
+ foreach (string core in e.MissingBetaKeys)
+ {
Console.WriteLine(core);
}
- Console.WriteLine("");
- }
- ShowSponsorLinks();
- FunFacts();
- }
- private static void ShowSponsorLinks()
- {
- if (GlobalHelper.Instance.InstalledCores.Count == 0) return;
- var random = new Random();
- var index = random.Next(GlobalHelper.Instance.InstalledCores.Count);
- var randomItem = GlobalHelper.Instance.InstalledCores[index];
- if(randomItem.sponsor != null) {
- var links = "";
- if (randomItem.sponsor.custom != null) {
- links += "\r\n" + String.Join("\r\n", randomItem.sponsor.custom);
- }
- if (randomItem.sponsor.github != null) {
- links += "\r\n" + String.Join("\r\n", randomItem.sponsor.github);
- }
- if (randomItem.sponsor.patreon != null) {
- links += "\r\n" + randomItem.sponsor.patreon;
- }
Console.WriteLine("");
- Console.WriteLine($"Please consider supporting {randomItem.getConfig().metadata.author} for their work on the {randomItem} core:");
- Console.WriteLine(links.Trim());
- }
- }
-
- private static string? GetSponsorLinks()
- {
- if (GlobalHelper.Instance.InstalledCores.Count == 0) return null;
- var random = new Random();
- var index = random.Next(GlobalHelper.Instance.InstalledCores.Count);
- var randomItem = GlobalHelper.Instance.InstalledCores[index];
- string output = "";
- if(randomItem.sponsor != null) {
- var links = "";
- if (randomItem.sponsor.custom != null) {
- links += "\r\n" + String.Join("\r\n", randomItem.sponsor.custom);
- }
- if (randomItem.sponsor.github != null) {
- links += "\r\n" + String.Join("\r\n", randomItem.sponsor.github);
- }
- if (randomItem.sponsor.patreon != null) {
- links += "\r\n" + randomItem.sponsor.patreon;
- }
- output += "\r\n";
- output += $"Please consider supporting {randomItem.getConfig().metadata.author} for their work on the {randomItem} core:";
- output += $"\r\n{links.Trim()}";
- }
-
- return output;
- }
-
- private static async Task Funding(string? identifier)
- {
- await updater.Initialize();
- if (GlobalHelper.Instance.InstalledCores.Count == 0) return;
-
- List cores = new List();
- if (identifier == null) {
- cores = GlobalHelper.Instance.InstalledCores;
- } else {
- var c = GlobalHelper.Instance.GetCore(identifier);
- if (c != null && c.isInstalled()) {
- cores.Add(c);
- }
- }
-
- foreach(Core core in cores) {
- if(core.sponsor != null) {
- var links = "";
- if (core.sponsor.custom != null) {
- links += "\r\n" + String.Join("\r\n", core.sponsor.custom);
- }
- if (core.sponsor.github != null) {
- links += "\r\n" + String.Join("\r\n", core.sponsor.github);
- }
- if (core.sponsor.patreon != null) {
- links += "\r\n" + core.sponsor.patreon;
- }
- Console.WriteLine("");
- Console.WriteLine($"{core.identifier}:");
- Console.WriteLine(links.Trim());
- }
}
- }
- private static void FunFacts()
- {
- if (GlobalHelper.Instance.InstalledCores.Count == 0) return;
- List cores = new List();
-
- foreach(Core c in GlobalHelper.Instance.InstalledCores) {
- if (c.getConfig().framework.sleep_supported) {
- cores.Add(c.identifier);
- }
- }
- Console.WriteLine("");
- string list = String.Join(", ", cores.ToArray());
- Console.WriteLine("Fun fact! The ONLY cores that support save states and sleep are the following:");
- Console.WriteLine(list);
- Console.WriteLine("Please don't bother the developers of the other cores about this feature. It's a lot of work and most likely will not be coming.");
-
- }
-
- //return true if newer version is available
- async static Task CheckVersion(string path)
- {
- try {
- List releases = await GithubApi.GetReleases(USER, REPOSITORY);
-
- string tag_name = releases[0].tag_name;
- string? v = SemverUtil.FindSemver(tag_name);
- if(v != null) {
- bool check = SemverUtil.SemverCompare(v, version);
- if(check) {
- Console.WriteLine("A new version is available. Downloading now...");
- string platform = GetPlatform();
- string url = String.Format(RELEASE_URL, tag_name, platform);
- string saveLocation = Path.Combine(path, "pupdate.zip");
- await Factory.GetHttpHelper().DownloadFileAsync(url, saveLocation);
- Console.WriteLine("Download complete.");
- Console.WriteLine(saveLocation);
- Console.WriteLine("Go to " + releases[0].html_url + " for a change log");
- } else {
- Console.WriteLine("Up to date.");
- }
- return check;
- }
-
- return false;
- } catch(HttpRequestException e) {
- return false;
- }
- }
-
- private static string GetPlatform()
- {
- if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
- return "win";
- }
- if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
- return "mac";
- }
- if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
- Architecture arch = RuntimeInformation.ProcessArchitecture;
- if(arch == Architecture.Arm64) {
- return "linux_arm64";
- } else if(arch == Architecture.Arm) {
- return "linux_arm32";
- }
- return "linux";
- }
-
- return "";
- }
-
- private static int DisplayMenuNew()
- {
- Console.Clear();
- Random random = new Random();
- int i = random.Next(0, welcomeMessages.Length);
- string welcome = welcomeMessages[i];
-
- int choice = 0;
-
- var menu = new ConsoleMenu()
- .Configure(config =>
- {
- config.Selector = "=>";
- //config.EnableFilter = true;
- config.Title = $"{welcome}\r\n{GetSponsorLinks()}\r\n";
- config.EnableWriteTitle = true;
- //config.EnableBreadcrumb = true;
- config.WriteHeaderAction = () => Console.WriteLine("Choose your destiny:");
- config.SelectedItemBackgroundColor = Console.ForegroundColor;
- config.SelectedItemForegroundColor = Console.BackgroundColor;
- });
-
- foreach(var (item, index) in menuItems.WithIndex()) {
- menu.Add(item, (thisMenu) =>
- {
- choice = thisMenu.CurrentItem.Index;
- thisMenu.CloseMenu();
- });
- }
-
- menu.Show();
-
- return choice;
- }
-
- private static int DisplayMenu()
- {
- Console.Clear();
- Random random = new Random();
- int i = random.Next(0, welcomeMessages.Length);
- string welcome = welcomeMessages[i];
-
- Console.WriteLine(welcome);
-
- foreach(var (item, index) in menuItems.WithIndex()) {
- Console.WriteLine($"{index}) {item}");
- }
- ShowSponsorLinks();
- Console.Write("\nChoose your destiny: ");
- int choice;
- bool result = int.TryParse(Console.ReadLine(), out choice);
- if(result) {
- return choice;
- }
- return 0;
- }
-
- private static async Task SettingsMenu()
- {
- Console.Clear();
-
- var menuItems = new Dictionary(){
- {"download_firmware", "Download Firmware Updates during 'Update All'"},
- {"download_assets", "Download Missing Assets (ROMs and BIOS Files) during 'Update All'"},
- {"build_instance_jsons", "Build game JSON files for supported cores during 'Update All'"},
- {"delete_skipped_cores", "Delete untracked cores during 'Update All'"},
- {"fix_jt_names", "Automatically rename Jotego cores during 'Update All"},
- {"crc_check", "Use CRC check when checking ROMs and BIOS files"},
- {"preserve_platforms_folder", "Preserve 'Platforms' folder during 'Update All'"},
- {"skip_alternative_assets", "Skip alternative roms when downloading assets"},
- {"backup_saves", "Compress and backup Saves directory during 'Update All'"},
- {"use_custom_archive", "Use custom asset archive"}
- };
-
- var type = typeof(Config);
-
- var menu = new ConsoleMenu()
- .Configure(config =>
- {
- config.Selector = "=>";
- config.EnableWriteTitle = false;
- config.WriteHeaderAction = () => Console.WriteLine("Settings. Use enter to check/uncheck your choices.");
- config.SelectedItemBackgroundColor = Console.ForegroundColor;
- config.SelectedItemForegroundColor = Console.BackgroundColor;
- config.WriteItemAction = item => Console.Write("{1}", item.Index, item.Name);
- });
-
- foreach(var (name, text) in menuItems) {
- var property = type.GetProperty(name);
- var value = (bool) property.GetValue(settings.GetConfig());
- var title = settingsMenuItem(text, value);
-
- menu.Add(title, (thisMenu) =>
- {
- value = !value;
- property.SetValue(settings.GetConfig(), value);
- thisMenu.CurrentItem.Name = settingsMenuItem(text, value);
- });
- }
-
- menu.Add("Save", (thisMenu) => {thisMenu.CloseMenu();});
-
- menu.Show();
-
- settings.SaveSettings();
- }
-
- private static string settingsMenuItem(string title, bool value)
- {
- var x = " ";
- if (value) {
- x = "X";
- }
-
- return $"[{x}] {title}";
- }
-
- private static async Task ImagePackSelector(string path)
- {
- Console.Clear();
- Console.WriteLine("Checking for image packs...\n");
- ImagePack[] packs = await ImagePacksService.GetImagePacks();
- if(packs.Length > 0) {
- int choice = 0;
- var menu = new ConsoleMenu()
- .Configure(config =>
- {
- config.Selector = "=>";
- config.EnableWriteTitle = false;
- //config.EnableBreadcrumb = true;
- config.WriteHeaderAction = () => Console.WriteLine("So, what'll it be?:");
- config.SelectedItemBackgroundColor = Console.ForegroundColor;
- config.SelectedItemForegroundColor = Console.BackgroundColor;
- });
-
- foreach(var (pack, index) in packs.WithIndex()) {
- menu.Add($"{pack.owner}: {pack.repository} {pack.variant}", (thisMenu) => { choice = thisMenu.CurrentItem.Index; thisMenu.CloseMenu(); });
- }
- menu.Add("Go Back", (thisMenu) => {choice = packs.Length; thisMenu.CloseMenu();});
-
- menu.Show();
-
- if(choice < packs.Length && choice >= 0) {
- await InstallImagePack(path, packs[choice]);
- Pause();
- } else if(choice == packs.Length) {
- return;
- } else {
- Console.WriteLine("you fucked up");
- Pause();
- }
- } else {
- Console.WriteLine("None found. Have a nice day");
- Pause();
- }
- }
-
- private static async Task InstallImagePack(string path, ImagePack pack)
- {
- await pack.Install(path);
- }
-
- private static void PauseExit(int exitcode = 0)
- {
- Console.WriteLine("Press any key to exit.");
- Console.ReadLine(); //wait for input so the console doesn't auto close in windows
- Environment.Exit(exitcode);
- }
-
- private static void Pause()
- {
- if(cliMode) return;
- Console.WriteLine("Press any key to continue.");
- Console.ReadKey(true);
- }
-
- private static void AskAboutNewCores(bool force = false)
- {
- while(settings.GetConfig().download_new_cores == null || force) {
- force = false;
-
- Console.WriteLine("Would you like to, by default, install new cores? [Y]es, [N]o, [A]sk for each:");
- ConsoleKey response = Console.ReadKey(false).Key;
- settings.GetConfig().download_new_cores = response switch {
- ConsoleKey.Y => "yes",
- ConsoleKey.N => "no",
- ConsoleKey.A => "ask",
- _ => null
- };
- }
+ Console.WriteLine(GetRandomSponsorLinks());
+ FunFacts();
}
-
- private static string[] menuItems = {
- "Update All",
- "Update Firmware",
- "Download Required Assets",
- "Select Cores",
- "Download Platform Image Packs",
- "Generate Instance JSON Files",
- "Generate Game and Watch ROMS",
- "Enable All Display Modes",
- "Backup Saves Directory",
- "Settings",
- "Exit"
- };
-
- private static string[] welcomeMessages = {
- @"
- _____ _ _ ___ _____ _
-| __ | |___ _____ ___ _ _ ___ _ _ ___ ___ ___| | _| ___ ___ | __|___ _| |
-| __ -| | .'| | -_| | | | . | | | _|_ -| -_| | _| | . | _| | | | . | . |
-|_____|_|__,|_|_|_|___| |_ |___|___|_| |___|___|_|_| |___|_| |_____|___|___|
- |___| ",
- @"
- _ _ _ _ _ _____ _ _
-| | | |___| |___ ___ _____ ___ | |_ ___ | __| |___ _ _ ___ ___| |_ ___ _ _ _ ___
-| | | | -_| | _| . | | -_| | _| . | | __| | .'| | | . | _| _| . | | | | |
-|_____|___|_|___|___|_|_|_|___| |_| |___| |__| |_|__,|\_/|___|_| |_| |___|_____|_|_|
- ",
- @"
- _ ___ _ _ _ _
- ___| |_ ___ | _|_|___ _| |___ _ _ ___ _ _ ___ ___ _ _ ___| |_ _ _ _| |___ _ _ ___
-|_ -| | -_| | _| | | . |_ -| | | | . | | | | _| _| | |_ -| _| | | | . | .'| | | -_|
-|___|_|_|___| |_| |_|_|_|___|___| |_ |___|___| |___|_| |___|___|_| |_ | |___|__,|\_/|___|
- |___| |___| ",
- @"
- _____ _ _ _ ___ _ _
-|_ _| |_|_|___ |_|___ ___ | _|___ ___ ___ _ _ ___ ___ ___| |_ ___ _ _ ___ ___ ___| |_
- | | | | |_ -| | |_ -| | .'| | _| .'| | _| | | | _| -_|_ -| _| .'| | | _| .'| | _|
- |_| |_|_|_|___| |_|___| |__,| |_| |__,|_|_|___|_ | |_| |___|___|_| |__,|___|_| |__,|_|_|_|
- |___| ",
- @" __
- _ _ _ _ _ _ _ _____ _ _ _____ _ _ | |
-| | | |___| |___ ___ _____ ___ | |_ ___ | |_| |_ ___ | __ | |___ ___| |_ | |___ ___| |_ ___| |_| |
-| | | | -_| | _| . | | -_| | _| . | | _| | -_| | __ -| | .'| _| '_| | | | | .'| _| '_| -_| _|__|
-|_____|___|_|___|___|_|_|_|___| |_| |___| |_| |_|_|___| |_____|_|__,|___|_,_| |_|_|_|__,|_| |_,_|___|_| |__|
- ",
- @"
- _____ _ _ _____ _
-| | |_ ___| |_ _ _ |_ _|___ ___| |_ _ _
-|- -| _| _| | | |_ | | | .'|_ -| _| | |_
-|_____|_| |___|_|_|_ |_| |_| |__,|___|_| |_ |_|
- |___| |___| ",
- @" _ _____
- _ _ _ _ _ | | _ _ |___ |
-| | | | |_ ___| |_|_|___ ___ _ _ ___ | |_ _ _ _ _|_|___| _|
-| | | | | .'| _| | _| -_| | | | .'| | . | | | | | | |_|
-|_____|_|_|__,|_| |_| |___| |_ |__,| |___|___|_ |_|_|_|_|
- |___| |___| ",
- @" _____
- _ _ _ _ _ _ |___ |
-| | | | |_ ___| |_ |_|___ ___ _____ ___ ___| _|
-| | | | | .'| _| | |_ -| | .'| | | .'| |_|
-|_____|_|_|__,|_| |_|___| |__,| |_|_|_|__,|_|_|_|
- ",
- @"
- _____ _ _ _____ _ _ _
-| __|_|___ ___|_|___ ___ | |___|_| |___ _| |
-| __| |_ -|_ -| | . | | | | | | .'| | | -_| . |
-|__| |_|___|___|_|___|_|_| |_|_|_|__,|_|_|___|___|
- ",
- @"
- _____ _
-| | |_____| |_ ___ ___ ___
-| | | | . | .'|_ -| .'|
-|_____|_|_|_|___|__,|___|__,|
- ",
- @" _
- __ _ | |
-| | ___| |_|_|___ _____ ___ ___ ___ _ _
-| |__| -_| _| |_ -| | | . |_ -| -_| | |
-|_____|___|_| |___| |_|_|_|___|___|___|_ |
- |___|",
-@" _=,_
- o_/6 /#\
- \__ |##/
- ='|--\
- / #'-.
- \#|_ _'-. /
- |/ \_( # |''
- C/ ,--___/"
- };
-}
-[Verb("menu", isDefault: true, HelpText = "Interactive Main Menu")]
-public class MenuOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option('s', "skip-update", HelpText = "Skip the self update check", Required = false)]
- public bool SkipUpdate { get; set; }
-}
-
-[Verb("update", HelpText = "Run update all. (You can configure via the settings menu)")]
-public class UpdateOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option ('c', "core", Required = false, HelpText = "The core you want to update.")]
- public string CoreName { get; set; }
-
- [Option('f', "platformsfolder", Required = false, HelpText = "Preserve the Platforms folder, so customizations aren't overwritten by updates.")]
- public bool PreservePlatformsFolder { get; set; }
-
- [Option('r', "clean", Required = false, HelpText = "Clean install. Remove all existing core files, before updating")]
- public bool CleanInstall { get; set; }
-
-}
-
-[Verb("uninstall", HelpText = "Delete a core")]
-public class UninstallOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option ('c', "core", Required = true, HelpText = "The core you want to delete.")]
- public string CoreName { get; set; }
-
- [Option('a', "assets", Required = false, HelpText = "Delete the core specific Assets folder")]
- public bool DeleteAssets { get; set; }
-}
-
-[Verb("assets", HelpText = "Run the asset downloader")]
-public class AssetsOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option ('c', "core", Required = false, HelpText = "The core you want to download assets for.")]
- public string CoreName { get; set; }
-}
-
-[Verb("instancegenerator", HelpText = "Run the instance JSON generator")]
-public class InstancegeneratorOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-}
-
-[Verb("images", HelpText = "Download image packs")]
-public class ImagesOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option('o', "owner", Required = true, HelpText = "Image pack repo username")]
- public string ImagePackOwner { get; set; }
-
- [Option('i', "imagepack", Required = true, HelpText = "Github repo name for image pack")]
- public string ImagePackRepo { get; set; }
-
- [Option('v', "variant", Required = false, HelpText = "The optional variant")]
- public string? ImagePackVariant { get; set; }
-}
-
-[Verb("firmware", HelpText = "Check for Pocket firmware updates")]
-public class FirmwareOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-}
-
-[Verb("fund", HelpText = "List sponsor links")]
-public class FundOptions
-{
- [Option('c', "core", HelpText = "The core to check funding links for", Required = false)]
- public string? Core { get; set; }
-}
-
-[Verb("update-self", HelpText = "Update this utility")]
-public class UpdateSelfOptions
-{
-}
-
-[Verb("backup-saves", HelpText = "Create a compressed zip file of the Saves directory.")]
-public class BackupSavesOptions
-{
- [Option('p', "path", HelpText = "Absolute path to install location", Required = false)]
- public string? InstallPath { get; set; }
-
- [Option('l', "location", HelpText = "Absolute path to backup location", Required = true)]
- public string BackupPath { get; set; } = null!;
-
- [Option('s', "save", HelpText = "Save settings to the config file", Required = false)]
- public bool Save { get; set; }
-}
-
-public static class EnumExtension
-{
- public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable self)
- => self.Select((item, index) => (item, index));
}
diff --git a/src/SettingsManager.cs b/src/SettingsManager.cs
index 869fed05..88cc7cfb 100644
--- a/src/SettingsManager.cs
+++ b/src/SettingsManager.cs
@@ -1,14 +1,16 @@
-using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
-using System.IO;
+using Pannella.Models;
+using Pannella.Models.Settings;
-namespace pannella.analoguepocket;
+namespace Pannella;
+[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")]
public class SettingsManager
{
- private Settings _settings;
- private string _settingsFile;
- private List _newCores = new();
+ private readonly Settings _settings;
+ private readonly string _settingsFile;
+ private readonly List _newCores = new();
private const string OLD_DEFAULT = "pocket-roms";
private const string NEW_DEFAULT = "openFPGA-Files";
@@ -16,9 +18,10 @@ public class SettingsManager
private const string OLD_SETTINGS_FILENAME = "pocket_updater_settings.json";
private const string SETTINGS_FILENAME = "pupdate_settings.json";
- public SettingsManager(string settingsPath, List? cores = null)
+ public SettingsManager(string settingsPath, List cores = null)
{
_settings = new Settings();
+
string file = Path.Combine(settingsPath, SETTINGS_FILENAME);
string oldFile = Path.Combine(settingsPath, OLD_SETTINGS_FILENAME);
string json = null!;
@@ -37,120 +40,96 @@ public SettingsManager(string settingsPath, List? cores = null)
{
_settings = JsonSerializer.Deserialize(json);
- //hack to force people over to new default :)
- if(_settings.config.archive_name == OLD_DEFAULT) {
+ // hack to force people over to new default :)
+ if (_settings.config.archive_name == OLD_DEFAULT)
+ {
_settings.config.archive_name = NEW_DEFAULT;
}
}
- //bandaid to fix old settings files
- if(_settings.config == null) {
- _settings.config = new Config();
- }
+ // bandaid to fix old settings files
+ _settings.config ??= new Config();
_settingsFile = file;
- if(cores != null) {
+ if (cores != null)
+ {
InitializeCoreSettings(cores);
}
SaveSettings();
}
- //loop through every core, and add any missing ones to the settings file
+ // loop through every core, and add any missing ones to the settings file
public void InitializeCoreSettings(List cores)
{
- if(_settings.coreSettings == null) {
- _settings.coreSettings = new Dictionary();
- }
- foreach(Core core in cores)
+ _settings.coreSettings ??= new Dictionary();
+
+ foreach (Core core in cores)
{
- if(!_settings.coreSettings.ContainsKey(core.identifier)) {
+ if (!_settings.coreSettings.ContainsKey(core.identifier))
+ {
_newCores.Add(core);
}
}
}
public List GetMissingCores() => _newCores;
+
public void EnableMissingCores(List cores)
{
foreach (var core in cores)
+ {
EnableCore(core.identifier);
+ }
}
+
public void DisableMissingCores(List cores)
{
foreach (var core in cores)
+ {
DisableCore(core.identifier);
+ }
}
- public bool SaveSettings()
+ public void SaveSettings()
{
var options = new JsonSerializerOptions { WriteIndented = true };
File.WriteAllText(_settingsFile, JsonSerializer.Serialize(_settings, options));
-
- return true;
}
public void DisableCore(string name)
{
- if(_settings.coreSettings.ContainsKey(name))
+ if (_settings.coreSettings.TryGetValue(name, out CoreSettings value))
{
- _settings.coreSettings[name].skip = true;
+ value.skip = true;
}
else
{
- CoreSettings core = new CoreSettings();
- core.skip = true;
+ CoreSettings core = new CoreSettings { skip = true };
+
_settings.coreSettings.Add(name, core);
}
}
public void EnableCore(string name)
{
- if (_settings.coreSettings.ContainsKey(name))
+ if (_settings.coreSettings.TryGetValue(name, out CoreSettings value))
{
- _settings.coreSettings[name].skip = false;
+ value.skip = false;
}
else
{
- CoreSettings core = new CoreSettings();
- core.skip = false;
- _settings.coreSettings.Add(name, core);
- }
- }
+ CoreSettings core = new CoreSettings { skip = false };
- public void UpdateCore(CoreSettings core, string name)
- {
- if (_settings.coreSettings.ContainsKey(name))
- {
- _settings.coreSettings[name] = core;
- }
- else
- {
_settings.coreSettings.Add(name, core);
}
}
public CoreSettings GetCoreSettings(string name)
{
- if (_settings.coreSettings.ContainsKey(name))
- {
- return _settings.coreSettings[name];
- }
- else
- {
- return new CoreSettings();
- }
- }
-
- public Firmware GetCurrentFirmware()
- {
- return _settings.firmware;
- }
-
- public void SetFirmwareVersion(string version)
- {
- _settings.firmware.version = version;
- SaveSettings();
+ return _settings.coreSettings.TryGetValue(name, out CoreSettings value)
+ ? value
+ : new CoreSettings();
}
public Config GetConfig()
@@ -158,9 +137,10 @@ public Config GetConfig()
return _settings.config;
}
+ // This is used by the RetroDriven Pocket Updater Windows Application
+ // ReSharper disable once UnusedMember.Global
public void UpdateConfig(Config config)
{
_settings.config = config;
}
-
}
diff --git a/src/Updater.cs b/src/Updater.cs
deleted file mode 100644
index 4467d50d..00000000
--- a/src/Updater.cs
+++ /dev/null
@@ -1,564 +0,0 @@
-using System;
-using System.IO;
-using System.IO.Compression;
-using System.Text.Json;
-using System.Text.RegularExpressions;
-
-namespace pannella.analoguepocket;
-
-public class PocketCoreUpdater : Base
-{
- private const string FIRMWARE_FILENAME_PATTERN = "pocket_firmware_*.bin";
- private const string FIRMWARE_URL = "https://www.analogue.co/support/pocket/firmware/latest";
- private static readonly Regex BIN_REGEX = new Regex(@"(?inx)
- ]*
- href \s* = \s*
- (? ['""] )
- (? [^'""]*\.bin )
- \k
- [^>]* >");
- private bool _downloadAssets = false;
- private bool _preservePlatformsFolder = false;
-
- private string _githubApiKey = "";
-
- private bool _downloadFirmware = true;
- private bool _deleteSkippedCores = true;
- private bool _useConsole = false;
- private bool _renameJotegoCores = true;
- private bool _jtBeta = false;
- private bool _backupSaves = false;
- private string _backupSavesLocation;
-
- private Dictionary _platformFiles = new Dictionary();
-
- ///
- /// Constructor
- ///
- /// The directory to install/update openFPGA cores in.
- /// Path to settings json file
- public PocketCoreUpdater(string updateDirectory, string? settingsPath = null)
- {
- Factory.GetGlobals().UpdateDirectory = updateDirectory;
- Directory.CreateDirectory(Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores"));
-
- if(settingsPath != null) {
- Factory.GetGlobals().SettingsPath = settingsPath;
- } else {
- Factory.GetGlobals().SettingsPath = updateDirectory;
- }
- }
-
- public async Task Initialize()
- {
- LoadSettings();
- await LoadPlatformFiles();
- await LoadCores();
- await RefreshInstalledCores();
- await LoadArchive();
- await LoadBlacklist();
- }
-
- private async Task RefreshInstalledCores()
- {
- var installedCores = new List();
- foreach(Core c in GlobalHelper.Instance.Cores) {
- if(c.isInstalled()) {
- installedCores.Add(c);
- }
- }
- GlobalHelper.Instance.InstalledCores = installedCores;
- }
-
- private async Task LoadPlatformFiles()
- {
- try {
- List files = await GithubApi.GetFiles("dyreschlock", "pocket-platform-images", "arcade/Platforms",
- GlobalHelper.Instance.SettingsManager.GetConfig().github_token);
- Dictionary platformFiles = new Dictionary();
- foreach(Github.File file in files) {
- string url = file.download_url;
- string filename = file.name;
- if (filename.EndsWith(".json")) {
- string platform = Path.GetFileNameWithoutExtension(filename);
- platformFiles.Add(platform, url);
- }
- }
- _platformFiles = platformFiles;
- } catch (Exception e) {
- _writeMessage("Unable to retrieve archive contents. Asset download may not work.");
- _platformFiles = new Dictionary();
- }
- }
-
- private async Task LoadArchive()
- {
- _writeMessage("Loading Assets Index...");
- if(Factory.GetGlobals().SettingsManager.GetConfig().use_custom_archive) {
- var custom = Factory.GetGlobals().SettingsManager.GetConfig().custom_archive;
- Uri baseUrl = new Uri(custom["url"]);
- Uri url = new Uri(baseUrl, custom["index"]);
-
- Factory.GetGlobals().ArchiveFiles = await ArchiveService.GetFilesCustom(url.ToString());
- } else {
- Factory.GetGlobals().ArchiveFiles = await ArchiveService.GetFiles(Factory.GetGlobals().SettingsManager.GetConfig().archive_name);
- }
- }
-
- private async Task LoadBlacklist()
- {
- Factory.GetGlobals().Blacklist = await AssetsService.GetBlacklist();
- }
-
- public async Task LoadCores()
- {
- Factory.GetGlobals().Cores = await CoresService.GetCores();
- Factory.GetGlobals().SettingsManager.InitializeCoreSettings(Factory.GetGlobals().Cores);
- foreach(Core core in Factory.GetGlobals().Cores) {
- core.StatusUpdated += updater_StatusUpdated; //attach handler to bubble event up
- }
- }
-
- public List GetCores()
- {
- return Factory.GetGlobals().Cores;
- }
-
- public void LoadSettings()
- {
- Factory.GetGlobals().SettingsManager = new SettingsManager(Factory.GetGlobals().SettingsPath, Factory.GetGlobals().Cores);
- }
-
- public List GetMissingCores() => Factory.GetGlobals().SettingsManager?.GetMissingCores() ?? new List();
-
- ///
- /// Turn on/off printing progress messages to the console
- ///
- /// Set to true to turn on console messages
- public void PrintToConsole(bool set)
- {
- _useConsole = set;
- }
-
- public void RenameJotegoCores(bool set)
- {
- _renameJotegoCores = set;
- }
-
- ///
- /// Turn on/off the automatic BIOS downloader
- ///
- /// Set to true to enable automatic BIOS downloading
- public void DownloadAssets(bool set)
- {
- _downloadAssets = set;
- }
-
- ///
- /// Turn on/off preserving customizations to /Platforms
- ///
- /// Set to true to enable preserving custom /Platforms changes
- public void PreservePlatformsFolder(bool set)
- {
- _preservePlatformsFolder = set;
- }
-
- public void DownloadFirmware(bool set)
- {
- _downloadFirmware = set;
- }
-
- public void BackupSaves(bool set, string location)
- {
- _backupSaves = set;
- _backupSavesLocation = location;
- }
-
- //get api and local cores
- private async Task> getAllCores()
- {
- List cores = Factory.GetGlobals().Cores;
- List local = await GetLocalCores();
- foreach(Core core in local) {
- core.StatusUpdated += updater_StatusUpdated; //attach handler to bubble event up
- }
- cores.AddRange(local);
-
- return cores;
- }
-
- public async Task BuildInstanceJSON(bool overwrite = false, string? corename = null)
- {
- List cores = await getAllCores();
- foreach(Core core in Factory.GetGlobals().Cores) {
- if(core.CheckInstancePackager() && (corename == null || corename == core.identifier)) {
- _writeMessage(core.identifier);
- core.BuildInstanceJSONs(overwrite);
- Divide();
- }
- }
- }
-
- ///
- /// Run the full openFPGA core download and update process
- ///
- public async Task RunUpdates(string? id = null, bool clean = false)
- {
- List> installed = new List>();
- List installedAssets = new List();
- List skippedAssets = new List();
- List missingBetaKeys = new List();
- Dictionary results = new Dictionary();
- string firmwareDownloaded = "";
- if(Factory.GetGlobals().Cores == null) {
- throw new Exception("Must initialize updater before running update process");
- }
-
- if (_backupSaves)
- {
- AssetsService.BackupSaves(Factory.GetGlobals().UpdateDirectory, _backupSavesLocation);
- }
-
- if(_downloadFirmware && id == null) {
- firmwareDownloaded = await UpdateFirmware();
- }
-
- await ExtractBetaKey();
-
- List cores = await getAllCores();
- string json;
- foreach(Core core in Factory.GetGlobals().Cores) {
- if(id != null && core.identifier != id) {
- continue;
- }
-
- core.downloadAssets = (_downloadAssets && (id==null));
- core.buildInstances = (Factory.GetGlobals().SettingsManager.GetConfig().build_instance_jsons && (id==null));
- try {
- if(Factory.GetGlobals().SettingsManager.GetCoreSettings(core.identifier).skip) {
- await DeleteCore(core);
- continue;
- }
-
- if (core.requires_license && !_jtBeta) {
- continue; //skip if you don't have the key
- }
-
- string name = core.identifier;
- if(name == null) {
- _writeMessage("Core Name is required. Skipping.");
- continue;
- }
-
- _writeMessage("Checking Core: " + name);
- var mostRecentRelease = core.version;
-
- if(mostRecentRelease == null) {
- _writeMessage("No releases found. Skipping");
- await CopyBetaKey(core);
- results = await core.DownloadAssets();
- installedAssets.AddRange(results["installed"] as List);
- skippedAssets.AddRange(results["skipped"] as List);
- if((bool)results["missingBetaKey"]) {
- missingBetaKeys.Add(core.identifier);
- }
- await JotegoRename(core);
- Divide();
- continue;
- }
-
- _writeMessage(mostRecentRelease + " is the most recent release, checking local core...");
- if (core.isInstalled()) {
- Analogue.Cores.Core.Core localCore = core.getConfig();
- string localVersion = localCore.metadata.version;
-
- if(localVersion != null) {
- _writeMessage("local core found: " + localVersion);
- }
-
- if (mostRecentRelease != localVersion || clean){
- _writeMessage("Updating core");
- } else {
- await CopyBetaKey(core);
- results = await core.DownloadAssets();
- await JotegoRename(core);
- installedAssets.AddRange(results["installed"] as List);
- skippedAssets.AddRange(results["skipped"] as List);
- if((bool)results["missingBetaKey"]) {
- missingBetaKeys.Add(core.identifier);
- }
- _writeMessage("Up to date. Skipping core");
- Divide();
- continue;
- }
- } else {
- _writeMessage("Downloading core");
- }
-
- if(await core.Install(clean)) {
- Dictionary summary = new Dictionary();
- summary.Add("version", mostRecentRelease);
- summary.Add("core", core.identifier);
- summary.Add("platform", core.platform.name);
- installed.Add(summary);
- }
- await JotegoRename(core);
- await CopyBetaKey(core);
- results = await core.DownloadAssets();
- installedAssets.AddRange(results["installed"] as List);
- skippedAssets.AddRange(results["skipped"] as List);
- if((bool)results["missingBetaKey"]) {
- missingBetaKeys.Add(core.identifier);
- }
- _writeMessage("Installation complete.");
- Divide();
-
- } catch(Exception e) {
- _writeMessage("Uh oh something went wrong.");
- _writeMessage(e.Message);
- }
- }
-
- UpdateProcessCompleteEventArgs args = new UpdateProcessCompleteEventArgs();
- args.Message = "Update Process Complete";
- args.InstalledCores = installed;
- args.InstalledAssets = installedAssets;
- args.SkippedAssets = skippedAssets;
- args.MissingBetaKeys = missingBetaKeys;
- args.FirmwareUpdated = firmwareDownloaded;
- OnUpdateProcessComplete(args);
- }
-
- private async Task JotegoRename(Core core)
- {
- if(_renameJotegoCores && Factory.GetGlobals().SettingsManager.GetCoreSettings(core.identifier).platform_rename
- && core.identifier.Contains("jotego")) {
- core.platform_id = core.identifier.Split('.')[1]; //whatever
- string path = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Platforms", core.platform_id + ".json");
- string json = File.ReadAllText(path);
- Dictionary data = JsonSerializer.Deserialize>(json);
- Platform platform = data["platform"];
- if(_platformFiles.ContainsKey(core.platform_id) && platform.name == core.platform_id) {
- _writeMessage("Updating JT Platform Name...");
- await Factory.GetHttpHelper().DownloadFileAsync(_platformFiles[core.platform_id], path);
- _writeMessage("Complete");
- }
- }
- }
-
- private async Task CopyBetaKey(Core core)
- {
- if(core.JTBetaCheck()) {
- Analogue.Cores.Core.Core info = core.getConfig();
- string path = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Assets", info.metadata.platform_ids[core.betaSlotPlatformIdIndex], "common");
- if(!Directory.Exists(path)) {
- Directory.CreateDirectory(path);
- }
- string keyPath = Path.Combine(Factory.GetGlobals().UpdateDirectory, "betakeys");
- if(Directory.Exists(keyPath) && Directory.Exists(path)) {
- Util.CopyDirectory(keyPath, path, false, true);
- _writeMessage("Beta key copied to common directory.");
- }
- }
- }
-
- private async Task ExtractBetaKey()
- {
- string keyPath = Path.Combine(Factory.GetGlobals().UpdateDirectory, "betakeys");
- string file = Path.Combine(Factory.GetGlobals().UpdateDirectory, "jtbeta.zip");
- if(File.Exists(file)) {
- _jtBeta = true;
- _writeMessage("Extracting JT beta key...");
- ZipFile.ExtractToDirectory(file, keyPath, true);
- }
- }
-
- public async Task RunAssetDownloader(string? id = null)
- {
- List installedAssets = new List();
- List skippedAssets = new List();
- List missingBetaKeys = new List();
- Dictionary results = new Dictionary();
- if(Factory.GetGlobals().Cores == null) {
- throw new Exception("Must initialize updater before running update process");
- }
- List cores = await getAllCores();
- foreach(Core core in Factory.GetGlobals().Cores) {
- if(id != null && core.identifier != id) {
- continue;
- }
-
- if(Factory.GetGlobals().SettingsManager.GetCoreSettings(core.identifier).skip) {
- continue;
- }
-
- core.downloadAssets = true;
- try {
- string name = core.identifier;
- if(name == null) {
- _writeMessage("Core Name is required. Skipping.");
- continue;
- }
- _writeMessage(core.identifier);
- results = await core.DownloadAssets();
- installedAssets.AddRange(results["installed"] as List);
- skippedAssets.AddRange(results["skipped"] as List);
- if((bool)results["missingBetaKey"]) {
- missingBetaKeys.Add(core.identifier);
- }
- Divide();
- } catch(Exception e) {
- _writeMessage("Uh oh something went wrong.");
- _writeMessage(e.Message);
- }
- }
-
- UpdateProcessCompleteEventArgs args = new UpdateProcessCompleteEventArgs();
- args.Message = "All Done";
- args.InstalledAssets = installedAssets;
- args.SkippedAssets = skippedAssets;
- args.MissingBetaKeys = missingBetaKeys;
- OnUpdateProcessComplete(args);
- }
-
- public async Task ForceDisplayModes(string? id = null)
- {
- if(Factory.GetGlobals().Cores == null) {
- throw new Exception("Must initialize updater before running update process");
- }
- List cores = await getAllCores();
- foreach(Core core in Factory.GetGlobals().Cores) {
- if(id != null && core.identifier != id) {
- continue;
- }
-
- if(Factory.GetGlobals().SettingsManager.GetCoreSettings(core.identifier).skip) {
- continue;
- }
-
- core.downloadAssets = true;
- try {
- string name = core.identifier;
- if(name == null) {
- _writeMessage("Core Name is required. Skipping.");
- continue;
- }
- _writeMessage("Updating " + core.identifier);
- await core.AddDisplayModes();
- Divide();
- } catch(Exception e) {
- _writeMessage("Uh oh something went wrong.");
- _writeMessage(e.Message);
- }
- }
- _writeMessage("Finished.");
- }
-
- private void Divide()
- {
- _writeMessage("-------------");
- }
-
- public async Task> GetLocalCores()
- {
- string coresDirectory = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores");
- string[] directories = Directory.GetDirectories(coresDirectory,"*", SearchOption.TopDirectoryOnly);
- List all = new List();
- foreach(string name in directories) {
- string n = Path.GetFileName(name);
- var matches = Factory.GetGlobals().Cores.Where(i=>i.identifier == n);
- if(matches.Count() == 0) {
- Core c = new Core {
- identifier = n
- };
- c.platform = c.ReadPlatformFile();
- all.Add(c);
- }
- }
-
- return all;
- }
-
- public void SetGithubApiKey(string key)
- {
- _githubApiKey = key;
- }
-
- protected virtual void OnUpdateProcessComplete(UpdateProcessCompleteEventArgs e)
- {
- EventHandler handler = UpdateProcessComplete;
- if(handler != null)
- {
- handler(this, e);
- }
- RefreshInstalledCores();
- }
-
- public async Task UpdateFirmware()
- {
- string version = "";
- _writeMessage("Checking for firmware updates...");
- var details = await AnalogueFirmware.GetDetails();
-
- string[] parts = details.download_url.Split("/");
- string filename = parts[parts.Length-1];
- string filepath = Path.Combine(Factory.GetGlobals().UpdateDirectory, filename);
- if(!File.Exists(filepath) || !Util.CompareChecksum(filepath, details.md5, Util.HashTypes.MD5)) {
- version = filename;
- var oldfiles = Directory.GetFiles(Factory.GetGlobals().UpdateDirectory, FIRMWARE_FILENAME_PATTERN);
- _writeMessage("Firmware update found. Downloading...");
- await Factory.GetHttpHelper().DownloadFileAsync(details.download_url, Path.Combine(Factory.GetGlobals().UpdateDirectory, filename));
- _writeMessage("Download Complete");
- _writeMessage(Path.Combine(Factory.GetGlobals().UpdateDirectory, filename));
- foreach (string oldfile in oldfiles) {
- if (File.Exists(oldfile) && Path.GetFileName(oldfile) != filename) {
- _writeMessage("Deleting old firmware file...");
- File.Delete(oldfile);
- }
- }
- _writeMessage("To install firmware, restart your Pocket.");
- } else {
- _writeMessage("Firmware up to date.");
- }
- Divide();
- return version;
- }
-
- public void DeleteSkippedCores(bool value)
- {
- _deleteSkippedCores = value;
- }
-
- public async Task DeleteCore(Core core, bool force = false, bool nuke = false)
- {
- if(!_deleteSkippedCores || !force) {
- return;
- }
-
- core.Uninstall(nuke);
- }
-
- private void updater_StatusUpdated(object sender, StatusUpdatedEventArgs e)
- {
- this.OnStatusUpdated(e);
- }
- public event EventHandler? UpdateProcessComplete;
-
- public void SetDownloadProgressHandler(EventHandler handler)
- {
- Factory.GetHttpHelper().DownloadProgressUpdate += handler;
- }
-}
-
-public class UpdateProcessCompleteEventArgs : EventArgs
-{
- ///
- /// Some kind of results
- ///
- public string Message { get; set; }
- public List> InstalledCores { get; set; }
- public List InstalledAssets { get; set; }
- public List SkippedAssets { get; set; }
- public string FirmwareUpdated { get; set; } = "";
- public List MissingBetaKeys { get; set; }
-}
diff --git a/src/exceptions/MissingRequiredInstanceFiles.cs b/src/exceptions/MissingRequiredInstanceFiles.cs
index 8ed62583..fd4dcb60 100644
--- a/src/exceptions/MissingRequiredInstanceFiles.cs
+++ b/src/exceptions/MissingRequiredInstanceFiles.cs
@@ -1,20 +1,12 @@
-namespace pannella.analoguepocket;
-
-using System;
+namespace Pannella;
public class MissingRequiredInstanceFiles : Exception
{
- public MissingRequiredInstanceFiles()
- {
- }
+ public MissingRequiredInstanceFiles() { }
public MissingRequiredInstanceFiles(string message)
- : base(message)
- {
- }
+ : base(message) { }
public MissingRequiredInstanceFiles(string message, Exception inner)
- : base(message, inner)
- {
- }
-}
\ No newline at end of file
+ : base(message, inner) { }
+}
diff --git a/src/helpers/GlobalHelper.cs b/src/helpers/GlobalHelper.cs
index 516ab7c2..a2e18370 100644
--- a/src/helpers/GlobalHelper.cs
+++ b/src/helpers/GlobalHelper.cs
@@ -1,42 +1,63 @@
-using System.IO;
-using System.Net.Http;
+using Pannella.Models;
+using Pannella.Models.Archive;
+using Pannella.Services;
-namespace pannella.analoguepocket;
+namespace Pannella.Helpers;
-public class GlobalHelper
+public static class GlobalHelper
{
- private static GlobalHelper instance = null;
- private static object syncLock = new object();
- public archiveorg.Archive ArchiveFiles { get; set; }
- public SettingsManager? SettingsManager { get; set ;}
- public string UpdateDirectory { get; set; }
- public string SettingsPath { get; set; }
- public string[] Blacklist { get; set; }
- public List? Cores { get; set; }
- public List? InstalledCores { get; set; }
-
- private GlobalHelper()
- {
-
- }
+ public static Archive ArchiveFiles { get; private set; }
+ public static SettingsManager SettingsManager { get; private set ;}
+ public static string UpdateDirectory { get; private set; }
+ public static string[] Blacklist { get; private set; }
+ public static List Cores { get; private set; }
+ public static List InstalledCores { get; private set; }
- public static GlobalHelper Instance
+ private static bool isInitialized;
+
+ public static async void Initialize(string path)
{
- get
+ if (!isInitialized)
{
- lock (syncLock)
+ isInitialized = true;
+ UpdateDirectory = path;
+ SettingsManager = new SettingsManager(path);
+ Cores = await CoresService.GetCores();
+ SettingsManager.InitializeCoreSettings(Cores);
+ RefreshInstalledCores();
+ Blacklist = await AssetsService.GetBlacklist();
+
+ Console.WriteLine("Loading Assets Index...");
+
+ if (SettingsManager.GetConfig().use_custom_archive)
{
- if (GlobalHelper.instance == null) {
- GlobalHelper.instance = new GlobalHelper();
- }
+ var custom = SettingsManager.GetConfig().custom_archive;
+ Uri baseUrl = new Uri(custom["url"]);
+ Uri url = new Uri(baseUrl, custom["index"]);
- return GlobalHelper.instance;
+ ArchiveFiles = await ArchiveService.GetFilesCustom(url.ToString());
+ }
+ else
+ {
+ ArchiveFiles = await ArchiveService.GetFiles(SettingsManager.GetConfig().archive_name);
}
+
+ RefreshInstalledCores();
}
- }
+ }
+
+ public static void ReloadSettings()
+ {
+ SettingsManager = new SettingsManager(UpdateDirectory, Cores);
+ }
+
+ public static void RefreshInstalledCores()
+ {
+ InstalledCores = Cores.Where(c => c.IsInstalled()).ToList();
+ }
- public Core? GetCore(string identifier)
+ public static Core GetCore(string identifier)
{
- return instance.Cores.Find(i => i.identifier == identifier);
+ return Cores.Find(i => i.identifier == identifier);
}
}
diff --git a/src/helpers/Hacks.cs b/src/helpers/Hacks.cs
deleted file mode 100644
index 746df410..00000000
--- a/src/helpers/Hacks.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.IO;
-
-namespace pannella.analoguepocket;
-
-public class Hacks
-{
- private static string gamegearCore = @"{
- ""core"": {
- ""magic"": ""APF_VER_1"",
- ""metadata"": {
- ""platform_ids"": [
- ""gg""
- ],
- ""shortname"": ""GG"",
- ""description"": ""GG Core"",
- ""author"": ""Spiritualized"",
- ""url"": """",
- ""version"": ""1.3.0"",
- ""date_release"": ""2022-08-25""
- },
- ""framework"": {
- ""target_product"": ""Analogue Pocket"",
- ""version_required"": ""1.1"",
- ""sleep_supported"": true,
- ""dock"": {
- ""supported"": true,
- ""analog_output"": false
- },
- ""hardware"": {
- ""link_port"": false,
- ""cartridge_adapter"": -1
- }
- },
- ""cores"": [
- {
- ""name"": ""default"",
- ""id"": 0,
- ""filename"": ""gg.rev""
- }
- ]
- }
-}";
-
- public static void GamegearFix(string path)
- {
- string corefile = Path.Combine(path, "Cores", "Spiritualized.GG", "core.json");
- File.WriteAllText(corefile, gamegearCore, System.Text.Encoding.Default);
- }
-
-}
diff --git a/src/helpers/HttpHelper.cs b/src/helpers/HttpHelper.cs
index f862f62b..4f6068b3 100644
--- a/src/helpers/HttpHelper.cs
+++ b/src/helpers/HttpHelper.cs
@@ -1,18 +1,16 @@
-using System.IO;
-using System.Net.Http;
-
-namespace pannella.analoguepocket;
+namespace Pannella.Helpers;
public class HttpHelper
{
- private static HttpHelper instance = null;
- private static object syncLock = new object();
- private HttpClient client = null;
+ private static HttpHelper instance;
+ private static readonly object syncLock = new();
+ private HttpClient client;
+
public event EventHandler DownloadProgressUpdate;
private HttpHelper()
{
- createClient();
+ this.CreateClient();
}
public static HttpHelper Instance
@@ -21,30 +19,33 @@ public static HttpHelper Instance
{
lock (syncLock)
{
- if (HttpHelper.instance == null) {
- HttpHelper.instance = new HttpHelper();
- }
-
- return HttpHelper.instance;
+ return instance ??= new HttpHelper();
}
}
}
-
- public async Task DownloadFileAsync(string uri, string outputPath, int timeout = 100)
- {
+ public async Task DownloadFileAsync(string uri, string outputPath, int timeout = 100)
+ {
bool console = false;
- try {
+
+ try
+ {
var test = Console.WindowWidth;
+
console = true;
- } catch (Exception) { }
+ }
+ catch (Exception)
+ {
+ // Do Nothing.
+ }
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(timeout));
- Uri? uriResult;
- if (!Uri.TryCreate(uri, UriKind.Absolute, out uriResult))
+ if (!Uri.TryCreate(uri, UriKind.Absolute, out _))
+ {
throw new InvalidOperationException("URI is invalid.");
+ }
using HttpResponseMessage r = await this.client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cts.Token);
@@ -59,23 +60,31 @@ public async Task DownloadFileAsync(string uri, string outputPath, int timeout =
while (isMoreToRead)
{
var read = await stream.ReadAsync(buffer, 0, buffer.Length);
+
if (read == 0)
{
isMoreToRead = false;
- if (console) {
+
+ if (console)
+ {
Console.Write("\r");
}
}
else
{
readSoFar += read;
+
var progress = (double)readSoFar / totalSize;
- if (console) {
+
+ if (console)
+ {
var progressWidth = Console.WindowWidth - 14;
var progressBarWidth = (int)(progress * progressWidth);
var progressBar = new string('=', progressBarWidth);
var emptyProgressBar = new string(' ', progressWidth - progressBarWidth);
+
Console.Write($"\r{progressBar}{emptyProgressBar}] {(progress * 100):0.00}%");
+
if (readSoFar == totalSize)
{
Console.CursorLeft = 0;
@@ -83,52 +92,57 @@ public async Task DownloadFileAsync(string uri, string outputPath, int timeout =
Console.CursorLeft = 0;
}
}
- DownloadProgressEventArgs args = new DownloadProgressEventArgs();
- args.progress = progress;
+
+ DownloadProgressEventArgs args = new()
+ {
+ Progress = progress
+ };
+
OnDownloadProgressUpdate(args);
+
await fileStream.WriteAsync(buffer, 0, read);
}
}
}
- public async Task GetHTML(string uri, bool allowRedirect = true)
- {
- Uri? uriResult;
-
- if (!Uri.TryCreate(uri, UriKind.Absolute, out uriResult))
+ public async Task GetHTML(string uri, bool allowRedirect = true)
+ {
+ if (!Uri.TryCreate(uri, UriKind.Absolute, out _))
+ {
throw new InvalidOperationException("URI is invalid.");
+ }
- if(!allowRedirect) {
- createClient(false);
+ if (!allowRedirect)
+ {
+ this.CreateClient(false);
}
var response = await this.client.GetAsync(uri);
string html = await response.Content.ReadAsStringAsync();
- if(!allowRedirect) {
- createClient();
+ if (!allowRedirect)
+ {
+ this.CreateClient();
}
-
+
return html;
- }
+ }
- private void createClient(bool allowRedirect = true)
- {
- this.client = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = allowRedirect });
- this.client.Timeout = TimeSpan.FromMinutes(10); //10min
- }
+ private void CreateClient(bool allowRedirect = true)
+ {
+ this.client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = allowRedirect });
+ this.client.Timeout = TimeSpan.FromMinutes(10); // 10min
+ }
- protected virtual void OnDownloadProgressUpdate(DownloadProgressEventArgs e)
+ private void OnDownloadProgressUpdate(DownloadProgressEventArgs e)
{
EventHandler handler = DownloadProgressUpdate;
- if(handler != null)
- {
- handler(this, e);
- }
+
+ handler?.Invoke(this, e);
}
}
public class DownloadProgressEventArgs : EventArgs
{
- public double progress = 0;
+ public double Progress;
}
diff --git a/src/helpers/SemverUtil.cs b/src/helpers/SemverUtil.cs
index abb8481a..13c7adbe 100644
--- a/src/helpers/SemverUtil.cs
+++ b/src/helpers/SemverUtil.cs
@@ -1,36 +1,41 @@
-namespace pannella.analoguepocket;
-
using System.Text.RegularExpressions;
+namespace Pannella.Helpers;
+
public class SemverUtil
{
private const string SEMVER_FINDER = @"\D*(\d+(\.\d+)*\.\d+)\D*";
- public static string? FindSemver(string input)
+ public static string FindSemver(string input)
{
Regex r = new Regex(SEMVER_FINDER);
Match matches = r.Match(input);
- if(matches == null || matches.Groups.Count <= 1) {
+
+ if (matches.Groups.Count <= 1)
+ {
return null;
}
+
var semver = matches.Groups[1].Value;
- //TODO throw some error if it doesn't find a semver in the tag
+
+ // TODO: throw some error if it doesn't find a semver in the tag
+
semver = CompleteSemver(semver);
return semver;
}
- ///
- /////even though its technically not a valid semver, allow use of 2 part versions, and just add a .0 to complete the 3rd part
- ///
- public static string CompleteSemver(string version)
+ // Even though its technically not a valid semver, allow use of 2 part versions,
+ // and just add a .0 to complete the 3rd part
+ private static string CompleteSemver(string version)
{
string[] parts = version.Split(".");
- if(parts.Length == 2) {
+ if (parts.Length == 2)
+ {
version += ".0";
}
-
+
return version;
}
@@ -38,22 +43,18 @@ public static bool SemverCompare(string semverA, string semverB)
{
Version verA = Version.Parse(semverA);
Version verB = Version.Parse(semverB);
-
- switch(verA.CompareTo(verB))
+
+ switch (verA.CompareTo(verB))
{
case 0:
case -1:
return false;
+
case 1:
return true;
+
default:
return true;
}
}
-
- public static bool IsActuallySemver(string potentiallySemver)
- {
- Version? ver = null;
- return Version.TryParse(potentiallySemver, out ver);
- }
-}
\ No newline at end of file
+}
diff --git a/src/helpers/StringConverter.cs b/src/helpers/StringConverter.cs
index 63aef1a9..df5bc635 100644
--- a/src/helpers/StringConverter.cs
+++ b/src/helpers/StringConverter.cs
@@ -1,25 +1,22 @@
-namespace pannella;
using System.Text.Json;
+using System.Text.Json.Serialization;
-public class StringConverter : System.Text.Json.Serialization.JsonConverter
+namespace Pannella.Helpers;
+
+public class StringConverter : JsonConverter
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- if (reader.TokenType == JsonTokenType.Number)
- {
- var stringValue = reader.GetInt32();
- return stringValue.ToString();
- }
- else if (reader.TokenType == JsonTokenType.String)
+ return reader.TokenType switch
{
- return reader.GetString();
- }
-
- throw new System.Text.Json.JsonException();
+ JsonTokenType.Number => reader.GetInt32().ToString(),
+ JsonTokenType.String => reader.GetString(),
+ _ => throw new JsonException()
+ };
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
-}
\ No newline at end of file
+}
diff --git a/src/helpers/Util.cs b/src/helpers/Util.cs
index f900cedc..c271effa 100644
--- a/src/helpers/Util.cs
+++ b/src/helpers/Util.cs
@@ -1,14 +1,16 @@
-using System.IO;
-using Force.Crc32;
using System.Security.Cryptography;
-namespace pannella.analoguepocket;
+using Force.Crc32;
+
+namespace Pannella.Helpers;
public class Util
{
- private static string _platformsDirectory = "Platforms";
- private static string _temp = "imagesbackup";
+ private const string PLATFORMS_DIRECTORY = "Platforms";
+
private static readonly string[] BAD_DIRS = { "__MACOSX" };
- public enum HashTypes {
+
+ public enum HashTypes
+ {
CRC32,
MD5
}
@@ -20,7 +22,9 @@ public static void CopyDirectory(string sourceDir, string destinationDir, bool r
// Check if the source directory exists
if (!dir.Exists)
+ {
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
+ }
// Cache directories before we start copying
DirectoryInfo[] dirs = dir.GetDirectories();
@@ -32,6 +36,7 @@ public static void CopyDirectory(string sourceDir, string destinationDir, bool r
foreach (FileInfo file in dir.GetFiles())
{
string targetFilePath = Path.Combine(destinationDir, file.Name);
+
file.CopyTo(targetFilePath, overwrite);
}
@@ -41,6 +46,7 @@ public static void CopyDirectory(string sourceDir, string destinationDir, bool r
foreach (DirectoryInfo subDir in dirs)
{
string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
+
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite);
}
}
@@ -49,82 +55,95 @@ public static void CopyDirectory(string sourceDir, string destinationDir, bool r
public static void CleanDir(string source, bool preservePlatformsFolder = false, string platform = "")
{
// Clean up any bad directories (like Mac OS directories).
- foreach(var dir in BAD_DIRS) {
- try {
+ foreach (var dir in BAD_DIRS)
+ {
+ try
+ {
Directory.Delete(Path.Combine(source, dir), true);
}
- catch { }
+ catch
+ {
+ // Ignore
+ }
}
- if(preservePlatformsFolder) {
- string existing = Path.Combine(Factory.GetGlobals().UpdateDirectory, _platformsDirectory, platform + ".json");
- if(File.Exists(existing)) {
- try {
- string dir = Path.Combine(source, _platformsDirectory);
+ if (preservePlatformsFolder)
+ {
+ string existing = Path.Combine(GlobalHelper.UpdateDirectory, PLATFORMS_DIRECTORY, platform + ".json");
+
+ if (File.Exists(existing))
+ {
+ try
+ {
+ string dir = Path.Combine(source, PLATFORMS_DIRECTORY);
+
Directory.Delete(dir, true);
}
- catch { }
+ catch
+ {
+ // Ignore
+ }
}
}
// Clean files.
- var files = Directory.EnumerateFiles(source).Where(file => isBadFile(Path.GetFileName(file)));
- foreach(var file in files) {
- try {
+ var files = Directory.EnumerateFiles(source).Where(file => IsBadFile(Path.GetFileName(file)));
+
+ foreach (var file in files)
+ {
+ try
+ {
File.Delete(file);
}
- catch { }
+ catch
+ {
+ // Ignore
+ }
}
// Recurse through subdirectories.
var dirs = Directory.GetDirectories(source);
- foreach(var dir in dirs) {
- CleanDir(Path.Combine(source, Path.GetFileName(dir)));
- }
- static bool isBadFile(string name)
+ foreach (var dir in dirs)
{
- if (name.StartsWith('.')) return true;
- if (name.EndsWith(".mra")) return true;
- if (name.EndsWith(".txt")) return true;
- return false;
+ CleanDir(Path.Combine(source, Path.GetFileName(dir)));
}
}
- public static string GetCRC32(string filepath)
+ private static bool IsBadFile(string name)
{
- if(File.Exists(filepath)) {
- var checksum = Crc32Algorithm.Compute(File.ReadAllBytes(filepath));
- return checksum.ToString("x8");
- } else {
- throw new Exception("File doesn't exist. Cannot compute checksum");
- }
+ return name.StartsWith('.') || name.EndsWith(".mra") || name.EndsWith(".txt");
}
- public static string GetMD5(string filepath)
+ public static bool CompareChecksum(string filepath, string checksum, HashTypes type = HashTypes.CRC32)
{
- if(File.Exists(filepath)) {
- var checksum = MD5.HashData(File.ReadAllBytes(filepath));
- return Convert.ToHexString(checksum);
- } else {
- throw new Exception("File doesn't exist. Cannot compute checksum");
+ if (!File.Exists(filepath))
+ {
+ throw new Exception("File doesn't exist. Cannot compute checksum.");
}
- }
- public static bool CompareChecksum(string filepath, string checksum, HashTypes type = HashTypes.CRC32)
- {
string hash;
- switch(type) {
+
+ switch (type)
+ {
case HashTypes.MD5:
- hash = GetMD5(filepath);
+ {
+ var newChecksum = MD5.HashData(File.ReadAllBytes(filepath));
+
+ hash = Convert.ToHexString(newChecksum);
break;
+ }
+
case HashTypes.CRC32:
default:
- hash = GetCRC32(filepath);
+ {
+ var newChecksum = Crc32Algorithm.Compute(File.ReadAllBytes(filepath));
+
+ hash = newChecksum.ToString("x8");
break;
+ }
}
-
+
return hash.Equals(checksum, StringComparison.CurrentCultureIgnoreCase);
}
-
}
diff --git a/src/models/Analogue/AnalogueData.cs b/src/models/Analogue/AnalogueData.cs
deleted file mode 100644
index 035fbfa7..00000000
--- a/src/models/Analogue/AnalogueData.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-public class Data
-{
- public DataSlot[] data_slots { get; set; }
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueDataJSON.cs b/src/models/Analogue/AnalogueDataJSON.cs
deleted file mode 100644
index a4c27df4..00000000
--- a/src/models/Analogue/AnalogueDataJSON.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-public class DataJSON
-{
- public Data? data { get; set; }
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueDataSlot.cs b/src/models/Analogue/AnalogueDataSlot.cs
deleted file mode 100644
index 776a0fc6..00000000
--- a/src/models/Analogue/AnalogueDataSlot.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-using System.Collections;
-
-public class DataSlot
-{
- public string id { get; set; }
- public string name { get; set; }
- public bool required { get; set; }
- public string parameters { get; set; }
-
- public string? filename { get; set; }
-
- public string[]? alternate_filenames{ get; set; }
-
- public string? md5 { get; set; }
-
- private BitArray? getBits()
- {
- if(parameters == null) {
- return null;
- }
- int p = 0;
- if(parameters.StartsWith("0x")) {
- p = Convert.ToInt32(parameters, 16);
- } else {
- p = Int32.Parse(parameters);
- }
-
- byte[] bytes = System.BitConverter.GetBytes(p);
- BitArray bits = new BitArray(bytes);
-
- return bits;
- }
-
- public bool isCoreSpecific()
- {
- var bits = getBits();
-
- if(bits == null) {
- return false;
- }
-
- return bits[1];
- }
-
- public int getPlatformIdIndex()
- {
- var bits = getBits();
-
- if(bits == null) {
- return 0;
- }
-
- var temp = new BitArray(2);
- temp[1] = bits[25];
- temp[0] = bits[24];
-
- int[] index = new int[1];
- temp.CopyTo(index, 0);
-
- return index[0];
- }
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueInstance.cs b/src/models/Analogue/AnalogueInstance.cs
deleted file mode 100644
index c2d153d9..00000000
--- a/src/models/Analogue/AnalogueInstance.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-public class Instance
-{
- public DataSlot[] data_slots { get; set; }
- public string data_path { get; set; } = "";
- public string magic { get; set; } = "APF_VER_1";
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueInstanceDataSlot.cs b/src/models/Analogue/AnalogueInstanceDataSlot.cs
deleted file mode 100644
index bfe67615..00000000
--- a/src/models/Analogue/AnalogueInstanceDataSlot.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-using System.Collections;
-
-public class InstanceDataSlot
-{
- public string id { get; set; }
- public string? filename { get; set; }
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueMetadata.cs b/src/models/Analogue/AnalogueMetadata.cs
deleted file mode 100644
index c23380a2..00000000
--- a/src/models/Analogue/AnalogueMetadata.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-public class Metadata
-{
- public string[]? platform_ids { get; set; }
- public string? shortname { get; set; }
- public string? description { get; set; }
- public string? author { get; set; }
- public string? url { get; set; }
- public string? version { get; set; }
- public string? date_release { get; set; }
-}
\ No newline at end of file
diff --git a/src/models/Analogue/AnalogueSimpleInstance.cs b/src/models/Analogue/AnalogueSimpleInstance.cs
deleted file mode 100644
index db2184e8..00000000
--- a/src/models/Analogue/AnalogueSimpleInstance.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace pannella.analoguepocket.Analogue;
-
-public class SimpleInstance
-{
- public InstanceDataSlot[] data_slots { get; set; }
- public string data_path { get; set; } = "";
- public string magic { get; set; } = "APF_VER_1";
-}
\ No newline at end of file
diff --git a/src/models/Analogue/Core/AnalogueCore.cs b/src/models/Analogue/Core/AnalogueCore.cs
new file mode 100644
index 00000000..5710b4b3
--- /dev/null
+++ b/src/models/Analogue/Core/AnalogueCore.cs
@@ -0,0 +1,10 @@
+namespace Pannella.Models.Analogue.Core;
+
+public class Core
+{
+ public Metadata metadata { get; set; }
+
+ public string magic { get; set; }
+
+ public Framework framework { get; set; }
+}
diff --git a/src/models/Analogue/AnalogueFramework.cs b/src/models/Analogue/Core/AnalogueFramework.cs
similarity index 78%
rename from src/models/Analogue/AnalogueFramework.cs
rename to src/models/Analogue/Core/AnalogueFramework.cs
index 8a2637cf..8a28eef5 100644
--- a/src/models/Analogue/AnalogueFramework.cs
+++ b/src/models/Analogue/Core/AnalogueFramework.cs
@@ -1,8 +1,8 @@
-namespace pannella.analoguepocket.Analogue;
+namespace Pannella.Models.Analogue.Core;
public class Framework
{
public string target_product { get; set; }
public string version_required { get; set; }
public bool sleep_supported { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Analogue/Core/AnalogueMetadata.cs b/src/models/Analogue/Core/AnalogueMetadata.cs
new file mode 100644
index 00000000..635bb773
--- /dev/null
+++ b/src/models/Analogue/Core/AnalogueMetadata.cs
@@ -0,0 +1,12 @@
+namespace Pannella.Models.Analogue.Core;
+
+public class Metadata
+{
+ public string[] platform_ids { get; set; }
+ public string shortname { get; set; }
+ public string description { get; set; }
+ public string author { get; set; }
+ public string url { get; set; }
+ public string version { get; set; }
+ public string date_release { get; set; }
+}
diff --git a/src/models/Analogue/Cores/Core/AnalogueCore.cs b/src/models/Analogue/Cores/Core/AnalogueCore.cs
deleted file mode 100644
index 9e2b0578..00000000
--- a/src/models/Analogue/Cores/Core/AnalogueCore.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace pannella.analoguepocket.Analogue.Cores.Core;
-
-public class Core
-{
- public Metadata? metadata { get; set; }
- public string? magic { get; set; }
-
- public Framework? framework { get; set; }
-
-}
\ No newline at end of file
diff --git a/src/models/Analogue/Cores/Video/Video.cs b/src/models/Analogue/Cores/Video/Video.cs
deleted file mode 100644
index 12acd054..00000000
--- a/src/models/Analogue/Cores/Video/Video.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace pannella.analoguepocket.Analogue.Cores.Video;
-
-public class Video
-{
- public string? magic { get; set; }
-
- public List? scaler_modes { get; set; }
-
- public List? display_modes { get; set; }
-
-}
\ No newline at end of file
diff --git a/src/models/Analogue/Data/AnalogueData.cs b/src/models/Analogue/Data/AnalogueData.cs
new file mode 100644
index 00000000..814143ab
--- /dev/null
+++ b/src/models/Analogue/Data/AnalogueData.cs
@@ -0,0 +1,8 @@
+using Pannella.Models.Analogue.Shared;
+
+namespace Pannella.Models.Analogue.Data;
+
+public class Data
+{
+ public DataSlot[] data_slots { get; set; }
+}
diff --git a/src/models/Analogue/Data/AnalogueDataJSON.cs b/src/models/Analogue/Data/AnalogueDataJSON.cs
new file mode 100644
index 00000000..830bbf09
--- /dev/null
+++ b/src/models/Analogue/Data/AnalogueDataJSON.cs
@@ -0,0 +1,6 @@
+namespace Pannella.Models.Analogue.Data;
+
+public class DataJSON
+{
+ public Data data { get; set; }
+}
diff --git a/src/models/Analogue/Instance/AnalogueInstance.cs b/src/models/Analogue/Instance/AnalogueInstance.cs
new file mode 100644
index 00000000..2c981b1b
--- /dev/null
+++ b/src/models/Analogue/Instance/AnalogueInstance.cs
@@ -0,0 +1,10 @@
+using Pannella.Models.Analogue.Shared;
+
+namespace Pannella.Models.Analogue.Instance;
+
+public class Instance
+{
+ public DataSlot[] data_slots { get; set; }
+ public string data_path { get; set; } = string.Empty;
+ public string magic { get; set; } = "APF_VER_1";
+}
diff --git a/src/models/Analogue/AnalogueInstanceJSON.cs b/src/models/Analogue/Instance/AnalogueInstanceJSON.cs
similarity index 60%
rename from src/models/Analogue/AnalogueInstanceJSON.cs
rename to src/models/Analogue/Instance/AnalogueInstanceJSON.cs
index 97df9e68..b8a43eb8 100644
--- a/src/models/Analogue/AnalogueInstanceJSON.cs
+++ b/src/models/Analogue/Instance/AnalogueInstanceJSON.cs
@@ -1,6 +1,6 @@
-namespace pannella.analoguepocket.Analogue;
+namespace Pannella.Models.Analogue.Instance;
public class InstanceJSON
{
public Instance instance { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Analogue/Instance/Simple/AnalogueSimpleInstance.cs b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstance.cs
new file mode 100644
index 00000000..ec00500c
--- /dev/null
+++ b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstance.cs
@@ -0,0 +1,8 @@
+namespace Pannella.Models.Analogue.Instance.Simple;
+
+public class SimpleInstance
+{
+ public SimpleDataSlot[] data_slots { get; set; }
+ public string data_path { get; set; } = string.Empty;
+ public string magic { get; set; } = "APF_VER_1";
+}
diff --git a/src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceDataSlot.cs b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceDataSlot.cs
new file mode 100644
index 00000000..953525e2
--- /dev/null
+++ b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceDataSlot.cs
@@ -0,0 +1,7 @@
+namespace Pannella.Models.Analogue.Instance.Simple;
+
+public class SimpleDataSlot
+{
+ public string id { get; set; }
+ public string filename { get; set; }
+}
diff --git a/src/models/Analogue/AnalogueSimpleInstanceJSON.cs b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceJSON.cs
similarity index 60%
rename from src/models/Analogue/AnalogueSimpleInstanceJSON.cs
rename to src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceJSON.cs
index be49cfb6..7c1b7326 100644
--- a/src/models/Analogue/AnalogueSimpleInstanceJSON.cs
+++ b/src/models/Analogue/Instance/Simple/AnalogueSimpleInstanceJSON.cs
@@ -1,6 +1,6 @@
-namespace pannella.analoguepocket.Analogue;
+namespace Pannella.Models.Analogue.Instance.Simple;
public class SimpleInstanceJSON
{
public SimpleInstance instance { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Analogue/Release.cs b/src/models/Analogue/Release.cs
index f8b433a6..f8040589 100644
--- a/src/models/Analogue/Release.cs
+++ b/src/models/Analogue/Release.cs
@@ -1,12 +1,12 @@
-namespace pannella.analoguepocket.Analogue;
+namespace Pannella.Models.Analogue;
public class ReleaseDetails
{
- public string? url { get; set; }
- public string? version { get; set; }
- public string? published_at { get; set; }
- public string? download_url { get; set; }
- public string? md5 { get; set; }
- public string? file_size { get; set; }
- public string? release_notes_html { get; set; }
-}
\ No newline at end of file
+ public string url { get; set; }
+ public string version { get; set; }
+ public string published_at { get; set; }
+ public string download_url { get; set; }
+ public string md5 { get; set; }
+ public string file_size { get; set; }
+ public string release_notes_html { get; set; }
+}
diff --git a/src/models/Analogue/Shared/AnalogueDataSlot.cs b/src/models/Analogue/Shared/AnalogueDataSlot.cs
new file mode 100644
index 00000000..c80147df
--- /dev/null
+++ b/src/models/Analogue/Shared/AnalogueDataSlot.cs
@@ -0,0 +1,67 @@
+using System.Collections;
+
+namespace Pannella.Models.Analogue.Shared;
+
+public class DataSlot
+{
+ public string id { get; set; }
+ public string name { get; set; }
+ public bool required { get; set; }
+ public string parameters { get; set; }
+ public string filename { get; set; }
+ public string[] alternate_filenames { get; set; }
+ public string md5 { get; set; }
+
+ private BitArray GetBits()
+ {
+ if (parameters == null)
+ {
+ return null;
+ }
+
+ int p;
+
+ if (parameters.StartsWith("0x"))
+ {
+ p = Convert.ToInt32(parameters, 16);
+ }
+ else
+ {
+ p = int.Parse(parameters);
+ }
+
+ byte[] bytes = BitConverter.GetBytes(p);
+ BitArray bits = new BitArray(bytes);
+
+ return bits;
+ }
+
+ public bool IsCoreSpecific()
+ {
+ var bits = this.GetBits();
+
+ return bits != null && bits[1];
+ }
+
+ public int GetPlatformIdIndex()
+ {
+ var bits = this.GetBits();
+
+ if (bits == null)
+ {
+ return 0;
+ }
+
+ var temp = new BitArray(2)
+ {
+ [1] = bits[25],
+ [0] = bits[24]
+ };
+
+ int[] index = new int[1];
+
+ temp.CopyTo(index, 0);
+
+ return index[0];
+ }
+}
diff --git a/src/models/Analogue/Cores/Video/DisplayMode.cs b/src/models/Analogue/Video/AnalogueDisplayMode.cs
similarity index 50%
rename from src/models/Analogue/Cores/Video/DisplayMode.cs
rename to src/models/Analogue/Video/AnalogueDisplayMode.cs
index 2a87a29e..f76b0b91 100644
--- a/src/models/Analogue/Cores/Video/DisplayMode.cs
+++ b/src/models/Analogue/Video/AnalogueDisplayMode.cs
@@ -1,7 +1,6 @@
-namespace pannella.analoguepocket.Analogue.Cores.Video;
+namespace Pannella.Models.Analogue.Video;
public class DisplayMode
{
public string id { get; set; }
-
-}
\ No newline at end of file
+}
diff --git a/src/models/Analogue/Cores/Video/ScalerMode.cs b/src/models/Analogue/Video/AnalogueScalerMode.cs
similarity index 81%
rename from src/models/Analogue/Cores/Video/ScalerMode.cs
rename to src/models/Analogue/Video/AnalogueScalerMode.cs
index dc77ab22..b8468fdf 100644
--- a/src/models/Analogue/Cores/Video/ScalerMode.cs
+++ b/src/models/Analogue/Video/AnalogueScalerMode.cs
@@ -1,4 +1,4 @@
-namespace pannella.analoguepocket.Analogue.Cores.Video;
+namespace Pannella.Models.Analogue.Video;
public class ScalerMode
{
@@ -8,4 +8,4 @@ public class ScalerMode
public int aspect_h { get; set; }
public int rotation { get; set; }
public int mirror { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Analogue/Video/AnalogueVideo.cs b/src/models/Analogue/Video/AnalogueVideo.cs
new file mode 100644
index 00000000..2d4483fd
--- /dev/null
+++ b/src/models/Analogue/Video/AnalogueVideo.cs
@@ -0,0 +1,10 @@
+namespace Pannella.Models.Analogue.Video;
+
+public class Video
+{
+ public string magic { get; set; }
+
+ public List scaler_modes { get; set; }
+
+ public List display_modes { get; set; }
+}
diff --git a/src/models/Archive/Archive.cs b/src/models/Archive/Archive.cs
index 51eac6f3..ad3a1673 100644
--- a/src/models/Archive/Archive.cs
+++ b/src/models/Archive/Archive.cs
@@ -1,16 +1,15 @@
-namespace archiveorg;
-
-using System.Linq;
+namespace Pannella.Models.Archive;
public class Archive
{
public int files_count { get; set; }
public int item_last_updated { get; set; }
- public archiveorg.File[] files { get; set; }
+ public File[] files { get; set; }
- public archiveorg.File? GetFile(string filename)
+ public File GetFile(string filename)
{
- archiveorg.File? file = files.Where(file => file.name == filename).FirstOrDefault() as archiveorg.File;
+ File file = this.files.FirstOrDefault(file => file.name == filename);
+
return file;
}
-}
\ No newline at end of file
+}
diff --git a/src/models/Archive/File.cs b/src/models/Archive/File.cs
index c98992d5..0346d945 100644
--- a/src/models/Archive/File.cs
+++ b/src/models/Archive/File.cs
@@ -1,9 +1,9 @@
-namespace archiveorg;
+namespace Pannella.Models.Archive;
public class File
{
- public string? name { get; set; }
- public string? md5 { get; set; }
+ public string name { get; set; }
+ public string md5 { get; set; }
public string crc32 { get; set; }
- public string? source { get; set; }
-}
\ No newline at end of file
+ public string source { get; set; }
+}
diff --git a/src/models/Asset.cs b/src/models/Asset.cs
deleted file mode 100644
index 249e264d..00000000
--- a/src/models/Asset.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace pannella.analoguepocket;
-
-public class Asset
-{
- public string platform{ get; set; } = "";
- public string? filename { get; set; }
- public bool core_specific { get; set; }
- public List? extensions { get; set; }
-}
\ No newline at end of file
diff --git a/src/Base.cs b/src/models/Base.cs
similarity index 58%
rename from src/Base.cs
rename to src/models/Base.cs
index e033dc13..ed9e9426 100644
--- a/src/Base.cs
+++ b/src/models/Base.cs
@@ -1,28 +1,31 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models;
public class Base
{
protected const string ARCHIVE_BASE_URL = "https://archive.org/download";
- public event EventHandler? StatusUpdated;
+
+ public event EventHandler StatusUpdated;
+
protected void Divide()
{
- _writeMessage("-------------");
+ WriteMessage("-------------");
}
- protected void _writeMessage(string message)
+ protected void WriteMessage(string message)
{
- StatusUpdatedEventArgs args = new StatusUpdatedEventArgs();
- args.Message = message;
+ StatusUpdatedEventArgs args = new StatusUpdatedEventArgs
+ {
+ Message = message
+ };
+
OnStatusUpdated(args);
}
- protected virtual void OnStatusUpdated(StatusUpdatedEventArgs e)
+ protected void OnStatusUpdated(StatusUpdatedEventArgs e)
{
EventHandler handler = StatusUpdated;
- if(handler != null)
- {
- handler(this, e);
- }
+
+ handler?.Invoke(this, e);
}
}
diff --git a/src/models/Core.cs b/src/models/Core.cs
index cfb52e11..3554662d 100644
--- a/src/models/Core.cs
+++ b/src/models/Core.cs
@@ -1,121 +1,149 @@
-namespace pannella.analoguepocket;
-
-using System.IO;
+using System.Collections;
+using System.Diagnostics.CodeAnalysis;
using System.IO.Compression;
-using System.Net.Http;
+using System.Net;
using System.Text.Json;
-using System.Collections;
-
+using Pannella.Helpers;
+using Pannella.Models.Analogue.Data;
+using Pannella.Models.Analogue.Instance;
+using Pannella.Models.Analogue.Instance.Simple;
+using Pannella.Models.Analogue.Video;
+using Pannella.Models.InstancePackager;
+using Pannella.Models.Updater;
+using AnalogueCore = Pannella.Models.Analogue.Core.Core;
+using ArchiveFile = Pannella.Models.Archive.File;
+using DataSlot = Pannella.Models.Analogue.Shared.DataSlot;
+using InstancePackagerDataSlot = Pannella.Models.InstancePackager.DataSlot;
+
+namespace Pannella.Models;
+
+[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")]
public class Core : Base
{
public string identifier { get; set; }
- public Repo? repository { get; set; }
- public Platform? platform { get; set; }
+ public Repo repository { get; set; }
+ public Platform platform { get; set; }
public string platform_id { get; set; }
- public Sponsor? sponsor { get; set; }
- public string? download_url { get; set; }
- public string? release_date { get; set; }
- public string? version { get; set; }
- public string? betaSlotId = null;
- public int betaSlotPlatformIdIndex = 0;
-
+ public Sponsor sponsor { get; set; }
+ public string download_url { get; set; }
+ public string release_date { get; set; }
+ public string version { get; set; }
+ public string beta_slot_id;
+ public int beta_slot_platform_id_index;
public bool requires_license { get; set; } = false;
- private const string ZIP_FILE_NAME = "core.zip";
- public bool downloadAssets { get; set; } = Factory.GetGlobals().SettingsManager.GetConfig().download_assets;
- public bool buildInstances { get; set; } = Factory.GetGlobals().SettingsManager.GetConfig().build_instance_jsons;
+ public bool download_assets { get; set; } = GlobalHelper.SettingsManager.GetConfig().download_assets;
+
+ public bool build_instances { get; set; } = GlobalHelper.SettingsManager.GetConfig().build_instance_jsons;
- private string[] allModes = {
- "0x10", "0x20", "0x30", "0x31", "0x32", "0x40", "0x41", "0x42", "0x51", "0x52", "0xE0"
- };
+ private const string ZIP_FILE_NAME = "core.zip";
- private string[] gbModes = {
- "0x21", "0x22", "0x23"
- };
+ private static string[] ALL_MODES = { "0x10", "0x20", "0x30", "0x31", "0x32", "0x40", "0x41", "0x42", "0x51", "0x52", "0xE0" };
+ private static string[] GB_MODES = { "0x21", "0x22", "0x23" };
public override string ToString()
{
return platform.name;
}
- public async Task Install(bool clean = false)
+ public async Task Install(bool preservePlatformsFolder, bool clean = false)
{
- if(this.repository == null) {
- _writeMessage("Core installed manually. Skipping.");
+ if (this.repository == null)
+ {
+ WriteMessage("Core installed manually. Skipping.");
+
return false;
}
- if (clean && this.isInstalled()) {
+
+ if (clean && this.IsInstalled())
+ {
Delete();
}
- //iterate through assets to find the zip release
- if(await _installGithubAsset()) {
- await this.ReplaceCheck();
+
+ // iterate through assets to find the zip release
+ if (await InstallGithubAsset(preservePlatformsFolder))
+ {
+ this.ReplaceCheck();
+
return true;
- } else {
- return false;
}
+
+ return false;
}
- private async Task _installGithubAsset()
+ private async Task InstallGithubAsset(bool preservePlatformsFolder)
{
- bool updated = false;
- if (this.download_url == null) {
- _writeMessage("No release URL found...");
- return updated;
+ if (this.download_url == null)
+ {
+ WriteMessage("No release URL found...");
+
+ return false;
}
- _writeMessage("Downloading file " + this.download_url + "...");
- string zipPath = Path.Combine(Factory.GetGlobals().UpdateDirectory, ZIP_FILE_NAME);
- string extractPath = Factory.GetGlobals().UpdateDirectory;
- await Factory.GetHttpHelper().DownloadFileAsync(this.download_url, zipPath);
- _writeMessage("Extracting...");
+ WriteMessage("Downloading file " + this.download_url + "...");
+
+ string zipPath = Path.Combine(GlobalHelper.UpdateDirectory, ZIP_FILE_NAME);
+ string extractPath = GlobalHelper.UpdateDirectory;
+
+ await HttpHelper.Instance.DownloadFileAsync(this.download_url, zipPath);
+
+ WriteMessage("Extracting...");
+
string tempDir = Path.Combine(extractPath, "temp", this.identifier);
+
ZipFile.ExtractToDirectory(zipPath, tempDir, true);
// Clean problematic directories and files.
- Util.CleanDir(tempDir, Factory.GetGlobals().SettingsManager.GetConfig().preserve_platforms_folder, this.platform_id);
+ Util.CleanDir(tempDir, preservePlatformsFolder, this.platform_id);
// Move the files into place and delete our core's temp directory.
- _writeMessage("Installing...");
+ WriteMessage("Installing...");
Util.CopyDirectory(tempDir, extractPath, true, true);
Directory.Delete(tempDir, true);
// See if the temp directory itself can be removed.
- // Probably not needed if we aren't going to multithread this, but this is an async function so let's future proof.
+ // Probably not needed if we aren't going to multi-thread this, but this is an async function so let's future proof.
if (!Directory.GetFiles(Path.Combine(extractPath, "temp")).Any())
+ {
Directory.Delete(Path.Combine(extractPath, "temp"));
+ }
- updated = true;
-
File.Delete(zipPath);
- return updated;
+ return true;
}
- private bool checkUpdateDirectory()
+ private static void CheckUpdateDirectory()
{
- if(!Directory.Exists(Factory.GetGlobals().UpdateDirectory)) {
+ if (!Directory.Exists(GlobalHelper.UpdateDirectory))
+ {
throw new Exception("Unable to access update directory");
}
-
- return true;
}
- public void Delete(bool nuke = false)
+ private void Delete(bool nuke = false)
{
- List folders = new List{"Cores", "Presets", "Settings"};
- foreach(string folder in folders) {
- string path = Path.Combine(Factory.GetGlobals().UpdateDirectory, folder, this.identifier);
- if(Directory.Exists(path)) {
- _writeMessage("Deleting " + path);
+ List folders = new List { "Cores", "Presets", "Settings" };
+
+ foreach (string folder in folders)
+ {
+ string path = Path.Combine(GlobalHelper.UpdateDirectory, folder, this.identifier);
+
+ if (Directory.Exists(path))
+ {
+ WriteMessage("Deleting " + path);
Directory.Delete(path, true);
}
}
- if(nuke) {
- string path = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Assets", this.platform_id, this.identifier);
- if (Directory.Exists(path)) {
- _writeMessage("Deleting " + path);
+
+ if (nuke)
+ {
+ string path = Path.Combine(GlobalHelper.UpdateDirectory, "Assets", this.platform_id, this.identifier);
+
+ if (Directory.Exists(path))
+ {
+ WriteMessage("Deleting " + path);
Directory.Delete(path, true);
}
}
@@ -123,123 +151,108 @@ public void Delete(bool nuke = false)
public void Uninstall(bool nuke = false)
{
- _writeMessage("Uninstalling " + this.identifier);
-
+ WriteMessage("Uninstalling " + this.identifier);
+
Delete(nuke);
- Factory.GetGlobals().SettingsManager.DisableCore(this.identifier);
- Factory.GetGlobals().SettingsManager.SaveSettings();
+ GlobalHelper.SettingsManager.DisableCore(this.identifier);
+ GlobalHelper.SettingsManager.SaveSettings();
- _writeMessage("Finished");
+ WriteMessage("Finished");
Divide();
}
- public Platform? ReadPlatformFile()
+ public Platform ReadPlatformFile()
{
- var info = this.getConfig();
+ var info = this.GetConfig();
+
if (info == null)
{
return this.platform;
}
-
- string UpdateDirectory = Factory.GetGlobals().UpdateDirectory;
- //cores with multiple platforms won't work...not sure any exist right now?
- string platformsFolder = Path.Combine(UpdateDirectory, "Platforms");
+ string updateDirectory = GlobalHelper.UpdateDirectory;
+ // cores with multiple platforms won't work...not sure any exist right now?
+ string platformsFolder = Path.Combine(updateDirectory, "Platforms");
string dataFile = Path.Combine(platformsFolder, info.metadata.platform_ids[0] + ".json");
- var p = JsonSerializer.Deserialize>(File.ReadAllText(dataFile));
-
+ var p = JsonSerializer.Deserialize>(File.ReadAllText(dataFile));
+
return p["platform"];
}
- public bool UpdatePlatform(string title, string category = null)
+ public async Task> DownloadAssets()
{
- var info = this.getConfig();
- if (info == null)
+ List installed = new List();
+ List skipped = new List();
+ bool missingBetaKey = false;
+
+ if (!this.download_assets || !GlobalHelper.SettingsManager.GetCoreSettings(this.identifier).download_assets)
{
- return false;
+ return new Dictionary
+ {
+ { "installed", installed },
+ { "skipped", skipped },
+ { "missingBetaKey", false }
+ };
}
-
- string UpdateDirectory = Factory.GetGlobals().UpdateDirectory;
- //cores with multiple platforms won't work...not sure any exist right now?
- string platformsFolder = Path.Combine(UpdateDirectory, "Platforms");
- string dataFile = Path.Combine(platformsFolder, info.metadata.platform_ids[0] + ".json");
- if (!File.Exists(dataFile))
+ CheckUpdateDirectory();
+ WriteMessage("Looking for Assets");
+ AnalogueCore info = this.GetConfig();
+ string updateDirectory = GlobalHelper.UpdateDirectory;
+ // cores with multiple platforms won't work...not sure any exist right now?
+ string instancesDirectory = Path.Combine(updateDirectory, "Assets", info.metadata.platform_ids[0], this.identifier);
+ var options = new JsonSerializerOptions { Converters = { new StringConverter() } };
+
+ DataJSON dataJson = ReadDataJSON();
+
+ if (this.beta_slot_id != null)
{
- return false;
+ // what to do?
}
- if (platform.name != title || platform.category != category)
+ if (dataJson.data.data_slots.Length > 0)
{
-
- Dictionary platform = new Dictionary();
- this.platform.name = title;
- if (category != null)
+ foreach (DataSlot slot in dataJson.data.data_slots)
{
- this.platform.category = category;
- }
- platform.Add("platform", this.platform);
- string json = JsonSerializer.Serialize(platform);
-
- File.WriteAllText(dataFile, json);
- Factory.GetGlobals().SettingsManager.GetConfig().preserve_platforms_folder = true;
- Factory.GetGlobals().SettingsManager.SaveSettings();
- }
-
- return true;
- }
-
- public async Task> DownloadAssets()
- {
- List installed = new List();
- List skipped = new List();
- bool missingBetaKey = false;
- if(!downloadAssets || !Factory.GetGlobals().SettingsManager.GetCoreSettings(this.identifier).download_assets) {
- return new Dictionary{
- {"installed", installed },
- {"skipped", skipped },
- {"missingBetaKey", missingBetaKey }
- };
- }
- checkUpdateDirectory();
- _writeMessage("Looking for Assets");
- Analogue.Cores.Core.Core info = this.getConfig();
- string UpdateDirectory = Factory.GetGlobals().UpdateDirectory;
- //cores with multiple platforms won't work...not sure any exist right now?
- string instancesDirectory = Path.Combine(UpdateDirectory, "Assets", info.metadata.platform_ids[0], this.identifier);
- var options = new JsonSerializerOptions
- {
- Converters = { new StringConverter() }
- };
-
- Analogue.DataJSON data = ReadDataJSON();
- if (betaSlotId != null) {
+ if (slot.filename != null && !slot.filename.EndsWith(".sav") &&
+ !GlobalHelper.Blacklist.Contains(slot.filename))
+ {
+ string path = Path.Combine(updateDirectory, "Assets", info.metadata.platform_ids[0]);
- }
- if(data.data.data_slots.Length > 0) {
- foreach(Analogue.DataSlot slot in data.data.data_slots) {
- if(slot.filename != null && !slot.filename.EndsWith(".sav") && !Factory.GetGlobals().Blacklist.Contains(slot.filename)) {
- string path = Path.Combine(UpdateDirectory, "Assets", info.metadata.platform_ids[0]);
- if(slot.isCoreSpecific()) {
+ if (slot.IsCoreSpecific())
+ {
path = Path.Combine(path, this.identifier);
- } else {
+ }
+ else
+ {
path = Path.Combine(path, "common");
}
- List files = new List();
- files.Add(slot.filename);
- if (slot.alternate_filenames != null) {
+
+ List files = new List { slot.filename };
+
+ if (slot.alternate_filenames != null)
+ {
files.AddRange(slot.alternate_filenames);
}
- foreach (string f in files) {
+
+ foreach (string f in files)
+ {
string filepath = Path.Combine(path, f);
- if(File.Exists(filepath) && CheckCRC(filepath)) {
- _writeMessage("Already installed: " + f);
- } else {
- if(await DownloadAsset(f, filepath)) {
- installed.Add(filepath.Replace(UpdateDirectory, ""));
- } else {
- skipped.Add(filepath.Replace(UpdateDirectory, ""));
+
+ if (File.Exists(filepath) && CheckCRC(filepath))
+ {
+ WriteMessage("Already installed: " + f);
+ }
+ else
+ {
+ if (await DownloadAsset(f, filepath))
+ {
+ installed.Add(filepath.Replace(updateDirectory, ""));
+ }
+ else
+ {
+ skipped.Add(filepath.Replace(updateDirectory, ""));
}
}
}
@@ -247,138 +260,186 @@ public async Task> DownloadAssets()
}
}
- if(this.identifier == "Mazamars312.NeoGeo" || this.identifier == "Mazamars312.NeoGeo_Overdrive") {
- return new Dictionary{
- {"installed", installed },
- {"skipped", skipped },
- {"missingBetaKey", false }
- }; //nah
+ if (this.identifier is "Mazamars312.NeoGeo" or "Mazamars312.NeoGeo_Overdrive")
+ {
+ return new Dictionary
+ {
+ { "installed", installed },
+ { "skipped", skipped },
+ { "missingBetaKey", false }
+ };
}
- if(CheckInstancePackager()) {
+ if (CheckInstancePackager())
+ {
BuildInstanceJSONs();
- return new Dictionary{
- {"installed", installed },
- {"skipped", skipped },
- {"missingBetaKey", missingBetaKey }
+
+ return new Dictionary
+ {
+ { "installed", installed },
+ { "skipped", skipped },
+ { "missingBetaKey", false }
};
}
-
- if(Directory.Exists(instancesDirectory)) {
- string[] files = Directory.GetFiles(instancesDirectory,"*.json", SearchOption.AllDirectories);
- foreach(string file in files) {
- try {
- //skip mac ._ files
- if(File.GetAttributes(file).HasFlag(FileAttributes.Hidden)) {
+
+ if (Directory.Exists(instancesDirectory))
+ {
+ string[] files = Directory.GetFiles(instancesDirectory, "*.json", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ try
+ {
+ // skip mac ._ files
+ if (File.GetAttributes(file).HasFlag(FileAttributes.Hidden))
+ {
continue;
}
- if(Factory.GetGlobals().SettingsManager.GetConfig().skip_alternative_assets && file.Contains(Path.Combine(instancesDirectory, "_alternatives"))) {
+
+ if (GlobalHelper.SettingsManager.GetConfig().skip_alternative_assets &&
+ file.Contains(Path.Combine(instancesDirectory, "_alternatives")))
+ {
continue;
}
- Analogue.InstanceJSON instance = JsonSerializer.Deserialize(File.ReadAllText(file), options);
- if(instance.instance.data_slots.Length > 0) {
- string data_path = instance.instance.data_path;
- foreach(Analogue.DataSlot slot in instance.instance.data_slots) {
- var plat = info.metadata.platform_ids[betaSlotPlatformIdIndex];
- if(!CheckBetaMD5(slot, plat)) {
- _writeMessage("Invalid or missing beta key.");
+
+ InstanceJSON instanceJson = JsonSerializer.Deserialize(File.ReadAllText(file), options);
+
+ if (instanceJson.instance.data_slots.Length > 0)
+ {
+ string dataPath = instanceJson.instance.data_path;
+
+ foreach (DataSlot slot in instanceJson.instance.data_slots)
+ {
+ var plat = info.metadata.platform_ids[this.beta_slot_platform_id_index];
+
+ if (!CheckBetaMD5(slot, plat))
+ {
+ WriteMessage("Invalid or missing beta key.");
missingBetaKey = true;
}
- if(!Factory.GetGlobals().Blacklist.Contains(slot.filename) && !slot.filename.EndsWith(".sav")) {
- string path = Path.Combine(UpdateDirectory, "Assets", info.metadata.platform_ids[0], "common", data_path, slot.filename);
- if(File.Exists(path) && CheckCRC(path)) {
- _writeMessage("Already installed: " + slot.filename);
- } else {
- if(await DownloadAsset(slot.filename, path)) {
- installed.Add(path.Replace(UpdateDirectory, ""));
- } else {
- skipped.Add(path.Replace(UpdateDirectory, ""));
+
+ if (!GlobalHelper.Blacklist.Contains(slot.filename) &&
+ !slot.filename.EndsWith(".sav"))
+ {
+ string path = Path.Combine(updateDirectory, "Assets", info.metadata.platform_ids[0],
+ "common", dataPath, slot.filename);
+
+ if (File.Exists(path) && CheckCRC(path))
+ {
+ WriteMessage("Already installed: " + slot.filename);
+ }
+ else
+ {
+ if (await DownloadAsset(slot.filename, path))
+ {
+ installed.Add(path.Replace(updateDirectory, ""));
+ }
+ else
+ {
+ skipped.Add(path.Replace(updateDirectory, ""));
}
}
}
}
}
- } catch (Exception e) {
- _writeMessage("Error while processing " + file);
- _writeMessage(e.Message);
+ }
+ catch (Exception e)
+ {
+ WriteMessage("Error while processing " + file);
+ WriteMessage(e.Message);
}
}
}
- Dictionary results = new Dictionary{
- {"installed", installed },
- {"skipped", skipped },
- {"missingBetaKey", missingBetaKey }
+
+ Dictionary results = new Dictionary
+ {
+ { "installed", installed },
+ { "skipped", skipped },
+ { "missingBetaKey", missingBetaKey }
};
return results;
}
- public Analogue.Cores.Core.Core? getConfig()
+ public AnalogueCore GetConfig()
{
- checkUpdateDirectory();
- string file = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "core.json");
+ CheckUpdateDirectory();
+
+ string file = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "core.json");
+
if (!File.Exists(file))
{
return null;
}
+
string json = File.ReadAllText(file);
- var options = new JsonSerializerOptions()
- {
- AllowTrailingCommas = true
- };
- Analogue.Cores.Core.Core? config = JsonSerializer.Deserialize>(json, options)["core"];
+ var options = new JsonSerializerOptions { AllowTrailingCommas = true };
+ AnalogueCore config = JsonSerializer.Deserialize>(json, options)["core"];
return config;
}
- public Updater.Substitute[]? getSubstitutes()
+ public Substitute[] GetSubstitutes()
{
- checkUpdateDirectory();
- string file = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "updaters.json");
+ CheckUpdateDirectory();
+
+ string file = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "updaters.json");
+
if (!File.Exists(file))
{
return null;
}
- string json = File.ReadAllText(file);
- Updater.Updaters? config = JsonSerializer.Deserialize(json);
- if (config == null) {
- return null;
- }
+ string json = File.ReadAllText(file);
+ Updaters config = JsonSerializer.Deserialize(json);
- return config.previous;
+ return config?.previous;
}
- public bool isInstalled()
+ public bool IsInstalled()
{
- checkUpdateDirectory();
- string localCoreFile = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "core.json");
+ CheckUpdateDirectory();
+
+ string localCoreFile = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "core.json");
+
return File.Exists(localCoreFile);
}
private async Task DownloadAsset(string filename, string destination)
{
- if(Factory.GetGlobals().ArchiveFiles != null) {
- archiveorg.File? file = Factory.GetGlobals().ArchiveFiles.GetFile(filename);
- if(file == null) {
- _writeMessage("Unable to find " + filename + " in archive");
+ if (GlobalHelper.ArchiveFiles != null)
+ {
+ ArchiveFile file = GlobalHelper.ArchiveFiles.GetFile(filename);
+
+ if (file == null)
+ {
+ WriteMessage("Unable to find " + filename + " in archive");
return false;
}
}
- try {
+ try
+ {
string url = BuildAssetUrl(filename);
int count = 0;
- do {
- _writeMessage("Downloading " + filename);
- await Factory.GetHttpHelper().DownloadFileAsync(url, destination, 600);
- _writeMessage("Finished downloading " + filename);
+
+ do
+ {
+ WriteMessage("Downloading " + filename);
+ await HttpHelper.Instance.DownloadFileAsync(url, destination, 600);
+ WriteMessage("Finished downloading " + filename);
count++;
- } while(count < 3 && !CheckCRC(destination));
- } catch(HttpRequestException e) {
- if(e.StatusCode == System.Net.HttpStatusCode.NotFound) {
- _writeMessage("Unable to find " + filename + " in archive");
- } else {
- _writeMessage("There was a problem downloading " + filename);
+ }
+ while (count < 3 && !CheckCRC(destination));
+ }
+ catch (HttpRequestException e)
+ {
+ if (e.StatusCode == HttpStatusCode.NotFound)
+ {
+ WriteMessage("Unable to find " + filename + " in archive");
+ }
+ else
+ {
+ WriteMessage("There was a problem downloading " + filename);
}
return false;
@@ -387,48 +448,53 @@ private async Task DownloadAsset(string filename, string destination)
return true;
}
- private string BuildAssetUrl(string filename)
+ private static string BuildAssetUrl(string filename)
{
- if(Factory.GetGlobals().SettingsManager.GetConfig().use_custom_archive) {
- var custom = Factory.GetGlobals().SettingsManager.GetConfig().custom_archive;
+ if (GlobalHelper.SettingsManager.GetConfig().use_custom_archive)
+ {
+ var custom = GlobalHelper.SettingsManager.GetConfig().custom_archive;
Uri baseUrl = new Uri(custom["url"]);
Uri url = new Uri(baseUrl, filename);
return url.ToString();
- } else {
- return ARCHIVE_BASE_URL + "/" + Factory.GetGlobals().SettingsManager.GetConfig().archive_name + "/" + filename;
}
+
+ return ARCHIVE_BASE_URL + "/" + GlobalHelper.SettingsManager.GetConfig().archive_name + "/" + filename;
}
private bool CheckCRC(string filepath)
{
- if(Factory.GetGlobals().ArchiveFiles == null || !Factory.GetGlobals().SettingsManager.GetConfig().crc_check) {
+ if (GlobalHelper.ArchiveFiles == null || !GlobalHelper.SettingsManager.GetConfig().crc_check)
+ {
return true;
}
+
string filename = Path.GetFileName(filepath);
- archiveorg.File? file = Factory.GetGlobals().ArchiveFiles.GetFile(filename);
- if(file == null) {
+ ArchiveFile file = GlobalHelper.ArchiveFiles.GetFile(filename);
+
+ if (file == null)
+ {
return true; //no checksum to compare to
}
- if(Util.CompareChecksum(filepath, file.crc32)) {
+ if (Util.CompareChecksum(filepath, file.crc32))
+ {
return true;
}
- _writeMessage(filename + ": Bad checksum!");
+ WriteMessage(filename + ": Bad checksum!");
return false;
}
- //return false if a beta ley is required and missing or wrong
- private bool CheckBetaMD5(Analogue.DataSlot slot, string platform)
+ // return false if a beta ley is required and missing or wrong
+ private bool CheckBetaMD5(DataSlot slot, string platform)
{
- if(slot.md5 != null && (betaSlotId != null && slot.id == betaSlotId)) {
- string UpdateDirectory = Factory.GetGlobals().UpdateDirectory;
- string path = Path.Combine(UpdateDirectory, "Assets", platform);
+ if (slot.md5 != null && (this.beta_slot_id != null && slot.id == this.beta_slot_id))
+ {
+ string updateDirectory = GlobalHelper.UpdateDirectory;
+ string path = Path.Combine(updateDirectory, "Assets", platform);
string filepath = Path.Combine(path, "common", slot.filename);
- if(!File.Exists(filepath)) {
- return false;
- }
- return Util.CompareChecksum(filepath, slot.md5, Util.HashTypes.MD5);
+
+ return File.Exists(filepath) && Util.CompareChecksum(filepath, slot.md5, Util.HashTypes.MD5);
}
return true;
@@ -436,115 +502,157 @@ private bool CheckBetaMD5(Analogue.DataSlot slot, string platform)
public void BuildInstanceJSONs(bool overwrite = true)
{
- if(!buildInstances) {
+ if (!this.build_instances)
+ {
return;
}
- string instancePackagerFile = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "instance-packager.json");
- if(!File.Exists(instancePackagerFile)) {
+
+ string instancePackagerFile = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "instance-packager.json");
+
+ if (!File.Exists(instancePackagerFile))
+ {
return;
}
- _writeMessage("Building instance json files.");
- InstancePackager packager = JsonSerializer.Deserialize(File.ReadAllText(instancePackagerFile));
- string commonPath = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Assets", packager.platform_id, "common");
- string outputDir = Path.Combine(Factory.GetGlobals().UpdateDirectory, packager.output);
+
+ WriteMessage("Building instance json files.");
+ InstanceJsonPackager jsonPackager = JsonSerializer.Deserialize(File.ReadAllText(instancePackagerFile));
+ string commonPath = Path.Combine(GlobalHelper.UpdateDirectory, "Assets", jsonPackager.platform_id, "common");
bool warning = false;
- foreach(string dir in Directory.GetDirectories(commonPath, "*", SearchOption.AllDirectories)) {
- Analogue.SimpleInstanceJSON instancejson = new Analogue.SimpleInstanceJSON();
- Analogue.SimpleInstance instance = new Analogue.SimpleInstance();
+
+ foreach (string dir in Directory.GetDirectories(commonPath, "*", SearchOption.AllDirectories))
+ {
+ SimpleInstanceJSON simpleInstanceJson = new SimpleInstanceJSON();
+ SimpleInstance instance = new SimpleInstance();
string dirName = Path.GetFileName(dir);
- try {
+
+ try
+ {
instance.data_path = dir.Replace(commonPath + Path.DirectorySeparatorChar, "") + "/";
- List slots = new List();
+
+ List slots = new();
string jsonFileName = dirName + ".json";
- foreach(DataSlot slot in packager.data_slots) {
+
+ foreach (InstancePackagerDataSlot slot in jsonPackager.data_slots)
+ {
string[] files = Directory.GetFiles(dir, slot.filename);
int index = slot.id;
- switch(slot.sort) {
+
+ switch (slot.sort)
+ {
case "single":
case "ascending":
Array.Sort(files);
break;
+
case "descending":
- IComparer myComparer = new myReverserClass();
+ IComparer myComparer = new ReverseComparer();
Array.Sort(files, myComparer);
break;
}
- if(slot.required && files.Count() == 0) {
+
+ if (slot.required && !files.Any())
+ {
throw new MissingRequiredInstanceFiles("Missing required files.");
}
- foreach(string file in files) {
- if(File.GetAttributes(file).HasFlag(FileAttributes.Hidden)) {
+
+ foreach (string file in files)
+ {
+ if (File.GetAttributes(file).HasFlag(FileAttributes.Hidden))
+ {
continue;
}
- Analogue.InstanceDataSlot current = new Analogue.InstanceDataSlot();
+
+ SimpleDataSlot current = new();
string filename = Path.GetFileName(file);
- if(slot.as_filename) {
+
+ if (slot.as_filename)
+ {
jsonFileName = Path.GetFileNameWithoutExtension(file) + ".json";
}
+
current.id = index.ToString();
current.filename = filename;
index++;
slots.Add(current);
}
}
- var limit = (JsonElement)packager.slot_limit["count"];
- if (slots.Count == 0 || (packager.slot_limit != null && slots.Count > limit.GetInt32())) {
- _writeMessage("Unable to build " + jsonFileName);
+
+ var limit = (JsonElement)jsonPackager.slot_limit["count"];
+
+ if (slots.Count == 0 || (jsonPackager.slot_limit != null && slots.Count > limit.GetInt32()))
+ {
+ WriteMessage("Unable to build " + jsonFileName);
warning = true;
continue;
}
+
instance.data_slots = slots.ToArray();
- instancejson.instance = instance;
- var options = new JsonSerializerOptions()
- {
- WriteIndented = true
- };
+ simpleInstanceJson.instance = instance;
+
+ var options = new JsonSerializerOptions { WriteIndented = true };
string[] parts = dir.Split(commonPath);
parts = parts[1].Split(jsonFileName.Remove(jsonFileName.Length - 5));
- string subdir = "";
- if(parts[0].Length > 1) {
- subdir = parts[0].Trim(Path.DirectorySeparatorChar);
+ string subDirectory = string.Empty;
+
+ if (parts[0].Length > 1)
+ {
+ subDirectory = parts[0].Trim(Path.DirectorySeparatorChar);
}
- string outputfile = Path.Combine(Factory.GetGlobals().UpdateDirectory, packager.output, subdir, jsonFileName);
- if(!overwrite && File.Exists(outputfile)) {
- _writeMessage(jsonFileName + " already exists.");
- } else {
- string json = JsonSerializer.Serialize(instancejson, options);
- _writeMessage("Saving " + jsonFileName);
- FileInfo file = new System.IO.FileInfo(outputfile);
+
+ string outputFile = Path.Combine(GlobalHelper.UpdateDirectory, jsonPackager.output, subDirectory, jsonFileName);
+
+ if (!overwrite && File.Exists(outputFile))
+ {
+ WriteMessage(jsonFileName + " already exists.");
+ }
+ else
+ {
+ string json = JsonSerializer.Serialize(simpleInstanceJson, options);
+
+ WriteMessage("Saving " + jsonFileName);
+
+ FileInfo file = new FileInfo(outputFile);
+
file.Directory.Create(); // If the directory already exists, this method does nothing.
- File.WriteAllText(outputfile, json);
+
+ File.WriteAllText(outputFile, json);
}
- } catch(MissingRequiredInstanceFiles) {
- //do nothin
- } catch(Exception e) {
- _writeMessage("Unable to build " + dirName);
+ }
+ catch (MissingRequiredInstanceFiles)
+ {
+ // Do nothing.
+ }
+ catch (Exception)
+ {
+ WriteMessage("Unable to build " + dirName);
}
}
- if (warning) {
- var message = (JsonElement)packager.slot_limit["message"];
- _writeMessage(message.GetString());
+
+ if (warning)
+ {
+ var message = (JsonElement)jsonPackager.slot_limit["message"];
+
+ WriteMessage(message.GetString());
}
- _writeMessage("Finished");
+
+ WriteMessage("Finished");
}
public bool CheckInstancePackager()
{
- string instancePackagerFile = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "instance-packager.json");
+ string instancePackagerFile = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "instance-packager.json");
+
return File.Exists(instancePackagerFile);
}
- public Analogue.DataJSON ReadDataJSON()
+ private DataJSON ReadDataJSON()
{
- string UpdateDirectory = Factory.GetGlobals().UpdateDirectory;
- string coreDirectory = Path.Combine(UpdateDirectory, "Cores", this.identifier);
+ string updateDirectory = GlobalHelper.UpdateDirectory;
+ string coreDirectory = Path.Combine(updateDirectory, "Cores", this.identifier);
string dataFile = Path.Combine(coreDirectory, "data.json");
- var options = new JsonSerializerOptions
- {
- Converters = { new StringConverter() }
- };
+ var options = new JsonSerializerOptions { Converters = { new StringConverter() } };
- Analogue.DataJSON data = JsonSerializer.Deserialize(File.ReadAllText(dataFile), options);
+ DataJSON data = JsonSerializer.Deserialize(File.ReadAllText(dataFile), options);
return data;
}
@@ -552,28 +660,35 @@ public Analogue.DataJSON ReadDataJSON()
public bool JTBetaCheck()
{
var data = ReadDataJSON();
- bool check = data.data.data_slots.Any(x=>x.name=="JTBETA");
+ bool check = data.data.data_slots.Any(x => x.name == "JTBETA");
+
+ if (check)
+ {
+ var slot = data.data.data_slots.First(x => x.name == "JTBETA");
- if (check) {
- var slot = data.data.data_slots.Where(x=>x.name=="JTBETA").First();
- betaSlotId = slot.id;
- betaSlotPlatformIdIndex = slot.getPlatformIdIndex();
+ this.beta_slot_id = slot.id;
+ this.beta_slot_platform_id_index = slot.GetPlatformIdIndex();
}
return check;
}
- public async Task ReplaceCheck()
+ public void ReplaceCheck()
{
- var replaces = this.getSubstitutes();
- if (replaces != null) {
- foreach(var replacement in replaces) {
+ var replaces = this.GetSubstitutes();
+
+ if (replaces != null)
+ {
+ foreach (var replacement in replaces)
+ {
string identifier = $"{replacement.author}.{replacement.shortname}";
- Core c = new Core(){identifier = identifier, platform_id = replacement.platform_id};
- if (c.isInstalled()) {
+ Core c = new Core { identifier = identifier, platform_id = replacement.platform_id };
+
+ if (c.IsInstalled())
+ {
Replace(c);
c.Uninstall();
- _writeMessage($"Uninstalled {identifier}. It was replaced by this core.");
+ WriteMessage($"Uninstalled {identifier}. It was replaced by this core.");
}
}
}
@@ -581,72 +696,79 @@ public async Task ReplaceCheck()
private void Replace(Core core)
{
- string root = Factory.GetGlobals().UpdateDirectory;
+ string root = GlobalHelper.UpdateDirectory;
string path = Path.Combine(root, "Assets", core.platform_id, core.identifier);
- if(Directory.Exists(path)) {
+
+ if (Directory.Exists(path))
+ {
Directory.Move(path, Path.Combine(root, "Assets", core.platform_id, this.identifier));
}
-
+
path = Path.Combine(root, "Saves", core.platform_id, core.identifier);
- if(Directory.Exists(path)) {
+ if (Directory.Exists(path))
+ {
Directory.Move(path, Path.Combine(root, "Saves", core.platform_id, this.identifier));
}
path = Path.Combine(root, "Settings", core.identifier);
- if(Directory.Exists(path)) {
+ if (Directory.Exists(path))
+ {
Directory.Move(path, Path.Combine(root, "Settings", this.identifier));
}
}
- public async Task GetVideoConfig()
+ public Video GetVideoConfig()
{
- checkUpdateDirectory();
- string file = Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "video.json");
+ CheckUpdateDirectory();
+
+ string file = Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "video.json");
+
if (!File.Exists(file))
{
return null;
}
+
string json = File.ReadAllText(file);
- var options = new JsonSerializerOptions()
- {
- AllowTrailingCommas = true
- };
- Analogue.Cores.Video.Video? config = JsonSerializer.Deserialize>(json, options)["video"];
+ var options = new JsonSerializerOptions { AllowTrailingCommas = true };
+ Video config = JsonSerializer.Deserialize>(json, options)["video"];
return config;
}
- public async Task AddDisplayModes()
+ public void AddDisplayModes()
{
- var info = this.getConfig();
- var video = await GetVideoConfig();
- List all = new List();
- foreach(string id in allModes) {
- all.Add(new Analogue.Cores.Video.DisplayMode{id = id});
- }
- if(info.metadata.platform_ids.Contains("gb")) {
- foreach(string id in gbModes) {
- all.Add(new Analogue.Cores.Video.DisplayMode{id = id});
+ var info = this.GetConfig();
+ var video = GetVideoConfig();
+ List all = new List();
+
+ foreach (string id in ALL_MODES)
+ {
+ all.Add(new DisplayMode { id = id });
+ }
+
+ if (info.metadata.platform_ids.Contains("gb"))
+ {
+ foreach (string id in GB_MODES)
+ {
+ all.Add(new DisplayMode { id = id });
}
}
+
video.display_modes = all;
- Dictionary output = new Dictionary();
- output.Add("video", video);
- var options = new JsonSerializerOptions()
- {
- WriteIndented = true
- };
+ Dictionary output = new Dictionary { { "video", video } };
+ var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(output, options);
-
- File.WriteAllText(Path.Combine(Factory.GetGlobals().UpdateDirectory, "Cores", this.identifier, "video.json"), json);
+
+ File.WriteAllText(Path.Combine(GlobalHelper.UpdateDirectory, "Cores", this.identifier, "video.json"), json);
}
}
-public class myReverserClass : IComparer {
-
- // Calls CaseInsensitiveComparer.Compare with the parameters reversed.
- int IComparer.Compare( Object x, Object y ) {
- return( (new CaseInsensitiveComparer()).Compare( y, x ) );
- }
- }
+public class ReverseComparer : IComparer
+{
+ // Calls CaseInsensitiveComparer.Compare with the parameters reversed.
+ int IComparer.Compare(object x, object y)
+ {
+ return new CaseInsensitiveComparer().Compare(y, x);
+ }
+}
diff --git a/src/models/Github/GithubAsset.cs b/src/models/Github/GithubAsset.cs
index bc882c3f..2c2deb9f 100644
--- a/src/models/Github/GithubAsset.cs
+++ b/src/models/Github/GithubAsset.cs
@@ -1,9 +1,9 @@
-namespace Github;
+namespace Pannella.Models.Github;
public class Asset
{
- public string? url {get; set;}
- public string? name {get; set;}
- public string? content_type {get; set;}
- public string? browser_download_url {get; set;}
-}
\ No newline at end of file
+ public string url {get; set;}
+ public string name {get; set;}
+ public string content_type {get; set;}
+ public string browser_download_url {get; set;}
+}
diff --git a/src/models/Github/GithubFile.cs b/src/models/Github/GithubFile.cs
index 7dde4b7c..a225ac54 100644
--- a/src/models/Github/GithubFile.cs
+++ b/src/models/Github/GithubFile.cs
@@ -1,12 +1,12 @@
-namespace Github;
+namespace Pannella.Models.Github;
public class File
{
- public string? name {get; set;}
- public string? path {get; set;}
- public string? sha {get; set;}
+ public string name {get; set;}
+ public string path {get; set;}
+ public string sha {get; set;}
public int? size {get; set;}
- public string? url {get; set;}
- public string? html_url {get; set;}
- public string? download_url {get; set;}
-}
\ No newline at end of file
+ public string url {get; set;}
+ public string html_url {get; set;}
+ public string download_url {get; set;}
+}
diff --git a/src/models/Github/GithubRelease.cs b/src/models/Github/GithubRelease.cs
index c21e1d79..8bf4be1c 100644
--- a/src/models/Github/GithubRelease.cs
+++ b/src/models/Github/GithubRelease.cs
@@ -1,12 +1,12 @@
-namespace Github;
+namespace Pannella.Models.Github;
public class Release
{
- public string? tag_name { get; set; }
- public string? name { get; set; }
+ public string tag_name { get; set; }
+ public string name { get; set; }
public bool prerelease { get; set; }
- public string? url { get; set; }
- public List? assets { get; set; }
+ public string url { get; set; }
+ public List assets { get; set; }
public bool draft { get; set; }
- public string? html_url { get; set; }
-}
\ No newline at end of file
+ public string html_url { get; set; }
+}
diff --git a/src/models/ImagePack.cs b/src/models/ImagePack.cs
index 7197d157..6c7e0032 100644
--- a/src/models/ImagePack.cs
+++ b/src/models/ImagePack.cs
@@ -1,74 +1,98 @@
-namespace pannella.analoguepocket;
-using System.IO;
using System.IO.Compression;
+using Pannella.Helpers;
+using Pannella.Models.Github;
+using Pannella.Services;
+using File = System.IO.File;
+
+namespace Pannella.Models;
public class ImagePack
{
public string owner { get; set; }
public string repository { get; set; }
- public string? variant { get; set; }
-
+ public string variant { get; set; }
- public async Task Install(string path)
+ public async Task Install(string path)
{
- string filepath = await fetchImagePack(path);
- return await installImagePack(path, filepath);
+ string filepath = await this.FetchImagePack(path);
+
+ InstallImagePack(path, filepath);
}
- private async Task fetchImagePack(string path)
+ private async Task FetchImagePack(string path)
{
- Github.Release release = await GithubApi.GetLatestRelease(this.owner, this.repository);
+ Release release = await GithubApiService.GetLatestRelease(this.owner, this.repository);
string localFile = Path.Combine(path, "imagepack.zip");
- string downloadUrl = "";
- if(release.assets == null) {
+ string downloadUrl = string.Empty;
+
+ if (release.assets == null)
+ {
throw new Exception("Github Release contains no assets");
}
- if(this.variant == null) {
+
+ if (this.variant == null)
+ {
downloadUrl = release.assets[0].browser_download_url;
- } else {
- foreach(Github.Asset asset in release.assets) {
- if(asset.name.Contains(this.variant)) {
- downloadUrl = asset.browser_download_url;
- }
+ }
+ else
+ {
+ foreach (var asset in release.assets.Where(asset => asset.name.Contains(this.variant)))
+ {
+ downloadUrl = asset.browser_download_url;
}
}
- if(downloadUrl != "") {
+
+ if (downloadUrl != string.Empty)
+ {
Console.WriteLine("Downloading image pack...");
- await Factory.GetHttpHelper().DownloadFileAsync(downloadUrl, localFile);
+
+ await HttpHelper.Instance.DownloadFileAsync(downloadUrl, localFile);
+
Console.WriteLine("Download complete.");
+
return localFile;
}
- return "";
+
+ return string.Empty;
}
- private async Task installImagePack(string path, string filepath)
+ private static void InstallImagePack(string path, string filepath)
{
Console.WriteLine("Installing...");
+
string extractPath = Path.Combine(path, "temp");
+
ZipFile.ExtractToDirectory(filepath, extractPath, true);
+
string imagePack = FindImagePack(extractPath);
string target = Path.Combine(path, "Platforms", "_images");
+
Util.CopyDirectory(imagePack, target, false, true);
Directory.Delete(extractPath, true);
File.Delete(filepath);
- Console.WriteLine("All Done");
- return true;
+ Console.WriteLine("All Done");
}
- private string FindImagePack(string temp)
+ private static string FindImagePack(string temp)
{
string path = Path.Combine(temp, "Platforms", "_images");
- if(Directory.Exists(path)) {
+
+ if (Directory.Exists(path))
+ {
return path;
}
- foreach(string d in Directory.EnumerateDirectories(temp)) {
+ foreach (string d in Directory.EnumerateDirectories(temp))
+ {
path = Path.Combine(d, "Platforms", "_images");
- if(Directory.Exists(path)) {
+
+ if (Directory.Exists(path))
+ {
return path;
}
}
+
throw new Exception("Can't find image pack");
}
}
diff --git a/src/models/InstancePackager/DataSlot.cs b/src/models/InstancePackager/DataSlot.cs
index 5bf0da94..f427cde9 100644
--- a/src/models/InstancePackager/DataSlot.cs
+++ b/src/models/InstancePackager/DataSlot.cs
@@ -1,4 +1,4 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.InstancePackager;
public class DataSlot
{
@@ -7,4 +7,4 @@ public class DataSlot
public bool required { get; set; }
public string sort { get; set; } = "ascending";
public bool as_filename { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/InstancePackager/InstancePackager.cs b/src/models/InstancePackager/InstanceJsonPackager.cs
similarity index 71%
rename from src/models/InstancePackager/InstancePackager.cs
rename to src/models/InstancePackager/InstanceJsonPackager.cs
index 2c30fd28..97b6cc27 100644
--- a/src/models/InstancePackager/InstancePackager.cs
+++ b/src/models/InstancePackager/InstanceJsonPackager.cs
@@ -1,9 +1,9 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.InstancePackager;
-public class InstancePackager
+public class InstanceJsonPackager
{
public List data_slots { get; set; }
public string output { get; set; }
public string platform_id { get; set; }
public Dictionary slot_limit { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Platform.cs b/src/models/Platform.cs
index 6e237c59..df94935f 100644
--- a/src/models/Platform.cs
+++ b/src/models/Platform.cs
@@ -1,4 +1,4 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models;
public class Platform
{
@@ -6,4 +6,4 @@ public class Platform
public string name { get; set; }
public int year { get; set; }
public string manufacturer { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/models/Repo.cs b/src/models/Repo.cs
index aee7ab37..75240eb0 100644
--- a/src/models/Repo.cs
+++ b/src/models/Repo.cs
@@ -1,8 +1,8 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models;
public class Repo
{
- public string? name { get; set; }
- public string? owner { get; set; }
- public string? platform { get; set; }
-}
\ No newline at end of file
+ public string name { get; set; }
+ public string owner { get; set; }
+ public string platform { get; set; }
+}
diff --git a/src/models/Settings/Config.cs b/src/models/Settings/Config.cs
index 74787984..0772406c 100644
--- a/src/models/Settings/Config.cs
+++ b/src/models/Settings/Config.cs
@@ -1,43 +1,26 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.Settings;
public class Config
{
- public bool download_assets { get; set; }
- public string archive_name { get; set; }
- public string? github_token { get; set; }
- public bool download_firmware { get; set; }
- public bool core_selector { get; set; }
- public bool preserve_platforms_folder { get; set; }
- public bool delete_skipped_cores { get; set; }
- public string? download_new_cores { get; set; }
- public bool build_instance_jsons { get; set; }
- public bool crc_check { get; set; }
- public bool fix_jt_names { get; set; }
- public bool skip_alternative_assets { get; set; }
+ public bool download_assets { get; set; } = true;
+ public string archive_name { get; set; } = "openFPGA-Files";
+ public string github_token { get; set; } = string.Empty;
+ public bool download_firmware { get; set; } = true;
+ public bool core_selector { get; set; } = true;
+ public bool preserve_platforms_folder { get; set; } = false;
+ public bool delete_skipped_cores { get; set; } = true;
+ public string download_new_cores { get; set; }
+ public bool build_instance_jsons { get; set; } = true;
+ public bool crc_check { get; set; } = true;
+ public bool fix_jt_names { get; set; } = true;
+ public bool skip_alternative_assets { get; set; } = true;
public bool backup_saves { get; set; }
- public string? backup_saves_location { get; set; }
- public bool use_custom_archive { get; set; }
- public Dictionary custom_archive { get; set; }
+ public string backup_saves_location { get; set; } = "Backups";
+ public bool use_custom_archive { get; set; } = false;
- public Config()
+ public Dictionary custom_archive { get; set; } = new()
{
- download_assets = true;
- download_firmware = true;
- archive_name = "openFPGA-Files";
- core_selector = true;
- preserve_platforms_folder = false;
- delete_skipped_cores = true;
- download_new_cores = null;
- build_instance_jsons = true;
- crc_check = true;
- fix_jt_names = true;
- skip_alternative_assets = true;
- backup_saves = false;
- backup_saves_location = "Backups";
- use_custom_archive = false;
- custom_archive = new Dictionary() {
- {"url", "https://updater.retrodriven.com"},
- {"index", "updater.php"}
- };
- }
-}
\ No newline at end of file
+ { "url", "https://updater.retrodriven.com" },
+ { "index", "updater.php" }
+ };
+}
diff --git a/src/models/Settings/CoreSettings.cs b/src/models/Settings/CoreSettings.cs
index 493e717c..fefb23c9 100644
--- a/src/models/Settings/CoreSettings.cs
+++ b/src/models/Settings/CoreSettings.cs
@@ -1,15 +1,8 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.Settings;
public class CoreSettings
{
public bool skip { get; set; }
- public bool download_assets { get; set; }
- public bool platform_rename { get; set; }
-
- public CoreSettings()
- {
- skip = false;
- download_assets = true;
- platform_rename = true;
- }
-}
\ No newline at end of file
+ public bool download_assets { get; set; } = true;
+ public bool platform_rename { get; set; } = true;
+}
diff --git a/src/models/Settings/Firmware.cs b/src/models/Settings/Firmware.cs
index 3e8c37ec..971529fa 100644
--- a/src/models/Settings/Firmware.cs
+++ b/src/models/Settings/Firmware.cs
@@ -1,11 +1,6 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.Settings;
public class Firmware
{
- public string version { get; set; }
-
- public Firmware()
- {
- version = "";
- }
-}
\ No newline at end of file
+ public string version { get; set; } = string.Empty;
+}
diff --git a/src/models/Settings/Settings.cs b/src/models/Settings/Settings.cs
index 9bdf5f34..6367f472 100644
--- a/src/models/Settings/Settings.cs
+++ b/src/models/Settings/Settings.cs
@@ -1,15 +1,8 @@
-namespace pannella.analoguepocket;
+namespace Pannella.Models.Settings;
public class Settings
{
- public Firmware firmware { get; set; }
- public Config config { get; set; }
- public Dictionary coreSettings { get; set; }
-
- public Settings()
- {
- firmware = new Firmware();
- config = new Config();
- coreSettings = new Dictionary();
- }
-}
\ No newline at end of file
+ public Firmware firmware { get; set; } = new();
+ public Config config { get; set; } = new();
+ public Dictionary coreSettings { get; set; } = new();
+}
diff --git a/src/models/Sponsor.cs b/src/models/Sponsor.cs
index ccff8403..215d4d15 100644
--- a/src/models/Sponsor.cs
+++ b/src/models/Sponsor.cs
@@ -1,15 +1,45 @@
-namespace pannella.analoguepocket;
+using System.Text;
+
+namespace Pannella.Models;
public class Sponsor
{
- public string? community_bridge { get; set; }
- public List? github { get; set; }
- public string? issuehunt { get; set; }
- public string? ko_fi { get; set; }
- public string? liberapay { get; set; }
- public string? open_collective { get; set; }
- public string? otechie { get; set; }
- public string? patreon { get; set; }
- public string? tidelift { get; set; }
- public List? custom { get; set; }
-}
\ No newline at end of file
+ public string community_bridge { get; set; }
+ public List github { get; set; }
+ public string issuehunt { get; set; }
+ public string ko_fi { get; set; }
+ public string liberapay { get; set; }
+ public string open_collective { get; set; }
+ public string otechie { get; set; }
+ public string patreon { get; set; }
+ public string tidelift { get; set; }
+ public List custom { get; set; }
+
+ public override string ToString()
+ {
+ var links = new StringBuilder();
+ var properties = typeof(Sponsor).GetProperties();
+
+ foreach (var prop in properties)
+ {
+ object value = prop.GetValue(this, null);
+
+ if (value == null) continue;
+
+ links.AppendLine();
+
+ if (value.GetType() == typeof(List))
+ {
+ var stringArray = (List