From b1056299b81d4ee19052ac156e9bfa46f4fd738b Mon Sep 17 00:00:00 2001 From: Michael Green <84688932+michael-j-green@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:39:27 +1100 Subject: [PATCH] Ensure ROMs are decompressed before loading them into a media group (#321) All compressed archives (zip, rar, and 7z) are decompressed when a media group is created. Only files with an extension defined in the platform mapping are added to the M3U file. Closes #307 --- gaseous-server/Classes/RomMediaGroup.cs | 122 ++++++++++++++++++++- gaseous-server/wwwroot/pages/emulator.html | 2 + gaseous-server/wwwroot/pages/game.html | 2 +- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/gaseous-server/Classes/RomMediaGroup.cs b/gaseous-server/Classes/RomMediaGroup.cs index b24c4b1..5fb0f52 100644 --- a/gaseous-server/Classes/RomMediaGroup.cs +++ b/gaseous-server/Classes/RomMediaGroup.cs @@ -5,6 +5,9 @@ using Microsoft.VisualBasic; using IGDB.Models; using gaseous_server.Classes.Metadata; using System.IO.Compression; +using SharpCompress.Archives; +using SharpCompress.Common; +using gaseous_server.Models; namespace gaseous_server.Classes { @@ -259,6 +262,7 @@ namespace gaseous_server.Classes { Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false); Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false); + PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(mediaGroupItem.PlatformId); Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name); @@ -293,10 +297,124 @@ namespace gaseous_server.Classes foreach (long RomId in mediaGroupItem.RomIds) { Roms.GameRomItem rom = Roms.GetRom(RomId); + bool fileNameFound = false; if (File.Exists(rom.Path)) { - Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name); - File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path))); + string romExt = Path.GetExtension(rom.Path); + if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt)) + { + Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name); + + // is compressed + switch (romExt) + { + case ".zip": + try + { + using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(rom.Path)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key); + if (fileNameFound == false) + { + //check if extension is in valid extensions + if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase)) + { + // update rom file name + rom.Name = entry.Key; + fileNameFound = true; + } + } + entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + } + catch (Exception zipEx) + { + Logging.Log(Logging.LogType.Warning, "Media Group", "Unzip error", zipEx); + throw; + } + break; + + case ".rar": + try + { + using (var archive = SharpCompress.Archives.Rar.RarArchive.Open(rom.Path)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key); + if (fileNameFound == false) + { + //check if extension is in valid extensions + if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase)) + { + // update rom file name + rom.Name = entry.Key; + fileNameFound = true; + } + } + entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + } + catch (Exception zipEx) + { + Logging.Log(Logging.LogType.Warning, "Media Group", "Unrar error", zipEx); + throw; + } + break; + + case ".7z": + try + { + using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(rom.Path)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key); + if (fileNameFound == false) + { + //check if extension is in valid extensions + if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase)) + { + // update rom file name + rom.Name = entry.Key; + fileNameFound = true; + } + } + entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + } + catch (Exception zipEx) + { + Logging.Log(Logging.LogType.Warning, "Media Group", "7z error", zipEx); + throw; + } + break; + + } + } + else + { + // is uncompressed + Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name); + File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path))); + } romItems.Add(rom); } diff --git a/gaseous-server/wwwroot/pages/emulator.html b/gaseous-server/wwwroot/pages/emulator.html index 3f2c65c..24f9bd2 100644 --- a/gaseous-server/wwwroot/pages/emulator.html +++ b/gaseous-server/wwwroot/pages/emulator.html @@ -23,6 +23,8 @@ var emuBios = ''; var emuBackground = ''; + console.log("Loading rom url: " + decodeURIComponent(getQueryString('rompath', 'string'))); + ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) { gameData = result; diff --git a/gaseous-server/wwwroot/pages/game.html b/gaseous-server/wwwroot/pages/game.html index 3256988..39e6f77 100644 --- a/gaseous-server/wwwroot/pages/game.html +++ b/gaseous-server/wwwroot/pages/game.html @@ -545,7 +545,7 @@ var saveStatesButton = ''; if (mediaGroup.emulator) { if (mediaGroup.emulator.type.length > 0) { - var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip'); + var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '.zip'); if (mediaGroup.hasSaveStates == true) { var modalVariables = {