" }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToArray();
285 | prs = prs.Take(prs.Length - 1).ToArray();
286 |
287 | for (int i = 0; i < prs.Length; i++)
288 | {
289 | var pr = new PR(prs[i]);
290 | //CHECK IF UNIQUE BECAUSE BUG IDK WHY
291 | if(prList.FirstOrDefault(x => x.idIssue == pr.idIssue) == null)
292 | prList.Add(pr);
293 | }
294 | }
295 |
296 |
297 | string changeLog = getChangeLog();
298 |
299 | MainUI.addTextConsole("New Version found , pass from " + currentVersion + " to " + releases[0].version + "\n" + getChangeLog());
300 | if(confirmDownload)
301 | {
302 | MainUI.addTextConsole("Do you want to download it ? (y/n)" + "\n");
303 | string answer = MainUI.waitInput().Result;
304 | if (answer != "y")
305 | return;
306 | }
307 | downloadRelease(releases[0]);
308 | }
309 | else
310 | {
311 | MainUI.addTextConsole("Yuzu is up to date" + "\n");
312 | }
313 |
314 | }
315 |
316 | public void downloadRelease(Release release)
317 | {
318 | try{
319 | killYuzus();
320 | MainUI.addTextConsole("Downloading "+ release.version + " version" + "\n");
321 |
322 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
323 | {
324 | String fileName = System.IO.Path.GetFileName(new Uri(release.downloadUrl).LocalPath);
325 | download(release.downloadUrl, fileName).GetAwaiter().GetResult();
326 | MainUI.addTextConsole("Make executable" + "\n");
327 | Process.Start("chmod", "+x " + fileName);
328 | MainUI.addTextConsole("Remove old version" + "\n");
329 | if (System.IO.File.Exists(currentExe))
330 | System.IO.File.Delete(currentExe);
331 |
332 | currentExe = fileName;
333 | }
334 | else
335 | {
336 | download(release.downloadUrl, "YuzuEA.zip").GetAwaiter().GetResult();
337 | ZipArchive zip = ZipFile.OpenRead("YuzuEA.zip");
338 | zip.ExtractToDirectory(System.Environment.CurrentDirectory, true);
339 | zip.Dispose();
340 | MainUI.addTextConsole("Remove zip file" + "\n");
341 | System.IO.File.Delete("YuzuEA.zip");
342 | string[] files = Directory.GetFiles(System.Environment.CurrentDirectory + "/yuzu-windows-msvc-early-access");
343 | MainUI.addTextConsole("Move files and directory to root directory" + "\n");
344 | if (System.IO.File.Exists(currentExe))
345 | System.IO.File.Delete(currentExe);
346 | Utils.DirectoryCopyAndDelete(System.Environment.CurrentDirectory + "/yuzu-windows-msvc-early-access", System.Environment.CurrentDirectory);
347 | System.IO.File.Move("yuzu.exe", currentExe);
348 | }
349 | MainUI.addTextConsole("Install to " + release.version + " success !\n");
350 | purgeUncessaryFiles();
351 | }
352 | catch(Exception ex){
353 | MainUI.addTextConsole(ex.StackTrace + " " + ex.Message + "\n");
354 |
355 | }
356 | }
357 |
358 | private string getChangeLog()
359 | {
360 | string changeLog = "";
361 | List
prs = prList.Where(x => x.releaseDate > myCurrentRelease.releaseDate && x.label.Contains("merge")).ToList();
362 |
363 | foreach(PR pr in prs)
364 | {
365 | changeLog += pr.idIssue + " - " + pr.description + " - " + pr.label + " - " + pr.releaseDate + "\n";
366 | }
367 | return changeLog;
368 | }
369 |
370 | private async Task download(String uri,String filename)
371 | {
372 | HttpClient _httpClient = httpClient();
373 | _httpClient.BaseAddress = new Uri(uri);
374 | _httpClient.DefaultRequestHeaders.Accept.Clear();
375 | _httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/octet-stream"));
376 | using (var file = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
377 | {
378 |
379 | await _httpClient.DownloadAsync(uri, file, MainUI.progress);
380 | }
381 |
382 | }
383 |
384 |
385 |
386 | public void scanTitlesIdAndGetName()
387 | {
388 | if(pathApp == "")
389 | {
390 | MainUI.addTextConsole("Path to yuzu data not found" + "\n");
391 | return;
392 | }
393 | else
394 | {
395 | MainUI.addTextConsole("Path to yuzu data found: " + pathApp + "\n");
396 | }
397 |
398 |
399 | if (games.Count == 0)
400 | {
401 |
402 | List directorys = Directory.GetDirectories(pathApp ,"010*",SearchOption.AllDirectories).Select(d => Path.GetFileName(d).ToUpper()).ToList();
403 | directorys = directorys.Distinct().ToList();
404 |
405 | HttpClient _httpClient = httpClient();
406 | String src = _httpClient.GetAsync("https://switchbrew.org/w/index.php?title=Title_list/Games&mobileaction=toggle_view_desktop").Result.Content.ReadAsStringAsync().Result;
407 |
408 | foreach (String directory in directorys)
409 | {
410 | String id = directory.Substring(0, 16);
411 | string name = Regex.Match(src, @"" + id + @" | \s*(.*) | ").Groups[1].Value;
412 |
413 | if (name != "")
414 | {
415 | games.Add(new Game(id, name, pathApp));
416 | }
417 |
418 | }
419 | }
420 | }
421 |
422 |
423 | private void _saveBackup()
424 | {
425 | try
426 | {
427 | MainUI.addTextConsole("Save game backup..." + "\n");
428 | string sourceDir = Path.Combine(pathApp, "nand", "user", "save");
429 | DirectoryInfo directoryInfo = new DirectoryInfo(sourceDir);
430 | if (this.backupSave && directoryInfo.Exists && directoryInfo.GetDirectories().Length>0)
431 | {
432 | if(!Directory.Exists(Path.Combine(Environment.CurrentDirectory, "savesBackup")))
433 | Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "savesBackup"));
434 |
435 | string zipFilePath = Path.Combine(Environment.CurrentDirectory,"savesBackup", DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".7z");
436 |
437 | SevenZip.SevenZipCompressor compressor = new SevenZip.SevenZipCompressor();
438 | compressor.CompressionLevel = SevenZip.CompressionLevel.Ultra;
439 | compressor.CompressionMethod = SevenZip.CompressionMethod.Lzma2;
440 | compressor.CompressionMode = SevenZip.CompressionMode.Create;
441 |
442 | compressor.CompressDirectory(sourceDir, zipFilePath);
443 |
444 | _deleteOldBackups();
445 |
446 | }
447 |
448 |
449 |
450 | }
451 | catch (Exception ex)
452 | {
453 | MainUI.addTextConsole(ex.StackTrace + " " + ex.Message + "\n");
454 | Console.ReadLine();
455 | }
456 |
457 |
458 | }
459 |
460 |
461 | private void _deleteOldBackups()
462 | {
463 | string backupDir = Path.Combine(Environment.CurrentDirectory, "savesBackup");
464 | if (!Directory.Exists(backupDir)) return; // backup directory does not exist
465 | var backupFiles = new DirectoryInfo(backupDir).GetFiles("*.7z", SearchOption.AllDirectories).OrderBy(f => f.LastWriteTime).ToList(); // get all backup files in the directory sorted by date
466 | if (backupFiles.Count < 4) return; // less than 3 backup files present
467 |
468 | backupFiles[0].Delete(); // delete the oldest backup file
469 | }
470 |
471 |
472 | public void restoreLatestBackup()
473 | {
474 | string backupDir = Path.Combine(Environment.CurrentDirectory, "savesBackup");
475 | DirectoryInfo dirInfo = new DirectoryInfo(backupDir);
476 | if (dirInfo.Exists)
477 | {
478 | FileInfo[] files = dirInfo.GetFiles("*.7z");
479 | if (files.Length > 0)
480 | {
481 | Array.Sort(files, (x, y) => y.CreationTime.CompareTo(x.CreationTime));
482 | FileInfo latestBackup = files[0];
483 | MainUI.addTextConsole("Restoring latest backup: " + latestBackup.CreationTime.ToString() + "\n");
484 | SevenZip.SevenZipExtractor extractor = new SevenZip.SevenZipExtractor(latestBackup.FullName);
485 | extractor.ExtractArchive(Path.Combine(pathApp, "nand", "user", "save"));
486 | MainUI.addTextConsole("Restore complete.\n");
487 | }
488 | else
489 | {
490 | MainUI.addTextConsole("No backup file found.\n");
491 | }
492 | }
493 | else
494 | {
495 | MainUI.addTextConsole("Backup directory does not exist.\n");
496 | }
497 | }
498 |
499 |
500 | private void initAppPath()
501 | {
502 | pathApp = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ,"yuzu");
503 |
504 | if (!Directory.Exists(pathApp))
505 | pathApp = "user";
506 | if (!Directory.Exists(pathApp))
507 | pathApp = "";
508 |
509 | }
510 |
511 |
512 | private void purgeUncessaryFiles()
513 | {
514 | MainUI.addTextConsole("Purging uncessary files...\n");
515 | //FIND all FILLS THAT BEGIN WITH yuzu-windows-msvc-source- in current directory
516 | var files = Directory.GetFiles(Environment.CurrentDirectory, "yuzu-windows-msvc-source-*");
517 | foreach (var file in files)
518 | {
519 | try
520 | {
521 | System.IO.File.Delete(file);
522 | FileInfo fileInfo = new FileInfo(file);
523 | MainUI.addTextConsole(" -Deleted " + fileInfo.Name + "\n");
524 | }
525 | catch (Exception ex)
526 | {
527 | MainUI.addTextConsole(ex.StackTrace + " " + ex.Message + "\n");
528 | Console.ReadLine();
529 | }
530 | }
531 |
532 | }
533 |
534 |
535 | public void checkUpdate()
536 | {
537 | MainUI.addTextConsole("W'll restart for updates...\n");
538 |
539 | WebClient webClient = new WebClient();
540 |
541 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
542 | {
543 | if(!File.Exists("updateUpdater.exe"))
544 | File.Delete("updateUpdater.exe");
545 | webClient.DownloadFile("https://github.com/pilout/YuzuUpdater/releases/download/updater/updateUpdater.exe", "updateUpdater.exe");
546 | }
547 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
548 | {
549 | if (!File.Exists("updateUpdater"))
550 | File.Delete("updateUpdater");
551 | webClient.DownloadFile("https://github.com/pilout/YuzuUpdater/releases/download/updater/updateUpdater", "updateUpdater");
552 | }
553 |
554 | ProcessStartInfo startInfo = null;
555 |
556 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
557 | {
558 | Process.Start("chmod", "+x updateUpdater");
559 | startInfo = new ProcessStartInfo("updateUpdater");
560 | }
561 | else
562 | startInfo = new ProcessStartInfo("updateUpdater.exe");
563 |
564 |
565 | startInfo.UseShellExecute = true;
566 | Process.Start(startInfo);
567 | Process.GetCurrentProcess().Kill();
568 | }
569 | }
570 |
571 |
572 | }
573 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Les informations générales relatives à un assembly dépendent de
6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
7 | // associées à un assembly.
8 | [assembly: AssemblyTitle("YuzuEAUpdater")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("YuzuEAUpdater")]
13 | [assembly: AssemblyCopyright("Copyright © 2023")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
23 | [assembly: Guid("7f565065-2cdb-45f1-a5a1-33fc5f52a043")]
24 |
25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
26 | //
27 | // Version principale
28 | // Version secondaire
29 | // Numéro de build
30 | // Révision
31 | //
32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
33 | // en utilisant '*', comme indiqué ci-dessous :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\netcoreapp3.1\publish\linux-x64\
10 | FileSystem
11 | <_TargetId>Folder
12 | netcoreapp3.1
13 | linux-x64
14 | true
15 | true
16 |
17 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Properties/PublishProfiles/FolderProfile1.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\netcoreapp3.1\publish\win-x64\
10 | FileSystem
11 | <_TargetId>Folder
12 | netcoreapp3.1
13 | win-x64
14 | true
15 | true
16 | false
17 |
18 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Ce code a été généré par un outil.
4 | // Version du runtime :4.0.30319.42000
5 | //
6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
7 | // le code est régénéré.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace YuzuEAUpdater.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
17 | ///
18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio.
20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
21 | // avec l'option /str ou régénérez votre projet VS.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("YuzuEAUpdater.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes
51 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | text/microsoft-resx
91 |
92 |
93 | 1.3
94 |
95 |
96 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
97 |
98 |
99 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
100 |
101 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/Release.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace YuzuEAUpdater
8 | {
9 | public class Release
10 | {
11 | public Release(string releaseVersion)
12 | {
13 |
14 | this.version = Regex.Match(releaseVersion, @""">(.*)").Groups[1].Value;
15 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
16 | this.downloadUrl = @"https://github.com/pineappleEA/pineapple-src/releases/download/" + this.version + "/Linux-Yuzu-" + this.version + ".AppImage";
17 | else
18 | this.downloadUrl = @"https://github.com/pineappleEA/pineapple-src/releases/download/" + this.version + "/Windows-Yuzu-" + this.version + ".zip";
19 |
20 |
21 | this.releaseDate = DateTime.Parse(Regex.Match(releaseVersion, @"datetime=""(.*)"">").Groups[1].Value);
22 |
23 | }
24 |
25 | public Release(string version, bool none)
26 | {
27 | if (version == null)
28 | {
29 | this.version = "EA-0";
30 | }
31 | else
32 | {
33 | this.version = "EA-" + version;
34 | }
35 |
36 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
37 | this.downloadUrl = @"https://github.com/pineappleEA/pineapple-src/releases/download/" + this.version + "/Linux-Yuzu-" + this.version + ".AppImage";
38 | else
39 | this.downloadUrl = @"https://github.com/pineappleEA/pineapple-src/releases/download/" + this.version + "/Windows-Yuzu-" + this.version + ".zip";
40 |
41 | this.releaseDate = DateTime.MinValue;
42 | }
43 |
44 | public string version;
45 | public string downloadUrl;
46 | public DateTime releaseDate;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/UI/MainUI.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Terminal.Gui;
7 |
8 | namespace YuzuEAUpdater.UI
9 | {
10 | public class MainUI
11 | {
12 | public static Label mainConsole;
13 | private static ProgressBar progressBar;
14 | private static ListView listView;
15 | private bool checkall = false;
16 | private Boolean _waitInput = false;
17 | private string _input = "";
18 | private static List linesIndex = new List();
19 |
20 | public MainUI(MainWindow window)
21 | {
22 | var MenuBar = new MenuBar();
23 | FrameView mainFram = new FrameView();
24 | FrameView switchFram = new FrameView();
25 | FrameView modFram = new FrameView();
26 | List items = new List();
27 | listView = new ListView()
28 | {
29 | X = 1,
30 | Y = 2,
31 | Height = Dim.Fill(),
32 | Width = Dim.Fill(1),
33 | //ColorScheme = Colors.TopLevel,
34 | AllowsMarking = true,
35 | AllowsMultipleSelection = true
36 | };
37 |
38 | Label labelFoundMods = new Label();
39 | labelFoundMods.X = 1;
40 | labelFoundMods.Y = 1;
41 | labelFoundMods.Text = "";
42 | Button btnDownloadMods = new Button("Install");
43 | btnDownloadMods.Visible = false;
44 | btnDownloadMods.X = Pos.Percent(60);
45 | btnDownloadMods.Y = 1;
46 | Button chkAll = new Button("Check All");
47 | chkAll.X = Pos.Right(btnDownloadMods) + 1;
48 | chkAll.Y = 1;
49 | chkAll.Visible = false;
50 | chkAll.Clicked += () =>
51 | {
52 | if (listView.Source == null)
53 | return;
54 | var i = 0;
55 | foreach (var mod in listView.Source.ToList())
56 | {
57 | listView.Source.SetMark(i, !checkall);
58 | i++;
59 | }
60 |
61 | checkall = !checkall;
62 | if (checkall)
63 | chkAll.Text = "Uncheck All";
64 | else
65 | chkAll.Text = "Check All";
66 | };
67 | Task modsTask = null;
68 | btnDownloadMods.Clicked += () =>
69 | {
70 | if (listView.Source.Count == 0 || (modsTask != null && !modsTask.IsCompleted))
71 | return;
72 |
73 | List mods = listView.Source.ToList() as List;
74 | modsTask = new Task(() =>
75 | {
76 | List markedMods = new List();
77 | var i = 0;
78 | foreach (var mod in mods)
79 | {
80 | if (listView.Source.IsMarked(i))
81 | markedMods.Add(mod);
82 | i++;
83 | }
84 |
85 | List tasks = new List();
86 | var index = 0;
87 | var nbTaskDone = 0;
88 | foreach (BananaMod mod in markedMods)
89 | {
90 | Task task = new Task(() =>
91 | {
92 | mod.download();
93 | mod.extract();
94 | lock (MainWindow.lockObj)
95 | {
96 | nbTaskDone++;
97 | progress.Report((float)nbTaskDone / (float)markedMods.Count);
98 | }
99 | });
100 | tasks.Add(task);
101 | task.Start();
102 | index++;
103 |
104 | if (index % 3 == 0)
105 | Task.WaitAll(tasks.ToArray());
106 |
107 | }
108 |
109 | Task.WaitAll(tasks.ToArray());
110 |
111 | });
112 | modsTask.Start();
113 | };
114 |
115 |
116 | var autoStartItem = new MenuItem("AutoStart Yuzu", null, null, null, null, Key.Null);
117 | Action autoStartAction = () =>
118 | {
119 | autoStartItem.Checked = !autoStartItem.Checked;
120 | window.autoStartYuzu = autoStartItem.Checked;
121 | window.setSettings();
122 | };
123 | autoStartItem.Action = autoStartAction;
124 | autoStartItem.Checked = window.autoStartYuzu;
125 | autoStartItem.CheckType = MenuItemCheckStyle.Checked;
126 |
127 |
128 | var confirmDownload = new MenuItem("Ask download", null, null, null, null, Key.Null);
129 | Action actionConfirmD = () =>
130 | {
131 | confirmDownload.Checked = !confirmDownload.Checked;
132 | window.confirmDownload = confirmDownload.Checked;
133 | window.setSettings();
134 | };
135 | confirmDownload.Action = actionConfirmD;
136 | confirmDownload.Checked = window.confirmDownload;
137 | confirmDownload.CheckType = MenuItemCheckStyle.Checked;
138 |
139 |
140 | var backupSave = new MenuItem("Backup Save at start", null, null, null, null, Key.Null);
141 | Action actionBackupSave = () =>
142 | {
143 | backupSave.Checked = !backupSave.Checked;
144 | window.backupSave = backupSave.Checked;
145 | window.setSettings();
146 | };
147 | backupSave.Action = actionBackupSave;
148 | backupSave.Checked = window.backupSave;
149 | backupSave.CheckType = MenuItemCheckStyle.Checked;
150 |
151 |
152 | var optimizePerfomance = new MenuItem("Optimise Perfomance", null, null, null, null, Key.Null);
153 | Action actionOptimizePerfomance = () =>
154 | {
155 | optimizePerfomance.Checked = !optimizePerfomance.Checked;
156 | window.optimizePerf = optimizePerfomance.Checked;
157 | window.setSettings();
158 | };
159 | optimizePerfomance.Action = actionOptimizePerfomance;
160 | optimizePerfomance.Checked = window.optimizePerf;
161 | optimizePerfomance.CheckType = MenuItemCheckStyle.Checked;
162 |
163 |
164 | var killProccessCPU = new MenuItem("Kill Proccess CPU", null, null, null, null, Key.Null);
165 | Action actionKillProccessCPU = () =>
166 | {
167 | killProccessCPU.Checked = !killProccessCPU.Checked;
168 | window.killCpuProccess = killProccessCPU.Checked;
169 | window.setSettings();
170 | };
171 | killProccessCPU.Action = actionKillProccessCPU;
172 | killProccessCPU.Checked = window.killCpuProccess;
173 | killProccessCPU.CheckType = MenuItemCheckStyle.Checked;
174 |
175 |
176 | items.Add(new MenuBarItem("[Settings]", new MenuItem[]
177 | {autoStartItem,
178 | confirmDownload,
179 | backupSave,
180 | optimizePerfomance,
181 | killProccessCPU
182 | }));
183 |
184 |
185 |
186 | window.Add(MenuBar);
187 | items.Add(new MenuBarItem("[Restore latest backup]", null, window.restoreLatestBackup));
188 | items.Add(new MenuBarItem("[Get last version]", null, window.checkUpdate));
189 |
190 | MenuBar.Menus = items.ToArray();
191 |
192 |
193 | Task t = new Task(() =>
194 | {
195 | window.scanTitlesIdAndGetName();
196 | if (window.games.Count > 0)
197 | items.Add(new MenuBarItem("[Mods]", window.games.Select(g => new MenuItem(g.name, null, () =>
198 | {
199 | Task task = new Task(() =>
200 | {
201 | g.loadMods(this.progress);
202 | modFram.Title = "Mods for " + g.name;
203 | labelFoundMods.Text = g.validBananaMods.Count + " mods found";
204 | listView.SetSource(g.validBananaMods);
205 | btnDownloadMods.Visible = true;
206 | chkAll.Visible = true;
207 | });
208 | task.Start();
209 | }, null, null, Key.Null)).ToArray()));
210 | else
211 | items.Add(new MenuBarItem("Mods", new MenuItem[] { new MenuItem("No game found", null, null, null, null, Key.Null) }));
212 | MenuBar.Menus = items.ToArray();
213 | });
214 |
215 | t.Start();
216 |
217 |
218 | mainFram.X = 0;
219 | mainFram.Y = 1;
220 | mainFram.Width = Dim.Fill();
221 | mainFram.Height = Dim.Percent(49);
222 | mainFram.Title = "Logs";
223 | mainConsole = new Label();
224 | mainConsole.X = 0;
225 | mainConsole.Y = 0;
226 | mainFram.Add(mainConsole);
227 | progressBar = new ProgressBar();
228 | progressBar.X = 0;
229 | progressBar.Y = 0;
230 | progressBar.Width = Dim.Fill();
231 | progressBar.Height = 1;
232 | progressBar.Visible = false;
233 | window.Add(mainFram);
234 |
235 | switchFram.Title = "Switch build";
236 | switchFram.X = 0;
237 | switchFram.Y = Pos.Percent(51);
238 | switchFram.Width = Dim.Percent(17);
239 | switchFram.Height = Dim.Percent(49);
240 | Label switchLabel = new Label();
241 | switchLabel.X = 0;
242 | switchLabel.Y = 0;
243 | switchLabel.Width = Dim.Fill();
244 | switchLabel.Height = 2;
245 | switchLabel.Text = "Enter build number: ";
246 | switchFram.Add(switchLabel);
247 | TextField textField = new TextField();
248 | textField.TextChanging += (args) =>
249 | {
250 | if (args.NewText.Any(c => !char.IsDigit((char)c) && !char.IsControl((char)c)))
251 | args.Cancel = true;
252 | };
253 | textField.X = 0;
254 | textField.Y = 2;
255 | textField.Width = Dim.Percent(80);
256 | textField.Height = 1;
257 | textField.Text = "";
258 | switchFram.Add(textField);
259 | Button button = new Button("Install");
260 | button.X = 0;
261 | button.Y = Pos.Bottom(textField) + 1;
262 | button.Width = Dim.Percent(50);
263 | button.Height = 1;
264 | button.Clicked += () =>
265 | {
266 | Task t = null;
267 | if (textField.Text.Length > 0 && (t == null || t.IsCompleted))
268 | {
269 | t = new Task(() =>
270 | {
271 | window.downloadRelease(new Release(textField.Text.ToString(), true));
272 | });
273 | t.Start();
274 | }
275 | };
276 | switchFram.Add(button);
277 |
278 | modFram.Title = "Mods";
279 | modFram.X = Pos.Percent(18);
280 | modFram.Y = Pos.Percent(51);
281 | modFram.Width = Dim.Fill();
282 | modFram.Height = Dim.Percent(49);
283 | modFram.Visible = true;
284 | modFram.Add(labelFoundMods);
285 | modFram.Add(listView);
286 | modFram.Add(btnDownloadMods);
287 | modFram.Add(chkAll);
288 | listView.RowRender += ListView_RowRender;
289 |
290 | var _scrollBar = new ScrollBarView(listView, true);
291 |
292 | _scrollBar.ChangedPosition += () => {
293 | listView.TopItem = _scrollBar.Position;
294 | if (listView.TopItem != _scrollBar.Position)
295 | {
296 | _scrollBar.Position = listView.TopItem;
297 | }
298 | listView.SetNeedsDisplay();
299 | };
300 |
301 | _scrollBar.OtherScrollBarView.ChangedPosition += () => {
302 | listView.LeftItem = _scrollBar.OtherScrollBarView.Position;
303 | if (listView.LeftItem != _scrollBar.OtherScrollBarView.Position)
304 | {
305 | _scrollBar.OtherScrollBarView.Position = listView.LeftItem;
306 | }
307 | listView.SetNeedsDisplay();
308 | };
309 |
310 | listView.DrawContent += (e) => {
311 | if (listView.Source != null)
312 | {
313 | _scrollBar.Size = listView.Source.Count - 1;
314 | _scrollBar.Position = listView.TopItem;
315 | _scrollBar.OtherScrollBarView.Size = listView.Maxlength - 1;
316 | _scrollBar.OtherScrollBarView.Position = listView.LeftItem;
317 | _scrollBar.Refresh();
318 | }
319 | };
320 |
321 |
322 | window.Add(switchFram);
323 | window.Add(modFram);
324 | window.Add(progressBar);
325 | Application.RootKeyEvent += Application_RootKeyEvent;
326 | }
327 |
328 |
329 | private void ListView_RowRender(ListViewRowEventArgs obj)
330 | {
331 | if (obj.Row == listView.SelectedItem)
332 | {
333 | return;
334 | }
335 | if (listView.AllowsMarking && listView.Source.IsMarked(obj.Row))
336 | {
337 | obj.RowAttribute = new Terminal.Gui.Attribute(Color.BrightRed, Color.BrightYellow);
338 | return;
339 | }
340 | if (obj.Row % 2 == 0)
341 | {
342 | obj.RowAttribute = new Terminal.Gui.Attribute(Color.BrightGreen, Color.Magenta);
343 | }
344 | else
345 | {
346 | obj.RowAttribute = new Terminal.Gui.Attribute(Color.BrightMagenta, Color.Green);
347 | }
348 | }
349 |
350 |
351 | public IProgress progress
352 | {
353 | get; set;
354 |
355 | } = new Progress(p => {
356 | if (progressBar.Visible == false)
357 | {
358 | progressBar.Y = progressBar.SuperView.Bounds.Bottom - 1;
359 | progressBar.Visible = true;
360 | }
361 |
362 | progressBar.Fraction = p;
363 |
364 | if (p == 1)
365 | progressBar.Visible = false;
366 | });
367 |
368 |
369 | public static void addTextConsole(String text)
370 | {
371 |
372 | int[] indexs = text.Select((b, i) => b == '\n' ? i + mainConsole.Text.Length : -1).Where(i => i != -1).ToArray();
373 | linesIndex.AddRange(indexs);
374 |
375 | Application.MainLoop.Invoke(() =>
376 | {
377 | mainConsole.Text += (text);
378 |
379 | if (mainConsole.SuperView.Bounds.Height > 0)
380 | {
381 | while (linesIndex.Count > 0 && (mainConsole.Frame.Bottom) > mainConsole.SuperView.Bounds.Height)
382 | {
383 | var index = linesIndex.First();
384 |
385 | if (index < mainConsole.Text.Length && index >0)
386 | mainConsole.Text = mainConsole.Text.Substring(index);
387 | else if(index >0)
388 | mainConsole.Text = "";
389 |
390 | linesIndex.RemoveAt(0);
391 |
392 | foreach (var l in linesIndex.ToList())
393 | {
394 | linesIndex[linesIndex.IndexOf(l)] = l - index;
395 | }
396 |
397 | }
398 | }
399 |
400 |
401 | mainConsole.SetNeedsDisplay();
402 | });
403 | }
404 |
405 |
406 | private bool Application_RootKeyEvent(KeyEvent arg)
407 | {
408 | if (_waitInput && MainUI.mainConsole.SuperView.SuperView.Visible)
409 | {
410 | if (arg.Key == Key.Enter)
411 | {
412 | _waitInput = false;
413 | addTextConsole("\n");
414 | }
415 | else if (arg.Key == Key.DeleteChar || arg.Key == Key.Backspace)
416 | {
417 | if (_input.Length >= 1)
418 | {
419 | MainUI.mainConsole.Text = MainUI.mainConsole.Text.Substring(0, MainUI.mainConsole.Text.Length - 1);
420 | _input = _input.Substring(0, _input.Length - 1);
421 | }
422 |
423 | }
424 | else if (!char.IsControl((char)arg.Key))
425 | {
426 |
427 | addTextConsole(((char)arg.Key).ToString());
428 | _input += ((char)arg.Key).ToString();
429 |
430 | }
431 | return true;
432 | }
433 | return false;
434 | }
435 |
436 | public async Task waitInput()
437 | {
438 | addTextConsole("\n");
439 | _waitInput = true;
440 | while (_waitInput)
441 | {
442 | await Task.Delay(100);
443 | }
444 | var temp = _input;
445 | _input = "";
446 | return temp;
447 | }
448 | }
449 |
450 | }
451 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/YuzuEAUpdater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp3.1
4 | Exe
5 | false
6 | YuzuEAUpdater.Program
7 | False
8 | embedded
9 | win-x64;linux-x64
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/YuzuEAUpdater/ZipExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.IO.Compression;
8 | using System.Net.Security;
9 | using System.Net;
10 | using System.Runtime.InteropServices;
11 | using SevenZip;
12 | using System.Net.Http;
13 | using System.Threading;
14 | using System.Diagnostics;
15 | using System.ServiceProcess;
16 |
17 | namespace YuzuEAUpdater
18 | {
19 | public static class Utils
20 | {
21 | public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
22 | {
23 |
24 | if (!overwrite)
25 | {
26 | archive.ExtractToDirectory(destinationDirectoryName);
27 | return;
28 | }
29 |
30 | DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
31 | string destinationDirectoryFullPath = di.FullName;
32 |
33 | foreach (ZipArchiveEntry file in archive.Entries)
34 | {
35 | string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));
36 | string directory = Path.GetDirectoryName(completeFileName);
37 |
38 | if (!Directory.Exists(directory))
39 | {
40 | Directory.CreateDirectory(directory);
41 | }
42 |
43 | if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
44 | {
45 | throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
46 | }
47 |
48 |
49 |
50 | if (file.Name == "")
51 | {// Assuming Empty for Directory
52 | Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
53 | continue;
54 | }
55 |
56 | file.ExtractToFile(completeFileName, true);
57 |
58 | }
59 | }
60 |
61 | public static void DirectoryCopyAndDelete(string strSource, string Copy_dest)
62 | {
63 | DirectoryInfo dirInfo = new DirectoryInfo(strSource);
64 |
65 | DirectoryInfo[] directories = dirInfo.GetDirectories();
66 |
67 | FileInfo[] files = dirInfo.GetFiles();
68 |
69 | foreach (DirectoryInfo tempdir in directories)
70 | {
71 |
72 | Directory.CreateDirectory(Copy_dest + "/" + tempdir.Name);// creating the Directory
73 |
74 | var ext = System.IO.Path.GetExtension(tempdir.Name);
75 |
76 | if (System.IO.Path.HasExtension(ext))
77 | {
78 | foreach (FileInfo tempfile in files)
79 | {
80 | tempfile.CopyTo(Path.Combine(strSource + "/" + tempfile.Name, Copy_dest + "/" + tempfile.Name),true);
81 | File.Delete(tempfile.FullName);
82 | }
83 | }
84 | DirectoryCopyAndDelete(strSource + "/" + tempdir.Name, Copy_dest + "/" + tempdir.Name);
85 | }
86 |
87 | FileInfo[] files1 = dirInfo.GetFiles();
88 |
89 | foreach (FileInfo tempfile in files1)
90 | {
91 | tempfile.CopyTo(Path.Combine(Copy_dest, tempfile.Name),true);
92 | File.Delete(tempfile.FullName);
93 |
94 | }
95 | Directory.Delete(dirInfo.FullName);
96 | }
97 |
98 |
99 | public static void init7ZipPaht()
100 | {
101 | var platForm = RuntimeInformation.OSArchitecture;
102 | var OS = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "Linux" : RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "Windows" : "MacOS";
103 | bool check = File.Exists(Path.Combine(Environment.CurrentDirectory, "7zip", OS == "Windows" ? "win32" : "linux", platForm == Architecture.X64 ? "x64" : platForm == Architecture.Arm64 ? "arm64" : platForm == Architecture.Arm ? "arm" : "ia32", OS == "Windows" ? "7za.dll" : "7zz"));
104 | SevenZipBase.SetLibraryPath(Path.Combine(Environment.CurrentDirectory, "7zip", OS == "Windows" ? "win32" : "linux", platForm == Architecture.X64 ? "x64" : platForm == Architecture.Arm64 ? "arm64" : platForm == Architecture.Arm ? "arm" : "ia32", OS == "Windows" ? "7za.dll" : "7zz"));
105 | }
106 |
107 |
108 | public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress progress = null, CancellationToken cancellationToken = default)
109 | {
110 | // Get the http headers first to examine the content length
111 | using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead))
112 | {
113 | var contentLength = response.Content.Headers.ContentLength;
114 |
115 | using (var download = await response.Content.ReadAsStreamAsync())
116 | {
117 |
118 | // Ignore progress reporting when no progress reporter was
119 | // passed or when the content length is unknown
120 | if (progress == null || !contentLength.HasValue)
121 | {
122 | await download.CopyToAsync(destination);
123 | return;
124 | }
125 |
126 | // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
127 | var relativeProgress = new Progress(totalBytes => progress.Report((float)totalBytes / contentLength.Value));
128 | // Use extension method to report progress while downloading
129 | await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken);
130 | progress.Report(1);
131 | }
132 | }
133 | }
134 |
135 | public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress = null, CancellationToken cancellationToken = default)
136 | {
137 | if (source == null)
138 | throw new ArgumentNullException(nameof(source));
139 | if (!source.CanRead)
140 | throw new ArgumentException("Has to be readable", nameof(source));
141 | if (destination == null)
142 | throw new ArgumentNullException(nameof(destination));
143 | if (!destination.CanWrite)
144 | throw new ArgumentException("Has to be writable", nameof(destination));
145 | if (bufferSize < 0)
146 | throw new ArgumentOutOfRangeException(nameof(bufferSize));
147 |
148 | var buffer = new byte[bufferSize];
149 | long totalBytesRead = 0;
150 | int bytesRead;
151 | while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
152 | {
153 | await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
154 | totalBytesRead += bytesRead;
155 | progress?.Report(totalBytesRead);
156 | }
157 | }
158 |
159 |
160 | public static void setAffinityMask(Process p)
161 | {
162 | // Récupération du nombre de processeurs logiques sur le système
163 | int processorCount = Environment.ProcessorCount;
164 |
165 | if (processorCount < 5)
166 | return;
167 |
168 | // Calcul du masque d'affinité en utilisant tous les threads disponibles
169 | long affinityMask = 0;
170 | for (int i = 0; i < processorCount; i++)
171 | {
172 | if (i % 2 == 0) // Activer chaque autre thread
173 | {
174 | affinityMask |= 1L << i;
175 | }
176 | }
177 | p.ProcessorAffinity= (IntPtr)affinityMask;
178 | }
179 |
180 | public static void SetPowerSavingMode(bool enable)
181 | {
182 | try
183 | {
184 | const int SC_MONITORPOWER = 0xF170;
185 | const int WM_SYSCOMMAND = 0x0112;
186 |
187 | IntPtr HWND_BROADCAST = new IntPtr(0xffff);
188 |
189 | int monitorState = enable ? 2 : -1; // 2 = POWER_ON, -1 = POWER_OFF
190 |
191 | NativeMethods.SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, monitorState);
192 | }
193 | catch (Exception ex)
194 | {
195 | Console.WriteLine("Error setting power saving mode: " + ex.Message);
196 | }
197 | }
198 |
199 |
200 | public static void KillProcessesByCpuUsage(float cpuUsageThreshold)
201 | {
202 | Process[] processes = Process.GetProcesses();
203 | String[] ignoreProcessNames = new string[] { "explorer", "taskmgr", "System", "Idle" };
204 |
205 | foreach (Process process in processes)
206 | {
207 | try
208 | {
209 | if (process.Id == Process.GetCurrentProcess().Id || ignoreProcessNames.Contains(process.ProcessName))
210 | continue;
211 |
212 | if (process.TotalProcessorTime.TotalSeconds > TimeSpan.FromSeconds(cpuUsageThreshold).TotalSeconds)
213 | {
214 | UI.MainUI.addTextConsole($"Terminating process: {process.ProcessName} (ID: {process.Id})\n");
215 | process.Kill();
216 |
217 | }
218 | }
219 | catch (Exception ex)
220 | {
221 | Console.WriteLine($"Error terminating process: {process.ProcessName} (ID: {process.Id})");
222 | Console.WriteLine(ex.Message);
223 | }
224 | }
225 | }
226 |
227 |
228 |
229 |
230 | internal static class NativeMethods
231 | {
232 | [System.Runtime.InteropServices.DllImport("user32.dll")]
233 | internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
234 | }
235 | }
236 | }
237 |
--------------------------------------------------------------------------------