From 98c12d46f0822872e9e1b44e2fb6c45f396a15aa Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Wed, 19 Jul 2023 20:08:08 +0100
Subject: [PATCH 01/57] added more visible error messages to avoid user
 confusion

added hard drive free space detection, added red error message text, removed overwrite checkbox, added wiki button link

extended the error text for starting wabbajack in protected location

removed debug code

shortened error message to fit in text box
---
 .../View Models/Installers/InstallerVM.cs     | 52 +++++++++++++++++--
 .../View Models/Installers/MO2InstallerVM.cs  |  4 --
 .../Installers/InstallationCompleteView.xaml  | 30 +++++++++--
 .../InstallationCompleteView.xaml.cs          |  3 ++
 .../InstallationConfigurationView.xaml        |  7 +++
 .../InstallationConfigurationView.xaml.cs     |  7 ++-
 .../Installers/MO2InstallerConfigView.xaml    | 16 ------
 .../ConfirmUpdateOfExistingInstallView.xaml   |  7 ---
 ...ConfirmUpdateOfExistingInstallView.xaml.cs |  5 --
 .../ViewModels/MainWindowViewModel.cs         |  3 +-
 10 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index c5198d133..d09683fe0 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -35,6 +35,8 @@
 using Wabbajack.Services.OSIntegrated;
 using Wabbajack.Util;
 using System.Windows.Forms;
+using System.Web;
+using System.Diagnostics;
 
 namespace Wabbajack;
 
@@ -140,6 +142,7 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
     // Command properties
     public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; }
     public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; }
+    public ReactiveCommand<Unit, Unit> OpenWikiCommand { get; }
     public ReactiveCommand<Unit, Unit> OpenDiscordButton { get; }
     public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; }
         
@@ -178,6 +181,11 @@ public InstallerVM(ILogger<InstallerVM> logger, DTOSerializer dtos, SettingsMana
             UIUtils.OpenWebsite(new Uri(ModList!.Readme));
         }, this.WhenAnyValue(vm => vm.LoadingLock.IsNotLoading, vm => vm.ModList.Readme, (isNotLoading, readme) => isNotLoading && !string.IsNullOrWhiteSpace(readme)));
 
+        OpenWikiCommand = ReactiveCommand.Create(() =>
+        {
+            UIUtils.OpenWebsite(new Uri("https://wiki.wabbajack.org/index.html"));
+        }, this.WhenAnyValue(vm => vm.LoadingLock.IsNotLoading));
+
         VisitModListWebsiteCommand = ReactiveCommand.Create(() =>
         {
             UIUtils.OpenWebsite(ModList!.Website);
@@ -280,6 +288,10 @@ private IEnumerable<ErrorResponse> Validate()
         {
             yield return ErrorResponse.Fail("Can't have identical install and download folders");
         }
+        if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && KnownFolders.IsSubDirectoryOf(installPath.ToString(), downloadPath.ToString()))
+        {
+            yield return ErrorResponse.Fail("Can't put the install folder inside the download folder");
+        }
         foreach (var game in GameRegistry.Games)
         {
             if (!_gameLocator.TryFindLocation(game.Key, out var location))
@@ -305,11 +317,12 @@ private IEnumerable<ErrorResponse> Validate()
         }
 
         if (installPath.ToString().Length != 0 && installPath != LastInstallPath &&
-            !Installer.AutomaticallyOverwrite &&
             Directory.EnumerateFileSystemEntries(installPath.ToString()).Any())
         {
             string message =
-                "There are existing files in the chosen install path, they will be deleted or overwritten (if updating existing modlist), continue?";
+                "There are files already in the chosen install path, if you are updating an existing modlist, this is fine. " + Environment.NewLine + 
+                " Otherwise, please ensure you intend for the folder contents to be deleted during the modlist install." + Environment.NewLine +
+                " Continue? ";
             string title = "Files found in install folder";
             MessageBoxButtons buttons = MessageBoxButtons.YesNo;
             DialogResult result = MessageBox.Show(message, title, buttons);
@@ -325,10 +338,43 @@ private IEnumerable<ErrorResponse> Validate()
 
         if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))
         {
-            yield return ErrorResponse.Fail("Can't install a modlist into Windows protected locations - such as Downloads, Documents etc");
+            yield return ErrorResponse.Fail("Can't install a modlist into Windows protected locations - such as Downloads,Documents etc, please make a new folder for the modlist.");
+        }
+
+        if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){
+            yield return ErrorResponse.Fail("Can't install modlist due to lack of free hard drive space, please read the modlist Readme to learn more.");
         }
     }
     
+    private bool HasEnoughSpace(AbsolutePath inpath, AbsolutePath downpath)
+    {      
+        string driveLetterInPath = inpath.ToString().Substring(0,1);
+        string driveLetterDownPath = inpath.ToString().Substring(0,1);
+        DriveInfo driveUsedInPath = new DriveInfo(driveLetterInPath);
+        DriveInfo driveUsedDownPath = new DriveInfo(driveLetterDownPath);
+        long spaceRequiredforInstall = ModlistMetadata.DownloadMetadata.SizeOfInstalledFiles;
+        long spaceRequiredforDownload = ModlistMetadata.DownloadMetadata.SizeOfArchives;
+        long spaceInstRemaining = driveUsedInPath.AvailableFreeSpace;
+        long spaceDownRemaining = driveUsedDownPath.AvailableFreeSpace;
+        if ( driveLetterInPath == driveLetterDownPath)
+        {
+            long totalSpaceRequired = spaceRequiredforInstall + spaceRequiredforDownload;
+            if (spaceInstRemaining < totalSpaceRequired)
+            {
+                return false;
+            }
+
+        } else
+        {
+            if( spaceInstRemaining < spaceRequiredforInstall || spaceDownRemaining < spaceRequiredforDownload)
+            {
+                return false;
+            }
+        }
+        return true;
+
+    }
+
     private async Task BeginSlideShow(CancellationToken token)
     {
         while (!token.IsCancellationRequested)
diff --git a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs
index 8e87a272d..c4f2e93d1 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
@@ -39,9 +39,6 @@ public class MO2InstallerVM : ViewModel, ISubInstallerVM
 
         public bool SupportsAfterInstallNavigation => true;
 
-        [Reactive]
-        public bool AutomaticallyOverwrite { get; set; }
-
         public int ConfigVisualVerticalOffset => 25;
 
         public MO2InstallerVM(InstallerVM installerVM)
@@ -166,7 +163,6 @@ private void SaveSettings(Mo2ModlistInstallationSettings settings)
             if (settings == null) return;
             settings.InstallationLocation = Location.TargetPath;
             settings.DownloadLocation = DownloadLocation.TargetPath;
-            settings.AutomaticallyOverrideExistingInstall = AutomaticallyOverwrite;
         }
 
         public void AfterInstallNavigation()
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml b/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml
index 74284763b..f76f9d150 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml
@@ -12,7 +12,7 @@
     x:TypeArguments="local:InstallerVM"
     mc:Ignorable="d">
     <local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True">
-        <Grid Margin="5">
+        <Grid Margin="6">
             <Grid.RowDefinitions>
                 <RowDefinition Height="*" />
                 <RowDefinition Height="3*" />
@@ -23,6 +23,7 @@
                 <ColumnDefinition Width="*" />
                 <ColumnDefinition Width="*" />
                 <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="*" />
             </Grid.ColumnDefinitions>
             <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5"
                 x:Name="TitleText"
@@ -124,11 +125,34 @@
                 <TextBlock Grid.Row="1"
                     Margin="0,10,0,0"
                     HorizontalAlignment="Center"
-                    Text="Readme" />
+                    Text="Modlist Readme" />
             </Grid>
             <Grid Grid.Row="1" Grid.Column="4"
+                VerticalAlignment="Center"
+                Background="Transparent">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <Button
+                    x:Name="OpenWikiButton"
+                    Width="50"
+                    Height="50"
+                    Style="{StaticResource CircleButtonStyle}">
+                    <icon:PackIconFontAwesome
+                        Width="25"
+                        Height="25"
+                        Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
+                        Kind="QuestionSolid" />
+                </Button>
+                <TextBlock Grid.Row="1"
+                    Margin="0,10,0,0"
+                    HorizontalAlignment="Center"
+                    Text="Help and Wiki" />
+            </Grid>
+            <Grid Grid.Row="1" Grid.Column="5"
                   VerticalAlignment="Center"
-                  Background="Transparent">
+                  Background="Transparent" Grid.ColumnSpan="2" Margin="0,0,10,0">
                 <Grid.RowDefinitions>
                     <RowDefinition Height="Auto" />
                     <RowDefinition Height="Auto" />
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml.cs b/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml.cs
index d2e70061b..b4000b86d 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationCompleteView.xaml.cs
@@ -46,6 +46,9 @@ public InstallationCompleteView()
                 this.WhenAny(x => x.ViewModel.OpenReadmeCommand)
                     .BindToStrict(this, x => x.OpenReadmeButton.Command)
                     .DisposeWith(dispose);
+                this.WhenAny(x => x.ViewModel.OpenWikiCommand)
+                    .BindToStrict(this, x => x.OpenWikiButton.Command)
+                    .DisposeWith(dispose);
                 this.WhenAny(x => x.ViewModel.CloseWhenCompleteCommand)
                     .BindToStrict(this, x => x.CloseButton.Command)
                     .DisposeWith(dispose);
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
index 225346f0d..5cd461c9c 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
@@ -39,6 +39,13 @@
                 FontSize="14"
                 Text="Target Modlist"
                 TextAlignment="Center" />
+            <TextBlock x:Name="errorTextBox"
+                Grid.Row="3"
+                FontFamily="Verdana" FontSize="10" FontWeight="ExtraBold"
+                Background="{StaticResource WindowBackgroundBrush}"
+                Foreground="Red"
+                Text=""
+                TextAlignment="Left" Margin="0,79,0,-45" Grid.ColumnSpan="3" />
             <local:FilePicker Grid.Row="1" Grid.Column="2"
                 x:Name="ModListLocationPicker"
                 Height="30"
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
index 121da58f1..a69a7450a 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
@@ -46,7 +46,12 @@ public InstallationConfigurationView()
                     .Select(v => !v.Failed)
                     .BindToStrict(this, view => view.BeginButton.IsEnabled)
                     .DisposeWith(dispose);
-                
+
+                this.WhenAnyValue(x => x.ViewModel.ErrorState)
+                    .Select(v => v.Reason)
+                    .BindToStrict(this, view => view.errorTextBox.Text)
+                    .DisposeWith(dispose);
+
                 this.WhenAnyValue(x => x.ViewModel.ErrorState)
                     .Select(v => v.Failed ? Visibility.Visible : Visibility.Hidden)
                     .BindToStrict(this, view => view.ErrorSummaryIcon.Visibility)
diff --git a/Wabbajack.App.Wpf/Views/Installers/MO2InstallerConfigView.xaml b/Wabbajack.App.Wpf/Views/Installers/MO2InstallerConfigView.xaml
index 5561d7fd3..f47095f33 100644
--- a/Wabbajack.App.Wpf/Views/Installers/MO2InstallerConfigView.xaml
+++ b/Wabbajack.App.Wpf/Views/Installers/MO2InstallerConfigView.xaml
@@ -46,21 +46,5 @@
             FontSize="14"
             PickerVM="{Binding DownloadLocation}"
             ToolTip="The directory where modlist archives will be downloaded to" />
-        <CheckBox Grid.Row="2" Grid.Column="2"
-            HorizontalAlignment="Right"
-            Content="Overwrite Installation"
-            IsChecked="{Binding AutomaticallyOverwrite}"
-            ToolTip="If installing over an existing installation, automatically replace it without asking permission.">
-            <CheckBox.Style>
-                <Style TargetType="CheckBox">
-                    <Setter Property="Opacity" Value="0.6" />
-                    <Style.Triggers>
-                        <DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
-                            <Setter Property="Opacity" Value="1" />
-                        </DataTrigger>
-                    </Style.Triggers>
-                </Style>
-            </CheckBox.Style>
-        </CheckBox>
     </Grid>
 </UserControl>
diff --git a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
index 60620f632..de4ff6b92 100644
--- a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
+++ b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
@@ -33,13 +33,6 @@
         <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
             x:Name="ExtendedDescription"
             TextWrapping="WrapWithOverflow" />
-        <CheckBox Grid.Row="2" Grid.Column="2"
-            x:Name="AutoOverwriteCheckbox"
-            Margin="4"
-            HorizontalAlignment="Right"
-            Content="Remember"
-            IsChecked="{Binding Installer.AutomaticallyOverwrite}"
-            ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." />
         <Button Grid.Row="3" Grid.Column="0"
             x:Name="CancelButton"
             Content="Cancel" />
diff --git a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs
index 093eb3eba..956e5b789 100644
--- a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs
@@ -40,11 +40,6 @@ public ConfirmUpdateOfExistingInstallView()
                 this.WhenAny(x => x.ViewModel.Source.CancelCommand)
                     .BindToStrict(this, x => x.CancelButton.Command)
                     .DisposeWith(dispose);
-
-                this.BindStrict(this.ViewModel, x => x.Installer.AutomaticallyOverwrite, x => x.AutoOverwriteCheckbox.IsChecked,
-                        vmToViewConverter: x => x,
-                        viewToVmConverter: x => x ?? false)
-                    .DisposeWith(dispose);
             });
         }
     }
diff --git a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
index 5b2c514b0..31a3f4790 100644
--- a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
+++ b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
@@ -22,7 +22,6 @@
 using Wabbajack.Networking.NexusApi;
 using Wabbajack.Paths;
 using Wabbajack.Paths.IO;
-#pragma warning disable SYSLIB0014
 
 namespace Wabbajack.Launcher.ViewModels;
 
@@ -231,7 +230,7 @@ private async Task VerifyCurrentLocation()
                         ShowInCenter = true,
                         ContentTitle = "Wabbajack Launcher: Bad startup path",
                         ContentMessage =
-                            "Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder."
+                            "Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder, creating a new folder if necessary ( example : C:\\Wabbajack\\, outside of these locations."
                     });
                 var result = await msg.Show();
                 Environment.Exit(1);

From 5b8e3725c6ff5b9da8ec51616e75f32a17f73db7 Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Wed, 19 Jul 2023 23:27:12 +0100
Subject: [PATCH 02/57] restored warning removed in error, updated changelog,
 removed debug includes

---
 CHANGELOG.md                                            | 3 +++
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs | 2 --
 Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs    | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39672fa43..50b7207a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ### Changelog
 
+### Version - TBA
+  * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, drive space checking, wiki link button
+
 #### Version - 3.2.0.0 - 7/16/2023
   * Fixed issues related to high RAM usage
   * The resumable downloads now reserve drive space to write to in advance instead of being managed in system RAM
diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index d09683fe0..d7fdd8d50 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -35,8 +35,6 @@
 using Wabbajack.Services.OSIntegrated;
 using Wabbajack.Util;
 using System.Windows.Forms;
-using System.Web;
-using System.Diagnostics;
 
 namespace Wabbajack;
 
diff --git a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
index 31a3f4790..76f06b4e9 100644
--- a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
+++ b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
@@ -22,6 +22,7 @@
 using Wabbajack.Networking.NexusApi;
 using Wabbajack.Paths;
 using Wabbajack.Paths.IO;
+#pragma warning disable SYSLIB0014
 
 namespace Wabbajack.Launcher.ViewModels;
 

From b6d4b5d1acb5b5b351891dc1d155674dd6a0afe0 Mon Sep 17 00:00:00 2001
From: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com>
Date: Wed, 26 Jul 2023 09:56:56 +0100
Subject: [PATCH 03/57] Update InstallerVM.cs

---
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index d7fdd8d50..20a19f6c9 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -336,7 +336,7 @@ private IEnumerable<ErrorResponse> Validate()
 
         if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))
         {
-            yield return ErrorResponse.Fail("Can't install a modlist into Windows protected locations - such as Downloads,Documents etc, please make a new folder for the modlist.");
+            yield return ErrorResponse.Fail("Can't install into Windows locations such as Documents etc, please make a new folder for the modlist - C:\Wabbajack\ for example.");
         }
 
         if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){
@@ -595,4 +595,4 @@ private async Task PopulateNextModSlide(ModList modList)
         }
     }
 
-}
\ No newline at end of file
+}

From b71003d829be91ac4654c9159358c52c20089b20 Mon Sep 17 00:00:00 2001
From: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com>
Date: Wed, 26 Jul 2023 10:02:32 +0100
Subject: [PATCH 04/57] Update InstallerVM.cs

---
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index 20a19f6c9..d0869e3ac 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -336,7 +336,7 @@ private IEnumerable<ErrorResponse> Validate()
 
         if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))
         {
-            yield return ErrorResponse.Fail("Can't install into Windows locations such as Documents etc, please make a new folder for the modlist - C:\Wabbajack\ for example.");
+            yield return ErrorResponse.Fail("Can't install into Windows locations such as Documents etc, please make a new folder for the modlist - C:\\ModList\\ for example.");
         }
 
         if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){

From cc76e3c699c16b22467b5a7d3de402f7b84f269f Mon Sep 17 00:00:00 2001
From: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com>
Date: Wed, 26 Jul 2023 10:05:42 +0100
Subject: [PATCH 05/57] Update MainWindowViewModel.cs

---
 Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
index 76f06b4e9..75472aa30 100644
--- a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
+++ b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
@@ -231,7 +231,7 @@ private async Task VerifyCurrentLocation()
                         ShowInCenter = true,
                         ContentTitle = "Wabbajack Launcher: Bad startup path",
                         ContentMessage =
-                            "Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder, creating a new folder if necessary ( example : C:\\Wabbajack\\, outside of these locations."
+                            "Cannot start in the root of a drive, or protected folder locations such as Downloads, Desktop etc.\nPlease move Wabbajack to another folder, creating a new folder if necessary ( example : C:\\Wabbajack\\), outside of these locations."
                     });
                 var result = await msg.Show();
                 Environment.Exit(1);

From 4d688b7ab91682aebdd0c6eaf4c761d030abd721 Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Sun, 30 Jul 2023 00:43:33 +0100
Subject: [PATCH 06/57] added json optional flag to only show version number
 over modlist image in installer view, if the modlist image already contains
 the title

removed debug code

change to pascal case and match existing code style

update changelog
---
 CHANGELOG.md                                             | 3 +++
 .../View Models/Gallery/ModListMetadataVM.cs             | 9 +++++++++
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs  | 9 ++++++++-
 Wabbajack.DTOs/ModList/ModListMetadata.cs                | 2 ++
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 247c9e6fe..f3f4dd057 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ### Changelog
 
+#### Version - TBA
+  * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
+
 #### Version - 3.2.0.1 - 7/23/2023
   * Code cleanup: re-added some network and diagnostic code missing since 2.5
 
diff --git a/Wabbajack.App.Wpf/View Models/Gallery/ModListMetadataVM.cs b/Wabbajack.App.Wpf/View Models/Gallery/ModListMetadataVM.cs
index 3bd14e441..93cce20c5 100644
--- a/Wabbajack.App.Wpf/View Models/Gallery/ModListMetadataVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Gallery/ModListMetadataVM.cs	
@@ -82,6 +82,13 @@ public class ModListMetadataVM : ViewModel
         [Reactive]
         public string VersionText { get; private set; }
 
+        [Reactive]
+        public bool ImageContainsTitle { get; private set; }
+
+        [Reactive]
+
+        public bool DisplayVersionOnlyInInstallerView { get; private set; }
+
         [Reactive]
         public IErrorResponse Error { get; private set; }
 
@@ -123,6 +130,8 @@ public ModListMetadataVM(ILogger logger, ModListGalleryVM parent, ModlistMetadat
                     Metadata.DownloadMetadata.SizeOfArchives + Metadata.DownloadMetadata.SizeOfInstalledFiles
                 );
             VersionText = "Modlist version : " + Metadata.Version;
+            ImageContainsTitle = Metadata.ImageContainsTitle;
+            DisplayVersionOnlyInInstallerView = Metadata.DisplayVersionOnlyInInstallerView;
             IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown;
             // https://www.wabbajack.org/modlist/wj-featured/aldrnari
             OpenWebsiteCommand = ReactiveCommand.Create(() => UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlist/{Metadata.NamespacedName}")));
diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index c5198d133..838bcf299 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -521,7 +521,14 @@ class SavedInstallSettings
 
     private void PopulateSlideShow(ModList modList)
     {
-        SlideShowTitle = modList.Name;
+        if (ModlistMetadata.ImageContainsTitle && ModlistMetadata.DisplayVersionOnlyInInstallerView)
+        {
+            SlideShowTitle = "v" + ModlistMetadata.Version.ToString();
+        }
+        else
+        {
+            SlideShowTitle = modList.Name;
+        }
         SlideShowAuthor = modList.Author;
         SlideShowDescription = modList.Description;
         SlideShowImage = ModListImage;
diff --git a/Wabbajack.DTOs/ModList/ModListMetadata.cs b/Wabbajack.DTOs/ModList/ModListMetadata.cs
index fbb27dab1..df3bfd507 100644
--- a/Wabbajack.DTOs/ModList/ModListMetadata.cs
+++ b/Wabbajack.DTOs/ModList/ModListMetadata.cs
@@ -30,6 +30,8 @@ public class ModlistMetadata
     [JsonPropertyName("image_contains_title")]
     public bool ImageContainsTitle { get; set; }
 
+    [JsonPropertyName("DisplayVersionOnlyInInstallerView")] public bool DisplayVersionOnlyInInstallerView { get; set; }
+
     [JsonPropertyName("force_down")] public bool ForceDown { get; set; }
 
     [JsonPropertyName("links")] public LinksObject Links { get; set; } = new();

From ae7402be581389caa63374d067968f1dfad66bf1 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Wed, 9 Aug 2023 21:03:56 +0200
Subject: [PATCH 07/57] Fix manual downloads sometimes launching in browser

---
 .../UserIntervention/ManualDownloadHandler.cs     | 15 ++++++---------
 .../View Models/BrowserWindowViewModel.cs         |  4 +++-
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
index 6bf219c11..003099bfd 100644
--- a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
+++ b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
@@ -1,10 +1,7 @@
-using System.Security.Policy;
 using System.Threading;
 using System.Threading.Tasks;
-using Wabbajack.DTOs;
 using Wabbajack.DTOs.DownloadStates;
 using Wabbajack.DTOs.Interventions;
-using Wabbajack.Paths;
 
 namespace Wabbajack.UserIntervention;
 
@@ -17,18 +14,18 @@ protected override async Task Run(CancellationToken token)
         //await WaitForReady();
         var archive = Intervention.Archive;
         var md = Intervention.Archive.State as Manual;
-        
+
         HeaderText = $"Manual download ({md.Url.Host})";
-        
-        Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt;
-        await NavigateTo(md.Url);
 
+        Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt;
 
-        var uri = await WaitForDownloadUri(token, async () =>
+        var task = WaitForDownloadUri(token, async () =>
         {
             await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => f.remove())");
         });
-        
+        await NavigateTo(md.Url);
+        var uri = await task;
+
         Intervention.Finish(uri);
     }
 }
\ No newline at end of file
diff --git a/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs b/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs
index b74cdd993..bd05085ce 100644
--- a/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs	
+++ b/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs	
@@ -112,11 +112,13 @@ public async Task<HtmlDocument> GetDom(CancellationToken token)
     {
         var source = new TaskCompletionSource<Uri>();
         var referer = _browser.Source;
+        while (_browser.CoreWebView2 == null)
+            await Task.Delay(10, token);
+
         _browser.CoreWebView2.DownloadStarting += (sender, args) =>
         {
             try
             {
-                
                 source.SetResult(new Uri(args.DownloadOperation.Uri));
             }
             catch (Exception)

From 6399ef07d501c9746f01ebb471d32c0419be2cde Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Wed, 9 Aug 2023 21:05:20 +0200
Subject: [PATCH 08/57] Fix manual downloads from secure servers

---
 .../View Models/BrowserWindowViewModel.cs     | 23 +++++++++++++------
 Wabbajack.Common/HttpExtensions.cs            | 11 ++-------
 .../Interventions/ManualDownload.cs           |  6 ++---
 3 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs b/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs
index bd05085ce..d0aa4a4ce 100644
--- a/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs	
+++ b/Wabbajack.App.Wpf/View Models/BrowserWindowViewModel.cs	
@@ -23,7 +23,7 @@ public abstract class BrowserWindowViewModel : ViewModel
     [Reactive] public string HeaderText { get; set; }
 
     [Reactive] public string Instructions { get; set; }
-    
+
     [Reactive] public string Address { get; set; }
 
     public BrowserWindow? Browser { get; set; }
@@ -83,6 +83,11 @@ public async Task RunJavaScript(string script)
 
     public async Task<Cookie[]> GetCookies(string domainEnding, CancellationToken token)
     {
+        // Strip www. before searching for cookies on a domain to handle websites saving their cookies like .example.org
+        if (domainEnding.StartsWith("www."))
+        {
+            domainEnding = domainEnding[4..];
+        }
         var cookies = (await _browser.CoreWebView2.CookieManager.GetCookiesAsync(""))
             .Where(c => c.Domain.EndsWith(domainEnding));
         return cookies.Select(c => new Cookie
@@ -125,7 +130,7 @@ public async Task<HtmlDocument> GetDom(CancellationToken token)
             {
                 source.SetCanceled();
             }
-            
+
             args.Cancel = true;
             args.Handled = true;
         };
@@ -146,12 +151,16 @@ public async Task<HtmlDocument> GetDom(CancellationToken token)
         }
 
         var cookies = await GetCookies(uri.Host, token);
-        return new ManualDownload.BrowserDownloadState(uri, cookies, new[]
-        {
-            ("Referer", referer.ToString())
-        });
+        return new ManualDownload.BrowserDownloadState(
+            uri,
+            cookies,
+            new[]
+            {
+                ("Referer", referer?.ToString() ?? uri.ToString())
+            },
+            _browser.CoreWebView2.Settings.UserAgent);
     }
-    
+
     public async Task<Hash> WaitForDownload(AbsolutePath path, CancellationToken token)
     {
         var source = new TaskCompletionSource();
diff --git a/Wabbajack.Common/HttpExtensions.cs b/Wabbajack.Common/HttpExtensions.cs
index a09001206..35ff173ce 100644
--- a/Wabbajack.Common/HttpExtensions.cs
+++ b/Wabbajack.Common/HttpExtensions.cs
@@ -19,7 +19,7 @@ public static HttpRequestMessage AddCookies(this HttpRequestMessage msg, Cookie[
         msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
         return msg;
     }
-    
+
     public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumerable<(string Key, string Value)> headers)
     {
         foreach (var header in headers)
@@ -29,17 +29,10 @@ public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumer
         return msg;
     }
 
-    public static HttpRequestMessage AddChromeAgent(this HttpRequestMessage msg)
-    {
-        msg.Headers.Add("User-Agent",
-            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
-        return msg;
-    }
-
     public static HttpRequestMessage ToHttpRequestMessage(this ManualDownload.BrowserDownloadState browserState)
     {
         var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri);
-        msg.AddChromeAgent();
+        msg.Headers.Add("User-Agent", browserState.UserAgent);
         msg.AddCookies(browserState.Cookies);
         msg.AddHeaders(browserState.Headers);
         return msg;
diff --git a/Wabbajack.DTOs/Interventions/ManualDownload.cs b/Wabbajack.DTOs/Interventions/ManualDownload.cs
index 15a3be245..84dda1dd2 100644
--- a/Wabbajack.DTOs/Interventions/ManualDownload.cs
+++ b/Wabbajack.DTOs/Interventions/ManualDownload.cs
@@ -10,14 +10,14 @@ namespace Wabbajack.DTOs.Interventions;
 public class ManualDownload : AUserIntervention<ManualDownload.BrowserDownloadState>
 {
     public Archive Archive { get; }
-    
+
     public ManualDownload(Archive archive)
     {
         Archive = archive;
     }
 
-    public record BrowserDownloadState(Uri Uri, Cookie[] Cookies, (string Key, string Value)[] Headers)
+    public record BrowserDownloadState(Uri Uri, Cookie[] Cookies, (string Key, string Value)[] Headers, string UserAgent)
     {
-        
+
     }
 }
\ No newline at end of file

From 63eaffd9e3f7576d727fd905df61a70da0544331 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Wed, 9 Aug 2023 21:29:34 +0200
Subject: [PATCH 09/57] Remove duplicate user agent code

---
 Wabbajack.App.Wpf/LauncherUpdater.cs          | 19 ++++++++--------
 .../UserIntervention/OAuth2LoginHandler.cs    | 10 ++++-----
 Wabbajack.Common/HttpExtensions.cs            | 11 +++++++++-
 .../GoogleDriveDownloader.cs                  | 22 +++++++++----------
 Wabbajack.Networking.Http/Extensions.cs       |  7 ------
 5 files changed, 36 insertions(+), 33 deletions(-)

diff --git a/Wabbajack.App.Wpf/LauncherUpdater.cs b/Wabbajack.App.Wpf/LauncherUpdater.cs
index 94e7031e4..96d3fd6be 100644
--- a/Wabbajack.App.Wpf/LauncherUpdater.cs
+++ b/Wabbajack.App.Wpf/LauncherUpdater.cs
@@ -8,6 +8,7 @@
 using Microsoft.Extensions.Logging;
 using Microsoft.VisualBasic.CompilerServices;
 using Newtonsoft.Json;
+using Wabbajack.Common;
 using Wabbajack.Downloaders;
 using Wabbajack.DTOs;
 using Wabbajack.DTOs.DownloadStates;
@@ -27,9 +28,9 @@ public class LauncherUpdater
         private readonly HttpClient _client;
         private readonly Client _wjclient;
         private readonly DTOSerializer _dtos;
-        
+
         private readonly DownloadDispatcher _downloader;
-        
+
         private static Uri GITHUB_REPO_RELEASES = new("https://api.github.com/repos/wabbajack-tools/wabbajack/releases");
 
         public LauncherUpdater(ILogger<LauncherUpdater> logger, HttpClient client, Client wjclient, DTOSerializer dtos,
@@ -41,8 +42,8 @@ public LauncherUpdater(ILogger<LauncherUpdater> logger, HttpClient client, Clien
             _dtos = dtos;
             _downloader = downloader;
         }
-            
-            
+
+
         public static Lazy<AbsolutePath> CommonFolder = new (() =>
         {
             var entryPoint = KnownFolders.EntryPoint;
@@ -105,7 +106,7 @@ public async Task Run()
 
             var launcherFolder = KnownFolders.EntryPoint.Parent;
             var exePath = launcherFolder.Combine("Wabbajack.exe");
-            
+
             var launcherVersion = FileVersionInfo.GetVersionInfo(exePath.ToString());
 
             if (release != default && release.version > Version.Parse(launcherVersion.FileVersion!))
@@ -119,7 +120,7 @@ await _downloader.Download(new Archive
                     Name = release.asset.Name,
                     Size = release.asset.Size
                 }, tempPath, CancellationToken.None);
-                    
+
                 if (tempPath.Size() != release.asset.Size)
                 {
                     _logger.LogInformation(
@@ -130,12 +131,12 @@ await _downloader.Download(new Archive
                 if (exePath.FileExists())
                     exePath.Delete();
                 await tempPath.MoveToAsync(exePath, true, CancellationToken.None);
-                
+
                 _logger.LogInformation("Finished updating wabbajack");
                 await _wjclient.SendMetric("updated_launcher", $"{launcherVersion.FileVersion} -> {release.version}");
             }
         }
-        
+
         private async Task<Release[]> GetReleases()
         {
             _logger.LogInformation("Getting new Wabbajack version list");
@@ -146,7 +147,7 @@ private async Task<Release[]> GetReleases()
         private HttpRequestMessage MakeMessage(Uri uri)
         {
             var msg =  new HttpRequestMessage(HttpMethod.Get, uri);
-            msg.UseChromeUserAgent();
+            msg.AddChromeAgent();
             return msg;
         }
 
diff --git a/Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs b/Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs
index 1d2870223..51f45c7b8 100644
--- a/Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs
+++ b/Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs
@@ -8,6 +8,7 @@
 using System.Web;
 using Microsoft.Extensions.Logging;
 using ReactiveUI;
+using Wabbajack.Common;
 using Wabbajack.DTOs.Interventions;
 using Wabbajack.DTOs.Logins;
 using Wabbajack.Messages;
@@ -40,7 +41,7 @@ protected override async Task Run(CancellationToken token)
 
         var tcs = new TaskCompletionSource<Uri>();
         await NavigateTo(tlogin.AuthorizationEndpoint);
-        
+
         Browser!.Browser.CoreWebView2.Settings.UserAgent = "Wabbajack";
         Browser!.Browser.NavigationStarting += (sender, args) =>
         {
@@ -50,7 +51,7 @@ protected override async Task Run(CancellationToken token)
                 tcs.TrySetResult(uri);
             }
         };
-        
+
         Instructions = $"Please log in and allow Wabbajack to access your {tlogin.SiteName} account";
 
         var scopes = string.Join(" ", tlogin.Scopes);
@@ -88,8 +89,7 @@ await NavigateTo(new Uri(tlogin.AuthorizationEndpoint +
         var msg = new HttpRequestMessage();
         msg.Method = HttpMethod.Post;
         msg.RequestUri = tlogin.TokenEndpoint;
-        msg.Headers.Add("User-Agent",
-            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
+        msg.AddChromeAgent();
         msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
         msg.Content = new FormUrlEncodedContent(formData.ToList());
 
@@ -101,6 +101,6 @@ await _tokenProvider.SetToken(new TLoginType
             Cookies = cookies,
             ResultState = data!
         });
-        
+
     }
 }
\ No newline at end of file
diff --git a/Wabbajack.Common/HttpExtensions.cs b/Wabbajack.Common/HttpExtensions.cs
index 35ff173ce..b2ca8d391 100644
--- a/Wabbajack.Common/HttpExtensions.cs
+++ b/Wabbajack.Common/HttpExtensions.cs
@@ -14,12 +14,21 @@ namespace Wabbajack.Common;
 
 public static class HttpExtensions
 {
+    private const string ChromeUserAgent =
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36";
     public static HttpRequestMessage AddCookies(this HttpRequestMessage msg, Cookie[] cookies)
     {
         msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
         return msg;
     }
 
+    public static HttpRequestMessage AddChromeAgent(this HttpRequestMessage msg, string? overrideUserAgent = null)
+    {
+        msg.Headers.UserAgent.Clear();
+        msg.Headers.Add("User-Agent", overrideUserAgent ?? ChromeUserAgent);
+        return msg;
+    }
+
     public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumerable<(string Key, string Value)> headers)
     {
         foreach (var header in headers)
@@ -32,7 +41,7 @@ public static HttpRequestMessage AddHeaders(this HttpRequestMessage msg, IEnumer
     public static HttpRequestMessage ToHttpRequestMessage(this ManualDownload.BrowserDownloadState browserState)
     {
         var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri);
-        msg.Headers.Add("User-Agent", browserState.UserAgent);
+        msg.AddChromeAgent(browserState.UserAgent);
         msg.AddCookies(browserState.Cookies);
         msg.AddHeaders(browserState.Headers);
         return msg;
diff --git a/Wabbajack.Downloaders.GoogleDrive/GoogleDriveDownloader.cs b/Wabbajack.Downloaders.GoogleDrive/GoogleDriveDownloader.cs
index 2dede342d..c49066948 100644
--- a/Wabbajack.Downloaders.GoogleDrive/GoogleDriveDownloader.cs
+++ b/Wabbajack.Downloaders.GoogleDrive/GoogleDriveDownloader.cs
@@ -65,7 +65,7 @@ public Uri UnParse(IDownloadState state)
         return new Uri(
             $"https://drive.google.com/uc?id={(state as DTOs.DownloadStates.GoogleDrive)?.Id}&export=download");
     }
-    
+
     public override IDownloadState? Resolve(IReadOnlyDictionary<string, string> iniData)
     {
         if (iniData.ContainsKey("directURL") && Uri.TryCreate(iniData["directURL"].CleanIniString(), UriKind.Absolute, out var uri))
@@ -74,8 +74,8 @@ public Uri UnParse(IDownloadState state)
     }
 
     public override Priority Priority => Priority.Normal;
-    
-    
+
+
     public async Task<T> DownloadStream<T>(Archive archive, Func<Stream, Task<T>> fn, CancellationToken token)
     {
         var state = archive.State as DTOs.DownloadStates.GoogleDrive;
@@ -112,8 +112,8 @@ public override IEnumerable<string> MetaIni(Archive a, DTOs.DownloadStates.Googl
         {
             var initialUrl = $"https://drive.google.com/uc?id={state.Id}&export=download";
             var msg = new HttpRequestMessage(HttpMethod.Get, initialUrl);
-            msg.UseChromeUserAgent();
-            
+            msg.AddChromeAgent();
+
             using var response = await _client.SendAsync(msg, token);
             var cookies = response.GetSetCookies();
             var warning = cookies.FirstOrDefault(c => c.Key.StartsWith("download_warning_"));
@@ -124,7 +124,7 @@ public override IEnumerable<string> MetaIni(Archive a, DTOs.DownloadStates.Googl
                 var txt = await response.Content.ReadAsStringAsync(token);
                 if (txt.Contains("<title>Google Drive - Quota exceeded</title>"))
                     throw new Exception("Google Drive - Quota Exceeded");
-                
+
                 doc.LoadHtml(txt);
 
                 var action = doc.DocumentNode.DescendantsAndSelf()
@@ -133,7 +133,7 @@ public override IEnumerable<string> MetaIni(Archive a, DTOs.DownloadStates.Googl
                     .Select(d => d.GetAttributeValue("action", ""))
                     .FirstOrDefault();
 
-                if (action != null) 
+                if (action != null)
                     warning = ("download_warning_", "t");
 
             }
@@ -145,18 +145,18 @@ public override IEnumerable<string> MetaIni(Archive a, DTOs.DownloadStates.Googl
 
             var url = $"https://drive.google.com/uc?export=download&confirm={warning.Value}&id={state.Id}";
             var httpState = new HttpRequestMessage(HttpMethod.Get, url);
-            httpState.UseChromeUserAgent();
+            httpState.AddChromeAgent();
             return httpState;
         }
         else
         {
             var url = $"https://drive.google.com/file/d/{state.Id}/edit";
             var msg = new HttpRequestMessage(HttpMethod.Get, url);
-            msg.UseChromeUserAgent();
-            
+            msg.AddChromeAgent();
+
             using var response = await _client.SendAsync(msg, token);
             msg = new HttpRequestMessage(HttpMethod.Get, url);
-            msg.UseChromeUserAgent();
+            msg.AddChromeAgent();
             return !response.IsSuccessStatusCode ? null : msg;
         }
     }
diff --git a/Wabbajack.Networking.Http/Extensions.cs b/Wabbajack.Networking.Http/Extensions.cs
index 81b751e6d..eed4666b0 100644
--- a/Wabbajack.Networking.Http/Extensions.cs
+++ b/Wabbajack.Networking.Http/Extensions.cs
@@ -10,13 +10,6 @@ namespace Wabbajack.Networking.Http;
 
 public static class Extensions
 {
-    public static HttpRequestMessage UseChromeUserAgent(this HttpRequestMessage msg)
-    {
-        msg.Headers.UserAgent.Clear();
-        msg.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36");
-        return msg;
-    }
-
     public static async Task<T> GetJsonFromSendAsync<T>(this HttpClient client, HttpRequestMessage msg,
         JsonSerializerOptions opts, CancellationToken? token = null)
     {

From 7350b632f722cd3a65e2b5f6e9ebcc1ed731c727 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Thu, 17 Aug 2023 19:14:58 +0200
Subject: [PATCH 10/57] Create configuration project and performance settings

---
 Wabbajack.Configuration/MainSettings.cs       | 29 +++++++++
 .../PerformanceSettings.cs                    |  6 ++
 .../Wabbajack.Configuration.csproj            |  9 +++
 .../Wabbajack.Networking.Http.csproj          |  1 +
 .../ProxiedNexusApi.cs                        |  6 +-
 .../ServiceExtensions.cs                      | 60 ++++++++++++-------
 Wabbajack.sln                                 |  6 ++
 7 files changed, 91 insertions(+), 26 deletions(-)
 create mode 100644 Wabbajack.Configuration/MainSettings.cs
 create mode 100644 Wabbajack.Configuration/PerformanceSettings.cs
 create mode 100644 Wabbajack.Configuration/Wabbajack.Configuration.csproj

diff --git a/Wabbajack.Configuration/MainSettings.cs b/Wabbajack.Configuration/MainSettings.cs
new file mode 100644
index 000000000..5068b7a14
--- /dev/null
+++ b/Wabbajack.Configuration/MainSettings.cs
@@ -0,0 +1,29 @@
+using System.Text.Json.Serialization;
+
+namespace Wabbajack.Configuration;
+
+public class MainSettings
+{
+    private const int SettingsVersion = 1;
+
+    [JsonInclude]
+    private int CurrentSettingsVersion { get; set; }
+
+    public PerformanceSettings PerformanceSettings { get; set; } = new();
+
+    public bool Upgrade()
+    {
+        if (CurrentSettingsVersion == SettingsVersion)
+        {
+            return false;
+        }
+
+        if (CurrentSettingsVersion < 1)
+        {
+            PerformanceSettings.MaximumMemoryPerDownloadThreadMb = -1;
+        }
+
+        CurrentSettingsVersion = SettingsVersion;
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/Wabbajack.Configuration/PerformanceSettings.cs b/Wabbajack.Configuration/PerformanceSettings.cs
new file mode 100644
index 000000000..93dff2406
--- /dev/null
+++ b/Wabbajack.Configuration/PerformanceSettings.cs
@@ -0,0 +1,6 @@
+namespace Wabbajack.Configuration;
+
+public class PerformanceSettings
+{
+    public int MaximumMemoryPerDownloadThreadMb { get; set; }
+}
\ No newline at end of file
diff --git a/Wabbajack.Configuration/Wabbajack.Configuration.csproj b/Wabbajack.Configuration/Wabbajack.Configuration.csproj
new file mode 100644
index 000000000..132c02c59
--- /dev/null
+++ b/Wabbajack.Configuration/Wabbajack.Configuration.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+</Project>
diff --git a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
index d285e4f43..6bdd0a88d 100644
--- a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
+++ b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
@@ -13,6 +13,7 @@
     </ItemGroup>
 
     <ItemGroup>
+        <ProjectReference Include="..\Wabbajack.Configuration\Wabbajack.Configuration.csproj" />
         <ProjectReference Include="..\Wabbajack.Downloaders.Interfaces\Wabbajack.Downloaders.Interfaces.csproj" />
         <ProjectReference Include="..\Wabbajack.Hashing.xxHash64\Wabbajack.Hashing.xxHash64.csproj" />
         <ProjectReference Include="..\Wabbajack.Networking.Http.Interfaces\Wabbajack.Networking.Http.Interfaces.csproj" />
diff --git a/Wabbajack.Networking.NexusApi/ProxiedNexusApi.cs b/Wabbajack.Networking.NexusApi/ProxiedNexusApi.cs
index 21397c0dc..703dc2419 100644
--- a/Wabbajack.Networking.NexusApi/ProxiedNexusApi.cs
+++ b/Wabbajack.Networking.NexusApi/ProxiedNexusApi.cs
@@ -8,15 +8,15 @@
 using Wabbajack.DTOs.Logins;
 using Wabbajack.Networking.Http.Interfaces;
 using Wabbajack.Networking.NexusApi.DTOs;
-using Wabbajack.Networking.WabbajackClientApi;
 using Wabbajack.RateLimiter;
+using ClientConfiguration = Wabbajack.Networking.WabbajackClientApi.Configuration;
 
 namespace Wabbajack.Networking.NexusApi;
 
 public class ProxiedNexusApi : NexusApi
 {
     private readonly ITokenProvider<WabbajackApiState> _apiState;
-    private readonly Configuration _wabbajackClientConfiguration;
+    private readonly ClientConfiguration _wabbajackClientConfiguration;
 
     public HashSet<string> ProxiedEndpoints = new()
     {
@@ -28,7 +28,7 @@ public class ProxiedNexusApi : NexusApi
     public ProxiedNexusApi(ITokenProvider<NexusApiState> apiKey, ILogger<ProxiedNexusApi> logger, HttpClient client,
         IResource<HttpClient> limiter,
         ApplicationInfo appInfo, JsonSerializerOptions jsonOptions, ITokenProvider<WabbajackApiState> apiState,
-        Configuration wabbajackClientConfiguration)
+        ClientConfiguration wabbajackClientConfiguration)
         : base(apiKey, logger, client, limiter, appInfo, jsonOptions)
     {
         _apiState = apiState;
diff --git a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
index 3a2b41e7b..b00aaec16 100644
--- a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
+++ b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
@@ -9,6 +9,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Wabbajack.Compiler;
+using Wabbajack.Configuration;
 using Wabbajack.Downloaders;
 using Wabbajack.Downloaders.GameFile;
 using Wabbajack.Downloaders.VerificationCache;
@@ -79,24 +80,36 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
             ? new BinaryPatchCache(s.GetRequiredService<ILogger<BinaryPatchCache>>(), s.GetService<TemporaryFileManager>()!.CreateFolder().Path)
             : new BinaryPatchCache(s.GetRequiredService<ILogger<BinaryPatchCache>>(),KnownFolders.WabbajackAppLocal.Combine("PatchCache")));
 
-        
+
         service.AddSingleton<IVerificationCache>(s =>
         {
             var dtos = s.GetRequiredService<DTOSerializer>();
             return options.UseLocalCache
                 ? new VerificationCache(s.GetRequiredService<ILogger<VerificationCache>>(),
-                    s.GetService<TemporaryFileManager>()!.CreateFile().Path, 
+                    s.GetService<TemporaryFileManager>()!.CreateFile().Path,
                     TimeSpan.FromDays(1),
                     dtos)
                 : new VerificationCache(s.GetRequiredService<ILogger<VerificationCache>>(),
-                    KnownFolders.WabbajackAppLocal.Combine("VerificationCacheV2.sqlite"), 
+                    KnownFolders.WabbajackAppLocal.Combine("VerificationCacheV2.sqlite"),
                     TimeSpan.FromDays(1),
                     dtos);
         });
 
         service.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
 
-        Func<Task<(int MaxTasks, long MaxThroughput)>> GetSettings(IServiceProvider provider, string name)
+        MainSettings GetAppSettings(IServiceProvider provider, string name)
+        {
+            var settingsManager = provider.GetService<SettingsManager>();
+            var settings = settingsManager!.Load<MainSettings>(name).Result;
+            if (settings.Upgrade())
+            {
+                settingsManager.Save("app_settings", settings).Wait();
+            }
+
+            return settings;
+        }
+
+        Func<Task<(int MaxTasks, long MaxThroughput)>> GetResourceSettings(IServiceProvider provider, string name)
         {
             return async () =>
             {
@@ -104,9 +117,9 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
                 return ((int) s.MaxTasks, s.MaxThroughput);
             };
         }
-        
+
         // Settings
-        
+
         service.AddSingleton(s => new Configuration
         {
             EncryptedDataLocation = KnownFolders.WabbajackAppLocal.Combine("encrypted"),
@@ -118,26 +131,27 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
 
         service.AddSingleton<SettingsManager>();
         service.AddSingleton<ResourceSettingsManager>();
-        
+        service.AddSingleton<MainSettings>(s => GetAppSettings(s, "app_settings"));
+
         // Resources
 
         service.AddAllSingleton<IResource, IResource<DownloadDispatcher>>(s =>
-            new Resource<DownloadDispatcher>("Downloads", GetSettings(s, "Downloads"), s.GetRequiredService<CancellationToken>()));
+            new Resource<DownloadDispatcher>("Downloads", GetResourceSettings(s, "Downloads"), s.GetRequiredService<CancellationToken>()));
 
-        service.AddAllSingleton<IResource, IResource<HttpClient>>(s => new Resource<HttpClient>("Web Requests", GetSettings(s, "Web Requests"), s.GetRequiredService<CancellationToken>()));
-        service.AddAllSingleton<IResource, IResource<Context>>(s => new Resource<Context>("VFS", GetSettings(s, "VFS"), s.GetRequiredService<CancellationToken>()));
+        service.AddAllSingleton<IResource, IResource<HttpClient>>(s => new Resource<HttpClient>("Web Requests", GetResourceSettings(s, "Web Requests"), s.GetRequiredService<CancellationToken>()));
+        service.AddAllSingleton<IResource, IResource<Context>>(s => new Resource<Context>("VFS", GetResourceSettings(s, "VFS"), s.GetRequiredService<CancellationToken>()));
         service.AddAllSingleton<IResource, IResource<FileHashCache>>(s =>
-            new Resource<FileHashCache>("File Hashing", GetSettings(s, "File Hashing"), s.GetRequiredService<CancellationToken>()));
+            new Resource<FileHashCache>("File Hashing", GetResourceSettings(s, "File Hashing"), s.GetRequiredService<CancellationToken>()));
         service.AddAllSingleton<IResource, IResource<Client>>(s =>
-            new Resource<Client>("Wabbajack Client", GetSettings(s, "Wabbajack Client"), s.GetRequiredService<CancellationToken>()));
+            new Resource<Client>("Wabbajack Client", GetResourceSettings(s, "Wabbajack Client"), s.GetRequiredService<CancellationToken>()));
         service.AddAllSingleton<IResource, IResource<FileExtractor.FileExtractor>>(s =>
-            new Resource<FileExtractor.FileExtractor>("File Extractor", GetSettings(s, "File Extractor"), s.GetRequiredService<CancellationToken>()));
+            new Resource<FileExtractor.FileExtractor>("File Extractor", GetResourceSettings(s, "File Extractor"), s.GetRequiredService<CancellationToken>()));
 
         service.AddAllSingleton<IResource, IResource<ACompiler>>(s =>
-            new Resource<ACompiler>("Compiler", GetSettings(s, "Compiler"), s.GetRequiredService<CancellationToken>()));
+            new Resource<ACompiler>("Compiler", GetResourceSettings(s, "Compiler"), s.GetRequiredService<CancellationToken>()));
 
         service.AddAllSingleton<IResource, IResource<IInstaller>>(s =>
-            new Resource<IInstaller>("Installer", GetSettings(s, "Installer"), s.GetRequiredService<CancellationToken>()));
+            new Resource<IInstaller>("Installer", GetResourceSettings(s, "Installer"), s.GetRequiredService<CancellationToken>()));
 
         service.AddAllSingleton<IResource, IResource<IUserInterventionHandler>>(s =>
             new Resource<IUserInterventionHandler>("User Intervention", 1, token: s.GetRequiredService<CancellationToken>()));
@@ -154,7 +168,7 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
         service.AddAllSingleton<IHttpDownloader, SingleThreadedDownloader>();
 
         service.AddSteam();
-            
+
         service.AddSingleton<Client>();
         service.AddSingleton<WriteOnlyClient>();
         service.AddBethesdaNet();
@@ -186,11 +200,11 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
             service.AddAllSingleton<IGameLocator, StubbedGameLocator>();
         else
             service.AddAllSingleton<IGameLocator, GameLocator>();
-        
+
         // ImageLoader
         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
             service.AddSingleton<IImageLoader, TexConvImageLoader>();
-        else 
+        else
             service.AddSingleton<IImageLoader, CrossPlatformImageLoader>();
 
         // Installer/Compiler Configuration
@@ -214,9 +228,9 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
             OSVersion = Environment.OSVersion.VersionString,
             Version = version
         });
-        
 
-        
+
+
         return service;
     }
 
@@ -224,7 +238,7 @@ private static void CleanAllTempData(AbsolutePath path)
     {
         // Get directories first and cache them, this freezes the directories were looking at
         // so any new ones don't show up in the middle of our deletes.
-        
+
         var dirs = path.EnumerateDirectories().ToList();
         var processIds = Process.GetProcesses().Select(p => p.Id).ToHashSet();
         foreach (var dir in dirs)
@@ -232,7 +246,7 @@ private static void CleanAllTempData(AbsolutePath path)
             var name = dir.FileName.ToString().Split("_");
             if (!int.TryParse(name[0], out var processId)) continue;
             if (processIds.Contains(processId)) continue;
-            
+
             try
             {
                 dir.DeleteDirectory();
@@ -242,7 +256,7 @@ private static void CleanAllTempData(AbsolutePath path)
                 // ignored
             }
         }
-        
+
     }
 
     public class OSIntegratedOptions
diff --git a/Wabbajack.sln b/Wabbajack.sln
index 33a2724ba..1800043e0 100644
--- a/Wabbajack.sln
+++ b/Wabbajack.sln
@@ -147,6 +147,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.CLI.Builder", "Wa
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Downloaders.VerificationCache", "Wabbajack.Downloaders.VerificationCache\Wabbajack.Downloaders.VerificationCache.csproj", "{D9560C73-4E58-4463-9DB9-D06491E0E1C8}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Configuration", "Wabbajack.Configuration\Wabbajack.Configuration.csproj", "{E7CDACA6-D3FF-4CF6-8EF8-05FCD27F6FBE}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -401,6 +403,10 @@ Global
 		{D9560C73-4E58-4463-9DB9-D06491E0E1C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{D9560C73-4E58-4463-9DB9-D06491E0E1C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{D9560C73-4E58-4463-9DB9-D06491E0E1C8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E7CDACA6-D3FF-4CF6-8EF8-05FCD27F6FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E7CDACA6-D3FF-4CF6-8EF8-05FCD27F6FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E7CDACA6-D3FF-4CF6-8EF8-05FCD27F6FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E7CDACA6-D3FF-4CF6-8EF8-05FCD27F6FBE}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

From a77bb6cc44ec0269f4880128b211c29435492a83 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Sun, 20 Aug 2023 11:18:24 +0200
Subject: [PATCH 11/57] Bind new performance settings to UI

---
 Wabbajack.App.Wpf/Settings.cs                 | 75 +++++++------------
 .../View Models/Settings/SettingsVM.cs        | 35 +++++++--
 .../Settings/PerformanceSettingsView.xaml     | 33 +++++++-
 .../Settings/PerformanceSettingsView.xaml.cs  | 10 +++
 Wabbajack.Configuration/MainSettings.cs       | 10 +--
 .../ServiceExtensions.cs                      |  5 +-
 6 files changed, 102 insertions(+), 66 deletions(-)

diff --git a/Wabbajack.App.Wpf/Settings.cs b/Wabbajack.App.Wpf/Settings.cs
index 4a65f6d73..d61e633f9 100644
--- a/Wabbajack.App.Wpf/Settings.cs
+++ b/Wabbajack.App.Wpf/Settings.cs
@@ -5,10 +5,11 @@
 using System.Threading.Tasks;
 using Newtonsoft.Json;
 using Wabbajack.Compiler;
+using Wabbajack.Downloaders;
 using Wabbajack.DTOs.JsonConverters;
-using Wabbajack;
 using Wabbajack.Paths;
-using Consts = Wabbajack.Consts;
+using Wabbajack.RateLimiter;
+using Wabbajack.Util;
 
 namespace Wabbajack
 {
@@ -24,7 +25,6 @@ public class MainSettings
         public InstallerSettings Installer { get; set; } = new();
         public FiltersSettings Filters { get; set; } = new();
         public CompilerSettings Compiler { get; set; } = new();
-        public PerformanceSettings Performance { get; set; } = new();
 
         private Subject<Unit> _saveSignal = new();
         [JsonIgnore]
@@ -52,7 +52,7 @@ public class MainSettings
 
             var backup = Consts.SettingsFile.AppendToName("-backup");
             await backup.DeleteAsync();
-            
+
             await Consts.SettingsFile.CopyToAsync(backup);
             await Consts.SettingsFile.DeleteAsync();
 */
@@ -97,71 +97,48 @@ public class FiltersSettings : ViewModel
         public string Search { get; set; }
         private bool _isPersistent = true;
         public bool IsPersistent { get => _isPersistent; set => RaiseAndSetIfChanged(ref _isPersistent, value); }
-        
+
         private bool _useCompression = false;
         public bool UseCompression { get => _useCompression; set => RaiseAndSetIfChanged(ref _useCompression, value); }
         public bool ShowUtilityLists { get; set; }
     }
 
-    [JsonName("PerformanceSettings")]
-    [JsonObject(MemberSerialization.OptOut)]
     public class PerformanceSettings : ViewModel
     {
-        public PerformanceSettings()
-        {
-            _reduceHDDThreads = true;
-            _favorPerfOverRam = false;
-            _diskThreads = Environment.ProcessorCount;
-            _downloadThreads = Environment.ProcessorCount <= 8 ? Environment.ProcessorCount : 8;
-        }
+        private readonly Configuration.MainSettings _settings;
+        private readonly int _defaultMaximumMemoryPerDownloadThreadMb;
 
-        private int _downloadThreads;
-        public int DownloadThreads { get => _downloadThreads; set => RaiseAndSetIfChanged(ref _downloadThreads, value); }
-        
-        private int _diskThreads;
-        public int DiskThreads { get => _diskThreads; set => RaiseAndSetIfChanged(ref _diskThreads, value); }
+        public PerformanceSettings(Configuration.MainSettings settings, IResource<DownloadDispatcher> downloadResources, SystemParametersConstructor systemParams)
+        {
+            var p = systemParams.Create();
 
-        private bool _reduceHDDThreads;
-        public bool ReduceHDDThreads { get => _reduceHDDThreads; set => RaiseAndSetIfChanged(ref _reduceHDDThreads, value); }
+            _settings = settings;
+            // Split half of available memory among download threads
+            _defaultMaximumMemoryPerDownloadThreadMb = (int)(p.SystemMemorySize / downloadResources.MaxTasks / 1024 / 1024) / 2;
+            _maximumMemoryPerDownloadThreadMb = settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb;
 
-        private bool _favorPerfOverRam;
-        public bool FavorPerfOverRam { get => _favorPerfOverRam; set => RaiseAndSetIfChanged(ref _favorPerfOverRam, value); }
-        
-        private bool _networkWorkaroundMode;
-        public bool NetworkWorkaroundMode
-        {
-            get => _networkWorkaroundMode;
-            set
+            if (MaximumMemoryPerDownloadThreadMb < 0)
             {
-                Consts.UseNetworkWorkaroundMode = value;
-                RaiseAndSetIfChanged(ref _networkWorkaroundMode, value);
+                ResetMaximumMemoryPerDownloadThreadMb();
             }
         }
 
-        
-        private bool _disableTextureResizing;
-        public bool DisableTextureResizing
+        private int _maximumMemoryPerDownloadThreadMb;
+
+        public int MaximumMemoryPerDownloadThreadMb
         {
-            get => _disableTextureResizing;
+            get => _maximumMemoryPerDownloadThreadMb;
             set
             {
-                RaiseAndSetIfChanged(ref _disableTextureResizing, value);
+                RaiseAndSetIfChanged(ref _maximumMemoryPerDownloadThreadMb, value);
+                _settings.PerformanceSettings.MaximumMemoryPerDownloadThreadMb = value;
             }
         }
 
-
-
-        /*
-        public void SetProcessorSettings(ABatchProcessor processor)
+        public void ResetMaximumMemoryPerDownloadThreadMb()
         {
-            processor.DownloadThreads = DownloadThreads;
-            processor.DiskThreads = DiskThreads;
-            processor.ReduceHDDThreads = ReduceHDDThreads;
-            processor.FavorPerfOverRam = FavorPerfOverRam;
-
-            if (processor is MO2Compiler mo2c)
-                mo2c.DisableTextureResizing = DisableTextureResizing;
-        }*/
+            MaximumMemoryPerDownloadThreadMb = _defaultMaximumMemoryPerDownloadThreadMb;
+        }
     }
 
     [JsonName("CompilationModlistSettings")]
@@ -174,7 +151,7 @@ public class CompilationModlistSettings
         public string Website { get; set; }
         public string Readme { get; set; }
         public bool IsNSFW { get; set; }
-        
+
         public string MachineUrl { get; set; }
         public AbsolutePath SplashScreen { get; set; }
         public bool Publish { get; set; }
diff --git a/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs b/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs
index 44ced9406..64fb3afb9 100644
--- a/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs	
@@ -2,25 +2,30 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
-using System.Linq;
 using System.Reflection;
-using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Input;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using ReactiveUI;
-using Wabbajack;
+using Wabbajack.Common;
+using Wabbajack.Downloaders;
 using Wabbajack.LoginManagers;
 using Wabbajack.Messages;
 using Wabbajack.Networking.WabbajackClientApi;
+using Wabbajack.RateLimiter;
+using Wabbajack.Services.OSIntegrated;
 using Wabbajack.Services.OSIntegrated.TokenProviders;
+using Wabbajack.Util;
 using Wabbajack.View_Models.Settings;
 
 namespace Wabbajack
 {
     public class SettingsVM : BackNavigatingVM
     {
+        private readonly Configuration.MainSettings _settings;
+        private readonly SettingsManager _settingsManager;
+
         public LoginManagerVM Login { get; }
         public PerformanceSettings Performance { get; }
         public FiltersSettings Filters { get; }
@@ -31,12 +36,30 @@ public class SettingsVM : BackNavigatingVM
         public SettingsVM(ILogger<SettingsVM> logger, IServiceProvider provider)
             : base(logger)
         {
-            Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this, 
+            _settings = provider.GetRequiredService<Configuration.MainSettings>();
+            _settingsManager = provider.GetRequiredService<SettingsManager>();
+
+            Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this,
                 provider.GetRequiredService<IEnumerable<INeedsLogin>>());
-            AuthorFile = new AuthorFilesVM(provider.GetRequiredService<ILogger<AuthorFilesVM>>()!, 
+            AuthorFile = new AuthorFilesVM(provider.GetRequiredService<ILogger<AuthorFilesVM>>()!,
                 provider.GetRequiredService<WabbajackApiTokenProvider>()!, provider.GetRequiredService<Client>()!, this);
             OpenTerminalCommand = ReactiveCommand.CreateFromTask(OpenTerminal);
-            BackCommand = ReactiveCommand.Create(NavigateBack.Send);
+            Performance = new PerformanceSettings(
+                _settings,
+                provider.GetRequiredService<IResource<DownloadDispatcher>>(),
+                provider.GetRequiredService<SystemParametersConstructor>());
+            BackCommand = ReactiveCommand.Create(() =>
+            {
+                NavigateBack.Send();
+                Unload();
+            });
+        }
+
+        public override void Unload()
+        {
+            _settingsManager.Save(Configuration.MainSettings.SettingsFileName, _settings).FireAndForget();
+
+            base.Unload();
         }
 
         private async Task OpenTerminal()
diff --git a/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml b/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml
index 7b23be3e0..d976f2b94 100644
--- a/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml
+++ b/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml
@@ -24,7 +24,7 @@
                 <RowDefinition Height="10" />
                 <RowDefinition Height="Auto" />
                 <RowDefinition Height="25" />
-                <RowDefinition Height="25" />
+                <RowDefinition Height="Auto" />
                 <RowDefinition Height="25" />
                 <RowDefinition Height="25" />
                 <RowDefinition Height="25" />
@@ -34,16 +34,43 @@
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="Auto" />
                 <ColumnDefinition Width="5" />
+                <ColumnDefinition Width="Auto" />
                 <ColumnDefinition Width="*" />
             </Grid.ColumnDefinitions>
-            <TextBlock Grid.Column="0" Grid.ColumnSpan="2"
+            <TextBlock
+                Grid.Column="0"
+                Grid.ColumnSpan="3"
                 FontFamily="Lucida Sans"
                 FontSize="20"
                 FontWeight="Bold"
                 Text="Performance" />
-            <Button Grid.Row="2" x:Name="EditResourceSettings">
+            <Button x:Name="EditResourceSettings" Grid.Row="2">
                 <TextBlock FontSize="14" FontWeight="Bold">Edit Resource Usage Settings and Close Wabbajack</TextBlock>
             </Button>
+            <TextBlock
+                Grid.Row="4"
+                FontSize="14"
+                Foreground="{StaticResource ForegroundBrush}"
+                Text="Maximum RAM per download thread (MB)"
+                ToolTip="Defines the maximum amount of RAM each download thread can use for buffering. Set to 0 to disable this limit completely." />
+            <xwpf:IntegerUpDown
+                x:Name="MaximumMemoryPerDownloadThreadIntegerUpDown"
+                Grid.Row="4"
+                Grid.Column="2"
+                Width="80"
+                HorizontalAlignment="Left"
+                Foreground="{StaticResource ForegroundBrush}"
+                Maximum="10000"
+                Minimum="0" />
+            <Button
+                x:Name="ResetMaximumMemoryPerDownloadThread"
+                Grid.Row="4"
+                Grid.Column="3"
+                Margin="20,0,0,0"
+                Padding="10,0"
+                HorizontalAlignment="Left">
+                <TextBlock FontSize="14">Reset</TextBlock>
+            </Button>
         </Grid>
     </Border>
 </rxui:ReactiveUserControl>
diff --git a/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml.cs b/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml.cs
index efed20274..d2a0ee5c4 100644
--- a/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Settings/PerformanceSettingsView.xaml.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Reactive.Disposables;
 using ReactiveUI;
 using Wabbajack.Paths.IO;
 
@@ -15,12 +16,21 @@ public PerformanceSettingsView()
 
             this.WhenActivated(disposable =>
             {
+                this.BindStrict(
+                        ViewModel,
+                        x => x.MaximumMemoryPerDownloadThreadMb,
+                        x => x.MaximumMemoryPerDownloadThreadIntegerUpDown.Value)
+                    .DisposeWith(disposable);
                 this.EditResourceSettings.Command = ReactiveCommand.Create(() =>
                 {
                     UIUtils.OpenFile(
                         KnownFolders.WabbajackAppLocal.Combine("saved_settings", "resource_settings.json"));
                     Environment.Exit(0);
                 });
+                ResetMaximumMemoryPerDownloadThread.Command = ReactiveCommand.Create(() =>
+                {
+                    ViewModel.ResetMaximumMemoryPerDownloadThreadMb();
+                });
             });
         }
     }
diff --git a/Wabbajack.Configuration/MainSettings.cs b/Wabbajack.Configuration/MainSettings.cs
index 5068b7a14..45eadd8ba 100644
--- a/Wabbajack.Configuration/MainSettings.cs
+++ b/Wabbajack.Configuration/MainSettings.cs
@@ -1,15 +1,13 @@
-using System.Text.Json.Serialization;
-
-namespace Wabbajack.Configuration;
+namespace Wabbajack.Configuration;
 
 public class MainSettings
 {
+    public const string SettingsFileName = "app_settings";
     private const int SettingsVersion = 1;
 
-    [JsonInclude]
-    private int CurrentSettingsVersion { get; set; }
+    public int CurrentSettingsVersion { get; private set; }
 
-    public PerformanceSettings PerformanceSettings { get; set; } = new();
+    public PerformanceSettings PerformanceSettings { get; } = new();
 
     public bool Upgrade()
     {
diff --git a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
index b00aaec16..87ce587f2 100644
--- a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
+++ b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
@@ -8,6 +8,7 @@
 using System.Threading.Tasks;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
+using Wabbajack.Common;
 using Wabbajack.Compiler;
 using Wabbajack.Configuration;
 using Wabbajack.Downloaders;
@@ -103,7 +104,7 @@ MainSettings GetAppSettings(IServiceProvider provider, string name)
             var settings = settingsManager!.Load<MainSettings>(name).Result;
             if (settings.Upgrade())
             {
-                settingsManager.Save("app_settings", settings).Wait();
+                settingsManager.Save(MainSettings.SettingsFileName, settings).FireAndForget();
             }
 
             return settings;
@@ -131,7 +132,7 @@ MainSettings GetAppSettings(IServiceProvider provider, string name)
 
         service.AddSingleton<SettingsManager>();
         service.AddSingleton<ResourceSettingsManager>();
-        service.AddSingleton<MainSettings>(s => GetAppSettings(s, "app_settings"));
+        service.AddSingleton<MainSettings>(s => GetAppSettings(s, MainSettings.SettingsFileName));
 
         // Resources
 

From 039e3603ceaa5a1d3c944ad7cc3e291e27cb8b48 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Sun, 20 Aug 2023 12:58:43 +0200
Subject: [PATCH 12/57] Use performance settings to limit maximum memory per
 download

---
 Wabbajack.Networking.Http/ResumableDownloader.cs           | 7 ++++++-
 Wabbajack.Networking.Http/SingleThreadedDownloader.cs      | 7 +++++--
 Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj | 2 +-
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/Wabbajack.Networking.Http/ResumableDownloader.cs b/Wabbajack.Networking.Http/ResumableDownloader.cs
index ca07712c4..025715e4c 100644
--- a/Wabbajack.Networking.Http/ResumableDownloader.cs
+++ b/Wabbajack.Networking.Http/ResumableDownloader.cs
@@ -7,6 +7,7 @@
 using System.Threading.Tasks;
 using Downloader;
 using Microsoft.Extensions.Logging;
+using Wabbajack.Configuration;
 using Wabbajack.Hashing.xxHash64;
 using Wabbajack.Paths;
 using Wabbajack.Paths.IO;
@@ -20,17 +21,19 @@ internal class ResumableDownloader
     private readonly HttpRequestMessage _msg;
     private readonly AbsolutePath _outputPath;
     private readonly AbsolutePath _packagePath;
+    private readonly PerformanceSettings _performanceSettings;
     private readonly ILogger<SingleThreadedDownloader> _logger;
     private CancellationToken _token;
     private Exception? _error;
 
 
-    public ResumableDownloader(HttpRequestMessage msg, AbsolutePath outputPath, IJob job, ILogger<SingleThreadedDownloader> logger)
+    public ResumableDownloader(HttpRequestMessage msg, AbsolutePath outputPath, IJob job, PerformanceSettings performanceSettings, ILogger<SingleThreadedDownloader> logger)
     {
         _job = job;
         _msg = msg;
         _outputPath = outputPath;
         _packagePath = outputPath.WithExtension(Extension.FromPath(".download_package"));
+        _performanceSettings = performanceSettings;
         _logger = logger;
     }
 
@@ -99,8 +102,10 @@ public async Task<Hash> Download(CancellationToken token)
 
     private DownloadConfiguration CreateConfiguration(HttpRequestMessage message)
     {
+        var maximumMemoryPerDownloadThreadMb = Math.Max(0, _performanceSettings.MaximumMemoryPerDownloadThreadMb);
         var configuration = new DownloadConfiguration
         {
+            MaximumMemoryBufferBytes = maximumMemoryPerDownloadThreadMb * 1024 * 1024,
             Timeout = (int)TimeSpan.FromSeconds(120).TotalMilliseconds,
             ReserveStorageSpaceBeforeStartingDownload = true,
             RequestConfiguration = new RequestConfiguration
diff --git a/Wabbajack.Networking.Http/SingleThreadedDownloader.cs b/Wabbajack.Networking.Http/SingleThreadedDownloader.cs
index 4790d4ac1..ed88e3bba 100644
--- a/Wabbajack.Networking.Http/SingleThreadedDownloader.cs
+++ b/Wabbajack.Networking.Http/SingleThreadedDownloader.cs
@@ -7,6 +7,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.Extensions.Logging;
+using Wabbajack.Configuration;
 using Wabbajack.Hashing.xxHash64;
 using Wabbajack.Networking.Http.Interfaces;
 using Wabbajack.Paths;
@@ -19,18 +20,20 @@ public class SingleThreadedDownloader : IHttpDownloader
 {
     private readonly HttpClient _client;
     private readonly ILogger<SingleThreadedDownloader> _logger;
+    private readonly PerformanceSettings _settings;
 
-    public SingleThreadedDownloader(ILogger<SingleThreadedDownloader> logger, HttpClient client)
+    public SingleThreadedDownloader(ILogger<SingleThreadedDownloader> logger, HttpClient client, MainSettings settings)
     {
         _logger = logger;
         _client = client;
+        _settings = settings.PerformanceSettings;
     }
 
     public async Task<Hash> Download(HttpRequestMessage message, AbsolutePath outputPath, IJob job,
         CancellationToken token)
     {
         Exception downloadError = null!;
-        var downloader = new ResumableDownloader(message, outputPath, job, _logger);
+        var downloader = new ResumableDownloader(message, outputPath, job, _settings, _logger);
         for (var i = 0; i < 3; i++)
         {
             try
diff --git a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
index 6bdd0a88d..191df7f37 100644
--- a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
+++ b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
@@ -8,7 +8,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <PackageReference Include="Downloader" Version="3.0.4" />
+        <PackageReference Include="Downloader" Version="3.0.6" />
         <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.2-mauipre.1.22102.15" />
     </ItemGroup>
 

From bdb60f26a7d66b7e355b811c999977223a99b575 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Sun, 20 Aug 2023 13:57:16 +0200
Subject: [PATCH 13/57] Remove unused settings and related classes

---
 Wabbajack.App.Wpf/App.xaml.cs                 |   4 +-
 Wabbajack.App.Wpf/Settings.cs                 | 126 +-----------------
 .../Compilers/ModlistSettingsEditorVM.cs      | 109 ---------------
 .../View Models/Gallery/ModListGalleryVM.cs   |   1 -
 .../View Models/Installers/MO2InstallerVM.cs  | 113 +---------------
 Wabbajack.App.Wpf/View Models/MainWindowVM.cs |   8 +-
 .../View Models/Settings/SettingsVM.cs        |   1 -
 .../Views/Common/CpuView.xaml.cs              |  32 +----
 .../Views/Installers/InstallationView.xaml    |  14 --
 .../ConfirmUpdateOfExistingInstallView.xaml   |  50 -------
 ...ConfirmUpdateOfExistingInstallView.xaml.cs |  51 -------
 Wabbajack.App.Wpf/Views/MainWindow.xaml.cs    |  67 +---------
 .../Views/Settings/MiscSettingsView.xaml      |  40 ++----
 .../Views/Settings/MiscSettingsView.xaml.cs   |   4 -
 14 files changed, 18 insertions(+), 602 deletions(-)
 delete mode 100644 Wabbajack.App.Wpf/View Models/Compilers/ModlistSettingsEditorVM.cs
 delete mode 100644 Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
 delete mode 100644 Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs

diff --git a/Wabbajack.App.Wpf/App.xaml.cs b/Wabbajack.App.Wpf/App.xaml.cs
index 4fd29c41e..dc9d2cd09 100644
--- a/Wabbajack.App.Wpf/App.xaml.cs
+++ b/Wabbajack.App.Wpf/App.xaml.cs
@@ -3,7 +3,6 @@
 using System.Reactive.Disposables;
 using System.Runtime.InteropServices;
 using System.Security.Principal;
-using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Threading;
 using Microsoft.Extensions.DependencyInjection;
@@ -166,7 +165,6 @@ private static IServiceCollection ConfigureServices(IServiceCollection services)
             services.AddSingleton<LauncherUpdater>();
             services.AddSingleton<ResourceMonitor>();
 
-            services.AddSingleton<MainSettings>();
             services.AddTransient<CompilerVM>();
             services.AddTransient<InstallerVM>();
             services.AddTransient<ModeSelectionVM>();
@@ -182,7 +180,7 @@ private static IServiceCollection ConfigureServices(IServiceCollection services)
             services.AddTransient<LoversLabLoginHandler>();
 
             // Login Managers
-            
+
             //Disabled LL because it is currently not used and broken due to the way LL butchers their API
             //services.AddAllSingleton<INeedsLogin, LoversLabLoginManager>();
             services.AddAllSingleton<INeedsLogin, NexusLoginManager>();
diff --git a/Wabbajack.App.Wpf/Settings.cs b/Wabbajack.App.Wpf/Settings.cs
index d61e633f9..170ad1a80 100644
--- a/Wabbajack.App.Wpf/Settings.cs
+++ b/Wabbajack.App.Wpf/Settings.cs
@@ -1,108 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.Reactive;
-using System.Reactive.Subjects;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Wabbajack.Compiler;
-using Wabbajack.Downloaders;
-using Wabbajack.DTOs.JsonConverters;
-using Wabbajack.Paths;
+using Wabbajack.Downloaders;
 using Wabbajack.RateLimiter;
 using Wabbajack.Util;
 
 namespace Wabbajack
 {
-    [JsonName("MainSettings")]
-    [JsonObject(MemberSerialization.OptOut)]
-    public class MainSettings
-    {
-        public byte Version { get; set; } = Consts.SettingsVersion;
-        public double PosX { get; set; }
-        public double PosY { get; set; }
-        public double Height { get; set; }
-        public double Width { get; set; }
-        public InstallerSettings Installer { get; set; } = new();
-        public FiltersSettings Filters { get; set; } = new();
-        public CompilerSettings Compiler { get; set; } = new();
-
-        private Subject<Unit> _saveSignal = new();
-        [JsonIgnore]
-        public IObservable<Unit> SaveSignal => _saveSignal;
-
-        public static async ValueTask<(MainSettings settings, bool loaded)> TryLoadTypicalSettings()
-        {
-            /*
-            if (!Consts.SettingsFile.Exists)
-            {
-                return default;
-            }
-
-            // Version check
-            try
-            {
-                var settings = Consts.SettingsFile.FromJson<MainSettings>();
-                if (settings.Version == Consts.SettingsVersion)
-                    return (settings, true);
-            }
-            catch (Exception ex)
-            {
-                Utils.Error(ex, "Error loading settings");
-            }
-
-            var backup = Consts.SettingsFile.AppendToName("-backup");
-            await backup.DeleteAsync();
-
-            await Consts.SettingsFile.CopyToAsync(backup);
-            await Consts.SettingsFile.DeleteAsync();
-*/
-            return default;
-        }
-
-        public static async ValueTask SaveSettings(MainSettings settings)
-        {
-            settings._saveSignal.OnNext(Unit.Default);
-
-            // Might add this if people are putting save work on other threads or other
-            // things that delay the operation.
-            //settings._saveSignal.OnCompleted();
-            //await settings._saveSignal;
-
-            //await settings.ToJsonAsync(Consts.SettingsFile);
-        }
-    }
-
-    [JsonName("InstallerSettings")]
-    public class InstallerSettings
-    {
-        public AbsolutePath LastInstalledListLocation { get; set; }
-        public Dictionary<AbsolutePath, Mo2ModlistInstallationSettings> Mo2ModlistSettings { get; } = new Dictionary<AbsolutePath, Mo2ModlistInstallationSettings>();
-    }
-
-    [JsonName("Mo2ModListInstallerSettings")]
-    public class Mo2ModlistInstallationSettings
-    {
-        public AbsolutePath InstallationLocation { get; set; }
-        public AbsolutePath DownloadLocation { get; set; }
-        public bool AutomaticallyOverrideExistingInstall { get; set; }
-    }
-
-    [JsonName("FiltersSettings")]
-    [JsonObject(MemberSerialization.OptOut)]
-    public class FiltersSettings : ViewModel
-    {
-        public bool ShowNSFW { get; set; }
-        public bool OnlyInstalled { get; set; }
-        public string Game { get; set; }
-        public string Search { get; set; }
-        private bool _isPersistent = true;
-        public bool IsPersistent { get => _isPersistent; set => RaiseAndSetIfChanged(ref _isPersistent, value); }
-
-        private bool _useCompression = false;
-        public bool UseCompression { get => _useCompression; set => RaiseAndSetIfChanged(ref _useCompression, value); }
-        public bool ShowUtilityLists { get; set; }
-    }
-
     public class PerformanceSettings : ViewModel
     {
         private readonly Configuration.MainSettings _settings;
@@ -140,29 +41,4 @@ public void ResetMaximumMemoryPerDownloadThreadMb()
             MaximumMemoryPerDownloadThreadMb = _defaultMaximumMemoryPerDownloadThreadMb;
         }
     }
-
-    [JsonName("CompilationModlistSettings")]
-    public class CompilationModlistSettings
-    {
-        public string ModListName { get; set; }
-        public string Version { get; set; }
-        public string Author { get; set; }
-        public string Description { get; set; }
-        public string Website { get; set; }
-        public string Readme { get; set; }
-        public bool IsNSFW { get; set; }
-
-        public string MachineUrl { get; set; }
-        public AbsolutePath SplashScreen { get; set; }
-        public bool Publish { get; set; }
-    }
-
-    [JsonName("MO2CompilationSettings")]
-    public class MO2CompilationSettings
-    {
-        public AbsolutePath DownloadLocation { get; set; }
-        public AbsolutePath LastCompiledProfileLocation { get; set; }
-        public Dictionary<AbsolutePath, CompilationModlistSettings> ModlistSettings { get; } = new Dictionary<AbsolutePath, CompilationModlistSettings>();
-    }
-
 }
diff --git a/Wabbajack.App.Wpf/View Models/Compilers/ModlistSettingsEditorVM.cs b/Wabbajack.App.Wpf/View Models/Compilers/ModlistSettingsEditorVM.cs
deleted file mode 100644
index 1552b98e1..000000000
--- a/Wabbajack.App.Wpf/View Models/Compilers/ModlistSettingsEditorVM.cs	
+++ /dev/null
@@ -1,109 +0,0 @@
-using System;
-using System.Reactive.Linq;
-using System.Windows.Input;
-using DynamicData;
-using Microsoft.WindowsAPICodePack.Dialogs;
-using ReactiveUI;
-using ReactiveUI.Fody.Helpers;
-using Wabbajack.Common;
-using Wabbajack;
-
-namespace Wabbajack
-{
-    public class ModlistSettingsEditorVM : ViewModel
-    {
-        private readonly CompilationModlistSettings _settings;
-
-        [Reactive]
-        public string ModListName { get; set; }
-
-        [Reactive]
-        public string VersionText { get; set; }
-
-        private readonly ObservableAsPropertyHelper<Version> _version;
-        public Version Version => _version.Value;
-
-        [Reactive]
-        public string AuthorText { get; set; }
-
-        [Reactive]
-        public string Description { get; set; }
-
-        public FilePickerVM ImagePath { get; }
-
-        [Reactive]
-        public string Readme { get; set; }
-
-        [Reactive] public string MachineUrl { get; set; } = "";
-        [Reactive] public bool Publish { get; set; } = false;
-
-        [Reactive]
-        public string Website { get; set; }
-
-        [Reactive]
-        public bool IsNSFW { get; set; }
-
-        public IObservable<bool> InError { get; }
-
-        public ModlistSettingsEditorVM(CompilationModlistSettings settings)
-        {
-            _settings = settings;
-            ImagePath = new FilePickerVM
-            {
-                ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
-                PathType = FilePickerVM.PathTypeOptions.File,
-            };
-            ImagePath.Filters.Add(new CommonFileDialogFilter("Banner image", "*.png"));
-
-            _version = this.WhenAny(x => x.VersionText)
-                .Select(x =>
-                {
-                    if (string.IsNullOrWhiteSpace(x))
-                        return new Version(0, 0);
-
-                    return !Version.TryParse(x, out var version) ? new Version(0, 0) : version;
-                }).ObserveOnGuiThread()
-                .ToProperty(this, x => x.Version);
-
-            InError = this.WhenAny(x => x.ImagePath.ErrorState)
-                .Select(err => err.Failed)
-                .CombineLatest(
-                    this.WhenAny(x => x.VersionText)
-                    .Select(x => Version.TryParse(x, out _)), 
-                    (image, version) => !image && !version)
-                .Publish()
-                .RefCount();
-        }
-
-        public void Init()
-        {
-            AuthorText = _settings.Author;
-            if (!string.IsNullOrWhiteSpace(_settings.ModListName))
-            {
-                ModListName = _settings.ModListName;
-            }
-            Description = _settings.Description;
-            Readme = _settings.Readme;
-            ImagePath.TargetPath = _settings.SplashScreen;
-            Website = _settings.Website;
-            VersionText = _settings.Version;
-            IsNSFW = _settings.IsNSFW;
-            MachineUrl = _settings.MachineUrl;
-            Publish = _settings.Publish;
-        }
-
-        public void Save()
-        {
-            _settings.Version = VersionText;
-            _settings.Author = AuthorText;
-            _settings.ModListName = ModListName;
-            _settings.Description = Description;
-            _settings.Readme = Readme;
-            _settings.SplashScreen = ImagePath.TargetPath;
-            _settings.Website = Website;
-            _settings.IsNSFW = IsNSFW;
-            _settings.MachineUrl = MachineUrl;
-            _settings.Publish = Publish;
-        }
-    }
-}
diff --git a/Wabbajack.App.Wpf/View Models/Gallery/ModListGalleryVM.cs b/Wabbajack.App.Wpf/View Models/Gallery/ModListGalleryVM.cs
index e91b3ce7a..c87dfde56 100644
--- a/Wabbajack.App.Wpf/View Models/Gallery/ModListGalleryVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Gallery/ModListGalleryVM.cs	
@@ -80,7 +80,6 @@ public GameTypeEntry SelectedGameTypeEntry
         private readonly SettingsManager _settingsManager;
         private readonly CancellationToken _cancellationToken;
 
-        private FiltersSettings settings { get; set; } = new();
         public ICommand ClearFiltersCommand { get; set; }
 
         public ModListGalleryVM(ILogger<ModListGalleryVM> logger, Client wjClient, GameLocator locator,
diff --git a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs
index 8e87a272d..5e871ad0b 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
@@ -1,38 +1,25 @@
 using System;
-using System.Collections.Generic;
 using System.Diagnostics;
-using System.IO;
-using System.Linq;
 using System.Reactive.Disposables;
-using System.Reactive.Linq;
-using System.Text;
 using System.Threading.Tasks;
 using ReactiveUI;
 using ReactiveUI.Fody.Helpers;
-using Wabbajack.Common;
 using Wabbajack.Installer;
-using Wabbajack;
-using Wabbajack.DTOs;
 using Wabbajack.DTOs.Interventions;
-using Wabbajack.Interventions;
 using Wabbajack.Paths;
-using Wabbajack.Util;
 
 namespace Wabbajack
 {
     public class MO2InstallerVM : ViewModel, ISubInstallerVM
     {
         public InstallerVM Parent { get; }
-        
+
         [Reactive]
         public ErrorResponse CanInstall { get; set; }
 
         [Reactive]
         public IInstaller ActiveInstallation { get; private set; }
 
-
-        [Reactive] public Mo2ModlistInstallationSettings CurrentSettings { get; set; }
-
         public FilePickerVM Location { get; }
 
         public FilePickerVM DownloadLocation { get; }
@@ -62,111 +49,17 @@ public MO2InstallerVM(InstallerVM installerVM)
                         DownloadLocation.TargetPath = newPath.Combine("downloads");
                     }
                 }).DisposeWith(CompositeDisposable);
-                
+
             DownloadLocation = new FilePickerVM()
             {
                 ExistCheckOption = FilePickerVM.CheckOptions.Off,
                 PathType = FilePickerVM.PathTypeOptions.Folder,
                 PromptTitle = "Select a location for MO2 downloads",
             };
-            /* TODO
-            DownloadLocation.AdditionalError = this.WhenAny(x => x.DownloadLocation.TargetPath)
-                .Select(x => Utils.IsDirectoryPathValid(x));
-            Location.AdditionalError = Observable.CombineLatest(
-                    this.WhenAny(x => x.Location.TargetPath),
-                    this.WhenAny(x => x.DownloadLocation.TargetPath),
-                    resultSelector: (target, download) => (target, download))
-                .ObserveOn(RxApp.TaskpoolScheduler)
-                .Select(i => MO2Installer.CheckValidInstallPath(i.target, i.download, Parent.ModList?.SourceModList?.GameType.MetaData()))
-                .ObserveOnGuiThread();
-
-            _CanInstall = Observable.CombineLatest(
-                    this.WhenAny(x => x.Location.ErrorState),
-                    this.WhenAny(x => x.DownloadLocation.ErrorState),
-                    installerVM.WhenAny(x => x.ModListLocation.ErrorState),
-                    resultSelector: (loc, modlist, download) =>
-                    {
-                        return ErrorResponse.FirstFail(loc, modlist, download);
-                    })
-                .ToProperty(this, nameof(CanInstall));
-
-            // Have Installation location updates modify the downloads location if empty or the same path
-            this.WhenAny(x => x.Location.TargetPath)
-                .Skip(1) // Don't do it initially
-                .Subscribe(installPath =>
-                {
-                    if (DownloadLocation.TargetPath == default || DownloadLocation.TargetPath == installPath)
-                    {
-                        if (installPath.Exists) DownloadLocation.TargetPath = installPath.Combine("downloads");
-                    }
-                })
-                .DisposeWith(CompositeDisposable);
-
-            // Have Download location updates change if the same as the install path
-            this.WhenAny(x => x.DownloadLocation.TargetPath)
-                .Skip(1) // Don't do it initially
-                .Subscribe(downloadPath =>
-                {
-                    if (downloadPath != default && downloadPath == Location.TargetPath)
-                    {
-                        DownloadLocation.TargetPath = Location.TargetPath.Combine("downloads");
-                    }
-                })
-            .DisposeWith(CompositeDisposable);
-
-            // Load settings
-            _CurrentSettings = installerVM.WhenAny(x => x.ModListLocation.TargetPath)
-                .Select(path => path == default ? null : installerVM.MWVM.Settings.Installer.Mo2ModlistSettings.TryCreate(path))
-                .ToGuiProperty(this, nameof(CurrentSettings));
-            this.WhenAny(x => x.CurrentSettings)
-                .Pairwise()
-                .Subscribe(settingsPair =>
-                {
-                    SaveSettings(settingsPair.Previous);
-                    if (settingsPair.Current == null) return;
-                    Location.TargetPath = settingsPair.Current.InstallationLocation;
-                    DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
-                    AutomaticallyOverwrite = settingsPair.Current.AutomaticallyOverrideExistingInstall;
-                })
-                .DisposeWith(CompositeDisposable);
-            installerVM.MWVM.Settings.SaveSignal
-                .Subscribe(_ => SaveSettings(CurrentSettings))
-                .DisposeWith(CompositeDisposable);
-
-            // Hook onto user interventions, and intercept MO2 specific ones for customization
-            this.WhenAny(x => x.ActiveInstallation)
-                .Select(x => x?.LogMessages ?? Observable.Empty<IStatusMessage>())
-                .Switch()
-                .Subscribe(x =>
-                {
-                    switch (x)
-                    {
-                        case ConfirmUpdateOfExistingInstall c:
-                            if (AutomaticallyOverwrite)
-                            {
-                                c.Confirm();
-                            }
-                            break;
-                        default:
-                            break;
-                    }
-                })
-                .DisposeWith(CompositeDisposable);
-                */
         }
 
         public void Unload()
         {
-            SaveSettings(this.CurrentSettings);
-        }
-
-        private void SaveSettings(Mo2ModlistInstallationSettings settings)
-        {
-            //Parent.MWVM.Settings.Installer.LastInstalledListLocation = Parent.ModListLocation.TargetPath;
-            if (settings == null) return;
-            settings.InstallationLocation = Location.TargetPath;
-            settings.DownloadLocation = DownloadLocation.TargetPath;
-            settings.AutomaticallyOverrideExistingInstall = AutomaticallyOverwrite;
         }
 
         public void AfterInstallNavigation()
@@ -205,7 +98,7 @@ public async Task<bool> Install()
             */
             return true;
         }
-        
+
         public IUserIntervention InterventionConverter(IUserIntervention intervention)
         {
             switch (intervention)
diff --git a/Wabbajack.App.Wpf/View Models/MainWindowVM.cs b/Wabbajack.App.Wpf/View Models/MainWindowVM.cs
index 804a14d6a..cd1430ed3 100644
--- a/Wabbajack.App.Wpf/View Models/MainWindowVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/MainWindowVM.cs	
@@ -16,11 +16,8 @@
 using Microsoft.Extensions.Logging;
 using Orc.FileAssociation;
 using Wabbajack.Common;
-using Wabbajack.Downloaders.GameFile;
-using Wabbajack;
 using Wabbajack.DTOs.Interventions;
 using Wabbajack.Interventions;
-using Wabbajack.LoginManagers;
 using Wabbajack.Messages;
 using Wabbajack.Models;
 using Wabbajack.Networking.WabbajackClientApi;
@@ -39,8 +36,6 @@ public class MainWindowVM : ViewModel
     {
         public MainWindow MainWindow { get; }
 
-        public MainSettings Settings { get; }
-
         [Reactive]
         public ViewModel ActivePane { get; private set; }
 
@@ -76,7 +71,7 @@ public class MainWindowVM : ViewModel
         [Reactive]
         public bool UpdateAvailable { get; private set; }
 
-        public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client wjClient,
+        public MainWindowVM(ILogger<MainWindowVM> logger, Client wjClient,
             IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM, ResourceMonitor resourceMonitor,
             InstallerVM installer, CompilerVM compilerVM, SettingsVM settingsVM, WebBrowserVM webBrowserVM)
         {
@@ -85,7 +80,6 @@ public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client
             _resourceMonitor = resourceMonitor;
             _serviceProvider = serviceProvider;
             ConverterRegistration.Register();
-            Settings = settings;
             Installer = installer;
             Compiler = compilerVM;
             SettingsPane = settingsVM;
diff --git a/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs b/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs
index 64fb3afb9..a32855cec 100644
--- a/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Settings/SettingsVM.cs	
@@ -28,7 +28,6 @@ public class SettingsVM : BackNavigatingVM
 
         public LoginManagerVM Login { get; }
         public PerformanceSettings Performance { get; }
-        public FiltersSettings Filters { get; }
         public AuthorFilesVM AuthorFile { get; }
 
         public ICommand OpenTerminalCommand { get; }
diff --git a/Wabbajack.App.Wpf/Views/Common/CpuView.xaml.cs b/Wabbajack.App.Wpf/Views/Common/CpuView.xaml.cs
index d56efa073..4541b3c4c 100644
--- a/Wabbajack.App.Wpf/Views/Common/CpuView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Common/CpuView.xaml.cs
@@ -1,24 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Disposables;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reactive.Disposables;
 using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
 using ReactiveUI;
-using ReactiveUI.Fody.Helpers;
-using Wabbajack;
-using System.Windows.Controls.Primitives;
 using System.Reactive.Linq;
-using Wabbajack.Common;
 using Wabbajack.RateLimiter;
 
 namespace Wabbajack
@@ -36,23 +19,12 @@ public Percent ProgressPercent
         public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(Percent), typeof(CpuView),
              new FrameworkPropertyMetadata(default(Percent), WireNotifyPropertyChanged));
 
-        public MainSettings SettingsHook
-        {
-            get => (MainSettings)GetValue(SettingsHookProperty);
-            set => SetValue(SettingsHookProperty, value);
-        }
-        public static readonly DependencyProperty SettingsHookProperty = DependencyProperty.Register(nameof(SettingsHook), typeof(MainSettings), typeof(CpuView),
-             new FrameworkPropertyMetadata(default(SettingsVM), WireNotifyPropertyChanged));
-
-        private bool _ShowingSettings;
-        public bool ShowingSettings { get => _ShowingSettings; set => this.RaiseAndSetIfChanged(ref _ShowingSettings, value); }
-
         public CpuView()
         {
             InitializeComponent();
             this.WhenActivated(disposable =>
             {
-               
+
                 this.WhenAny(x => x.ViewModel.StatusList)
                     .BindToStrict(this, x => x.CpuListControl.ItemsSource)
                     .DisposeWith(disposable);
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationView.xaml b/Wabbajack.App.Wpf/Views/Installers/InstallationView.xaml
index 9dc049e9f..39fc63eed 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationView.xaml
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationView.xaml
@@ -324,20 +324,6 @@
             <local:CpuView Grid.Column="2"
                 x:Name="CpuView"
                 ViewModel="{Binding}" />
-            <!--
-            <local:AttentionBorder Grid.Column="2"
-                x:Name="UserInterventionsControl"
-                Content="{Binding ActiveGlobalUserIntervention}">
-                <local:AttentionBorder.Resources>
-                    <DataTemplate DataType="{x:Type lib1:ConfirmationIntervention}">
-                        <local:ConfirmationInterventionView ViewModel="{Binding}" />
-                    </DataTemplate>
-                    <DataTemplate DataType="{x:Type local:ConfirmUpdateOfExistingInstallVM}">
-                        <local:ConfirmUpdateOfExistingInstallView ViewModel="{Binding}" />
-                    </DataTemplate>
-                </local:AttentionBorder.Resources>
-            </local:AttentionBorder>
-            -->
             <local:InstallationCompleteView Grid.Column="2"
                 x:Name="InstallComplete"
                 ViewModel="{Binding}" />
diff --git a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
deleted file mode 100644
index 60620f632..000000000
--- a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml
+++ /dev/null
@@ -1,50 +0,0 @@
-<rxui:ReactiveUserControl
-    x:Class="Wabbajack.ConfirmUpdateOfExistingInstallView"
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:lib="clr-namespace:Wabbajack;assembly=Wabbajack"
-    xmlns:local="clr-namespace:Wabbajack"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:rxui="http://reactiveui.net"
-    d:DesignHeight="450"
-    d:DesignWidth="800"
-    x:TypeArguments="local:ConfirmUpdateOfExistingInstallVM"
-    mc:Ignorable="d">
-    <Grid Margin="10">
-        <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="*" />
-            <ColumnDefinition Width="10" />
-            <ColumnDefinition Width="*" />
-        </Grid.ColumnDefinitions>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="5*" />
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="2*" />
-        </Grid.RowDefinitions>
-        <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
-            x:Name="ShortDescription"
-            Margin="0,0,0,5"
-            FontFamily="Lucida Sans"
-            FontSize="14"
-            FontWeight="Bold"
-            TextWrapping="WrapWithOverflow" />
-        <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
-            x:Name="ExtendedDescription"
-            TextWrapping="WrapWithOverflow" />
-        <CheckBox Grid.Row="2" Grid.Column="2"
-            x:Name="AutoOverwriteCheckbox"
-            Margin="4"
-            HorizontalAlignment="Right"
-            Content="Remember"
-            IsChecked="{Binding Installer.AutomaticallyOverwrite}"
-            ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." />
-        <Button Grid.Row="3" Grid.Column="0"
-            x:Name="CancelButton"
-            Content="Cancel" />
-        <Button Grid.Row="3" Grid.Column="2"
-            x:Name="ConfirmButton"
-            Content="Confirm" />
-    </Grid>
-</rxui:ReactiveUserControl>
diff --git a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs b/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs
deleted file mode 100644
index 093eb3eba..000000000
--- a/Wabbajack.App.Wpf/Views/Interventions/ConfirmUpdateOfExistingInstallView.xaml.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Disposables;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using ReactiveUI;
-using Wabbajack;
-
-namespace Wabbajack
-{
-    /// <summary>
-    /// Interaction logic for ConfirmUpdateOfExistingInstallView.xaml
-    /// </summary>
-    public partial class ConfirmUpdateOfExistingInstallView : ReactiveUserControl<ConfirmUpdateOfExistingInstallVM>
-    {
-        public ConfirmUpdateOfExistingInstallView()
-        {
-            InitializeComponent();
-            this.WhenActivated(dispose =>
-            {
-                this.WhenAny(x => x.ViewModel.ShortDescription)
-                    .BindToStrict(this, x => x.ShortDescription.Text)
-                    .DisposeWith(dispose);
-                this.WhenAny(x => x.ViewModel.ExtendedDescription)
-                    .BindToStrict(this, x => x.ExtendedDescription.Text)
-                    .DisposeWith(dispose);
-                this.WhenAny(x => x.ViewModel.Source.ConfirmCommand)
-                    .BindToStrict(this, x => x.ConfirmButton.Command)
-                    .DisposeWith(dispose);
-                this.WhenAny(x => x.ViewModel.Source.CancelCommand)
-                    .BindToStrict(this, x => x.CancelButton.Command)
-                    .DisposeWith(dispose);
-
-                this.BindStrict(this.ViewModel, x => x.Installer.AutomaticallyOverwrite, x => x.AutoOverwriteCheckbox.IsChecked,
-                        vmToViewConverter: x => x,
-                        viewToVmConverter: x => x ?? false)
-                    .DisposeWith(dispose);
-            });
-        }
-    }
-}
diff --git a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
index 5bb1d7878..8f7aba3c6 100644
--- a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
@@ -1,26 +1,17 @@
 using System;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
-using System.Linq;
 using System.Reactive.Linq;
-using System.Threading;
 using System.Windows;
 using System.Windows.Input;
-using DynamicData;
 using DynamicData.Binding;
 using MahApps.Metro.Controls;
 using Microsoft.Extensions.Logging;
 using ReactiveUI;
-using ReactiveUI.Fody.Helpers;
 using Wabbajack.Common;
-using Wabbajack.DTOs;
-using Wabbajack.DTOs.DownloadStates;
-using Wabbajack.DTOs.Interventions;
 using Wabbajack.Messages;
 using Wabbajack.Paths.IO;
-using Wabbajack.UserIntervention;
 using Wabbajack.Util;
-using Wabbajack.Views;
 
 namespace Wabbajack
 {
@@ -30,7 +21,6 @@ namespace Wabbajack
     public partial class MainWindow : MetroWindow
     {
         private MainWindowVM _mwvm;
-        private MainSettings _settings;
         private readonly ILogger<MainWindow> _logger;
         private readonly SystemParametersConstructor _systemParams;
 
@@ -75,7 +65,7 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                 var p = _systemParams.Create();
 
                 _logger.LogInformation("Detected Windows Version: {Version}", Environment.OSVersion.VersionString);
-                
+
                 _logger.LogInformation(
                     "System settings - ({MemorySize} RAM) ({PageSize} Page), Display: {ScreenWidth} x {ScreenHeight} ({Vram} VRAM - VideoMemorySizeMb={ENBVRam})",
                     p.SystemMemorySize.ToFileSizeString(), p.SystemPageSize.ToFileSizeString(), p.ScreenWidth, p.ScreenHeight, p.VideoMemorySize.ToFileSizeString(), p.EnbLEVRAMSize);
@@ -85,25 +75,8 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                 else if (p.SystemPageSize < 2e+10)
                     _logger.LogInformation("Pagefile below recommended! Consider increasing to 20000MB. A suboptimal pagefile can cause crashes and poor in-game performance");
 
-                //Warmup();
-                
                 var _ = updater.Run();
 
-                var (settings, loadedSettings) = MainSettings.TryLoadTypicalSettings().AsTask().Result;
-                // Load settings
-                /*
-                if (CLIArguments.NoSettings || !loadedSettings)
-                {
-                    _settings = new MainSettings {Version = Consts.SettingsVersion};
-                    RunWhenLoaded(DefaultSettings);
-                }
-                else
-                {
-                    _settings = settings;
-                    RunWhenLoaded(LoadSettings);
-                }*/
-                
-
                 // Bring window to the front if it isn't already
                 this.Initialized += (s, e) =>
                 {
@@ -135,45 +108,7 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                 .BindToStrict(this, view => view.ResourceUsage.Text);
             vm.WhenAnyValue(vm => vm.AppName)
                 .BindToStrict(this, view => view.AppName.Text);
-            
-        }
-
-        public void Init(MainWindowVM vm, MainSettings settings)
-        {
-            DataContext = vm;
-            _mwvm = vm;
-            _settings = settings;
-        }
 
-        private void RunWhenLoaded(Action a)
-        {
-            if (IsLoaded)
-            {
-                a();
-            }
-            else
-            {
-                this.Loaded += (sender, e) =>
-                {
-                    a();
-                };
-            }
-        }
-
-        private void LoadSettings()
-        {
-            Width = _settings.Width;
-            Height = _settings.Height;
-            Left = _settings.PosX;
-            Top = _settings.PosY;
-        }
-
-        private void DefaultSettings()
-        {
-            Width = 1300;
-            Height = 960;
-            Left = 15;
-            Top = 15;
         }
 
         private void Window_Closing(object sender, CancelEventArgs e)
diff --git a/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml b/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml
index 8b2a755b2..4e5180445 100644
--- a/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml
+++ b/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml
@@ -6,7 +6,6 @@
     xmlns:local="clr-namespace:Wabbajack"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:rxui="http://reactiveui.net"
-    xmlns:xwpf="http://schemas.xceed.com/wpf/xaml/toolkit"
     d:DesignHeight="450"
     d:DesignWidth="800"
     x:TypeArguments="local:SettingsVM"
@@ -32,17 +31,19 @@
                 <ColumnDefinition Width="5" />
                 <ColumnDefinition Width="*" />
             </Grid.ColumnDefinitions>
-            <TextBlock Grid.Column="0" Grid.ColumnSpan="2"
+            <TextBlock
+                Grid.Column="0"
+                Grid.ColumnSpan="2"
                 FontFamily="Lucida Sans"
                 FontSize="20"
                 FontWeight="Bold"
                 Text="Misc Settings" />
-            <Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3">
+            <Grid
+                Grid.Row="2"
+                Grid.Column="0"
+                Grid.ColumnSpan="3">
                 <Grid.RowDefinitions>
                     <RowDefinition />
-                    <RowDefinition />
-                    <RowDefinition />
-                    <RowDefinition />
                 </Grid.RowDefinitions>
                 <Grid.Resources>
                     <Style BasedOn="{StaticResource MainButtonStyle}" TargetType="Button">
@@ -55,32 +56,9 @@
                         </Style.Triggers>
                     </Style>
                 </Grid.Resources>
-                <CheckBox Grid.Row="0"
-                    Name="FilterPersistCheckBox"
-                    Margin="0,5,0,0"
-                    HorizontalAlignment="Left"
-                    VerticalAlignment="Top"
-                    Content="Gallery filters are saved on exit">
-                    <CheckBox.LayoutTransform>
-                        <ScaleTransform ScaleX="1.2" ScaleY="1.2" />
-                    </CheckBox.LayoutTransform>
-                </CheckBox>
-                <CheckBox Grid.Row="1"
-                    Name="UseCompressionCheckBox"
-                    Margin="0,5,0,0"
-                    HorizontalAlignment="Left"
-                    VerticalAlignment="Top"
-                    Content="Use NTFS LZS compression during install">
-                    <CheckBox.LayoutTransform>
-                        <ScaleTransform ScaleX="1.2" ScaleY="1.2" />
-                    </CheckBox.LayoutTransform>
-                </CheckBox>
-                <Button Grid.Row="2"
-                    Name="ClearCefCache"
-                    Margin="0,5,0,0"
-                    Content="Clear In-App Browser Cache" />
-                <Button Grid.Row="3"
+                <Button
                     Name="OpenTerminal"
+                    Grid.Row="0"
                     Margin="0,5,0,0"
                     Content="Launch Wabbajack CLI" />
             </Grid>
diff --git a/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml.cs b/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml.cs
index 298a195ab..52a1d5786 100644
--- a/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Settings/MiscSettingsView.xaml.cs
@@ -15,10 +15,6 @@ public MiscSettingsView()
             this.WhenActivated(disposable =>
             {
                 // Bind Values
-                this.BindStrict(this.ViewModel, x => x.Filters.IsPersistent, x => x.FilterPersistCheckBox.IsChecked)
-                    .DisposeWith(disposable);
-                this.BindStrict(this.ViewModel, x => x.Filters.UseCompression, x => x.UseCompressionCheckBox.IsChecked)
-                    .DisposeWith(disposable);
                 this.WhenAnyValue(x => x.ViewModel.OpenTerminalCommand)
                     .BindToStrict(this, x => x.OpenTerminal.Command)
                     .DisposeWith(disposable);

From c23a7ad794c1aafaf5b70c9ad9ddf561a28dab14 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Tue, 22 Aug 2023 20:04:57 +0200
Subject: [PATCH 14/57] Updated CHANGELOG.md

---
 CHANGELOG.md | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9708f104..a47567863 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,25 +1,27 @@
 ### Changelog
 
-### Version - TBA
+### Version - TBA - Preview
 * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, drive space checking, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
+* Fixed manual downloader downloading in the OS's "Downloads" folder
+* Added RAM Limit setting for downloads
 
 #### Version - 3.2.0.1 - 7/23/2023
-  * Code cleanup: re-added some network and diagnostic code missing since 2.5
+* Code cleanup: re-added some network and diagnostic code missing since 2.5
 
 #### Version - 3.2.0.0 - 7/16/2023
-  * Fixed issues related to high RAM usage
-  * The resumable downloads now reserve drive space to write to in advance instead of being managed in system RAM
-  * remove LoversLab from the "Logins" Setting because it is deprecated for ages now and only causes confusion,
-    just for the unlikely probability that LL will fix their proper API.
-  * Added safety to install path selection, to ensure that no files are deleted that are not intended to be.
-  * Fixed allowing back button during install which can result in multiple install processes
-  * fixed search filter not applying when pressing back button and reaccessing gallery
-  * Added more robust checking for protected location paths and subfolders for the launcher exe and install and download paths
-  * Fixed readme double opening when modlist details are prepoulated
-  * Added a check if Downloadpath is alongside Wabbajack.exe location, to match the install path check that already exists
-  * Added check for identical download and install paths
-  * Fixed No Delete and NoDelete being handled by stripping whitespace before the regex, to idiotproof things a bit
+* Fixed issues related to high RAM usage
+* The resumable downloads now reserve drive space to write to in advance instead of being managed in system RAM
+* remove LoversLab from the "Logins" Setting because it is deprecated for ages now and only causes confusion,
+  just for the unlikely probability that LL will fix their proper API.
+* Added safety to install path selection, to ensure that no files are deleted that are not intended to be.
+* Fixed allowing back button during install which can result in multiple install processes
+* fixed search filter not applying when pressing back button and reaccessing gallery
+* Added more robust checking for protected location paths and subfolders for the launcher exe and install and download paths
+* Fixed readme double opening when modlist details are prepoulated
+* Added a check if Downloadpath is alongside Wabbajack.exe location, to match the install path check that already exists
+* Added check for identical download and install paths
+* Fixed No Delete and NoDelete being handled by stripping whitespace before the regex, to idiotproof things a bit
 
 #### Version - 3.1.0.0 - 5/7/2023
 * Fixed Readme opening twice

From f1390380e4cc9a93605d8dcb7239590f90a8e64c Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Tue, 22 Aug 2023 20:16:25 +0200
Subject: [PATCH 15/57] update CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a47567863..9f0ddace8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 ### Changelog
 
-### Version - TBA - Preview
+### Version - 3.3.0.0-Pre - 08/22/2023
 * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, drive space checking, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder

From 8edbb697b0e467ac789edc604fbba8074b3228ed Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Thu, 24 Aug 2023 18:16:38 +0100
Subject: [PATCH 16/57] moved the existing files popup to an error message ,
 heralding the return of the overwrite install checkbox

---
 .../View Models/Installers/InstallerVM.cs     | 32 +++++++++----------
 .../View Models/Installers/MO2InstallerVM.cs  |  4 +++
 .../InstallationConfigurationView.xaml        | 22 ++++++++++++-
 .../InstallationConfigurationView.xaml.cs     |  6 ++--
 4 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index d0869e3ac..b9393eda6 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -135,6 +135,8 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
     public LogStream LoggerProvider { get; }
 
     private AbsolutePath LastInstallPath { get; set; }
+
+    [Reactive] public bool OverwriteFiles { get; set; }
     
     
     // Command properties
@@ -225,7 +227,10 @@ public InstallerVM(ILogger<InstallerVM> logger, DTOSerializer dtos, SettingsMana
         {
             UIUtils.OpenFolder(Installer.Location.TargetPath);
         });
-        
+
+        this.WhenAnyValue(x => x.OverwriteFiles)
+            .Subscribe(x => ConfirmOverwrite());
+
         MessageBus.Current.Listen<LoadModlistForInstalling>()
             .Subscribe(msg => LoadModlistFromGallery(msg.Path, msg.Metadata).FireAndForget())
             .DisposeWith(CompositeDisposable);
@@ -314,24 +319,10 @@ private IEnumerable<ErrorResponse> Validate()
             yield return ErrorResponse.Fail("Installing in this folder may overwrite Wabbajack");
         }
 
-        if (installPath.ToString().Length != 0 && installPath != LastInstallPath &&
+        if (installPath.ToString().Length != 0 && installPath != LastInstallPath && !OverwriteFiles &&
             Directory.EnumerateFileSystemEntries(installPath.ToString()).Any())
         {
-            string message =
-                "There are files already in the chosen install path, if you are updating an existing modlist, this is fine. " + Environment.NewLine + 
-                " Otherwise, please ensure you intend for the folder contents to be deleted during the modlist install." + Environment.NewLine +
-                " Continue? ";
-            string title = "Files found in install folder";
-            MessageBoxButtons buttons = MessageBoxButtons.YesNo;
-            DialogResult result = MessageBox.Show(message, title, buttons);
-            if (result == DialogResult.Yes)
-            {
-                // everythings fine
-            }
-            else
-            {
-                Installer.Location.TargetPath = "".ToAbsolutePath();
-            }
+            yield return ErrorResponse.Fail("There are files in the install folder, please tick 'Overwrite Installation' to confirm you want to install to this folder, if you are updating an existing modlist, this is fine.");
         }
 
         if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))
@@ -455,6 +446,13 @@ private async Task LoadModlist(AbsolutePath path, ModlistMetadata? metadata)
         }
     }
 
+    private void ConfirmOverwrite()
+    {
+        AbsolutePath prev = Installer.Location.TargetPath;
+        Installer.Location.TargetPath = "".ToAbsolutePath();
+        Installer.Location.TargetPath = prev;
+    }
+
     private async Task BeginInstall()
     {
         await Task.Run(async () =>
diff --git a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs
index c4f2e93d1..85abe23a8 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
@@ -39,6 +39,9 @@ public class MO2InstallerVM : ViewModel, ISubInstallerVM
 
         public bool SupportsAfterInstallNavigation => true;
 
+        [Reactive]
+        public bool AutomaticallyOverwrite { get; set; }
+        
         public int ConfigVisualVerticalOffset => 25;
 
         public MO2InstallerVM(InstallerVM installerVM)
@@ -163,6 +166,7 @@ private void SaveSettings(Mo2ModlistInstallationSettings settings)
             if (settings == null) return;
             settings.InstallationLocation = Location.TargetPath;
             settings.DownloadLocation = DownloadLocation.TargetPath;
+            settings.AutomaticallyOverrideExistingInstall = AutomaticallyOverwrite;
         }
 
         public void AfterInstallNavigation()
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
index 5cd461c9c..6580df932 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml
@@ -81,10 +81,11 @@
                 <RowDefinition Height="*" />
                 <RowDefinition Height="Auto" />
                 <RowDefinition Height="*" />
+                <RowDefinition Height="*" />
             </Grid.RowDefinitions>
             <local:BeginButton Grid.Row="1"
                 x:Name="BeginButton"
-                HorizontalAlignment="Right"
+                HorizontalAlignment="Center"
                 VerticalAlignment="Center" />
             <icon:PackIconFontAwesome Grid.Row="2"
                 x:Name="ErrorSummaryIconGlow"
@@ -99,8 +100,27 @@
             <icon:PackIconFontAwesome Grid.Row="2"
                 x:Name="ErrorSummaryIcon"
                 HorizontalAlignment="Center"
+                VerticalAlignment="Top"
                 Foreground="{StaticResource WarningBrush}"
                 Kind="ExclamationTriangleSolid" />
+            <CheckBox Grid.Row="2" Grid.Column="2"
+            HorizontalAlignment="Center"
+            VerticalAlignment="Bottom"
+            x:Name="OverwriteCheckBox"
+            Content="Overwrite Installation"
+            IsChecked="False"
+            ToolTip="Confirm to overwrite files in install folder.">
+                <CheckBox.Style>
+                    <Style TargetType="CheckBox">
+                        <Setter Property="Opacity" Value="0.6" />
+                        <Style.Triggers>
+                            <DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
+                                <Setter Property="Opacity" Value="1" />
+                            </DataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </CheckBox.Style>
+            </CheckBox>
         </Grid>
     </Grid>
 </rxui:ReactiveUserControl>
diff --git a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
index a69a7450a..178780e7f 100644
--- a/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/Installers/InstallationConfigurationView.xaml.cs
@@ -39,9 +39,11 @@ public InstallationConfigurationView()
                 this.WhenAny(x => x.ViewModel.BeginCommand)
                     .BindToStrict(this, x => x.BeginButton.Command)
                     .DisposeWith(dispose);
-                
+                this.BindStrict(ViewModel, vm => vm.OverwriteFiles, x => x.OverwriteCheckBox.IsChecked)
+                    .DisposeWith(dispose);
+
                 // Error handling
-                
+
                 this.WhenAnyValue(x => x.ViewModel.ErrorState)
                     .Select(v => !v.Failed)
                     .BindToStrict(this, view => view.BeginButton.IsEnabled)

From c54f223bde2a319c9d90257627253890c94c4865 Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Thu, 24 Aug 2023 18:49:44 +0100
Subject: [PATCH 17/57] added newline

---
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index b9393eda6..929e92153 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -322,7 +322,8 @@ private IEnumerable<ErrorResponse> Validate()
         if (installPath.ToString().Length != 0 && installPath != LastInstallPath && !OverwriteFiles &&
             Directory.EnumerateFileSystemEntries(installPath.ToString()).Any())
         {
-            yield return ErrorResponse.Fail("There are files in the install folder, please tick 'Overwrite Installation' to confirm you want to install to this folder, if you are updating an existing modlist, this is fine.");
+            yield return ErrorResponse.Fail("There are files in the install folder, please tick 'Overwrite Installation' to confirm you want to install to this folder " + Environment.NewLine + 
+                 "if you are updating an existing modlist, then this is expected and can be overwritten.");
         }
 
         if (KnownFolders.IsInSpecialFolder(installPath) || KnownFolders.IsInSpecialFolder(downloadPath))

From 081a68cd0ba74e88619a7c9331a4dc87ca2abff4 Mon Sep 17 00:00:00 2001
From: JanuarySnow <bobfordiscord12@gmail.com>
Date: Thu, 24 Aug 2023 18:53:01 +0100
Subject: [PATCH 18/57] reverted erroneous edit

---
 Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs
index 85abe23a8..8e87a272d 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/MO2InstallerVM.cs	
@@ -41,7 +41,7 @@ public class MO2InstallerVM : ViewModel, ISubInstallerVM
 
         [Reactive]
         public bool AutomaticallyOverwrite { get; set; }
-        
+
         public int ConfigVisualVerticalOffset => 25;
 
         public MO2InstallerVM(InstallerVM installerVM)

From c93a4af7d29bf03e3967e4f9809a1e09dd5f252d Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Sun, 27 Aug 2023 18:03:16 +0200
Subject: [PATCH 19/57] gogID for fallout4 added

---
 Wabbajack.DTOs/Game/GameRegistry.cs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index 95bec0e6d..b202eebe5 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -130,6 +130,7 @@ public static class GameRegistry
                 MO2Name = "Fallout 4",
                 MO2ArchiveName = "fallout4",
                 SteamIDs = new[] {377160},
+                GOGIDs = new []{1998527297},
                 RequiredFiles = new[]
                 {
                     "Fallout4.exe".ToRelativePath()

From 4384cfcb2fd692444cde6a6bfc128e09bbfecfac Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Sun, 27 Aug 2023 18:05:54 +0200
Subject: [PATCH 20/57] update CHANGELOG.md

---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 247c9e6fe..5075d1919 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ### Changelog
 
+#### Version - TBD
+* Added Fallout 4 (GOG) to the index
+
 #### Version - 3.2.0.1 - 7/23/2023
   * Code cleanup: re-added some network and diagnostic code missing since 2.5
 

From 21bf0a87c9e199f664d68e8630931f908f08d4ea Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Mon, 28 Aug 2023 17:28:44 +0200
Subject: [PATCH 21/57] Fix deadlock when loading new settings

---
 Wabbajack.Configuration/MainSettings.cs              | 4 ++--
 Wabbajack.Services.OSIntegrated/ServiceExtensions.cs | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Wabbajack.Configuration/MainSettings.cs b/Wabbajack.Configuration/MainSettings.cs
index 45eadd8ba..5b8bf4eb8 100644
--- a/Wabbajack.Configuration/MainSettings.cs
+++ b/Wabbajack.Configuration/MainSettings.cs
@@ -5,9 +5,9 @@ public class MainSettings
     public const string SettingsFileName = "app_settings";
     private const int SettingsVersion = 1;
 
-    public int CurrentSettingsVersion { get; private set; }
+    public int CurrentSettingsVersion { get; set; }
 
-    public PerformanceSettings PerformanceSettings { get; } = new();
+    public PerformanceSettings PerformanceSettings { get; set; } = new();
 
     public bool Upgrade()
     {
diff --git a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
index 87ce587f2..d89cf4e27 100644
--- a/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
+++ b/Wabbajack.Services.OSIntegrated/ServiceExtensions.cs
@@ -100,8 +100,8 @@ public static IServiceCollection AddOSIntegrated(this IServiceCollection service
 
         MainSettings GetAppSettings(IServiceProvider provider, string name)
         {
-            var settingsManager = provider.GetService<SettingsManager>();
-            var settings = settingsManager!.Load<MainSettings>(name).Result;
+            var settingsManager = provider.GetRequiredService<SettingsManager>();
+            var settings = Task.Run(() => settingsManager.Load<MainSettings>(name)).Result;
             if (settings.Upgrade())
             {
                 settingsManager.Save(MainSettings.SettingsFileName, settings).FireAndForget();

From 70c1f3ad33d7bd1d902d7eca70460b1fd1d52981 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 2 Oct 2023 16:21:10 +0200
Subject: [PATCH 22/57] change folder/directory check logic

---
 Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index 8901b6100..3648520a4 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -279,11 +279,11 @@ private IEnumerable<ErrorResponse> Validate()
             yield return ErrorResponse.Fail("Mod list source does not exist");
 
         var downloadPath = Installer.DownloadLocation.TargetPath;
-        if (downloadPath.Depth <= 1)
+        if (!downloadPath.DirectoryExists())
             yield return ErrorResponse.Fail("Download path isn't set to a folder");
         
         var installPath = Installer.Location.TargetPath;
-        if (installPath.Depth <= 1)
+        if (!installPath.DirectoryExists())
             yield return ErrorResponse.Fail("Install path isn't set to a folder");
         if (installPath.InFolder(KnownFolders.Windows))
             yield return ErrorResponse.Fail("Don't install modlists into your Windows folder");

From 1f79598dfe458bc39fed4c3ae3a5f670de9723f6 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 2 Oct 2023 16:32:31 +0200
Subject: [PATCH 23/57] update CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d0474d30..a8e3a37e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 ### Changelog
 
-### Version - 3.3.0.0-Pre - 08/22/2023
+#### Version - 3.3.0.0-Pre - 10/02/2023
 * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, drive space checking, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder

From e9aeec7b4ac76dc9ee0c0148f8ae3bd6a340ffdc Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 2 Oct 2023 22:37:15 +0200
Subject: [PATCH 24/57] revert unnecessary change

---
 .../View Models/Installers/InstallerVM.cs         | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs
index 3648520a4..e5c16540b 100644
--- a/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
+++ b/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs	
@@ -279,11 +279,11 @@ private IEnumerable<ErrorResponse> Validate()
             yield return ErrorResponse.Fail("Mod list source does not exist");
 
         var downloadPath = Installer.DownloadLocation.TargetPath;
-        if (!downloadPath.DirectoryExists())
+        if (downloadPath.Depth <= 1)
             yield return ErrorResponse.Fail("Download path isn't set to a folder");
         
         var installPath = Installer.Location.TargetPath;
-        if (!installPath.DirectoryExists())
+        if (installPath.Depth <= 1)
             yield return ErrorResponse.Fail("Install path isn't set to a folder");
         if (installPath.InFolder(KnownFolders.Windows))
             yield return ErrorResponse.Fail("Don't install modlists into your Windows folder");
@@ -330,12 +330,13 @@ private IEnumerable<ErrorResponse> Validate()
         {
             yield return ErrorResponse.Fail("Can't install into Windows locations such as Documents etc, please make a new folder for the modlist - C:\\ModList\\ for example.");
         }
-
-        if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){
-            yield return ErrorResponse.Fail("Can't install modlist due to lack of free hard drive space, please read the modlist Readme to learn more.");
-        }
+        // Disabled Because it was causing issues for people trying to update lists.
+        //if (installPath.ToString().Length > 0 && downloadPath.ToString().Length > 0 && !HasEnoughSpace(installPath, downloadPath)){
+        //    yield return ErrorResponse.Fail("Can't install modlist due to lack of free hard drive space, please read the modlist Readme to learn more.");
+        //}
     }
     
+    /*
     private bool HasEnoughSpace(AbsolutePath inpath, AbsolutePath downpath)
     {      
         string driveLetterInPath = inpath.ToString().Substring(0,1);
@@ -363,7 +364,7 @@ private bool HasEnoughSpace(AbsolutePath inpath, AbsolutePath downpath)
         }
         return true;
 
-    }
+    }*/
 
     private async Task BeginSlideShow(CancellationToken token)
     {

From aa7471a8a7176a7aabda10782d54e41f8ddc1651 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 2 Oct 2023 23:09:01 +0200
Subject: [PATCH 25/57] update CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a8e3a37e9..6de8b2bf5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
 ### Changelog
 
 #### Version - 3.3.0.0-Pre - 10/02/2023
-* Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, drive space checking, wiki link button
+* Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder
 * Added RAM Limit setting for downloads

From a631ca934e6dbd553d85f14b910a78a5ff9d5ff2 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Wed, 4 Oct 2023 22:26:49 +0200
Subject: [PATCH 26/57] Bump Wabbajack to .NET 7

---
 Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj                     | 2 +-
 Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj             | 2 +-
 Wabbajack.CLI/Wabbajack.CLI.csproj                             | 3 ++-
 Wabbajack.Common/Wabbajack.Common.csproj                       | 2 +-
 Wabbajack.Compiler.Test/Wabbajack.Compiler.Test.csproj         | 2 +-
 Wabbajack.Compiler/Wabbajack.Compiler.csproj                   | 2 +-
 .../Wabbajack.Compression.BSA.Test.csproj                      | 2 +-
 Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj     | 2 +-
 .../Wabbajack.Compression.Zip.Test.csproj                      | 2 +-
 Wabbajack.Compression.Zip/Wabbajack.Compression.Zip.csproj     | 2 +-
 Wabbajack.Configuration/Wabbajack.Configuration.csproj         | 2 +-
 .../Wabbajack.DTOs.ConverterGenerators.csproj                  | 2 +-
 Wabbajack.DTOs.Test/Wabbajack.DTOs.Test.csproj                 | 2 +-
 Wabbajack.DTOs/Wabbajack.DTOs.csproj                           | 2 +-
 .../Wabbajack.Downloaders.Bethesda.csproj                      | 2 +-
 .../Wabbajack.Downloaders.Dispatcher.Test.csproj               | 2 +-
 .../Wabbajack.Downloaders.Dispatcher.csproj                    | 2 +-
 .../Wabbajack.Downloaders.GameFile.csproj                      | 2 +-
 .../Wabbajack.Downloaders.GoogleDrive.csproj                   | 2 +-
 Wabbajack.Downloaders.Http/Wabbajack.Downloaders.Http.csproj   | 2 +-
 .../Wabbajack.Downloaders.IPS4OAuth2Downloader.csproj          | 2 +-
 .../Wabbajack.Downloaders.Interfaces.csproj                    | 2 +-
 .../Wabbajack.Downloaders.Manual.csproj                        | 2 +-
 .../Wabbajack.Downloaders.MediaFire.csproj                     | 2 +-
 Wabbajack.Downloaders.Mega/Wabbajack.Downloaders.Mega.csproj   | 2 +-
 Wabbajack.Downloaders.ModDB/Wabbajack.Downloaders.ModDB.csproj | 2 +-
 Wabbajack.Downloaders.Nexus/Wabbajack.Downloaders.Nexus.csproj | 2 +-
 .../Wabbajack.Downloaders.VerificationCache.csproj             | 2 +-
 .../Wabbajack.Downloaders.WabbajackCDN.csproj                  | 2 +-
 .../Wabbajack.FileExtractor.Test.csproj                        | 2 +-
 Wabbajack.FileExtractor/Wabbajack.FileExtractor.csproj         | 2 +-
 .../Wabbajack.Hashing.PHash.Test.csproj                        | 2 +-
 Wabbajack.Hashing.PHash/Wabbajack.Hashing.PHash.csproj         | 2 +-
 .../Wabbajack.Hashing.xxHash64.Benchmark.csproj                | 2 +-
 .../Wabbajack.Hashing.xxHash64.Test.csproj                     | 2 +-
 Wabbajack.Hashing.xxHash64/Wabbajack.Hashing.xxHash64.csproj   | 2 +-
 Wabbajack.IO.Async/Wabbajack.IO.Async.csproj                   | 2 +-
 Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj       | 2 +-
 Wabbajack.Installer/Wabbajack.Installer.csproj                 | 2 +-
 Wabbajack.Launcher/Wabbajack.Launcher.csproj                   | 1 +
 .../Wabbajack.Networking.BethesdaNet.csproj                    | 2 +-
 .../Wabbajack.Networking.Discord.csproj                        | 2 +-
 Wabbajack.Networking.GitHub/Wabbajack.Networking.GitHub.csproj | 2 +-
 .../Wabbajack.Networking.Http.Interfaces.csproj                | 2 +-
 .../Wabbajack.Networking.Http.Test.csproj                      | 2 +-
 Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj     | 2 +-
 .../Wabbajack.Networking.NexusApi.Test.csproj                  | 2 +-
 .../Wabbajack.Networking.NexusApi.csproj                       | 2 +-
 .../Wabbajack.Networking.Steam.Test.csproj                     | 2 +-
 Wabbajack.Networking.Steam/Wabbajack.Networking.Steam.csproj   | 2 +-
 .../Wabbajack.Networking.WabbajackClientApi.csproj             | 2 +-
 Wabbajack.Paths.IO.Test/Wabbajack.Paths.IO.Test.csproj         | 2 +-
 Wabbajack.Paths.IO/Wabbajack.Paths.IO.csproj                   | 2 +-
 Wabbajack.Paths.Test/Wabbajack.Paths.Test.csproj               | 2 +-
 Wabbajack.Paths/Wabbajack.Paths.csproj                         | 2 +-
 Wabbajack.RateLimiter.Test/Wabbajack.RateLimiter.Test.csproj   | 2 +-
 Wabbajack.RateLimiter/Wabbajack.RateLimiter.csproj             | 2 +-
 Wabbajack.Server.Lib/Wabbajack.Server.Lib.csproj               | 2 +-
 Wabbajack.Server/Wabbajack.Server.csproj                       | 2 +-
 .../Wabbajack.Services.OSIntegrated.csproj                     | 2 +-
 Wabbajack.VFS.Interfaces/Wabbajack.VFS.Interfaces.csproj       | 2 +-
 Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj                   | 2 +-
 Wabbajack.VFS/Wabbajack.VFS.csproj                             | 2 +-
 63 files changed, 64 insertions(+), 62 deletions(-)

diff --git a/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj b/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
index 6cec03111..6b537f7df 100644
--- a/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
+++ b/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
-    <TargetFramework>net6.0-windows</TargetFramework>
+    <TargetFramework>net7.0-windows</TargetFramework>
     <UseWPF>true</UseWPF>
     <Platforms>x64</Platforms>
     <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
diff --git a/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj b/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
index 28ed9b4ed..beb8a0c96 100644
--- a/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
+++ b/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.CLI/Wabbajack.CLI.csproj b/Wabbajack.CLI/Wabbajack.CLI.csproj
index c9edf2b70..b03bef558 100644
--- a/Wabbajack.CLI/Wabbajack.CLI.csproj
+++ b/Wabbajack.CLI/Wabbajack.CLI.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
         <OutputType>Exe</OutputType>
@@ -13,6 +13,7 @@
         <NoWarn>CS8600</NoWarn>
         <NoWarn>CS8601</NoWarn>
         <NoWarn>CS8618</NoWarn>
+        <TargetFramework>net7.0</TargetFramework>
     </PropertyGroup>
 
     <ItemGroup>
diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj
index 35b829e3b..cc58703bc 100644
--- a/Wabbajack.Common/Wabbajack.Common.csproj
+++ b/Wabbajack.Common/Wabbajack.Common.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Compiler.Test/Wabbajack.Compiler.Test.csproj b/Wabbajack.Compiler.Test/Wabbajack.Compiler.Test.csproj
index 019ec0301..b9b776925 100644
--- a/Wabbajack.Compiler.Test/Wabbajack.Compiler.Test.csproj
+++ b/Wabbajack.Compiler.Test/Wabbajack.Compiler.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
 
diff --git a/Wabbajack.Compiler/Wabbajack.Compiler.csproj b/Wabbajack.Compiler/Wabbajack.Compiler.csproj
index 62584356b..9ca4cf586 100644
--- a/Wabbajack.Compiler/Wabbajack.Compiler.csproj
+++ b/Wabbajack.Compiler/Wabbajack.Compiler.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Compression.BSA.Test/Wabbajack.Compression.BSA.Test.csproj b/Wabbajack.Compression.BSA.Test/Wabbajack.Compression.BSA.Test.csproj
index c9ee60108..270a509f1 100644
--- a/Wabbajack.Compression.BSA.Test/Wabbajack.Compression.BSA.Test.csproj
+++ b/Wabbajack.Compression.BSA.Test/Wabbajack.Compression.BSA.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj b/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
index ae648ab24..d9d112849 100644
--- a/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
+++ b/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Compression.Zip.Test/Wabbajack.Compression.Zip.Test.csproj b/Wabbajack.Compression.Zip.Test/Wabbajack.Compression.Zip.Test.csproj
index 3d04da28a..6d15e0058 100644
--- a/Wabbajack.Compression.Zip.Test/Wabbajack.Compression.Zip.Test.csproj
+++ b/Wabbajack.Compression.Zip.Test/Wabbajack.Compression.Zip.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
diff --git a/Wabbajack.Compression.Zip/Wabbajack.Compression.Zip.csproj b/Wabbajack.Compression.Zip/Wabbajack.Compression.Zip.csproj
index bad414541..01178a672 100644
--- a/Wabbajack.Compression.Zip/Wabbajack.Compression.Zip.csproj
+++ b/Wabbajack.Compression.Zip/Wabbajack.Compression.Zip.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Configuration/Wabbajack.Configuration.csproj b/Wabbajack.Configuration/Wabbajack.Configuration.csproj
index 132c02c59..cfadb03dd 100644
--- a/Wabbajack.Configuration/Wabbajack.Configuration.csproj
+++ b/Wabbajack.Configuration/Wabbajack.Configuration.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net6.0</TargetFramework>
+    <TargetFramework>net7.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
   </PropertyGroup>
diff --git a/Wabbajack.DTOs.ConverterGenerators/Wabbajack.DTOs.ConverterGenerators.csproj b/Wabbajack.DTOs.ConverterGenerators/Wabbajack.DTOs.ConverterGenerators.csproj
index f549991b0..3831f9b24 100644
--- a/Wabbajack.DTOs.ConverterGenerators/Wabbajack.DTOs.ConverterGenerators.csproj
+++ b/Wabbajack.DTOs.ConverterGenerators/Wabbajack.DTOs.ConverterGenerators.csproj
@@ -2,7 +2,7 @@
 
     <PropertyGroup>
         <OutputType>Exe</OutputType>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
         <NoWarn>CS8600</NoWarn>
diff --git a/Wabbajack.DTOs.Test/Wabbajack.DTOs.Test.csproj b/Wabbajack.DTOs.Test/Wabbajack.DTOs.Test.csproj
index eb42bd832..6bc364132 100644
--- a/Wabbajack.DTOs.Test/Wabbajack.DTOs.Test.csproj
+++ b/Wabbajack.DTOs.Test/Wabbajack.DTOs.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.DTOs/Wabbajack.DTOs.csproj b/Wabbajack.DTOs/Wabbajack.DTOs.csproj
index 4e232d269..04b1cc65b 100644
--- a/Wabbajack.DTOs/Wabbajack.DTOs.csproj
+++ b/Wabbajack.DTOs/Wabbajack.DTOs.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Downloaders.Bethesda/Wabbajack.Downloaders.Bethesda.csproj b/Wabbajack.Downloaders.Bethesda/Wabbajack.Downloaders.Bethesda.csproj
index 7544d14cb..02afa7a1c 100644
--- a/Wabbajack.Downloaders.Bethesda/Wabbajack.Downloaders.Bethesda.csproj
+++ b/Wabbajack.Downloaders.Bethesda/Wabbajack.Downloaders.Bethesda.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj b/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
index 901a70cc7..6dda57347 100644
--- a/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
+++ b/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Downloaders.Dispatcher/Wabbajack.Downloaders.Dispatcher.csproj b/Wabbajack.Downloaders.Dispatcher/Wabbajack.Downloaders.Dispatcher.csproj
index 0db2bd81b..7cebb5536 100644
--- a/Wabbajack.Downloaders.Dispatcher/Wabbajack.Downloaders.Dispatcher.csproj
+++ b/Wabbajack.Downloaders.Dispatcher/Wabbajack.Downloaders.Dispatcher.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
index 26f0e1cac..10e8ff112 100644
--- a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
+++ b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Downloaders.GoogleDrive/Wabbajack.Downloaders.GoogleDrive.csproj b/Wabbajack.Downloaders.GoogleDrive/Wabbajack.Downloaders.GoogleDrive.csproj
index a2b5a85d0..a4637175c 100644
--- a/Wabbajack.Downloaders.GoogleDrive/Wabbajack.Downloaders.GoogleDrive.csproj
+++ b/Wabbajack.Downloaders.GoogleDrive/Wabbajack.Downloaders.GoogleDrive.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Downloaders.Http/Wabbajack.Downloaders.Http.csproj b/Wabbajack.Downloaders.Http/Wabbajack.Downloaders.Http.csproj
index f0190d2e4..e0fbecdb1 100644
--- a/Wabbajack.Downloaders.Http/Wabbajack.Downloaders.Http.csproj
+++ b/Wabbajack.Downloaders.Http/Wabbajack.Downloaders.Http.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Downloaders.IPS4OAuth2Downloader/Wabbajack.Downloaders.IPS4OAuth2Downloader.csproj b/Wabbajack.Downloaders.IPS4OAuth2Downloader/Wabbajack.Downloaders.IPS4OAuth2Downloader.csproj
index ae2488eb8..6fdce2eac 100644
--- a/Wabbajack.Downloaders.IPS4OAuth2Downloader/Wabbajack.Downloaders.IPS4OAuth2Downloader.csproj
+++ b/Wabbajack.Downloaders.IPS4OAuth2Downloader/Wabbajack.Downloaders.IPS4OAuth2Downloader.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
diff --git a/Wabbajack.Downloaders.Interfaces/Wabbajack.Downloaders.Interfaces.csproj b/Wabbajack.Downloaders.Interfaces/Wabbajack.Downloaders.Interfaces.csproj
index 88869b1c8..d3acee8ec 100644
--- a/Wabbajack.Downloaders.Interfaces/Wabbajack.Downloaders.Interfaces.csproj
+++ b/Wabbajack.Downloaders.Interfaces/Wabbajack.Downloaders.Interfaces.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Downloaders.Manual/Wabbajack.Downloaders.Manual.csproj b/Wabbajack.Downloaders.Manual/Wabbajack.Downloaders.Manual.csproj
index efbf5c33d..575e7e12b 100644
--- a/Wabbajack.Downloaders.Manual/Wabbajack.Downloaders.Manual.csproj
+++ b/Wabbajack.Downloaders.Manual/Wabbajack.Downloaders.Manual.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj b/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
index 7c3378e9d..8c5ff86f2 100644
--- a/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
+++ b/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
diff --git a/Wabbajack.Downloaders.Mega/Wabbajack.Downloaders.Mega.csproj b/Wabbajack.Downloaders.Mega/Wabbajack.Downloaders.Mega.csproj
index 300a2784b..2c58d3a0f 100644
--- a/Wabbajack.Downloaders.Mega/Wabbajack.Downloaders.Mega.csproj
+++ b/Wabbajack.Downloaders.Mega/Wabbajack.Downloaders.Mega.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
diff --git a/Wabbajack.Downloaders.ModDB/Wabbajack.Downloaders.ModDB.csproj b/Wabbajack.Downloaders.ModDB/Wabbajack.Downloaders.ModDB.csproj
index ed35adc17..d32eb433b 100644
--- a/Wabbajack.Downloaders.ModDB/Wabbajack.Downloaders.ModDB.csproj
+++ b/Wabbajack.Downloaders.ModDB/Wabbajack.Downloaders.ModDB.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
diff --git a/Wabbajack.Downloaders.Nexus/Wabbajack.Downloaders.Nexus.csproj b/Wabbajack.Downloaders.Nexus/Wabbajack.Downloaders.Nexus.csproj
index 96c120497..6fc137e10 100644
--- a/Wabbajack.Downloaders.Nexus/Wabbajack.Downloaders.Nexus.csproj
+++ b/Wabbajack.Downloaders.Nexus/Wabbajack.Downloaders.Nexus.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Downloaders.VerificationCache/Wabbajack.Downloaders.VerificationCache.csproj b/Wabbajack.Downloaders.VerificationCache/Wabbajack.Downloaders.VerificationCache.csproj
index 775a95976..864b1a379 100644
--- a/Wabbajack.Downloaders.VerificationCache/Wabbajack.Downloaders.VerificationCache.csproj
+++ b/Wabbajack.Downloaders.VerificationCache/Wabbajack.Downloaders.VerificationCache.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Downloaders.WabbajackCDN/Wabbajack.Downloaders.WabbajackCDN.csproj b/Wabbajack.Downloaders.WabbajackCDN/Wabbajack.Downloaders.WabbajackCDN.csproj
index c04a827f9..c9a9c634a 100644
--- a/Wabbajack.Downloaders.WabbajackCDN/Wabbajack.Downloaders.WabbajackCDN.csproj
+++ b/Wabbajack.Downloaders.WabbajackCDN/Wabbajack.Downloaders.WabbajackCDN.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj b/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
index 6e070afea..f6fa66092 100644
--- a/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
+++ b/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.FileExtractor/Wabbajack.FileExtractor.csproj b/Wabbajack.FileExtractor/Wabbajack.FileExtractor.csproj
index 356afd7d0..358a3e0ae 100644
--- a/Wabbajack.FileExtractor/Wabbajack.FileExtractor.csproj
+++ b/Wabbajack.FileExtractor/Wabbajack.FileExtractor.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Hashing.PHash.Test/Wabbajack.Hashing.PHash.Test.csproj b/Wabbajack.Hashing.PHash.Test/Wabbajack.Hashing.PHash.Test.csproj
index 2f5f8283d..7119afd0f 100644
--- a/Wabbajack.Hashing.PHash.Test/Wabbajack.Hashing.PHash.Test.csproj
+++ b/Wabbajack.Hashing.PHash.Test/Wabbajack.Hashing.PHash.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Hashing.PHash/Wabbajack.Hashing.PHash.csproj b/Wabbajack.Hashing.PHash/Wabbajack.Hashing.PHash.csproj
index 0d66a3e1e..78d738ce4 100644
--- a/Wabbajack.Hashing.PHash/Wabbajack.Hashing.PHash.csproj
+++ b/Wabbajack.Hashing.PHash/Wabbajack.Hashing.PHash.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Hashing.xxHash64.Benchmark/Wabbajack.Hashing.xxHash64.Benchmark.csproj b/Wabbajack.Hashing.xxHash64.Benchmark/Wabbajack.Hashing.xxHash64.Benchmark.csproj
index 4e9b1f496..03dff657b 100644
--- a/Wabbajack.Hashing.xxHash64.Benchmark/Wabbajack.Hashing.xxHash64.Benchmark.csproj
+++ b/Wabbajack.Hashing.xxHash64.Benchmark/Wabbajack.Hashing.xxHash64.Benchmark.csproj
@@ -2,7 +2,7 @@
 
     <PropertyGroup>
         <OutputType>Exe</OutputType>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <RootNamespace>Wabbajac.Hash.xxHash64.Benchmark</RootNamespace>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     </PropertyGroup>
diff --git a/Wabbajack.Hashing.xxHash64.Test/Wabbajack.Hashing.xxHash64.Test.csproj b/Wabbajack.Hashing.xxHash64.Test/Wabbajack.Hashing.xxHash64.Test.csproj
index d4523c528..204f9d5f3 100644
--- a/Wabbajack.Hashing.xxHash64.Test/Wabbajack.Hashing.xxHash64.Test.csproj
+++ b/Wabbajack.Hashing.xxHash64.Test/Wabbajack.Hashing.xxHash64.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Hashing.xxHash64/Wabbajack.Hashing.xxHash64.csproj b/Wabbajack.Hashing.xxHash64/Wabbajack.Hashing.xxHash64.csproj
index f6edd4e19..f26d307ec 100644
--- a/Wabbajack.Hashing.xxHash64/Wabbajack.Hashing.xxHash64.csproj
+++ b/Wabbajack.Hashing.xxHash64/Wabbajack.Hashing.xxHash64.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.IO.Async/Wabbajack.IO.Async.csproj b/Wabbajack.IO.Async/Wabbajack.IO.Async.csproj
index eb2460e91..6836c6808 100644
--- a/Wabbajack.IO.Async/Wabbajack.IO.Async.csproj
+++ b/Wabbajack.IO.Async/Wabbajack.IO.Async.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj b/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
index c1dbcbe26..b80d41bd6 100644
--- a/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
+++ b/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Installer/Wabbajack.Installer.csproj b/Wabbajack.Installer/Wabbajack.Installer.csproj
index 845d9ca3d..282776121 100644
--- a/Wabbajack.Installer/Wabbajack.Installer.csproj
+++ b/Wabbajack.Installer/Wabbajack.Installer.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Launcher/Wabbajack.Launcher.csproj b/Wabbajack.Launcher/Wabbajack.Launcher.csproj
index a188ab0bd..616ff0a17 100644
--- a/Wabbajack.Launcher/Wabbajack.Launcher.csproj
+++ b/Wabbajack.Launcher/Wabbajack.Launcher.csproj
@@ -16,6 +16,7 @@
     </ItemGroup>
     <PropertyGroup>
         <ApplicationIcon>Resources\Icons\wabbajack.ico</ApplicationIcon>
+        <TargetFramework>net7.0-windows</TargetFramework>
     </PropertyGroup>
     <ItemGroup>
         <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview4" />
diff --git a/Wabbajack.Networking.BethesdaNet/Wabbajack.Networking.BethesdaNet.csproj b/Wabbajack.Networking.BethesdaNet/Wabbajack.Networking.BethesdaNet.csproj
index 0267a74fe..68bb36ab0 100644
--- a/Wabbajack.Networking.BethesdaNet/Wabbajack.Networking.BethesdaNet.csproj
+++ b/Wabbajack.Networking.BethesdaNet/Wabbajack.Networking.BethesdaNet.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Networking.Discord/Wabbajack.Networking.Discord.csproj b/Wabbajack.Networking.Discord/Wabbajack.Networking.Discord.csproj
index 1061d857c..c9ab6aabc 100644
--- a/Wabbajack.Networking.Discord/Wabbajack.Networking.Discord.csproj
+++ b/Wabbajack.Networking.Discord/Wabbajack.Networking.Discord.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Networking.GitHub/Wabbajack.Networking.GitHub.csproj b/Wabbajack.Networking.GitHub/Wabbajack.Networking.GitHub.csproj
index d75d9f31f..40e655420 100644
--- a/Wabbajack.Networking.GitHub/Wabbajack.Networking.GitHub.csproj
+++ b/Wabbajack.Networking.GitHub/Wabbajack.Networking.GitHub.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Networking.Http.Interfaces/Wabbajack.Networking.Http.Interfaces.csproj b/Wabbajack.Networking.Http.Interfaces/Wabbajack.Networking.Http.Interfaces.csproj
index e9ee3e621..5037943c0 100644
--- a/Wabbajack.Networking.Http.Interfaces/Wabbajack.Networking.Http.Interfaces.csproj
+++ b/Wabbajack.Networking.Http.Interfaces/Wabbajack.Networking.Http.Interfaces.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Networking.Http.Test/Wabbajack.Networking.Http.Test.csproj b/Wabbajack.Networking.Http.Test/Wabbajack.Networking.Http.Test.csproj
index 0aecc8b76..a20f6ab2e 100644
--- a/Wabbajack.Networking.Http.Test/Wabbajack.Networking.Http.Test.csproj
+++ b/Wabbajack.Networking.Http.Test/Wabbajack.Networking.Http.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
diff --git a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
index 191df7f37..2cf94a56e 100644
--- a/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
+++ b/Wabbajack.Networking.Http/Wabbajack.Networking.Http.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Networking.NexusApi.Test/Wabbajack.Networking.NexusApi.Test.csproj b/Wabbajack.Networking.NexusApi.Test/Wabbajack.Networking.NexusApi.Test.csproj
index 552f015cf..fac1ed502 100644
--- a/Wabbajack.Networking.NexusApi.Test/Wabbajack.Networking.NexusApi.Test.csproj
+++ b/Wabbajack.Networking.NexusApi.Test/Wabbajack.Networking.NexusApi.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj b/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
index 05977cf3e..56feb5f95 100644
--- a/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
+++ b/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj b/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
index b8f20c0b4..f403df799 100644
--- a/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
+++ b/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
diff --git a/Wabbajack.Networking.Steam/Wabbajack.Networking.Steam.csproj b/Wabbajack.Networking.Steam/Wabbajack.Networking.Steam.csproj
index d9364b705..ee8403623 100644
--- a/Wabbajack.Networking.Steam/Wabbajack.Networking.Steam.csproj
+++ b/Wabbajack.Networking.Steam/Wabbajack.Networking.Steam.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.Networking.WabbajackClientApi/Wabbajack.Networking.WabbajackClientApi.csproj b/Wabbajack.Networking.WabbajackClientApi/Wabbajack.Networking.WabbajackClientApi.csproj
index 7aeb859bc..557128880 100644
--- a/Wabbajack.Networking.WabbajackClientApi/Wabbajack.Networking.WabbajackClientApi.csproj
+++ b/Wabbajack.Networking.WabbajackClientApi/Wabbajack.Networking.WabbajackClientApi.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.Paths.IO.Test/Wabbajack.Paths.IO.Test.csproj b/Wabbajack.Paths.IO.Test/Wabbajack.Paths.IO.Test.csproj
index bbd2b0ea1..3948bc11f 100644
--- a/Wabbajack.Paths.IO.Test/Wabbajack.Paths.IO.Test.csproj
+++ b/Wabbajack.Paths.IO.Test/Wabbajack.Paths.IO.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Paths.IO/Wabbajack.Paths.IO.csproj b/Wabbajack.Paths.IO/Wabbajack.Paths.IO.csproj
index 2494c58e4..0cd88c4d3 100644
--- a/Wabbajack.Paths.IO/Wabbajack.Paths.IO.csproj
+++ b/Wabbajack.Paths.IO/Wabbajack.Paths.IO.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.Paths.Test/Wabbajack.Paths.Test.csproj b/Wabbajack.Paths.Test/Wabbajack.Paths.Test.csproj
index 1415da3d0..a5d4fe491 100644
--- a/Wabbajack.Paths.Test/Wabbajack.Paths.Test.csproj
+++ b/Wabbajack.Paths.Test/Wabbajack.Paths.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.Paths/Wabbajack.Paths.csproj b/Wabbajack.Paths/Wabbajack.Paths.csproj
index 2502d56d1..1ffbca14d 100644
--- a/Wabbajack.Paths/Wabbajack.Paths.csproj
+++ b/Wabbajack.Paths/Wabbajack.Paths.csproj
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
         <Version>$(VERSION)</Version>
diff --git a/Wabbajack.RateLimiter.Test/Wabbajack.RateLimiter.Test.csproj b/Wabbajack.RateLimiter.Test/Wabbajack.RateLimiter.Test.csproj
index 8b16f12f4..3db11fcf5 100644
--- a/Wabbajack.RateLimiter.Test/Wabbajack.RateLimiter.Test.csproj
+++ b/Wabbajack.RateLimiter.Test/Wabbajack.RateLimiter.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
 
         <IsPackable>false</IsPackable>
diff --git a/Wabbajack.RateLimiter/Wabbajack.RateLimiter.csproj b/Wabbajack.RateLimiter/Wabbajack.RateLimiter.csproj
index 72d6b4a49..444af79a4 100644
--- a/Wabbajack.RateLimiter/Wabbajack.RateLimiter.csproj
+++ b/Wabbajack.RateLimiter/Wabbajack.RateLimiter.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
diff --git a/Wabbajack.Server.Lib/Wabbajack.Server.Lib.csproj b/Wabbajack.Server.Lib/Wabbajack.Server.Lib.csproj
index d69e3e3cb..03942d81d 100644
--- a/Wabbajack.Server.Lib/Wabbajack.Server.Lib.csproj
+++ b/Wabbajack.Server.Lib/Wabbajack.Server.Lib.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
     </PropertyGroup>
     
diff --git a/Wabbajack.Server/Wabbajack.Server.csproj b/Wabbajack.Server/Wabbajack.Server.csproj
index eb5484145..a8da70932 100644
--- a/Wabbajack.Server/Wabbajack.Server.csproj
+++ b/Wabbajack.Server/Wabbajack.Server.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <ImplicitUsings>enable</ImplicitUsings>
         <OutputType>Exe</OutputType>
diff --git a/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj b/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
index b2cfce820..e1ee4667a 100644
--- a/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
+++ b/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
diff --git a/Wabbajack.VFS.Interfaces/Wabbajack.VFS.Interfaces.csproj b/Wabbajack.VFS.Interfaces/Wabbajack.VFS.Interfaces.csproj
index bf68d60e0..5b854cb58 100644
--- a/Wabbajack.VFS.Interfaces/Wabbajack.VFS.Interfaces.csproj
+++ b/Wabbajack.VFS.Interfaces/Wabbajack.VFS.Interfaces.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
     </PropertyGroup>
diff --git a/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj b/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
index ebcd27900..367e4b81f 100644
--- a/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
+++ b/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
 
         <IsPackable>false</IsPackable>
     </PropertyGroup>
diff --git a/Wabbajack.VFS/Wabbajack.VFS.csproj b/Wabbajack.VFS/Wabbajack.VFS.csproj
index 07ec317f6..a4501f7c3 100644
--- a/Wabbajack.VFS/Wabbajack.VFS.csproj
+++ b/Wabbajack.VFS/Wabbajack.VFS.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>net6.0</TargetFramework>
+        <TargetFramework>net7.0</TargetFramework>
         <Nullable>enable</Nullable>
         <Version>$(VERSION)</Version>
         <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

From a64e70d9abdd6ce4f12f47758d50ef0e9d88c6ae Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Wed, 4 Oct 2023 22:30:17 +0200
Subject: [PATCH 27/57] Bump ReactiveUI packages & deps

---
 Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj   | 12 ++++++------
 Wabbajack.Common/Wabbajack.Common.csproj     |  2 +-
 Wabbajack.Launcher/Wabbajack.Launcher.csproj |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj b/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
index 6b537f7df..af71c3106 100644
--- a/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
+++ b/Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
@@ -73,12 +73,12 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="DynamicData" Version="7.12.1" />
+    <PackageReference Include="DynamicData" Version="8.0.2" />
     <PackageReference Include="Extended.Wpf.Toolkit" Version="4.4.0">
       <NoWarn>NU1701</NoWarn>
     </PackageReference>
     <PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
-    <PackageReference Include="Fody" Version="6.6.4">
+    <PackageReference Include="Fody" Version="6.8.0">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
@@ -95,11 +95,11 @@
     <PackageReference Include="NLog.Extensions.Logging" Version="5.1.0" />
     <PackageReference Include="Orc.FileAssociation" Version="5.0.0-alpha0061" />
     <PackageReference Include="PInvoke.User32" Version="0.7.124" />
-    <PackageReference Include="ReactiveUI" Version="18.3.1" />
-    <PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
-    <PackageReference Include="ReactiveUI.WPF" Version="18.3.1" />
+    <PackageReference Include="ReactiveUI" Version="19.5.1" />
+    <PackageReference Include="ReactiveUI.Fody" Version="19.5.1" />
+    <PackageReference Include="ReactiveUI.WPF" Version="19.5.1" />
     <PackageReference Include="Silk.NET.DXGI" Version="2.16.0" />
-    <PackageReference Include="System.Reactive" Version="5.0.0" />
+    <PackageReference Include="System.Reactive" Version="6.0.1-preview.1" />
     <PackageReference Include="WPFThemes.DarkBlend" Version="1.0.8" />
   </ItemGroup>
 
diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj
index cc58703bc..a382ae26f 100644
--- a/Wabbajack.Common/Wabbajack.Common.csproj
+++ b/Wabbajack.Common/Wabbajack.Common.csproj
@@ -34,7 +34,7 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
-        <PackageReference Include="System.Reactive" Version="5.0.0" />
+        <PackageReference Include="System.Reactive" Version="6.0.1-preview.1" />
     </ItemGroup>
 
     <PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
diff --git a/Wabbajack.Launcher/Wabbajack.Launcher.csproj b/Wabbajack.Launcher/Wabbajack.Launcher.csproj
index 616ff0a17..a47fefab1 100644
--- a/Wabbajack.Launcher/Wabbajack.Launcher.csproj
+++ b/Wabbajack.Launcher/Wabbajack.Launcher.csproj
@@ -31,7 +31,7 @@
         <PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
         <PackageReference Include="MessageBox.Avalonia" Version="2.3.1-prev2" />
         <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
-        <PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
+        <PackageReference Include="ReactiveUI.Fody" Version="19.5.1" />
         <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="6.0.2-mauipre.1.22102.15" />
     </ItemGroup>
     <ItemGroup>

From 84e55cedefad705b0debb872388e6856859a3ce4 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Sat, 7 Oct 2023 14:29:36 +0200
Subject: [PATCH 28/57] Update GameFinder to 4.0.0

---
 .../Wabbajack.CLI.Builder.csproj              |  2 +-
 Wabbajack.CLI/Wabbajack.CLI.csproj            |  2 +-
 Wabbajack.DTOs/Game/GameMetaData.cs           |  2 +-
 Wabbajack.DTOs/Game/GameRegistry.cs           | 38 ++++++++--------
 ...bbajack.Downloaders.Dispatcher.Test.csproj |  2 +-
 Wabbajack.Downloaders.GameFile/GameLocator.cs | 44 ++++++++++---------
 .../Wabbajack.Downloaders.GameFile.csproj     |  8 ++--
 .../Wabbajack.Downloaders.MediaFire.csproj    |  2 +-
 .../Wabbajack.FileExtractor.Test.csproj       |  2 +-
 .../Wabbajack.Installer.Test.csproj           |  2 +-
 .../Wabbajack.Networking.NexusApi.csproj      |  2 +-
 .../Wabbajack.Networking.Steam.Test.csproj    |  2 +-
 .../Wabbajack.Services.OSIntegrated.csproj    |  2 +-
 Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj  |  2 +-
 14 files changed, 58 insertions(+), 54 deletions(-)

diff --git a/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj b/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
index beb8a0c96..87e50f365 100644
--- a/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
+++ b/Wabbajack.CLI.Builder/Wabbajack.CLI.Builder.csproj
@@ -8,7 +8,7 @@
     
     <ItemGroup>
         <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" />
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
         <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
diff --git a/Wabbajack.CLI/Wabbajack.CLI.csproj b/Wabbajack.CLI/Wabbajack.CLI.csproj
index b03bef558..fe9ebfc9f 100644
--- a/Wabbajack.CLI/Wabbajack.CLI.csproj
+++ b/Wabbajack.CLI/Wabbajack.CLI.csproj
@@ -18,7 +18,7 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22102.15" />
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22102.15" />
         <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
diff --git a/Wabbajack.DTOs/Game/GameMetaData.cs b/Wabbajack.DTOs/Game/GameMetaData.cs
index 36dc7c9f9..1b4a4061b 100644
--- a/Wabbajack.DTOs/Game/GameMetaData.cs
+++ b/Wabbajack.DTOs/Game/GameMetaData.cs
@@ -21,7 +21,7 @@ public class GameMetaData
     public int[] SteamIDs { get; internal init; } = Array.Empty<int>();
 
     // to get gog ids: https://www.gogdb.org
-    public int[] GOGIDs { get; internal init; } = Array.Empty<int>();
+    public long[] GOGIDs { get; internal init; } = Array.Empty<long>();
 
     // to get these ids, split the numbers from the letters in file names found in
     // C:\ProgramData\Origin\LocalContent\{game name)\*.mfst
diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index b202eebe5..4bf839a32 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -14,7 +14,7 @@ public static class GameRegistry
             {
                 Game = Game.Morrowind,
                 SteamIDs = new[] {22320},
-                GOGIDs = new[] {1440163901, 1435828767},
+                GOGIDs = new long[] {1440163901, 1435828767},
                 NexusName = "morrowind",
                 NexusGameId = 100,
                 MO2Name = "Morrowind",
@@ -38,7 +38,7 @@ public static class GameRegistry
                 MO2Name = "Oblivion",
                 MO2ArchiveName = "oblivion",
                 SteamIDs = new[] {22330},
-                GOGIDs = new[] {1458058109},
+                GOGIDs = new long[] {1458058109},
                 RequiredFiles = new[]
                 {
                     "oblivion.exe".ToRelativePath()
@@ -56,7 +56,7 @@ public static class GameRegistry
                 MO2Name = "Fallout 3",
                 MO2ArchiveName = "fallout3",
                 SteamIDs = new[] {22300, 22370}, // base game and GotY
-                GOGIDs = new[] {1454315831}, // GotY edition
+                GOGIDs = new long[] {1454315831}, // GotY edition
                 RequiredFiles = new[]
                 {
                     "Fallout3.exe".ToRelativePath()
@@ -73,7 +73,7 @@ public static class GameRegistry
                 MO2Name = "New Vegas",
                 MO2ArchiveName = "falloutnv",
                 SteamIDs = new[] {22380, 22490}, // normal and RU version
-                GOGIDs = new[] {1454587428},
+                GOGIDs = new long[] {1454587428},
                 RequiredFiles = new[]
                 {
                     "FalloutNV.exe".ToRelativePath()
@@ -107,7 +107,7 @@ public static class GameRegistry
                 MO2Name = "Skyrim Special Edition",
                 MO2ArchiveName = "skyrimse",
                 SteamIDs = new[] {489830},
-                GOGIDs = new[]
+                GOGIDs = new long[]
                 {
                     1711230643,// The Elder Scrolls V: Skyrim Special Edition AKA Base Game
                     1801825368,// The Elder Scrolls V: Skyrim Anniversary Edition AKA The Store Bundle 
@@ -130,7 +130,7 @@ public static class GameRegistry
                 MO2Name = "Fallout 4",
                 MO2ArchiveName = "fallout4",
                 SteamIDs = new[] {377160},
-                GOGIDs = new []{1998527297},
+                GOGIDs = new long[]{1998527297},
                 RequiredFiles = new[]
                 {
                     "Fallout4.exe".ToRelativePath()
@@ -183,7 +183,7 @@ public static class GameRegistry
                 MO2Name = "Enderal Special Edition",
                 MO2ArchiveName = "enderalse",
                 SteamIDs = new[] {976620},
-                GOGIDs = new [] {1708684988},
+                GOGIDs = new long[] {1708684988},
                 RequiredFiles = new[]
                 {
                     "SkyrimSE.exe".ToRelativePath()
@@ -217,7 +217,7 @@ public static class GameRegistry
                 MO2Name = "Darkest Dungeon",
                 NexusGameId = 804,
                 SteamIDs = new[] {262060},
-                GOGIDs = new[] {1450711444},
+                GOGIDs = new long[] {1450711444},
                 EpicGameStoreIDs = new[] {"b4eecf70e3fe4e928b78df7855a3fc2d"},
                 IsGenericMO2Plugin = true,
                 RequiredFiles = new[]
@@ -236,7 +236,7 @@ public static class GameRegistry
                 MO2ArchiveName = "dishonored",
                 NexusGameId = 802,
                 SteamIDs = new[] {205100},
-                GOGIDs = new[] {1701063787},
+                GOGIDs = new long[] {1701063787},
                 RequiredFiles = new[]
                 {
                     @"Binaries\Win32\Dishonored.exe".ToRelativePath()
@@ -253,7 +253,7 @@ public static class GameRegistry
                 MO2Name = "The Witcher: Enhanced Edition",
                 MO2ArchiveName = "witcher",
                 SteamIDs = new[] {20900}, // normal and GotY
-                GOGIDs = new[] {1207658924}, // normal, GotY and both in packages
+                GOGIDs = new long[] {1207658924}, // normal, GotY and both in packages
                 RequiredFiles = new[]
                 {
                     @"System\witcher.exe".ToRelativePath()
@@ -270,7 +270,7 @@ public static class GameRegistry
                 MO2Name = "The Witcher 3: Wild Hunt",
                 MO2ArchiveName = "witcher3",
                 SteamIDs = new[] {292030, 499450}, // normal and GotY
-                GOGIDs = new[]
+                GOGIDs = new long[]
                     {1207664643, 1495134320, 1207664663, 1640424747}, // normal, GotY and both in packages
                 RequiredFiles = new[]
                 {
@@ -288,7 +288,7 @@ public static class GameRegistry
                 MO2ArchiveName = "stardewvalley",
                 NexusGameId = 1303,
                 SteamIDs = new[] {413150},
-                GOGIDs = new[] {1453375253},
+                GOGIDs = new long[] {1453375253},
                 IsGenericMO2Plugin = true,
                 RequiredFiles = new[]
                 {
@@ -306,7 +306,7 @@ public static class GameRegistry
                 MO2ArchiveName = "kingdomcomedeliverance",
                 NexusGameId = 2298,
                 SteamIDs = new[] {379430},
-                GOGIDs = new[] {1719198803},
+                GOGIDs = new long[] {1719198803},
                 IsGenericMO2Plugin = true,
                 RequiredFiles = new[]
                 {
@@ -340,7 +340,7 @@ public static class GameRegistry
                 NexusGameId = 1634,
                 MO2Name = "No Man's Sky",
                 SteamIDs = new[] {275850},
-                GOGIDs = new[] {1446213994},
+                GOGIDs = new long[] {1446213994},
                 RequiredFiles = new[]
                 {
                     @"Binaries\NMS.exe".ToRelativePath()
@@ -357,7 +357,7 @@ public static class GameRegistry
                 MO2Name = "Dragon Age: Origins",
                 SteamIDs = new[] {47810},
                 OriginIDs = new[] {"DR:169789300", "DR:208591800"},
-                GOGIDs = new[] {1949616134},
+                GOGIDs = new long[] {1949616134},
                 RequiredFiles = new[]
                 {
                     @"bin_ship\daorigins.exe".ToRelativePath()
@@ -405,7 +405,7 @@ public static class GameRegistry
                 MO2Name = "Kerbal Space Program",
                 NexusGameId = 272,
                 SteamIDs = new[] {220200},
-                GOGIDs = new[] {1429864849},
+                GOGIDs = new long[] {1429864849},
                 IsGenericMO2Plugin = true,
                 RequiredFiles = new[]
                 {
@@ -433,7 +433,7 @@ public static class GameRegistry
            {
                 Game = Game.Cyberpunk2077,
                 SteamIDs = new[] {1091500},
-                GOGIDs = new [] {2093619782, 1423049311},
+                GOGIDs = new long[] {2093619782, 1423049311},
                 EpicGameStoreIDs = new[] {"5beededaad9743df90e8f07d92df153f"},
                 MO2Name = "Cyberpunk 2077",
                 NexusName = "cyberpunk2077",
@@ -467,7 +467,7 @@ public static class GameRegistry
             {
                 Game = Game.DragonsDogma,
                 SteamIDs = new[] {367500 },
-                GOGIDs = new []{1242384383},
+                GOGIDs = new long[]{1242384383},
                 MO2Name = "Dragon's Dogma: Dark Arisen",
                 MO2ArchiveName = "dragonsdogma",
                 NexusName = "dragonsdogma",
@@ -521,7 +521,7 @@ public static class GameRegistry
                 MO2Name = "Mount & Blade II: Bannerlord",
                 MO2ArchiveName = "mountandblade2bannerlord",
                 SteamIDs = new[] { 261550 },
-                GOGIDs = new [] {
+                GOGIDs = new long[] {
                     1564781494, //Mount & Blade II: Bannerlord : Game
                     1681929523, //Mount & Blade II: Bannerlord - Digital Deluxe : Package
                     1802539526, //Mount & Blade II: Bannerlord : Package
diff --git a/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj b/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
index 6dda57347..9070839d0 100644
--- a/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
+++ b/Wabbajack.Downloaders.Dispatcher.Test/Wabbajack.Downloaders.Dispatcher.Test.csproj
@@ -11,7 +11,7 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
           <PrivateAssets>all</PrivateAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
         <PackageReference Include="xunit" Version="2.4.2" />
         <PackageReference Include="Xunit.DependencyInjection.Logging" Version="8.0.1" />
diff --git a/Wabbajack.Downloaders.GameFile/GameLocator.cs b/Wabbajack.Downloaders.GameFile/GameLocator.cs
index 2cf9aef91..8c2a9d942 100644
--- a/Wabbajack.Downloaders.GameFile/GameLocator.cs
+++ b/Wabbajack.Downloaders.GameFile/GameLocator.cs
@@ -5,6 +5,8 @@
 using GameFinder.StoreHandlers.GOG;
 using GameFinder.StoreHandlers.Origin;
 using GameFinder.StoreHandlers.Steam;
+using GameFinder.StoreHandlers.Steam.Models;
+using GameFinder.StoreHandlers.Steam.Models.ValueTypes;
 using Microsoft.Extensions.Logging;
 using Wabbajack.DTOs;
 using Wabbajack.Paths;
@@ -19,10 +21,10 @@ public class GameLocator : IGameLocator
     private readonly EGSHandler? _egs;
     private readonly OriginHandler? _origin;
 
-    private readonly Dictionary<int, AbsolutePath> _steamGames = new();
-    private readonly Dictionary<long, AbsolutePath> _gogGames = new();
-    private readonly Dictionary<string, AbsolutePath> _egsGames = new(StringComparer.OrdinalIgnoreCase);
-    private readonly Dictionary<string, AbsolutePath> _originGames = new(StringComparer.OrdinalIgnoreCase);
+    private readonly Dictionary<AppId, AbsolutePath> _steamGames = new();
+    private readonly Dictionary<GOGGameId, AbsolutePath> _gogGames = new();
+    private readonly Dictionary<EGSGameId, AbsolutePath> _egsGames = new();
+    private readonly Dictionary<OriginGameId, AbsolutePath> _originGames = new();
 
     private readonly Dictionary<Game, AbsolutePath> _locationCache;
     private readonly ILogger<GameLocator> _logger;
@@ -30,19 +32,20 @@ public class GameLocator : IGameLocator
     public GameLocator(ILogger<GameLocator> logger)
     {
         _logger = logger;
+        var fileSystem = NexusMods.Paths.FileSystem.Shared;
 
         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
         {
             var windowsRegistry = new WindowsRegistry();
 
-            _steam = new SteamHandler(windowsRegistry);
-            _gog = new GOGHandler(windowsRegistry);
-            _egs = new EGSHandler(windowsRegistry);
-            _origin = new OriginHandler();
+            _steam = new SteamHandler(fileSystem, windowsRegistry);
+            _gog = new GOGHandler(windowsRegistry, fileSystem);
+            _egs = new EGSHandler(windowsRegistry, fileSystem);
+            _origin = new OriginHandler(fileSystem);
         }
         else
         {
-            _steam = new SteamHandler(null);
+            _steam = new SteamHandler(fileSystem, null);
         }
 
         _locationCache = new Dictionary<Game, AbsolutePath>();
@@ -54,7 +57,7 @@ private void FindAllGames()
     {
         try
         {
-            FindStoreGames(_steam, _steamGames, game => game.Path);
+            FindStoreGames(_steam, _steamGames, game => (AbsolutePath)game.Path.GetFullPath());
         }
         catch (Exception e)
         {
@@ -63,7 +66,7 @@ private void FindAllGames()
 
         try
         {
-            FindStoreGames(_gog, _gogGames, game => game.Path);
+            FindStoreGames(_gog, _gogGames, game => (AbsolutePath)game.Path.GetFullPath());
         }
         catch (Exception e)
         {
@@ -72,7 +75,7 @@ private void FindAllGames()
 
         try
         {
-            FindStoreGames(_egs, _egsGames, game => game.InstallLocation);
+            FindStoreGames(_egs, _egsGames, game => (AbsolutePath)game.InstallLocation.GetFullPath());
         }
         catch (Exception e)
         {
@@ -81,7 +84,7 @@ private void FindAllGames()
 
         try
         {
-            FindStoreGames(_origin, _originGames, game => game.InstallPath);
+            FindStoreGames(_origin, _originGames, game => (AbsolutePath)game.InstallPath.GetFullPath());
         }
         catch (Exception e)
         {
@@ -92,8 +95,9 @@ private void FindAllGames()
     private void FindStoreGames<TGame, TId>(
         AHandler<TGame, TId>? handler,
         Dictionary<TId, AbsolutePath> paths,
-        Func<TGame, string> getPath)
-        where TGame : class
+        Func<TGame, AbsolutePath> getPath)
+        where TGame : class, IGame
+        where TId : notnull
     {
         if (handler is null) return;
 
@@ -103,7 +107,7 @@ private void FindStoreGames<TGame, TId>(
         {
             try
             {
-                var path = getPath(game).ToAbsolutePath();
+                var path = getPath(game);
                 if (!path.DirectoryExists())
                 {
                     _logger.LogError("Game does not exist: {Game}", game);
@@ -160,28 +164,28 @@ private bool TryFindLocationInner(Game game, out AbsolutePath path)
 
         foreach (var id in metaData.SteamIDs)
         {
-            if (!_steamGames.TryGetValue(id, out var found)) continue;
+            if (!_steamGames.TryGetValue(AppId.From((uint)id), out var found)) continue;
             path = found;
             return true;
         }
 
         foreach (var id in metaData.GOGIDs)
         {
-            if (!_gogGames.TryGetValue(id, out var found)) continue;
+            if (!_gogGames.TryGetValue(GOGGameId.From(id), out var found)) continue;
             path = found;
             return true;
         }
 
         foreach (var id in metaData.EpicGameStoreIDs)
         {
-            if (!_egsGames.TryGetValue(id, out var found)) continue;
+            if (!_egsGames.TryGetValue(EGSGameId.From(id), out var found)) continue;
             path = found;
             return true;
         }
 
         foreach (var id in metaData.OriginIDs)
         {
-            if (!_originGames.TryGetValue(id, out var found)) continue;
+            if (!_originGames.TryGetValue(OriginGameId.From(id), out var found)) continue;
             path = found;
             return true;
         }
diff --git a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
index 10e8ff112..598216a23 100644
--- a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
+++ b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
@@ -18,10 +18,10 @@
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="GameFinder.StoreHandlers.EGS" Version="2.2.2" />
-        <PackageReference Include="GameFinder.StoreHandlers.GOG" Version="2.2.2" />
-        <PackageReference Include="GameFinder.StoreHandlers.Origin" Version="2.2.2" />
-        <PackageReference Include="GameFinder.StoreHandlers.Steam" Version="2.2.2" />
+        <PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.0.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.0.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.0.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.0.0" />
     </ItemGroup>
 
 </Project>
diff --git a/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj b/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
index 8c5ff86f2..883ad2d0c 100644
--- a/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
+++ b/Wabbajack.Downloaders.MediaFire/Wabbajack.Downloaders.MediaFire.csproj
@@ -7,7 +7,7 @@
 
     <ItemGroup>
         <PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
     </ItemGroup>
 
diff --git a/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj b/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
index f6fa66092..40378dd9f 100644
--- a/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
+++ b/Wabbajack.FileExtractor.Test/Wabbajack.FileExtractor.Test.csproj
@@ -11,7 +11,7 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
           <PrivateAssets>all</PrivateAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
         <PackageReference Include="xunit" Version="2.4.2" />
diff --git a/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj b/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
index b80d41bd6..590be2998 100644
--- a/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
+++ b/Wabbajack.Installer.Test/Wabbajack.Installer.Test.csproj
@@ -11,7 +11,7 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
           <PrivateAssets>all</PrivateAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
         <PackageReference Include="xunit" Version="2.4.2" />
         <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
diff --git a/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj b/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
index 56feb5f95..500ad9fa1 100644
--- a/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
+++ b/Wabbajack.Networking.NexusApi/Wabbajack.Networking.NexusApi.csproj
@@ -12,7 +12,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
     </ItemGroup>
 
diff --git a/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj b/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
index f403df799..c7e6d73b0 100644
--- a/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
+++ b/Wabbajack.Networking.Steam.Test/Wabbajack.Networking.Steam.Test.csproj
@@ -12,7 +12,7 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
           <PrivateAssets>all</PrivateAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
         <PackageReference Include="xunit" Version="2.4.2" />
         <PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" />
diff --git a/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj b/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
index e1ee4667a..2223ea6d4 100644
--- a/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
+++ b/Wabbajack.Services.OSIntegrated/Wabbajack.Services.OSIntegrated.csproj
@@ -17,7 +17,7 @@
             <PrivateAssets>all</PrivateAssets>
             <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
     </ItemGroup>
 
     <ItemGroup>
diff --git a/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj b/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
index 367e4b81f..29e3421ce 100644
--- a/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
+++ b/Wabbajack.VFS.Test/Wabbajack.VFS.Test.csproj
@@ -11,7 +11,7 @@
           <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
           <PrivateAssets>all</PrivateAssets>
         </PackageReference>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22102.15" />
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
         <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
         <PackageReference Include="System.Data.SQLite.Core" Version="1.0.116" />
         <PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" />

From 3b776692ca81031012e69450fc7dd7aa3e350811 Mon Sep 17 00:00:00 2001
From: Luca <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 12 Oct 2023 19:45:21 +0200
Subject: [PATCH 29/57] Update CHANGELOG.md

---
 CHANGELOG.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6de8b2bf5..7bb94d398 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,14 @@
 ### Changelog
 
-#### Version - 3.3.0.0-Pre - 10/02/2023
+#### Version - 3.3.0.0 - TBA
 * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder
 * Added RAM Limit setting for downloads
 * Added Fallout 4 (GOG) to the index
+* Updated App to .NET 7.0
+  * Should fix random crashes on some systems
+* Updated GameFinder to 4.0.0
 
 #### Version - 3.2.0.1 - 7/23/2023
   * Code cleanup: re-added some network and diagnostic code missing since 2.5

From 03be13b0100b0bc2ae27d26603728d2689329f8e Mon Sep 17 00:00:00 2001
From: Luca <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 12 Oct 2023 19:48:37 +0200
Subject: [PATCH 30/57] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7bb94d398..f6a08e81d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder
 * Added RAM Limit setting for downloads
+  * This fixes the High RAM usage (and sometimes app crashes) on some Hardware + Very High Speed Internet Connection Systems
 * Added Fallout 4 (GOG) to the index
 * Updated App to .NET 7.0
   * Should fix random crashes on some systems

From d62f59faddcadd89f959c91f0857b3d42ec744ac Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Fri, 20 Oct 2023 20:26:41 +0200
Subject: [PATCH 31/57] Don't try to add cookies if array is empty

---
 Wabbajack.Common/HttpExtensions.cs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Wabbajack.Common/HttpExtensions.cs b/Wabbajack.Common/HttpExtensions.cs
index b2ca8d391..dee1b3d0a 100644
--- a/Wabbajack.Common/HttpExtensions.cs
+++ b/Wabbajack.Common/HttpExtensions.cs
@@ -18,7 +18,11 @@ public static class HttpExtensions
         "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36";
     public static HttpRequestMessage AddCookies(this HttpRequestMessage msg, Cookie[] cookies)
     {
-        msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
+        if (cookies.Length > 0)
+        {
+            msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
+        }
+
         return msg;
     }
 

From 058b1bb287e1cd44c63181c1f83befca3deda4a7 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Fri, 20 Oct 2023 21:24:31 +0200
Subject: [PATCH 32/57] Start download from scratch if .download_package can't
 be parsed

---
 Wabbajack.Networking.Http/ResumableDownloader.cs | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.Networking.Http/ResumableDownloader.cs b/Wabbajack.Networking.Http/ResumableDownloader.cs
index 025715e4c..078de77d4 100644
--- a/Wabbajack.Networking.Http/ResumableDownloader.cs
+++ b/Wabbajack.Networking.Http/ResumableDownloader.cs
@@ -166,8 +166,17 @@ private void DeletePackage()
             return null;
         }
 
-        var packageJson = _packagePath.ReadAllText();
-        return JsonSerializer.Deserialize<DownloadPackage>(packageJson);
+        try
+        {
+            var packageJson = _packagePath.ReadAllText();
+            return JsonSerializer.Deserialize<DownloadPackage>(packageJson);
+        }
+        catch (JsonException ex)
+        {
+            _logger.LogWarning(ex, "Package for '{name}' couldn't be parsed. Deleting package and starting from scratch...", _outputPath.FileName.ToString());
+            DeletePackage();
+            return null;
+        }
     }
 
     private void SavePackage(DownloadPackage package)

From 45c346316c7215d72859eef64440cf8b444589f5 Mon Sep 17 00:00:00 2001
From: UrbanCMC <UrbanCMC@web.de>
Date: Fri, 20 Oct 2023 21:25:50 +0200
Subject: [PATCH 33/57] Log when application is shutting down

---
 Wabbajack.App.Wpf/Views/MainWindow.xaml.cs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
index 8f7aba3c6..4641e7dd0 100644
--- a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
@@ -45,6 +45,7 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
 
                 Closed += (s, e) =>
                 {
+                    _logger.LogInformation("Beginning shutdown...");
                     _mwvm.CancelRunningTasks(TimeSpan.FromSeconds(10));
                     Application.Current.Shutdown();
                 };

From d562afc4a8f350af5cf83bf65ad7a35218e8c8aa Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Sat, 21 Oct 2023 18:07:54 +0200
Subject: [PATCH 34/57] update CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1fb7d354b..6901b587b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@
 * Added RAM Limit setting for downloads
   * This fixes the High RAM usage (and sometimes app crashes) on some Hardware + Very High Speed Internet Connection Systems
 * Added Fallout 4 (GOG) to the index
-* Updated App to .NET 7.0
+* Updated App to .NET 8.0
   * Should fix random crashes on some systems
 * Updated GameFinder to 4.0.0
 

From f425bbc9e96fc790d93ce7d6a98c5dd36fe0fa1f Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Tue, 31 Oct 2023 13:45:38 +0100
Subject: [PATCH 35/57] exclude the "SP Consent Message" on nexus from the
 cleared iframes

---
 Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
index 003099bfd..337a839ab 100644
--- a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
+++ b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
@@ -21,7 +21,7 @@ protected override async Task Run(CancellationToken token)
 
         var task = WaitForDownloadUri(token, async () =>
         {
-            await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => f.remove())");
+            await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => {if (f.title != \"SP Consent Message\") f.remove()})");
         });
         await NavigateTo(md.Url);
         var uri = await task;

From f2a2ae40ea63c7efb992331d08742128b38d6e46 Mon Sep 17 00:00:00 2001
From: Marco Antonio Jaguaribe Costa <marco.antonio.costa@gmail.com>
Date: Wed, 25 Oct 2023 04:32:02 -0300
Subject: [PATCH 36/57] Actually use the --outputPath compile option if the
 user provides one

It was just not being used, defaulting to the parent of installPath. it
still does, if the user does not specify a directory using --outputPath
---
 Wabbajack.CLI/Verbs/Compile.cs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Wabbajack.CLI/Verbs/Compile.cs b/Wabbajack.CLI/Verbs/Compile.cs
index 692a8e0b1..969a5d7e1 100644
--- a/Wabbajack.CLI/Verbs/Compile.cs
+++ b/Wabbajack.CLI/Verbs/Compile.cs
@@ -11,6 +11,7 @@
 using Wabbajack.DTOs.JsonConverters;
 using Wabbajack.Networking.WabbajackClientApi;
 using Wabbajack.Paths;
+using Wabbajack.Paths.IO;
 using Wabbajack.VFS;
 
 namespace Wabbajack.CLI.Verbs;
@@ -58,6 +59,12 @@ public async Task<int> Run(AbsolutePath installPath, AbsolutePath outputPath,
 
         inferredSettings.UseGamePaths = true;
         
+        if(outputPath.DirectoryExists())
+        {
+            inferredSettings.OutputFile = outputPath.Combine(inferredSettings.OutputFile.FileName);
+            _logger.LogInformation("Output file will be in: {outputPath}", inferredSettings.OutputFile);
+        }
+
         var compiler = MO2Compiler.Create(_serviceProvider, inferredSettings);
         var result = await compiler.Begin(token);
         if (!result)

From d59fc87e388465c606e8fb77d7c1971cc461c9d3 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 14:19:15 +0100
Subject: [PATCH 37/57] update Wabbajack.Compression.BSA dependencies

---
 Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj b/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
index 4e1d94e70..14f1cf60d 100644
--- a/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
+++ b/Wabbajack.Compression.BSA/Wabbajack.Compression.BSA.csproj
@@ -18,8 +18,8 @@
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.4-beta" />
-        <PackageReference Include="SharpZipLib" Version="1.4.1" />
+        <PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.7-beta" />
+        <PackageReference Include="SharpZipLib" Version="1.4.2" />
     </ItemGroup>
 
 </Project>

From ccff5b822abe11d67e30badaeeab77b11238103c Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 14:20:11 +0100
Subject: [PATCH 38/57] improve log message to include storage space reference

---
 Wabbajack.VFS/VirtualFile.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Wabbajack.VFS/VirtualFile.cs b/Wabbajack.VFS/VirtualFile.cs
index ea2324c84..f149ddba7 100644
--- a/Wabbajack.VFS/VirtualFile.cs
+++ b/Wabbajack.VFS/VirtualFile.cs
@@ -244,6 +244,8 @@ public static async Task<VirtualFile> Analyze(Context context, VirtualFile? pare
         catch (Exception ex)
         {
             context.Logger.LogError(ex, "Error while examining the contents of {path}", relPath.FileName);
+            if (!ex.Message.Equals("End of stream before end of limit")) throw;
+            context.Logger.LogError("Possibly not enough free storage space in Wabbajack Folder Location");
             throw;
         }
 

From 7fd36718f53c65570c3b236990124059716a8e4a Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 15:18:23 +0100
Subject: [PATCH 39/57] clearing temp folder when the app closes

---
 Wabbajack.App.Wpf/Views/MainWindow.xaml.cs | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
index 4641e7dd0..bb786e5d8 100644
--- a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
+using System.IO;
 using System.Reactive.Linq;
 using System.Windows;
 using System.Windows.Input;
@@ -47,6 +48,31 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                 {
                     _logger.LogInformation("Beginning shutdown...");
                     _mwvm.CancelRunningTasks(TimeSpan.FromSeconds(10));
+                    
+                    // Cleaning the temp folder when the app closes since it can take up multiple Gigabytes of Storage
+                    var tempDirectory = Environment.CurrentDirectory + "\\temp";
+                    _logger.LogInformation("Clearing {TempDir}",tempDirectory);
+                    try
+                    {
+                        var directoryInfo = new DirectoryInfo(tempDirectory);
+                        
+                        foreach (var file in directoryInfo.EnumerateFiles())
+                        {
+                            file.Delete(); 
+                        }
+                        foreach (var dir in directoryInfo.EnumerateDirectories())
+                        {
+                            dir.Delete(true); 
+                        }
+                        
+                        _logger.LogInformation("Finished clearing {TempDir}",tempDirectory);
+                    }
+                    catch (Exception ex)
+                    {
+                        _logger.LogDebug("Directory {TempDir} doesn't exist",tempDirectory);
+                    }
+                    
+                    
                     Application.Current.Shutdown();
                 };
 

From f3a0f658a0db87e3363844fec6475f543fb91234 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 17:08:05 +0100
Subject: [PATCH 40/57] update logging message

---
 Wabbajack.VFS/VirtualFile.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.VFS/VirtualFile.cs b/Wabbajack.VFS/VirtualFile.cs
index f149ddba7..9bb33bd68 100644
--- a/Wabbajack.VFS/VirtualFile.cs
+++ b/Wabbajack.VFS/VirtualFile.cs
@@ -243,9 +243,9 @@ public static async Task<VirtualFile> Analyze(Context context, VirtualFile? pare
         }
         catch (Exception ex)
         {
-            context.Logger.LogError(ex, "Error while examining the contents of {path}", relPath.FileName);
+            context.Logger.LogError(ex, "Error while examining the contents of {Path}", relPath.FileName);
             if (!ex.Message.Equals("End of stream before end of limit")) throw;
-            context.Logger.LogError("Possibly not enough free storage space in Wabbajack Folder Location");
+            context.Logger.LogError("Not enough free storage space in {TempFolder}",Environment.CurrentDirectory+"\\temp");
             throw;
         }
 

From 7572135c1ab594bbf6089147fd30b63b450233cc Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 17:27:35 +0100
Subject: [PATCH 41/57] update CHANGELOG.md

---
 CHANGELOG.md | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6901b587b..f8bbfba12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,21 @@
 ### Changelog
 
-#### Version - 3.3.0.0 - 10/13/2023
+#### Version - 3.3.1.0 - TBA
+* Fixed `--outputPath` not being used for the CLI `compile` (thanks to @majcosta for fixing that)
+* Improved Log message for cases where low storage on the drive Wabbajack is installed on causes compiles to fail
+  * **To list authors still compiling on Wabbajack 3.0.5.0:**  
+    This is what is causing your compiles with any newer Wabbajack version to fail.
+    The reason the compile works is that you already have a full cache for all your mods and BSAs with that version and WJ only needs to add a small amount of new files to that cache and needs less temporary drive space because of that. Any version higher than 3.0.5.0 needs a new cache that can't be converted and needs WJ to unpack every Archive (zip/rar/7z/BSA/BA2) and add the files inside to the new cache.  
+    Finding ways to reduce the storage footprint when compiling huge lists for the first time (since any following compiles won't need that space requirement anymore) has become the next big priority.
+* Wabbajack will now clean the `temp` folder when closed
+* Updated Dependencies
+  * LZ4 to version 1.3.7-beta
+  * SharpZipLib to version 1.4.2
+
+#### Version - 3.3.0.1 - (Was only a Pre-Release)
+* Fixed Manual Downloading on NexusMods being blocked by a hidden cookie consent banner
+
+#### Version - 3.3.0.0 - 10/13/2023 (taken down due to build issues)
 * Fixed some UI issues arising from 3.2.0.0 changes - more informative error text, wiki link button
 * Added optional JSON flag for `DisplayVersionOnlyInInstallerView` to enable the installer image to only show version number.
 * Fixed manual downloader downloading in the OS's "Downloads" folder

From d3eeb17e0bc1ff2e0cd64cba9aa40aa617841a7c Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 2 Nov 2023 18:01:08 +0100
Subject: [PATCH 42/57] update CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8bbfba12..623fa999a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,7 @@
   * **To list authors still compiling on Wabbajack 3.0.5.0:**  
     This is what is causing your compiles with any newer Wabbajack version to fail.
     The reason the compile works is that you already have a full cache for all your mods and BSAs with that version and WJ only needs to add a small amount of new files to that cache and needs less temporary drive space because of that. Any version higher than 3.0.5.0 needs a new cache that can't be converted and needs WJ to unpack every Archive (zip/rar/7z/BSA/BA2) and add the files inside to the new cache.  
-    Finding ways to reduce the storage footprint when compiling huge lists for the first time (since any following compiles won't need that space requirement anymore) has become the next big priority.
+    Finding ways to reduce the storage footprint when compiling huge lists for the first time (since any following compiles won't need that space requirement anymore) will be investigated.
 * Wabbajack will now clean the `temp` folder when closed
 * Updated Dependencies
   * LZ4 to version 1.3.7-beta

From e40845b8ee7e44e2008337e5be8c08071ac9f947 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Fri, 3 Nov 2023 14:24:55 +0100
Subject: [PATCH 43/57] update logging for possible exceptions thrown when
 clearing temp folder

---
 Wabbajack.App.Wpf/Views/MainWindow.xaml.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
index bb786e5d8..6f3247260 100644
--- a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
@@ -69,7 +69,7 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                     }
                     catch (Exception ex)
                     {
-                        _logger.LogDebug("Directory {TempDir} doesn't exist",tempDirectory);
+                        _logger.LogError(ex,"Failed clearing {TempDir}",tempDirectory);
                     }
                     
                     

From 276ecde729d0cc71eb4f1f10ded096fd7a5d727b Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Sun, 5 Nov 2023 01:11:22 +0100
Subject: [PATCH 44/57] fix cloudflare captcha

---
 Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
index 337a839ab..8ed363ced 100644
--- a/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
+++ b/Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
@@ -21,7 +21,7 @@ protected override async Task Run(CancellationToken token)
 
         var task = WaitForDownloadUri(token, async () =>
         {
-            await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => {if (f.title != \"SP Consent Message\") f.remove()})");
+            await RunJavaScript("Array.from(document.getElementsByTagName(\"iframe\")).forEach(f => {if (f.title != \"SP Consent Message\" && !f.src.includes(\"challenges.cloudflare.com\")) f.remove()})");
         });
         await NavigateTo(md.Url);
         var uri = await task;

From 2e56c7069e79849ab173d4a96479ede8a66ae711 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 4 Jan 2024 19:09:58 +0100
Subject: [PATCH 45/57] update Final Fantasy VII: RI metadata

---
 Wabbajack.DTOs/Game/GameRegistry.cs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index e3310ebbd..71b89c2e7 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -546,9 +546,10 @@ public static class GameRegistry
                 IsGenericMO2Plugin = true,
                 RequiredFiles = new []
                 {
-                    @"ff7remake.exe".ToRelativePath()
+                    @"End\Binaries\Win64\ff7remake_.exe".ToRelativePath(),
+                    @"ff7remake_.exe".ToRelativePath()
                 },
-                MainExecutable = @"ff7remake.exe".ToRelativePath()
+                MainExecutable = @"End\Binaries\Win64\ff7remake_.exe"ToRelativePath()
             }
         },
         {

From 5daefc577500618451b5e9a6b4e8bf87ca16c92d Mon Sep 17 00:00:00 2001
From: Luca <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 4 Jan 2024 19:13:40 +0100
Subject: [PATCH 46/57] Update CHANGELOG.md

---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d1e4b92c..57812be86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ### Changelog
 
+#### Version - TBD
+* Fixed Final Fantasy 7: Remake Intergrade meta data
+
 #### Version - 3.4.1.0 - 12/21/2023
 * Added Support for Final Fantasy 7: Remake Intergrade
 * Update CLI to .NET 8.0 (was missed in the last update)

From f95d467b99d90cf03481952271f28237f01f2182 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Thu, 4 Jan 2024 19:25:05 +0100
Subject: [PATCH 47/57] fix error

---
 Wabbajack.DTOs/Game/GameRegistry.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index 71b89c2e7..73b996289 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -549,7 +549,7 @@ public static class GameRegistry
                     @"End\Binaries\Win64\ff7remake_.exe".ToRelativePath(),
                     @"ff7remake_.exe".ToRelativePath()
                 },
-                MainExecutable = @"End\Binaries\Win64\ff7remake_.exe"ToRelativePath()
+                MainExecutable = @"End\Binaries\Win64\ff7remake_.exe".ToRelativePath()
             }
         },
         {

From 545d9ae40426aa7e07251760e2f52d8f8a239193 Mon Sep 17 00:00:00 2001
From: Luca <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Sat, 6 Jan 2024 20:40:51 +0100
Subject: [PATCH 48/57] Update GameRegistry.cs

---
 Wabbajack.DTOs/Game/GameRegistry.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index 73b996289..2ad55b0f8 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -540,7 +540,7 @@ public static class GameRegistry
                 Game = Game.FinalFantasy7Remake,
                 NexusName = "finalfantasy7remake",
                 NexusGameId = 4202,
-                MO2Name = "FINAL FANTASY VII REMAKE",
+                MO2Name = "FINAL FANTASY VII REMAKE INTERGRADE",
                 MO2ArchiveName = "finalfantasy7remake",
                 SteamIDs = new[] { 1462040 },
                 IsGenericMO2Plugin = true,

From fb3f8a79680c90db4e1faefab9bc95c341a94f48 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 8 Jan 2024 20:20:59 +0100
Subject: [PATCH 49/57] Updated GameFinder, Added EADesktop module

---
 CHANGELOG.md                                  |  7 ++++
 Wabbajack.DTOs/Game/GameMetaData.cs           |  3 ++
 Wabbajack.DTOs/Game/GameRegistry.cs           | 32 +++++++++++++++++++
 Wabbajack.Downloaders.GameFile/GameLocator.cs | 22 ++++++++++++-
 .../Wabbajack.Downloaders.GameFile.csproj     |  9 +++---
 5 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d1e4b92c..f041f619e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 ### Changelog
 
+#### Version - TBD
+* Updated GameFinder
+  * Fixes Wabbajack not Launching on some systems
+* Added the GameFinder module for EA Desktop
+  * Only `Dragon Age: Origins` & `Dragon Age: Inquisition` supported for now.
+  * For other games we still need to collect the right store IDs
+
 #### Version - 3.4.1.0 - 12/21/2023
 * Added Support for Final Fantasy 7: Remake Intergrade
 * Update CLI to .NET 8.0 (was missed in the last update)
diff --git a/Wabbajack.DTOs/Game/GameMetaData.cs b/Wabbajack.DTOs/Game/GameMetaData.cs
index 1b4a4061b..79b9e81fa 100644
--- a/Wabbajack.DTOs/Game/GameMetaData.cs
+++ b/Wabbajack.DTOs/Game/GameMetaData.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Runtime.InteropServices.JavaScript;
 using Wabbajack.Paths;
 
 namespace Wabbajack.DTOs;
@@ -29,6 +30,8 @@ public class GameMetaData
     // EAPlay games may have @subscription appended to the file name
     public string[] OriginIDs { get; set; } = Array.Empty<string>();
 
+    public string[] EADesktopIDs { get; set; } = Array.Empty<string>();
+
     public string[] EpicGameStoreIDs { get; internal init; } = Array.Empty<string>();
 
     // to get BethNet IDs: check the registry
diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index e3310ebbd..1deefa43f 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -357,6 +357,22 @@ public static class GameRegistry
                 MO2Name = "Dragon Age: Origins",
                 SteamIDs = new[] {47810},
                 OriginIDs = new[] {"DR:169789300", "DR:208591800"},
+                EADesktopIDs = new [] // Possibly Wrong
+                {
+                    "9df89a8e-b201-4507-8a8d-bd6799fedb18",
+                    "Origin.SFT.50.0000078", 
+                    "Origin.SFT.50.0000078",
+                    "Origin.SFT.50.0000078",
+                    "Origin.SFT.50.0000085",
+                    "Origin.SFT.50.0000086",
+                    "Origin.SFT.50.0000087",
+                    "Origin.SFT.50.0000088",
+                    "Origin.SFT.50.0000089",
+                    "Origin.SFT.50.0000090",
+                    "Origin.SFT.50.0000091",
+                    "Origin.SFT.50.0000097",
+                    "Origin.SFT.50.0000098"
+                },
                 GOGIDs = new long[] {1949616134},
                 RequiredFiles = new[]
                 {
@@ -374,6 +390,22 @@ public static class GameRegistry
                 MO2Name = "Dragon Age 2", // Probably wrong
                 SteamIDs = new[] {1238040},
                 OriginIDs = new[] {"OFB-EAST:59474", "DR:201797000"},
+                EADesktopIDs = new [] // Possibly Wrong
+                {
+                    "Origin.SFT.50.0000073",
+                    "Origin.SFT.50.0000255",
+                    "Origin.SFT.50.0000256",
+                    "Origin.SFT.50.0000257",
+                    "Origin.SFT.50.0000288",
+                    "Origin.SFT.50.0000310",
+                    "Origin.SFT.50.0000311",
+                    "Origin.SFT.50.0000356",
+                    "Origin.SFT.50.0000385",
+                    "Origin.SFT.50.0000429",
+                    "Origin.SFT.50.0000449",
+                    "Origin.SFT.50.0000452",
+                    "Origin.SFT.50.0000453"
+                },
                 RequiredFiles = new[]
                 {
                     @"bin_ship\DragonAge2.exe".ToRelativePath()
diff --git a/Wabbajack.Downloaders.GameFile/GameLocator.cs b/Wabbajack.Downloaders.GameFile/GameLocator.cs
index 8c2a9d942..f5e887a03 100644
--- a/Wabbajack.Downloaders.GameFile/GameLocator.cs
+++ b/Wabbajack.Downloaders.GameFile/GameLocator.cs
@@ -1,6 +1,8 @@
 using System.Runtime.InteropServices;
 using GameFinder.Common;
 using GameFinder.RegistryUtils;
+using GameFinder.StoreHandlers.EADesktop;
+using GameFinder.StoreHandlers.EADesktop.Crypto.Windows;
 using GameFinder.StoreHandlers.EGS;
 using GameFinder.StoreHandlers.GOG;
 using GameFinder.StoreHandlers.Origin;
@@ -20,12 +22,14 @@ public class GameLocator : IGameLocator
     private readonly GOGHandler? _gog;
     private readonly EGSHandler? _egs;
     private readonly OriginHandler? _origin;
+    private readonly EADesktopHandler? _eaDesktop;
 
     private readonly Dictionary<AppId, AbsolutePath> _steamGames = new();
     private readonly Dictionary<GOGGameId, AbsolutePath> _gogGames = new();
     private readonly Dictionary<EGSGameId, AbsolutePath> _egsGames = new();
     private readonly Dictionary<OriginGameId, AbsolutePath> _originGames = new();
-
+    private readonly Dictionary<EADesktopGameId, AbsolutePath> _eaDesktopGames = new();
+    
     private readonly Dictionary<Game, AbsolutePath> _locationCache;
     private readonly ILogger<GameLocator> _logger;
 
@@ -42,6 +46,7 @@ public GameLocator(ILogger<GameLocator> logger)
             _gog = new GOGHandler(windowsRegistry, fileSystem);
             _egs = new EGSHandler(windowsRegistry, fileSystem);
             _origin = new OriginHandler(fileSystem);
+            _eaDesktop = new EADesktopHandler(fileSystem, new HardwareInfoProvider());
         }
         else
         {
@@ -90,6 +95,14 @@ private void FindAllGames()
         {
             _logger.LogError(e, "While finding games installed with Origin");
         }
+        try
+        {
+            FindStoreGames(_eaDesktop, _eaDesktopGames, game => (AbsolutePath)game.BaseInstallPath.GetFullPath());
+        }
+        catch (Exception e)
+        {
+            _logger.LogError(e, "While finding games installed with EADesktop");
+        }
     }
 
     private void FindStoreGames<TGame, TId>(
@@ -189,6 +202,13 @@ private bool TryFindLocationInner(Game game, out AbsolutePath path)
             path = found;
             return true;
         }
+        
+        foreach (var id in metaData.EADesktopIDs)
+        {
+            if (!_eaDesktopGames.TryGetValue(EADesktopGameId.From(id), out var found)) continue;
+            path = found;
+            return true;
+        }
 
         path = default;
         return false;
diff --git a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
index 8f0054844..0a03a0ad8 100644
--- a/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
+++ b/Wabbajack.Downloaders.GameFile/Wabbajack.Downloaders.GameFile.csproj
@@ -18,10 +18,11 @@
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.0.0" />
-        <PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.0.0" />
-        <PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.0.0" />
-        <PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.0.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.EADesktop" Version="4.1.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.EGS" Version="4.1.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.GOG" Version="4.1.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.Origin" Version="4.1.0" />
+        <PackageReference Include="GameFinder.StoreHandlers.Steam" Version="4.1.0" />
     </ItemGroup>
 
 </Project>

From 3b81f3b856f312f150c383fc5ca82349ff66bf67 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 8 Jan 2024 20:30:36 +0100
Subject: [PATCH 50/57] updated version number in CHANGELOG.md

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f041f619e..f3246b485 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
 ### Changelog
 
 #### Version - TBD
-* Updated GameFinder
+* Updated GameFinder to 4.1.0
   * Fixes Wabbajack not Launching on some systems
 * Added the GameFinder module for EA Desktop
   * Only `Dragon Age: Origins` & `Dragon Age: Inquisition` supported for now.

From a8aad32995d5d445ab58271c16b98c30b1bf66ef Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 8 Jan 2024 20:52:13 +0100
Subject: [PATCH 51/57] updated logging code

---
 Wabbajack.App.Wpf/Views/MainWindow.xaml.cs | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
index 6f3247260..2135f5c04 100644
--- a/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/MainWindow.xaml.cs
@@ -52,27 +52,26 @@ public MainWindow(ILogger<MainWindow> logger, SystemParametersConstructor system
                     // Cleaning the temp folder when the app closes since it can take up multiple Gigabytes of Storage
                     var tempDirectory = Environment.CurrentDirectory + "\\temp";
                     _logger.LogInformation("Clearing {TempDir}",tempDirectory);
+                    var directoryInfo = new DirectoryInfo(tempDirectory);
                     try
                     {
-                        var directoryInfo = new DirectoryInfo(tempDirectory);
-                        
                         foreach (var file in directoryInfo.EnumerateFiles())
                         {
-                            file.Delete(); 
+                            file.Delete();
                         }
+
                         foreach (var dir in directoryInfo.EnumerateDirectories())
                         {
-                            dir.Delete(true); 
+                            dir.Delete(true);
                         }
-                        
-                        _logger.LogInformation("Finished clearing {TempDir}",tempDirectory);
+
+                        _logger.LogInformation("Finished clearing {TempDir}", tempDirectory);
                     }
-                    catch (Exception ex)
+                    catch (DirectoryNotFoundException)
                     {
-                        _logger.LogError(ex,"Failed clearing {TempDir}",tempDirectory);
+                        _logger.LogInformation("Unable to find {TempDir}", tempDirectory);
                     }
                     
-                    
                     Application.Current.Shutdown();
                 };
 

From 0446e3143e5cf0c1f59b6929dc38fb9bb86dbc64 Mon Sep 17 00:00:00 2001
From: EzioTheDeadPoet <52624146+EzioTheDeadPoet@users.noreply.github.com>
Date: Mon, 8 Jan 2024 20:56:22 +0100
Subject: [PATCH 52/57] update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d1e4b92c..92b293a4a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 * Added Support for Baldur's Gate 3 
   * Very Work in Progress
   * **NOT** Plug and Play for compiling and installing!
+* Fixed a logging error when closing the App without a `temp` folder to delete
 
 #### Version - 3.4.0.0 - 11/19/2023
 * Fixed `--outputPath` not being used for the CLI `compile` (thanks to @majcosta for fixing that)

From 3cdf3c9ed6a290a5df6483283b43f29741fd2991 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Thu, 11 Jan 2024 06:24:18 +0100
Subject: [PATCH 53/57] Fix Nexus login (#2476)

* Fix Nexus login handler after API keys web page changes

* Automatically press request button

* Automatically press request API key button
---
 .../UserIntervention/NexusLoginHandler.cs          | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs b/Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs
index 617885ebd..aa9e2f360 100644
--- a/Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs
+++ b/Wabbajack.App.Wpf/UserIntervention/NexusLoginHandler.cs
@@ -45,7 +45,7 @@ await NavigateTo(new Uri(
 
         Instructions = "Getting API Key...";
 
-        await NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
+        await NavigateTo(new Uri("https://next.nexusmods.com/settings/api-keys"));
 
         var key = "";
 
@@ -53,12 +53,7 @@ await NavigateTo(new Uri(
         {
             try
             {
-                key = (await GetDom(token))
-                    .DocumentNode
-                    .QuerySelectorAll("input[value=wabbajack]")
-                    .SelectMany(p => p.ParentNode.ParentNode.QuerySelectorAll("textarea.application-key"))
-                    .Select(node => node.InnerHtml)
-                    .FirstOrDefault() ?? "";
+                key = (await GetDom(token)).DocumentNode.QuerySelectorAll("img[alt='Wabbajack']").SelectMany(p => p.ParentNode.ParentNode.QuerySelectorAll("input[aria-label='api key']")).Select(node => node.Attributes["value"]).FirstOrDefault()?.Value;
             }
             catch (Exception)
             {
@@ -71,11 +66,10 @@ await NavigateTo(new Uri(
             try
             {
                 await EvaluateJavaScript(
-                    "var found = document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"form button[type=submit]\");" +
+                    "var found = document.querySelector(\"img[alt='Wabbajack']\").parentElement.parentElement.querySelector(\"button[aria-label='Request Api Key']\");" +
                     "found.onclick= function() {return true;};" +
                     "found.class = \" \"; " +
-                    "found.click();" +
-                    "found.remove(); found = undefined;"
+                    "found.click();"
                 );
                 Instructions = "Generating API Key, Please Wait...";
             }

From fdabeae9d1bcf0d69aa16d343d003ae43673fc65 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Fri, 12 Jan 2024 18:45:18 +0100
Subject: [PATCH 54/57] Fix BG3 being named badlursgate3 in Game enum instead
 of baldursgate3

---
 Wabbajack.DTOs/Game/Game.cs         | 2 +-
 Wabbajack.DTOs/Game/GameRegistry.cs | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Wabbajack.DTOs/Game/Game.cs b/Wabbajack.DTOs/Game/Game.cs
index c99153ef7..dcd6fef96 100644
--- a/Wabbajack.DTOs/Game/Game.cs
+++ b/Wabbajack.DTOs/Game/Game.cs
@@ -54,5 +54,5 @@ public enum Game
     [Description("Modding Tools")] ModdingTools,
 
     [Description("Final Fantasy VII Remake")] FinalFantasy7Remake,
-    [Description("Baldur's Gate 3")] BadlursGate3
+    [Description("Baldur's Gate 3")] BaldursGate3
 }
diff --git a/Wabbajack.DTOs/Game/GameRegistry.cs b/Wabbajack.DTOs/Game/GameRegistry.cs
index cc09a10f4..23a18faf9 100644
--- a/Wabbajack.DTOs/Game/GameRegistry.cs
+++ b/Wabbajack.DTOs/Game/GameRegistry.cs
@@ -585,9 +585,9 @@ public static class GameRegistry
             }
         },
         {
-            Game.BadlursGate3, new GameMetaData
+            Game.BaldursGate3, new GameMetaData
             {
-                Game = Game.BadlursGate3,
+                Game = Game.BaldursGate3,
                 NexusName = "baldursgate3",
                 NexusGameId = 3474,
                 MO2Name = "Baldur's Gate 3",

From 91ddb3934468d75245b9f0821b822da9a002547b Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Fri, 12 Jan 2024 20:57:58 +0100
Subject: [PATCH 55/57] Fix WebView2 taking up tons of memory, use single
 WebView window - still needs refactoring

---
 Wabbajack.App.Wpf/App.xaml.cs                 |  2 ++
 .../LoginManagers/LoversLabLoginManager.cs    |  2 +-
 .../LoginManagers/NexusLoginManager.cs        |  2 +-
 .../LoginManagers/VectorPlexusLoginManager.cs |  2 +-
 Wabbajack.App.Wpf/Verbs/NexusLogin.cs         |  2 +-
 Wabbajack.App.Wpf/Views/BrowserWindow.xaml    |  4 ++--
 Wabbajack.App.Wpf/Views/BrowserWindow.xaml.cs | 22 +++++++++++++++++--
 7 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/Wabbajack.App.Wpf/App.xaml.cs b/Wabbajack.App.Wpf/App.xaml.cs
index dc9d2cd09..1ad25eeef 100644
--- a/Wabbajack.App.Wpf/App.xaml.cs
+++ b/Wabbajack.App.Wpf/App.xaml.cs
@@ -8,6 +8,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
+using Microsoft.Web.WebView2.Wpf;
 using NLog.Extensions.Logging;
 using NLog.Targets;
 using Orc.FileAssociation;
@@ -164,6 +165,7 @@ private static IServiceCollection ConfigureServices(IServiceCollection services)
             services.AddSingleton<SystemParametersConstructor>();
             services.AddSingleton<LauncherUpdater>();
             services.AddSingleton<ResourceMonitor>();
+            services.AddSingleton<WebView2>();
 
             services.AddTransient<CompilerVM>();
             services.AddTransient<InstallerVM>();
diff --git a/Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs b/Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs
index 985fec986..8e982af75 100644
--- a/Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs
+++ b/Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs
@@ -66,7 +66,7 @@ public LoversLabLoginManager(ILogger<LoversLabLoginManager> logger, ITokenProvid
     
     private void StartLogin()
     {
-        var view = new BrowserWindow();
+        var view = new BrowserWindow(_serviceProvider);
         view.Closed += (sender, args) => { RefreshTokenState(); };
         var provider = _serviceProvider.GetRequiredService<LoversLabLoginHandler>();
         view.DataContext = provider;
diff --git a/Wabbajack.App.Wpf/LoginManagers/NexusLoginManager.cs b/Wabbajack.App.Wpf/LoginManagers/NexusLoginManager.cs
index a7115a764..440b60fe2 100644
--- a/Wabbajack.App.Wpf/LoginManagers/NexusLoginManager.cs
+++ b/Wabbajack.App.Wpf/LoginManagers/NexusLoginManager.cs
@@ -62,7 +62,7 @@ public NexusLoginManager(ILogger<NexusLoginManager> logger, ITokenProvider<Nexus
 
     private void StartLogin()
     {
-        var view = new BrowserWindow();
+        var view = new BrowserWindow(_serviceProvider);
         view.Closed += (sender, args) => { RefreshTokenState(); };
         var provider = _serviceProvider.GetRequiredService<NexusLoginHandler>();
         view.DataContext = provider;
diff --git a/Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs b/Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs
index 9e8f691d2..62a13e260 100644
--- a/Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs
+++ b/Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs
@@ -66,7 +66,7 @@ public VectorPlexusLoginManager(ILogger<VectorPlexusLoginManager> logger, IToken
         
     private void StartLogin()
     {
-        var view = new BrowserWindow();
+        var view = new BrowserWindow(_serviceProvider);
         view.Closed += (sender, args) => { RefreshTokenState(); };
         var provider = _serviceProvider.GetRequiredService<VectorPlexusLoginHandler>();
         view.DataContext = provider;
diff --git a/Wabbajack.App.Wpf/Verbs/NexusLogin.cs b/Wabbajack.App.Wpf/Verbs/NexusLogin.cs
index b4140cece..b91148fe3 100644
--- a/Wabbajack.App.Wpf/Verbs/NexusLogin.cs
+++ b/Wabbajack.App.Wpf/Verbs/NexusLogin.cs
@@ -25,7 +25,7 @@ public NexusLogin(ILogger<NexusLogin> logger, IServiceProvider services)
     public async Task<int> Run(CancellationToken token)
     {
         var tcs = new TaskCompletionSource<int>();
-        var view = new BrowserWindow();
+        var view = new BrowserWindow(_services);
         view.Closed += (sender, args) => { tcs.TrySetResult(0); };
         var provider = _services.GetRequiredService<NexusLoginHandler>();
         view.DataContext = provider;
diff --git a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
index 62a13a0f9..3fb470a2d 100644
--- a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
+++ b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
@@ -23,7 +23,7 @@
                  WindowTitleBrush="{StaticResource MahApps.Brushes.Accent}"
                  ContentRendered="BrowserWindow_OnActivated"
                  mc:Ignorable="d">
-    <Grid  Background="#121212" MouseDown="UIElement_OnMouseDown">
+    <Grid x:Name="MainGrid" Background="#121212" MouseDown="UIElement_OnMouseDown">
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"></RowDefinition>
             <RowDefinition Height="Auto"></RowDefinition>
@@ -47,7 +47,7 @@
         </Button>
         <TextBox  Grid.Row="2" Grid.Column="3" Margin="4" VerticalContentAlignment="Center" Name="AddressBar" IsEnabled="False"></TextBox>
         
-        <wpf:WebView2 Grid.Row="3" Grid.ColumnSpan="3" Name="Browser"></wpf:WebView2>
+        <!--<wpf:WebView2 Grid.Row="3" Grid.ColumnSpan="3" Name="Browser"></wpf:WebView2>-->
         
     </Grid>
 </mahapps:MetroWindow>
diff --git a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml.cs b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml.cs
index 175de016e..a77c5b789 100644
--- a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml.cs
+++ b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml.cs
@@ -1,11 +1,15 @@
 using System;
+using System.Reactive.Concurrency;
 using System.Reactive.Disposables;
 using System.Reactive.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
+using System.Windows.Controls;
 using System.Windows.Input;
 using MahApps.Metro.Controls;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Web.WebView2.Wpf;
 using ReactiveUI;
 using Wabbajack.Common;
 
@@ -14,12 +18,27 @@ namespace Wabbajack;
 public partial class BrowserWindow : MetroWindow
 {
     private readonly CompositeDisposable _disposable;
+    private readonly IServiceProvider _serviceProvider;
+    public WebView2 Browser { get; set; }
 
-    public BrowserWindow()
+    public BrowserWindow(IServiceProvider serviceProvider)
     {
         InitializeComponent();
 
+
         _disposable = new CompositeDisposable();
+        _serviceProvider = serviceProvider;
+        Browser = _serviceProvider.GetRequiredService<WebView2>();
+        RxApp.MainThreadScheduler.Schedule(() =>
+        {
+            if(Browser.Parent != null)
+            {
+                ((Panel)Browser.Parent).Children.Remove(Browser);
+            }
+            MainGrid.Children.Add(Browser);
+            Grid.SetRow(Browser, 3);
+            Grid.SetColumnSpan(Browser, 3);
+        });
     }
 
     private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
@@ -58,7 +77,6 @@ private void BrowserWindow_OnActivated(object sender, EventArgs e)
             .ContinueWith(_ => Dispatcher.Invoke(() =>
             {
                 Close();
-                Browser = null;
             }));
     }
 }
\ No newline at end of file

From 591f9bac54644c292a17d8e45b5bc3e173586430 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Sat, 13 Jan 2024 00:01:03 +0100
Subject: [PATCH 56/57] Remove commented WebView

---
 Wabbajack.App.Wpf/Views/BrowserWindow.xaml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
index 3fb470a2d..a1fa5033d 100644
--- a/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
+++ b/Wabbajack.App.Wpf/Views/BrowserWindow.xaml
@@ -46,8 +46,5 @@
             <icon:PackIconModern Kind="PageCopy"></icon:PackIconModern>
         </Button>
         <TextBox  Grid.Row="2" Grid.Column="3" Margin="4" VerticalContentAlignment="Center" Name="AddressBar" IsEnabled="False"></TextBox>
-        
-        <!--<wpf:WebView2 Grid.Row="3" Grid.ColumnSpan="3" Name="Browser"></wpf:WebView2>-->
-        
     </Grid>
 </mahapps:MetroWindow>

From 2618d53f7b5bf2ec3bfa160adbc50de40ed858e0 Mon Sep 17 00:00:00 2001
From: trawzified <55751269+tr4wzified@users.noreply.github.com>
Date: Sat, 13 Jan 2024 00:35:43 +0100
Subject: [PATCH 57/57] Add changelog, fix Wabbajack CLI bat pointing to the
 wrong directory

---
 CHANGELOG.md                                         | 4 ++++
 Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs | 5 ++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d356bead1..72e76022b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@
   * Only `Dragon Age: Origins` & `Dragon Age: Inquisition` supported for now.
   * For other games we still need to collect the right store IDs
 * Fixed Final Fantasy 7: Remake Intergrade meta data
+* Fixed new WebView2 instances being created constantly causing a memory leak
+* Fixed the Nexus API key no longer being picked up when logging in
+* Fixed Baldur's Gate 3 having to be named 'badlursgate3' instead of 'baldursgate3' when defining a modlist JSON
+* Fixed wabbajack-cli.bat pointing to the wrong CLI executable path
 
 #### Version - 3.4.1.0 - 12/21/2023
 * Added Support for Final Fantasy 7: Remake Intergrade
diff --git a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
index 47e169823..2e8f76504 100644
--- a/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
+++ b/Wabbajack.Launcher/ViewModels/MainWindowViewModel.cs
@@ -303,10 +303,13 @@ private async Task CreateBatchFile(AbsolutePath filename)
     {
         try
         {
-            filename = filename.Parent.Combine("wabbajack-cli.exe");
+            filename = filename.Parent.Combine("cli", "wabbajack-cli.exe");
             var data = $"\"{filename}\" %*";
             var file = Path.Combine(Directory.GetCurrentDirectory(), "wabbajack-cli.bat");
             if (File.Exists(file) && await File.ReadAllTextAsync(file) == data) return;
+            var parent = Directory.GetParent(file).FullName;
+            if (!Directory.Exists(file))
+                Directory.CreateDirectory(parent);
             await File.WriteAllTextAsync(file, data);
         }
         catch (Exception ex)