diff --git a/.DS_Store b/.DS_Store index 75ed3e9..9711862 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitmodules b/.gitmodules index 6863741..fc7ecb4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "gaseous-server/wwwroot/EmulatorJS"] - path = gaseous-server/wwwroot/EmulatorJS +[submodule "gaseous-server/wwwroot/emulators/EmulatorJS"] + path = gaseous-server/wwwroot/emulators/EmulatorJS url = https://github.com/EmulatorJS/EmulatorJS.git diff --git a/Gaseous.sln b/Gaseous.sln index 645a64c..dc21479 100644 --- a/Gaseous.sln +++ b/Gaseous.sln @@ -21,6 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Dockerfile = Dockerfile README.MD = README.MD LICENSE = LICENSE + .gitignore = .gitignore EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "screenshots", "screenshots", "{F1A847C7-57BC-4DA9-8F83-CD060A7F5122}" diff --git a/gaseous-server/.DS_Store b/gaseous-server/.DS_Store index a751656..a7c3482 100644 Binary files a/gaseous-server/.DS_Store and b/gaseous-server/.DS_Store differ diff --git a/gaseous-server/Classes/Bios.cs b/gaseous-server/Classes/Bios.cs new file mode 100644 index 0000000..8b9273c --- /dev/null +++ b/gaseous-server/Classes/Bios.cs @@ -0,0 +1,120 @@ +using System; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using gaseous_tools; + +namespace gaseous_server.Classes +{ + public class Bios + { + public Bios() + { + + } + + public static Models.PlatformMapping.PlatformMapItem? BiosHashSignatureLookup(string MD5) + { + foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap) + { + if (platformMapping.WebEmulator != null) + { + if (platformMapping.WebEmulator.Bios != null) + { + foreach (Models.PlatformMapping.PlatformMapItem.WebEmulatorItem.EmulatorBiosItem emulatorBiosItem in platformMapping.WebEmulator.Bios) + { + if (emulatorBiosItem.hash.ToLower() == MD5.ToLower()) + { + return platformMapping; + } + } + } + } + } + + return null; + } + + public static List GetBios() + { + return BuildBiosList(); + } + + public static List GetBios(long PlatformId, bool HideUnavailable) + { + List biosItems = new List(); + foreach (BiosItem biosItem in BuildBiosList()) + { + if (biosItem.platformid == PlatformId) + { + if (HideUnavailable == true) + { + if (biosItem.Available == true) + { + biosItems.Add(biosItem); + } + } + else + { + biosItems.Add(biosItem); + } + } + } + + return biosItems; + } + + private static List BuildBiosList() + { + List biosItems = new List(); + + foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap) + { + if (platformMapping.WebEmulator != null) + { + if (platformMapping.WebEmulator.Bios != null) + { + IGDB.Models.Platform platform = Metadata.Platforms.GetPlatform(platformMapping.IGDBId); + + foreach (Models.PlatformMapping.PlatformMapItem.WebEmulatorItem.EmulatorBiosItem emulatorBios in platformMapping.WebEmulator.Bios) + { + BiosItem biosItem = new BiosItem + { + platformid = platformMapping.IGDBId, + platformslug = platform.Slug, + platformname = platform.Name, + description = emulatorBios.description, + filename = emulatorBios.filename, + region = emulatorBios.region, + hash = emulatorBios.hash + }; + biosItems.Add(biosItem); + } + } + } + } + return biosItems; + } + + public class BiosItem : Models.PlatformMapping.PlatformMapItem.WebEmulatorItem.EmulatorBiosItem + { + public long platformid { get; set; } + public string platformslug { get; set; } + public string platformname { get; set; } + public string biosPath + { + get + { + return Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platformslug, base.filename); + } + } + public bool Available { + get + { + bool fileExists = File.Exists(biosPath); + return fileExists; + } + } + } + } +} + diff --git a/gaseous-server/Classes/ImportGames.cs b/gaseous-server/Classes/ImportGames.cs index cad8337..2e1e6ea 100644 --- a/gaseous-server/Classes/ImportGames.cs +++ b/gaseous-server/Classes/ImportGames.cs @@ -58,36 +58,64 @@ namespace gaseous_server.Classes FileInfo fi = new FileInfo(GameFileImportPath); Common.hashObject hash = new Common.hashObject(GameFileImportPath); - // check to make sure we don't already have this file imported - sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1"; - dbDict.Add("md5", hash.md5hash); - dbDict.Add("sha1", hash.sha1hash); - DataTable importDB = db.ExecuteCMD(sql, dbDict); - if ((Int64)importDB.Rows[0]["count"] > 0) - { - if (!GameFileImportPath.StartsWith(Config.LibraryConfiguration.LibraryImportDirectory)) - { - Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping"); - } - } - else - { - Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " not in database - processing"); + Models.PlatformMapping.PlatformMapItem? IsBios = Classes.Bios.BiosHashSignatureLookup(hash.md5hash); - // process as a single file - Models.Signatures_Games discoveredSignature = GetFileSignature(hash, fi, GameFileImportPath); + if (IsBios == null) + { + // file is a rom + // check to make sure we don't already have this file imported + sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1"; + dbDict.Add("md5", hash.md5hash); + dbDict.Add("sha1", hash.sha1hash); + DataTable importDB = db.ExecuteCMD(sql, dbDict); + if ((Int64)importDB.Rows[0]["count"] > 0) + { + if (!GameFileImportPath.StartsWith(Config.LibraryConfiguration.LibraryImportDirectory)) + { + Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping"); + } + } + else + { + Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " not in database - processing"); - // get discovered platform - IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(discoveredSignature.Flags.IGDBPlatformId); - if (determinedPlatform == null) - { - determinedPlatform = new IGDB.Models.Platform(); - } + // process as a single file + Models.Signatures_Games discoveredSignature = GetFileSignature(hash, fi, GameFileImportPath); - IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature.Game.Name, discoveredSignature.Flags.IGDBPlatformId); + // get discovered platform + IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(discoveredSignature.Flags.IGDBPlatformId); + if (determinedPlatform == null) + { + determinedPlatform = new IGDB.Models.Platform(); + } - // add to database - StoreROM(hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath); + IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature.Game.Name, discoveredSignature.Flags.IGDBPlatformId); + + // add to database + StoreROM(hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath); + } + } + else + { + // file is a bios + if (IsBios.WebEmulator != null) + { + foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios()) + { + if (biosItem.Available == false && biosItem.hash == hash.md5hash) + { + string biosPath = biosItem.biosPath.Replace(biosItem.filename, ""); + if (!Directory.Exists(biosPath)) + { + Directory.CreateDirectory(biosPath); + } + + File.Move(GameFileImportPath, biosItem.biosPath, true); + + break; + } + } + } } } } diff --git a/gaseous-server/Classes/Roms.cs b/gaseous-server/Classes/Roms.cs index 70c59cc..c32e314 100644 --- a/gaseous-server/Classes/Roms.cs +++ b/gaseous-server/Classes/Roms.cs @@ -128,8 +128,9 @@ namespace gaseous_server.Classes public long Id { get; set; } public long PlatformId { get; set; } public IGDB.Models.Platform Platform { get; set; } - public Dictionary? Emulator { get; set; } - public long GameId { get; set; } + //public Dictionary? Emulator { get; set; } + public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; } + public long GameId { get; set; } public string? Name { get; set; } public long Size { get; set; } public string? CRC { get; set; } diff --git a/gaseous-server/Controllers/BiosController.cs b/gaseous-server/Controllers/BiosController.cs new file mode 100644 index 0000000..b78cc9b --- /dev/null +++ b/gaseous-server/Controllers/BiosController.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace gaseous_server.Controllers +{ + [ApiController] + [Route("api/v1/[controller]")] + public class BiosController : Controller + { + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + public List GetBios() + { + return Classes.Bios.GetBios(); + } + + [HttpGet] + [Route("{PlatformId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + public List GetBios(long PlatformId, bool AvailableOnly = true) + { + return Classes.Bios.GetBios(PlatformId, AvailableOnly); + } + + [HttpGet] + [HttpHead] + [Route("{PlatformId}/{BiosName}")] + [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult BiosFile(long PlatformId, string BiosName) + { + try + { + foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios(PlatformId, true)) + { + if (biosItem.filename == BiosName) + { + if (System.IO.File.Exists(biosItem.biosPath)) + { + string filename = Path.GetFileName(biosItem.biosPath); + string filepath = biosItem.biosPath; + byte[] filedata = System.IO.File.ReadAllBytes(filepath); + string contentType = "application/octet-stream"; + + var cd = new System.Net.Mime.ContentDisposition + { + FileName = filename, + Inline = false, + }; + + Response.Headers.Add("Content-Disposition", cd.ToString()); + Response.Headers.Add("Cache-Control", "public, max-age=604800"); + + return File(filedata, contentType); + } + else + { + return NotFound(); + } + } + } + + return NotFound(); + } + catch + { + return NotFound(); + } + } + } +} + diff --git a/gaseous-server/Models/PlatformMapping.cs b/gaseous-server/Models/PlatformMapping.cs index 70408c8..5c7d221 100644 --- a/gaseous-server/Models/PlatformMapping.cs +++ b/gaseous-server/Models/PlatformMapping.cs @@ -1,5 +1,7 @@ using System; using System.Reflection; +using System.Text.Json.Serialization; +using gaseous_server.Classes; namespace gaseous_server.Models { @@ -10,23 +12,21 @@ namespace gaseous_server.Models } - private static List _PlatformMaps = new List(); + //private static List _PlatformMaps = new List(); public static List PlatformMap { get { - if (_PlatformMaps.Count == 0) + // load platform maps from: gaseous_server.Support.PlatformMap.json + List _PlatformMaps = new List(); + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = "gaseous_server.Support.PlatformMap.json"; + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + using (StreamReader reader = new StreamReader(stream)) { - // load platform maps from: gaseous_server.Support.PlatformMap.json - var assembly = Assembly.GetExecutingAssembly(); - var resourceName = "gaseous_server.Support.PlatformMap.json"; - using (Stream stream = assembly.GetManifestResourceStream(resourceName)) - using (StreamReader reader = new StreamReader(stream)) - { - string rawJson = reader.ReadToEnd(); - _PlatformMaps.Clear(); - _PlatformMaps = Newtonsoft.Json.JsonConvert.DeserializeObject>(rawJson); - } + string rawJson = reader.ReadToEnd(); + _PlatformMaps.Clear(); + _PlatformMaps = Newtonsoft.Json.JsonConvert.DeserializeObject>(rawJson); } return _PlatformMaps; @@ -73,13 +73,28 @@ namespace gaseous_server.Models } public class PlatformMapItem - { + { public int IGDBId { get; set; } public string IGDBName { get; set; } public List AlternateNames { get; set; } = new List(); public List KnownFileExtensions { get; set; } = new List(); - public Dictionary? WebEmulator { get; set; } + //public Dictionary? WebEmulator { get; set; } + public WebEmulatorItem? WebEmulator { get; set; } + public class WebEmulatorItem + { + public string Type { get; set; } + public string Core { get; set; } + public List Bios { get; set; } + + public class EmulatorBiosItem + { + public string hash { get; set; } + public string description { get; set; } + public string filename { get; set; } + public string region { get; set; } + } + } } } } diff --git a/gaseous-server/Models/Signatures_Games.cs b/gaseous-server/Models/Signatures_Games.cs index 0208008..0ff1f41 100644 --- a/gaseous-server/Models/Signatures_Games.cs +++ b/gaseous-server/Models/Signatures_Games.cs @@ -236,7 +236,7 @@ namespace gaseous_server.Models public class SignatureFlags { - public int IGDBPlatformId { get; set; } + public long IGDBPlatformId { get; set; } public string IGDBPlatformName { get; set; } } } diff --git a/gaseous-server/Program.cs b/gaseous-server/Program.cs index 08d0eec..7a7f1b7 100644 --- a/gaseous-server/Program.cs +++ b/gaseous-server/Program.cs @@ -20,6 +20,11 @@ if (Config.ReadSetting("API Key", "Test API Key") == "Test API Key") Logging.Log(Logging.LogType.Information, "Startup", "Setting initial API key"); Config.SetSetting("API Key", APIKey.ToString()); } +if (Config.ReadSetting("Emulator: Default BIOS Region", "Default Value") == "Default Value") +{ + Logging.Log(Logging.LogType.Information, "Startup", "Setting default BIOS region to US"); + Config.SetSetting("Emulator: Default BIOS Region", "US"); +} // set up server var builder = WebApplication.CreateBuilder(args); @@ -32,6 +37,9 @@ builder.Services.AddControllers().AddJsonOptions(x => // suppress nulls x.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + + // set max depth + x.JsonSerializerOptions.MaxDepth = 64; }); builder.Services.AddResponseCaching(); builder.Services.AddControllers(options => diff --git a/gaseous-server/Support/PlatformMap.json b/gaseous-server/Support/PlatformMap.json index 2b61be6..cc688a2 100644 --- a/gaseous-server/Support/PlatformMap.json +++ b/gaseous-server/Support/PlatformMap.json @@ -44,7 +44,31 @@ ], "KnownFileExtensions": [ ".SMS" - ] + ], + "WebEmulator": { + "Type": "EmulatorJS", + "Core": "segaMS", + "Bios": [ + { + "hash": "840481177270d5642a14ca71ee72844c", + "description": "MasterSystem EU BIOS", + "filename": "bios_E.sms", + "region": "EU" + }, + { + "hash": "840481177270d5642a14ca71ee72844c", + "description": "MasterSystem US BIOS", + "filename": "bios_U.sms", + "region": "US" + }, + { + "hash": "24a519c53f67b00640d0048ef7089105", + "description": "MasterSystem JP BIOS", + "filename": "bios_J.sms", + "region": "JP" + } + ] + } }, { "IGDBId": 29, @@ -101,5 +125,67 @@ "Type": "EmulatorJS", "Core": "nes" } + }, + { + "IGDBId": 19, + "IGDBName": "Super Nintendo Entertainment System", + "AlternateNames": [ + "Nintendo Super Famicom & Super Entertainment System", + "Super Nintendo Entertainment System", + "Super Nintendo", + "SNES" + ], + "KnownFileExtensions": [], + "WebEmulator": { + "Type": "EmulatorJS", + "Core": "snes" + } + }, + { + "IGDBId": 7, + "IGDBName": "PlayStation", + "AlternateNames": [ + "Sony PlayStation", + "PS1", + "PSX", + "PSOne", + "PS" + ], + "KnownFileExtensions": [], + "WebEmulator": { + "Type": "EmulatorJS", + "Core": "psx", + "Bios": [ + { + "hash": "8dd7d5296a650fac7319bce665a6a53c", + "description": "PS1 JP BIOS - Required for JP games", + "filename": "scph5500.bin", + "region": "JP" + }, + { + "hash": "490f666e1afb15b7362b406ed1cea246", + "description": "PS1 US BIOS - Required for US games", + "filename": "scph5501.bin", + "region": "US" + }, + { + "hash": "32736f17079d0b2b7024407c39bd3050", + "description": "PS1 EU BIOS - Required for EU games", + "filename": "scph5502.bin", + "region": "EU" + } + ] + } + }, + { + "IGDBId": 52, + "IGDBName": "Arcade", + "AlternateNames": [], + "KnownFileExtensions": [], + "WebEmulator": { + "Type": "EmulatorJS", + "Core": "arcade", + "Bios": [] + } } ] diff --git a/gaseous-server/gaseous-server.csproj b/gaseous-server/gaseous-server.csproj index f503cc6..b11ab34 100644 --- a/gaseous-server/gaseous-server.csproj +++ b/gaseous-server/gaseous-server.csproj @@ -105,6 +105,7 @@ + @@ -119,6 +120,7 @@ + diff --git a/gaseous-server/wwwroot/.DS_Store b/gaseous-server/wwwroot/.DS_Store index d8ac01f..43dca08 100644 Binary files a/gaseous-server/wwwroot/.DS_Store and b/gaseous-server/wwwroot/.DS_Store differ diff --git a/gaseous-server/wwwroot/EmulatorJS b/gaseous-server/wwwroot/emulators/EmulatorJS similarity index 100% rename from gaseous-server/wwwroot/EmulatorJS rename to gaseous-server/wwwroot/emulators/EmulatorJS diff --git a/gaseous-server/wwwroot/images/SettingsWallpaper.jpg b/gaseous-server/wwwroot/images/SettingsWallpaper.jpg new file mode 100644 index 0000000..60f3e9e Binary files /dev/null and b/gaseous-server/wwwroot/images/SettingsWallpaper.jpg differ diff --git a/gaseous-server/wwwroot/index.html b/gaseous-server/wwwroot/index.html index ade658a..c2484f3 100644 --- a/gaseous-server/wwwroot/index.html +++ b/gaseous-server/wwwroot/index.html @@ -23,7 +23,7 @@ -