diff --git a/ModAssistant/App.config b/ModAssistant/App.config
index 7a673b8e..c08719a4 100644
--- a/ModAssistant/App.config
+++ b/ModAssistant/App.config
@@ -1,10 +1,11 @@
-
+
-
+
+
@@ -69,4 +70,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ModAssistant/Classes/External Interfaces/BeatSaver.cs b/ModAssistant/Classes/External Interfaces/BeatSaver.cs
index 0f9a3af4..3ea40c5b 100644
--- a/ModAssistant/Classes/External Interfaces/BeatSaver.cs
+++ b/ModAssistant/Classes/External Interfaces/BeatSaver.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
+using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
@@ -181,6 +182,30 @@ public static async Task InstallMap(BeatSaverApiResponseMap Map, bool sh
}
throw new Exception("Zip file not found.");
}
+
+ // Verify and patch separate audio file if needed
+ var hasFingerprintFile = File.Exists(Path.Combine(directory, "fingerprint.bin"));
+ if (hasFingerprintFile)
+ {
+ var noAudioFile = !Directory.EnumerateFiles(directory).Any(file =>
+ {
+ var ext = Path.GetExtension(file);
+ return ext == ".egg" || ext == ".ogg" || ext == ".wav";
+ });
+ if (noAudioFile)
+ {
+ var patchSucccess = await SongPatcher.PromptAndPatchSongFromDisk(directory);
+ if (!patchSucccess)
+ {
+ if (showNotification)
+ {
+ MessageBox.Show($"{Application.Current.FindResource("OneClick:PatchSong:Failed")}");
+ }
+ throw new Exception("Verification and patching failed.");
+ }
+ }
+ }
+
return mapName;
}
diff --git a/ModAssistant/Classes/External Interfaces/SongPatcher.cs b/ModAssistant/Classes/External Interfaces/SongPatcher.cs
new file mode 100644
index 00000000..e33ae790
--- /dev/null
+++ b/ModAssistant/Classes/External Interfaces/SongPatcher.cs
@@ -0,0 +1,91 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using SaberSongPatcher;
+using Application = System.Windows.Application;
+
+namespace ModAssistant.API
+{
+ public class SongPatcher
+ {
+ public static async Task PromptAndPatchSongFromDisk(string directory)
+ {
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ var supportedExtensions = new[]
+ {
+ "mp3",
+ "m4a",
+ "ogg",
+ "wav",
+ "flac",
+ "aiff",
+ "wma",
+ };
+ var audioExtensions = string.Join(";", supportedExtensions.Select(ext => $"*.{ext}"));
+ openFileDialog.Title = (string)Application.Current.FindResource("OneClick:PatchSong:SelectFile");
+ openFileDialog.Filter = $"Audio files ({audioExtensions})|{audioExtensions}|All files (*.*)|*.*";
+ openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
+
+ var success = false;
+ if (openFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ success = await PerformPatch(openFileDialog.FileName, directory);
+ }
+ return success;
+ }
+
+ private static async Task PerformPatch(string inputFile, string mapDirectory)
+ {
+ var config = ConfigParser.ParseConfig(true, mapDirectory);
+ var context = new Context(config);
+ var inputValidator = new InputValidator(context);
+ var inputTransformer = new InputTransformer(context);
+
+ var seemsCorrect = await inputValidator.ValidateInput(inputFile, mapDirectory);
+ if (!seemsCorrect)
+ {
+ return false;
+ }
+
+ var filename = "song.egg";
+ var infoFile = Path.Combine(mapDirectory, "info.dat");
+ if (!File.Exists(infoFile))
+ {
+ infoFile = Path.Combine(mapDirectory, "Info.dat");
+ }
+ if (File.Exists(infoFile))
+ {
+ try
+ {
+ // Try to use the output filename from the info.dat file
+ using (StreamReader file = File.OpenText(infoFile))
+ using (JsonTextReader reader = new JsonTextReader(file))
+ {
+ JObject info = JObject.Load(reader);
+ var filenameToken = info.Value("_songFilename");
+ if (!string.IsNullOrEmpty(filenameToken))
+ {
+ filename = filenameToken;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ var outputFile = Path.Combine(mapDirectory, filename);
+ var success = await inputTransformer.TransformInput(inputFile, outputFile);
+ if (!success)
+ {
+ throw new Exception("Failed to transform audio.");
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/ModAssistant/Localisation/de.xaml b/ModAssistant/Localisation/de.xaml
index 1d02ce20..a190a140 100644
--- a/ModAssistant/Localisation/de.xaml
+++ b/ModAssistant/Localisation/de.xaml
@@ -216,6 +216,8 @@
Beat Saber Installationspfad nicht gefunden.
Installiert: {0}
Installation fehlgeschlagen.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ Installation Handler registriert!
{0} OneClick™ Installation Handler entfernt!
Installing: {0}
diff --git a/ModAssistant/Localisation/en-DEBUG.xaml b/ModAssistant/Localisation/en-DEBUG.xaml
index d7daea69..84f1c15b 100644
--- a/ModAssistant/Localisation/en-DEBUG.xaml
+++ b/ModAssistant/Localisation/en-DEBUG.xaml
@@ -157,6 +157,8 @@
OneClick:InstallDirNotFound
{0} OneClick:InstalledAsset
OneClick:AssetInstallFailed
+ OneClick:PatchSong:Failed
+ OneClick:PatchSong:SelectFile
{0} OneClick:ProtocolHandler:Registered
{0} OneClick:ProtocolHandler:Unregistered
{0} OneClick:Installing
diff --git a/ModAssistant/Localisation/en.xaml b/ModAssistant/Localisation/en.xaml
index 21dc8c7d..5685ee13 100644
--- a/ModAssistant/Localisation/en.xaml
+++ b/ModAssistant/Localisation/en.xaml
@@ -220,6 +220,8 @@
Beat Saber installation path not found.
Installed: {0}
Failed to install.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ Install handlers registered!
{0} OneClick™ Install handlers unregistered!
Installing: {0}
diff --git a/ModAssistant/Localisation/fr.xaml b/ModAssistant/Localisation/fr.xaml
index 1cdc5450..3d01c059 100644
--- a/ModAssistant/Localisation/fr.xaml
+++ b/ModAssistant/Localisation/fr.xaml
@@ -223,6 +223,8 @@
Chemin de l'installation de Beat Saber non trouvé.
Installé : {0}
Échec de l'installation.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} : gestionnaires d'installation OneClick™ inscrits !
{0} : gestionnaires d'installation OneClick™ désinscrits !
Installation de : {0}
diff --git a/ModAssistant/Localisation/it.xaml b/ModAssistant/Localisation/it.xaml
index d01fde6f..43158f89 100644
--- a/ModAssistant/Localisation/it.xaml
+++ b/ModAssistant/Localisation/it.xaml
@@ -216,6 +216,8 @@
Directory d'installazione di Beat Saber non trovata.
Installato: {0}
Non sono riuscito ad installare la mappa.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} Registrazione dei gestori OneClick™ riuscita!
{0} De-Regitrazione dei gestori OneClick™ riuscita!
Installing: {0}
diff --git a/ModAssistant/Localisation/ko.xaml b/ModAssistant/Localisation/ko.xaml
index c2885356..f150c9d4 100644
--- a/ModAssistant/Localisation/ko.xaml
+++ b/ModAssistant/Localisation/ko.xaml
@@ -215,6 +215,8 @@
비트세이버 설치 폴더를 찾을 수 없었습니다.
설치됨: {0}
설치에 실패하였습니다.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ 설치 관리자가 등록되었습니다!
{0} OneClick™ 설치 관리자가 등록 취소되었습니다!
Installing: {0}
diff --git a/ModAssistant/Localisation/nl.xaml b/ModAssistant/Localisation/nl.xaml
index b7f67fe3..342ec720 100644
--- a/ModAssistant/Localisation/nl.xaml
+++ b/ModAssistant/Localisation/nl.xaml
@@ -214,6 +214,8 @@
Kon het Beat Saber installatie pad niet vinden
{0} Geïnstalleerd
Installatie mislukt
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ Installeer afhandelingen geregistreerd!
{0} OneClick™ Install afhandelingen uitgeregistreerd!
{0} word geïnstalleerd
diff --git a/ModAssistant/Localisation/ru.xaml b/ModAssistant/Localisation/ru.xaml
index 8b643492..628e4fdb 100644
--- a/ModAssistant/Localisation/ru.xaml
+++ b/ModAssistant/Localisation/ru.xaml
@@ -216,6 +216,8 @@
Установочный путь к Beat Saber не найден.
Установлено: {0}
Ошибка установки.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ установки зарегистрированы
{0} OneClick™ установки не зарегистрированы!
Установка: {0}
diff --git a/ModAssistant/Localisation/sv.xaml b/ModAssistant/Localisation/sv.xaml
index 1d973dec..07343744 100644
--- a/ModAssistant/Localisation/sv.xaml
+++ b/ModAssistant/Localisation/sv.xaml
@@ -205,6 +205,8 @@
Det gick inte att ladda ned låten.
Det kan vara strul med BeatSaver eller din internetuppkoppling.
Misslyckades med att ladda ned låtens ZIP-fil.
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
Det gick inte att hitta installationsvägen för Beat Saber.
Installerade: {0}
Misslyckades med att installera.
diff --git a/ModAssistant/Localisation/zh.xaml b/ModAssistant/Localisation/zh.xaml
index 8a048edc..9205c5bd 100644
--- a/ModAssistant/Localisation/zh.xaml
+++ b/ModAssistant/Localisation/zh.xaml
@@ -215,6 +215,8 @@
找不到Beat Saber安装路径。
已添加:{0}
添加失败。
+ Input audio file does not match master audio file for this map.
+ Select master song audio file
{0} OneClick™ 一键添加处理程序已注册!
{0} OneClick™ 一键添加处理程序已移除!
正在下载:{0}
diff --git a/ModAssistant/ModAssistant.csproj b/ModAssistant/ModAssistant.csproj
index 48e6bfb7..748dd096 100644
--- a/ModAssistant/ModAssistant.csproj
+++ b/ModAssistant/ModAssistant.csproj
@@ -1,4 +1,4 @@
-
+
@@ -13,6 +13,8 @@
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
4
true
+
+
AnyCPU
@@ -37,13 +39,63 @@
Resources\icon.ico
+
+ ..\packages\FFmpeg.AutoGen.4.2.0\lib\net45\FFmpeg.AutoGen.dll
+
+
+ ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\Newtonsoft.Json.Schema.3.0.13\lib\net45\Newtonsoft.Json.Schema.dll
+
+
+ ..\packages\NLog.4.7.3\lib\net45\NLog.dll
+
+
+ ..\packages\protobuf-net.3.0.29\lib\net461\protobuf-net.dll
+
+
+ ..\packages\protobuf-net.Core.3.0.29\lib\net461\protobuf-net.Core.dll
+
+
+ ..\packages\SaberSongPatcher.1.0.2\lib\netstandard2.0\SaberSongPatcherCommon.dll
+
+
+ ..\packages\SoundFingerprinting.7.4.12\lib\netstandard2.0\SoundFingerprinting.dll
+
+
+ ..\packages\SoundFingerprinting.Emy.7.4.12\lib\netstandard2.0\SoundFingerprinting.Emy.dll
+
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
+
+ ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll
+
+
+
+ ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+
+
+ ..\packages\System.ServiceModel.Primitives.4.7.0\lib\net461\System.ServiceModel.Primitives.dll
+
+
@@ -60,6 +112,9 @@
+
+ ..\packages\Xabe.FFmpeg.4.1.1\lib\netstandard2.0\Xabe.FFmpeg.dll
+
@@ -69,6 +124,7 @@
+
@@ -290,6 +346,7 @@
ResXFileCodeGenerator
Resources.Designer.cs
+
PublicSettingsSingleFileGenerator
Settings.Designer.cs
@@ -305,4 +362,11 @@
-
\ No newline at end of file
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
diff --git a/ModAssistant/packages.config b/ModAssistant/packages.config
new file mode 100644
index 00000000..f32b90ed
--- /dev/null
+++ b/ModAssistant/packages.config
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file