Compare commits

...

11 Commits

Author SHA1 Message Date
Michael Green
9081b0bed9 Merge pull request #26 from gaseous-project/dependabot/nuget/Microsoft.VisualStudio.Web.CodeGeneration.Design-7.0.8
chore(deps): bump Microsoft.VisualStudio.Web.CodeGeneration.Design from 7.0.7 to 7.0.8
2023-07-19 13:27:40 +10:00
Michael Green
d64877543a Merge branch 'main' into dependabot/nuget/Microsoft.VisualStudio.Web.CodeGeneration.Design-7.0.8 2023-07-19 13:27:29 +10:00
Michael Green
649fba1bfa Merge pull request #27 from gaseous-project/dependabot/nuget/Microsoft.AspNetCore.OpenApi-7.0.9
chore(deps): bump Microsoft.AspNetCore.OpenApi from 7.0.8 to 7.0.9
2023-07-19 13:27:09 +10:00
Michael Green
7dfb97608f Merge branch 'main' into dependabot/nuget/Microsoft.AspNetCore.OpenApi-7.0.9 2023-07-19 13:26:46 +10:00
Michael Green
35bb2f18d9 Add support for adding EmulatorJS firmware (#28)
* feat: EmulatorJS support - importing of BIOS files #15

* feat: added Bios controller to make Bios files available to the emulator, also resolved SNES identification issues (see: #25)

* feat: added firmware selector to emulator screen

* refactor: moved EmulatorJS to a subfolder

* feat: added firmware image availability page
2023-07-19 13:18:39 +10:00
dependabot[bot]
ad84f5ae58 chore(deps): bump Microsoft.AspNetCore.OpenApi from 7.0.8 to 7.0.9
Bumps [Microsoft.AspNetCore.OpenApi](https://github.com/dotnet/aspnetcore) from 7.0.8 to 7.0.9.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v7.0.8...v7.0.9)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.OpenApi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 04:33:32 +00:00
dependabot[bot]
922c429716 chore(deps): bump Microsoft.VisualStudio.Web.CodeGeneration.Design
Bumps [Microsoft.VisualStudio.Web.CodeGeneration.Design](https://github.com/dotnet/Scaffolding) from 7.0.7 to 7.0.8.
- [Release notes](https://github.com/dotnet/Scaffolding/releases)
- [Commits](https://github.com/dotnet/Scaffolding/commits)

---
updated-dependencies:
- dependency-name: Microsoft.VisualStudio.Web.CodeGeneration.Design
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 04:33:26 +00:00
Michael Green
a2d634d96f fix: included accidentally excluded scripts (#24) 2023-07-13 14:52:43 +10:00
Michael Green
7a8e445471 EmulatorJS - First Version (#23)
* feat: added EmulatorJS support for Mega Drive, NES, and N64 (see: #15)

* doc: updated attribution in README.MD to include EmulatorJS

* ci: updated action to include submodules
2023-07-13 13:31:38 +10:00
Michael Green
b010f9742b fix: copy external js to local wwwroot (#22) 2023-07-12 11:00:27 +10:00
Michael Green
afd70e6b02 Update README.MD (#14)
* doc: updated documentation to include instructions on starting with docker-compose
2023-07-11 23:00:24 +10:00
33 changed files with 6495 additions and 82 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -12,6 +12,8 @@ jobs:
-
name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "gaseous-server/wwwroot/emulators/EmulatorJS"]
path = gaseous-server/wwwroot/emulators/EmulatorJS
url = https://github.com/EmulatorJS/EmulatorJS.git

View File

@@ -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}"

View File

@@ -16,6 +16,7 @@ The following projects are used by Gaseous
* https://github.com/JamesNK/Newtonsoft.Json
* https://www.nuget.org/packages/MySql.Data/8.0.32.1
* https://github.com/kamranayub/igdb-dotnet
* https://github.com/EmulatorJS/EmulatorJS
## Configuration File
When Gaseous-Server is started for the first time, it creates a configuration file at ~/.gaseous-server/config.json if it doesn't exist. Some values can be filled in using environment variables (such as in the case of using docker).
@@ -57,10 +58,17 @@ When Gaseous-Server is started for the first time, it creates a configuration fi
## Deploy with Docker
Dockerfile and docker-compose.yml files have been provided to make deployment of the server as easy as possible.
1. Download the docker-compose.yml file
2. Open the docker-compose.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
3. Run the command "docker-compose up -d"
4. Connect to the host on port 5198
## Build and Deploy with Docker
Dockerfile and docker-compose-build.yml files have been provided to make deployment of the server as easy as possible.
1. Clone the repo with "git clone https://github.com/gaseous-project/gaseous-server.git"
2. Change into the gaseous-server directory
3. Open the docker-compose.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
4. Run the command "docker-compose up -d"
3. Open the docker-compose-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
4. Run the command "docker-compose up --file docker-compose-build.yml -d"
5. Connect to the host on port 5198
## Adding Content
@@ -98,4 +106,4 @@ Loop through each of the search candidates searching using:
2. "wherefuzzy" - partial match using wildcards
3. "search" - uses a more flexible search method
Note: that if more than one result is found, the image will be set as "Unknown" as there is no way for Gaseous to know which title is the correct one.
Note: that if more than one result is found, the image will be set as "Unknown" as there is no way for Gaseous to know which title is the correct one.

Binary file not shown.

View File

@@ -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<BiosItem> GetBios()
{
return BuildBiosList();
}
public static List<BiosItem> GetBios(long PlatformId, bool HideUnavailable)
{
List<BiosItem> biosItems = new List<BiosItem>();
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<BiosItem> BuildBiosList()
{
List<BiosItem> biosItems = new List<BiosItem>();
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;
}
}
}
}
}

View File

@@ -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;
}
}
}
}
}
}

View File

@@ -107,6 +107,19 @@ namespace gaseous_server.Classes
Path = (string)romDR["path"],
Source = (GameRomItem.SourceType)(Int32)romDR["metadatasource"]
};
// check for a web emulator and update the romItem
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
{
if (platformMapping.IGDBId == romItem.PlatformId)
{
if (platformMapping.WebEmulator != null)
{
romItem.Emulator = platformMapping.WebEmulator;
}
}
}
return romItem;
}
@@ -115,7 +128,9 @@ namespace gaseous_server.Classes
public long Id { get; set; }
public long PlatformId { get; set; }
public IGDB.Models.Platform Platform { get; set; }
public long GameId { get; set; }
//public Dictionary<string, object>? 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; }

View File

@@ -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<Classes.Bios.BiosItem> GetBios()
{
return Classes.Bios.GetBios();
}
[HttpGet]
[Route("{PlatformId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public List<Classes.Bios.BiosItem> 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();
}
}
}
}

View File

@@ -749,6 +749,7 @@ namespace gaseous_server.Controllers
}
[HttpGet]
[HttpHead]
[Route("{GameId}/roms/{RomId}/file")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]

View File

@@ -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<PlatformMapItem> _PlatformMaps = new List<PlatformMapItem>();
//private static List<PlatformMapItem> _PlatformMaps = new List<PlatformMapItem>();
public static List<PlatformMapItem> PlatformMap
{
get
{
if (_PlatformMaps.Count == 0)
// load platform maps from: gaseous_server.Support.PlatformMap.json
List<PlatformMapItem> _PlatformMaps = new List<PlatformMapItem>();
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<List<PlatformMapItem>>(rawJson);
}
string rawJson = reader.ReadToEnd();
_PlatformMaps.Clear();
_PlatformMaps = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson);
}
return _PlatformMaps;
@@ -73,11 +73,28 @@ namespace gaseous_server.Models
}
public class PlatformMapItem
{
{
public int IGDBId { get; set; }
public string IGDBName { get; set; }
public List<string> AlternateNames { get; set; } = new List<string>();
public List<string> KnownFileExtensions { get; set; } = new List<string>();
//public Dictionary<string, object>? WebEmulator { get; set; }
public WebEmulatorItem? WebEmulator { get; set; }
public class WebEmulatorItem
{
public string Type { get; set; }
public string Core { get; set; }
public List<EmulatorBiosItem> 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; }
}
}
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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 =>
@@ -76,7 +84,11 @@ app.UseResponseCaching();
app.UseAuthorization();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true, //allow unkown file types also to be served
DefaultContentType = "plain/text" //content type to returned if fileType is not known.
});
app.MapControllers();

View File

@@ -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,
@@ -60,7 +84,11 @@
".MD",
".SG",
".SMD"
]
],
"WebEmulator": {
"Type": "EmulatorJS",
"Core": "segaMD"
}
},
{
"IGDBId": 4,
@@ -71,7 +99,11 @@
],
"KnownFileExtensions": [
".Z64"
]
],
"WebEmulator": {
"Type": "EmulatorJS",
"Core": "n64"
}
},
{
"IGDBId": 18,
@@ -88,6 +120,72 @@
".SFC",
".SMC",
".SWC"
]
],
"WebEmulator": {
"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": []
}
}
]

View File

@@ -14,9 +14,9 @@
<DocumentationFile>bin\Debug\net7.0\gaseous-server.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.8" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.7" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.8" />
<PackageReference Include="IGDB" Version="2.3.2" />
</ItemGroup>
@@ -105,6 +105,7 @@
<Folder Include="Assets\Ratings\CLASS_IND\" />
<Folder Include="wwwroot\fonts\" />
<Folder Include="wwwroot\pages\dialogs\" />
<Folder Include="wwwroot\pages\settings\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\gaseous-tools\gaseous-tools.csproj">
@@ -119,6 +120,7 @@
</ItemGroup>
<ItemGroup>
<Content Remove="Support\PlatformMap.json" />
<Content Remove="wwwroot\pages\settings\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Support\PlatformMap.json" Condition="'$(ExcludeConfigFilesFromBuildOutput)'!='true'">

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 KiB

View File

@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="/styles/style.css" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://momentjs.com/downloads/moment.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="/scripts/jquery-3.6.0.min.js"></script>
<script src="/scripts/moment.js"></script>
<link href="/styles/select2.min.css" rel="stylesheet" />
<script src="/scripts/select2.min.js"></script>
<script src="/scripts/main.js" type="text/javascript"></script>
<script src="/scripts/filterformating.js" type="text/javascript"></script>
<script src="/scripts/gamesformating.js" type="text/javascript"></script>
@@ -23,7 +23,7 @@
<div id="banner_header">
<div id="banner_header_label">Gaseous Games</div>
</div>
<div id="banner_cog" onclick="window.location.href = '/index.html?page=system';">
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';">
<img src="/images/cog.jpg" alt="System" id="banner_system_image" />
</div>

View File

@@ -0,0 +1,25 @@
<div style='width:640px;height:480px;max-width:100%'>
<div id='game'></div>
</div>
<script type='text/javascript'>
EJS_player = '#game';
// Can also be fceumm or nestopia
EJS_core = urlParams.get('core');
// Lightgun
EJS_lightgun = false; // can be true or false
// URL to BIOS file
EJS_biosUrl = emuBios;
// URL to Game rom
EJS_gameUrl = decodeURIComponent(urlParams.get('rompath'));
// Path to the data directory
EJS_pathtodata = '/emulators/EmulatorJS/data/';
EJS_DEBUG_XX = true;
</script>
<script src='/emulators/EmulatorJS/data/loader.js'></script>

View File

@@ -0,0 +1,100 @@
<div id="bgImage">
<div id="bgImage_Opacity"></div>
</div>
<div id="emulator"></div>
<div id="emulatorbios">
<table style="width: 100%;">
<tr>
<td>Firmware:</td>
<td><select id="emulatorbiosselector" onchange="loadEmulator();"></select></td>
</tr>
</table>
</div>
<script type="text/javascript">
const urlParams = new URLSearchParams(window.location.search);
var gameId = urlParams.get('gameid');
var platformId = urlParams.get('platformid');
var gameData;
var artworks = null;
var artworksPosition = 0;
var emuBios = '';
var availableEmuBios = [];
ajaxCall('/api/v1/Games/' + gameId, 'GET', function (result) {
gameData = result;
// load artwork
if (result.artworks) {
artworks = result.artworks.ids;
var startPos = randomIntFromInterval(0, result.artworks.ids.length);
artworksPosition = startPos;
rotateBackground();
} else {
if (result.cover) {
var bg = document.getElementById('bgImage');
bg.setAttribute('style', 'background-image: url("/api/v1/Games/' + gameId + '/cover/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
}
}
});
ajaxCall('/api/v1/Bios/' + platformId, 'GET', function (result) {
var emulatorbiosDiv = document.getElementById('emulatorbios');
availableEmuBios = result;
if (result.length == 0) {
emuBios = '';
emulatorbiosDiv.setAttribute('style', 'display: none;');
} else {
emuBios = '/api/v1/Bios/' + platformId + '/' + availableEmuBios[0].filename;
var emulatorbiosselect = document.getElementById('emulatorbiosselector');
for (var i = 0; i < availableEmuBios.length; i++) {
var biosOption = document.createElement('option');
biosOption.value = availableEmuBios[i].filename;
biosOption.innerHTML = availableEmuBios[i].description + ' (' + availableEmuBios[i].filename + ')';
if (availableEmuBios[i].region == "US") {
emuBios = '/api/v1/Bios/' + platformId + '/' + availableEmuBios[i].filename;
biosOption.setAttribute('selected', 'selected');
}
emulatorbiosselect.appendChild(biosOption);
}
}
loadEmulator();
});
function rotateBackground() {
if (artworks) {
artworksPosition += 1;
if (artworks[artworksPosition] == null) {
artworksPosition = 0;
}
var bg = document.getElementById('bgImage');
bg.setAttribute('style', 'background-image: url("/api/v1/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
}
}
function loadEmulator() {
if (availableEmuBios.length > 0) {
var emulatorbiosselect = document.getElementById('emulatorbiosselector');
emuBios = emulatorbiosselect.value;
} else {
emuBios = '';
}
switch (urlParams.get('engine')) {
case 'EmulatorJS':
$('#emulator').load('/pages/EmulatorJS.html');
break;
}
}
</script>

View File

@@ -304,7 +304,7 @@
var newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Name', 'Size', 'Media', '', '']));
newTable.appendChild(createTableRow(true, ['Name', 'Size', 'Media', '', '', '']));
var lastPlatform = '';
for (var i = 0; i < result.length; i++) {
@@ -312,18 +312,24 @@
lastPlatform = result[i].platform.name;
var platformRow = document.createElement('tr');
var platformHeader = document.createElement('th');
platformHeader.setAttribute('colspan', 4);
platformHeader.setAttribute('colspan', 6);
platformHeader.innerHTML = result[i].platform.name;
platformRow.appendChild(platformHeader);
newTable.appendChild(platformRow);
}
var launchButton = '';
if (result[i].emulator) {
launchButton = '<a href="/index.html?page=emulator&engine=' + result[i].emulator.type + '&core=' + result[i].emulator.core + '&platformid=' + result[i].platform.id + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1/Games/' + gameId + '/roms/' + result[i].id + '/file') + '" class="romstart">Launch</a>';
}
var newRow = [
'<a href="/api/v1/Games/' + gameId + '/roms/' + result[i].id + '/file" class="romlink">' + result[i].name + '</a>',
formatBytes(result[i].size, 2),
result[i].romTypeMedia,
result[i].mediaLabel,
'<span class="romlink" onclick="showDialog(\'rominfo\', ' + result[i].id + ');">...</span>'
launchButton,
'<div class="properties_button" onclick="showDialog(\'rominfo\', ' + result[i].id + ');">i</div>'
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}

View File

@@ -0,0 +1,48 @@
<div id="bgImage" style="background-image: url('/images/SettingsWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
<div id="bgImage_Opacity"></div>
</div>
<div id="gamepage">
<div id="properties_toc" class="settings_toc">
<div class="filter_header">Settings</div>
<div id="properties_toc_system" name="properties_toc_item" onclick="SelectTab('system');">System</div>
<div id="properties_toc_bios" name="properties_toc_item" onclick="SelectTab('bios');">Firmware</div>
<div id="properties_toc_about" name="properties_toc_item" onclick="SelectTab('about');">About</div>
</div>
<div id="properties_bodypanel">
</div>
</div>
<div id="settings_photocredit">
Wallpaper by <a href="https://unsplash.com/@lorenzoherrera" class="romlink">Lorenzo Herrera</a> / <a href="https://unsplash.com/photos/p0j-mE6mGo4" class="romlink">Unsplash</a>
</div>
<script type="text/javascript">
const urlParams = new URLSearchParams(window.location.search);
var myParam = urlParams.get('sub');
var selectedTab = '';
if (myParam) {
selectedTab = myParam;
} else {
selectedTab = 'system';
}
SelectTab(selectedTab);
function SelectTab(TabName) {
var tocs = document.getElementsByName('properties_toc_item');
for (var i = 0; i < tocs.length; i++) {
if ((tocs[i].id) == ("properties_toc_" + TabName)) {
tocs[i].className = "properties_toc_item_selected";
} else {
tocs[i].className = '';
}
}
$('#properties_bodypanel').load('/pages/settings/' + TabName + '.html');
}
</script>

View File

@@ -0,0 +1,14 @@
<div id="gametitle">
<h1 id="gametitle_label">About Gaseous</h1>
</div>
<table>
<tr>
<th>Home Page</th>
<td><a href="https://github.com/gaseous-project/gaseous-server" class="romlink">https://github.com/gaseous-project/gaseous-server</a></td>
</tr>
<tr>
<th>Bugs and Feature Requests</th>
<td><a href="https://github.com/gaseous-project/gaseous-server/issues" class="romlink">https://github.com/gaseous-project/gaseous-server/issues</a></td>
</tr>
</table>

View File

@@ -0,0 +1,53 @@
<div id="gametitle">
<h1 id="gametitle_label">Firmware</h1>
</div>
<h3>Firmware Availablility</h3>
<table id="table_firmware" class="romtable" cellspacing="0">
</table>
<script type="text/javascript">
ajaxCall('/api/v1/Bios', 'GET', function (result) {
result.sort((a, b) => a.platformname.charCodeAt(0) - b.platformname.charCodeAt(0));
var lastPlatform = '';
var newTable = document.getElementById('table_firmware');
newTable.appendChild(createTableRow(true, ['Description', 'File name', 'MD5 Hash', 'Available']));
for (var i = 0; i < result.length; i++) {
if (result[i].platformname != lastPlatform) {
lastPlatform = result[i].platformname;
var platformRow = document.createElement('tr');
var platformHeader = document.createElement('th');
platformHeader.setAttribute('colspan', 4);
platformHeader.innerHTML = result[i].platformname;
platformRow.appendChild(platformHeader);
newTable.appendChild(platformRow);
}
var biosFilename = document.createElement('a');
biosFilename.href = '/api/v1/Bios/' + result[i].platformid + '/' + result[i].filename;
biosFilename.innerHTML = result[i].filename;
biosFilename.className = 'romlink';
var availableText = document.createElement('span');
if (result[i].available == true) {
availableText.innerHTML = 'Available';
availableText.className = 'greentext';
} else {
availableText.innerHTML = 'Unavailable';
availableText.className = 'redtext';
}
var newRow = [
result[i].description,
biosFilename,
result[i].hash,
availableText
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}
});
</script>

View File

@@ -1,23 +1,20 @@
<div id="gamepage">
<div id="gametitle">
<h1 id="gametitle_label">System</h1>
</div>
<h3>Background Tasks</h3>
<div id="system_tasks"></div>
<h3>Usage</h3>
<p><strong>Library</strong></p>
<div id="system_disks"></div>
<p><strong>Database</strong></p>
<div id="system_database"></div>
<h3>Signatures</h3>
<div id="system_signatures"></div>
<div id="gametitle">
<h1 id="gametitle_label">System</h1>
</div>
<script type="text/javascript">
function SystemLoadStatus() {
<h3>Background Tasks</h3>
<div id="system_tasks"></div>
<h3>Usage</h3>
<p><strong>Library</strong></p>
<div id="system_disks"></div>
<p><strong>Database</strong></p>
<div id="system_database"></div>
<h3>Signatures</h3>
<div id="system_signatures"></div>
<script type="text/javascript">function SystemLoadStatus() {
ajaxCall('/api/v1/BackgroundTasks', 'GET', function (result) {
var newTable = document.createElement('table');
newTable.className = 'romtable';
@@ -71,7 +68,7 @@
var startButton = '';
if (result[i].itemState != "Running") {
startButton = "<span id='startProcess' class='romlink' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
startButton = "<span id='startProcess' class='romstart' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
}
var newRow = [
@@ -111,7 +108,7 @@
formatBytes(spaceUsedByOthers),
formatBytes(result.Paths[i].TotalSpace)
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
var spaceRow = document.createElement('tr');
@@ -202,5 +199,4 @@
SystemLoadSystemStatus();
setInterval(SystemLoadStatus, 60000);
SystemSignaturesStatus();
setInterval(SystemSignaturesStatus, 300000);
</script>
setInterval(SystemSignaturesStatus, 300000);</script>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -168,6 +168,7 @@ h3 {
}
.filter_header {
font-weight: bold;
padding: 10px;
background-color: #2b2b2b;
}
@@ -469,7 +470,7 @@ th {
.romlink {
color: white;
text-decoration: none;
/*text-decoration: none;*/
}
.romlink:hover {
@@ -478,6 +479,56 @@ th {
cursor: pointer;
}
.romstart {
padding-left: 7px;
padding-right: 7px;
padding-top: 3px;
padding-bottom: 3px;
background-color: #02B01B;
color: white;
text-shadow: 2px 2px 6px #003506;
text-decoration: none;
border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
border: 1px solid #19d348;
box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
}
.romstart:hover {
background-color: #003506;
border-color: #129834;
cursor: pointer;
}
.properties_button {
width: 15px;
height: 15px;
border-radius: 15px;
font-size: 13px;
font-weight: bold;
color: blue;
line-height: 17px;
text-align: center;
border-color: blue;
border-width: 2px;
border-style: solid;
background-color: white;
outline-color: white;
outline-width: 1px;
outline-style: solid;
}
.properties_button:hover {
cursor: pointer;
color: white;
border-color: white;
background-color: blue;
outline-color: blue;
}
#gamedev_logo {
float: right;
max-height: 48px;
@@ -492,6 +543,8 @@ th {
display: block;
width: 150px;
min-width: 150px;
background-color: #383838;
height: 100%;
}
div[name="properties_toc_item"] {
@@ -518,6 +571,10 @@ div[name="properties_toc_item"]:hover {
padding-left: 10px;
}
.settings_toc {
margin-top: 20px;
}
.select2-container--open .select2-dropdown--below,
.select2-container--open .select2-dropdown--above {
background: #2b2b2b;
@@ -578,4 +635,36 @@ button:disabled {
.redbutton:disabled {
background-color: #555;
}
#emulator {
margin: 0 auto;
width: 640px;
padding-top: 100px;
}
#emulatorbios {
margin: 0 auto;
width: 640px;
padding-top: 20px;
}
.greentext {
color: lightgreen;
}
.redtext {
color: red;
}
#settings_photocredit {
position: fixed;
bottom: 0px;
left: 0px;
right: 0px;
height: 20px;
background-color: rgba(0, 22, 56, 0.8);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
padding: 5px;
}

View File

@@ -335,6 +335,14 @@ namespace gaseous_tools
}
}
public string LibraryBIOSDirectory
{
get
{
return Path.Combine(LibraryRootDirectory, "BIOS");
}
}
public string LibraryMetadataDirectory
{
get
@@ -385,6 +393,7 @@ namespace gaseous_tools
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
if (!Directory.Exists(LibraryImportDirectory)) { Directory.CreateDirectory(LibraryImportDirectory); }
if (!Directory.Exists(LibraryDataDirectory)) { Directory.CreateDirectory(LibraryDataDirectory); }
if (!Directory.Exists(LibraryBIOSDirectory)) { Directory.CreateDirectory(LibraryBIOSDirectory); }
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
if (!Directory.Exists(LibrarySignatureImportDirectory)) { Directory.CreateDirectory(LibrarySignatureImportDirectory); }
if (!Directory.Exists(LibrarySignatureImportDirectory_TOSEC)) { Directory.CreateDirectory(LibrarySignatureImportDirectory_TOSEC); }