Compare commits
8 Commits
branch-v1.
...
v1.5.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
129fd6d4e4 | ||
![]() |
28823d940f | ||
![]() |
4b6174e3e2 | ||
![]() |
8e922182e2 | ||
![]() |
25f1895fe5 | ||
![]() |
07caab074a | ||
![]() |
f7906f692d | ||
![]() |
14f836d46a |
6
.github/workflows/BuildDockerOnTag.yml
vendored
@@ -14,6 +14,12 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
-
|
||||
name: Install dotnet tool
|
||||
run: dotnet tool install -g dotnetCampus.TagToVersion
|
||||
-
|
||||
name: Set tag to version
|
||||
run: dotnet TagToVersion -t ${{ github.ref }}
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
michael.green@mrgtech.net.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
3
Directory.Build.props
Normal file
@@ -0,0 +1,3 @@
|
||||
<Project>
|
||||
<Import Project="build\Version.props" />
|
||||
</Project>
|
@@ -5,6 +5,7 @@ This is the server for the Gaseous system. All your games and metadata are store
|
||||
## Screenshots
|
||||

|
||||

|
||||

|
||||
|
||||
## Requirements
|
||||
* MySQL Server 8+
|
||||
@@ -18,6 +19,9 @@ The following projects are used by Gaseous
|
||||
* https://github.com/kamranayub/igdb-dotnet
|
||||
* https://github.com/EmulatorJS/EmulatorJS
|
||||
|
||||
## Discord Server
|
||||
[](https://discord.gg/Nhu7wpT3k4)
|
||||
|
||||
## 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).
|
||||
|
||||
|
5
build/Version.props
Normal file
@@ -0,0 +1,5 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.5.0</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/Assets/Ratings/.DS_Store
vendored
607
gaseous-server/Classes/Collections.cs
Normal file
@@ -0,0 +1,607 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Controllers;
|
||||
using gaseous_tools;
|
||||
using IGDB.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Collections
|
||||
{
|
||||
public Collections()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static List<CollectionItem> GetCollections() {
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM RomCollections ORDER BY `Name`";
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
|
||||
List<CollectionItem> collectionItems = new List<CollectionItem>();
|
||||
|
||||
foreach(DataRow row in data.Rows) {
|
||||
collectionItems.Add(BuildCollectionItem(row));
|
||||
}
|
||||
|
||||
return collectionItems;
|
||||
}
|
||||
|
||||
public static CollectionItem GetCollection(long Id) {
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM RomCollections WHERE Id = @id ORDER BY `Name`";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
DataRow row = romDT.Rows[0];
|
||||
CollectionItem collectionItem = BuildCollectionItem(row);
|
||||
|
||||
return collectionItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unknown Collection Id");
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionItem NewCollection(CollectionItem item)
|
||||
{
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "INSERT INTO RomCollections (`Name`, Description, Platforms, Genres, Players, PlayerPerspectives, Themes, MinimumRating, MaximumRating, MaximumRomsPerPlatform, MaximumBytesPerPlatform, MaximumCollectionSizeInBytes, BuiltStatus) VALUES (@name, @description, @platforms, @genres, @players, @playerperspectives, @themes, @minimumrating, @maximumrating, @maximumromsperplatform, @maximumbytesperplatform, @maximumcollectionsizeinbytes, @builtstatus); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("name", item.Name);
|
||||
dbDict.Add("description", item.Description);
|
||||
dbDict.Add("platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())));
|
||||
dbDict.Add("genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())));
|
||||
dbDict.Add("players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())));
|
||||
dbDict.Add("playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())));
|
||||
dbDict.Add("themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())));
|
||||
dbDict.Add("minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1));
|
||||
dbDict.Add("maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1));
|
||||
dbDict.Add("maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1));
|
||||
dbDict.Add("maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1));
|
||||
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
long CollectionId = (long)romDT.Rows[0][0];
|
||||
|
||||
CollectionItem collectionItem = GetCollection(CollectionId);
|
||||
|
||||
StartCollectionItemBuild(CollectionId);
|
||||
|
||||
return collectionItem;
|
||||
}
|
||||
|
||||
public static CollectionItem EditCollection(long Id, CollectionItem item)
|
||||
{
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE RomCollections SET `Name`=@name, Description=@description, Platforms=@platforms, Genres=@genres, Players=@players, PlayerPerspectives=@playerperspectives, Themes=@themes, MinimumRating=@minimumrating, MaximumRating=@maximumrating, MaximumRomsPerPlatform=@maximumromsperplatform, MaximumBytesPerPlatform=@maximumbytesperplatform, MaximumCollectionSizeInBytes=@maximumcollectionsizeinbytes, BuiltStatus=@builtstatus WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
dbDict.Add("name", item.Name);
|
||||
dbDict.Add("description", item.Description);
|
||||
dbDict.Add("platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())));
|
||||
dbDict.Add("genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())));
|
||||
dbDict.Add("players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())));
|
||||
dbDict.Add("playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())));
|
||||
dbDict.Add("themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())));
|
||||
dbDict.Add("minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1));
|
||||
dbDict.Add("maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1));
|
||||
dbDict.Add("maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1));
|
||||
dbDict.Add("maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1));
|
||||
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
||||
if (File.Exists(CollectionZipFile))
|
||||
{
|
||||
File.Delete(CollectionZipFile);
|
||||
}
|
||||
|
||||
CollectionItem collectionItem = GetCollection(Id);
|
||||
|
||||
StartCollectionItemBuild(Id);
|
||||
|
||||
return collectionItem;
|
||||
}
|
||||
|
||||
public static void DeleteCollection(long Id)
|
||||
{
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM RomCollections WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
||||
if (File.Exists(CollectionZipFile))
|
||||
{
|
||||
File.Delete(CollectionZipFile);
|
||||
}
|
||||
}
|
||||
|
||||
public static void StartCollectionItemBuild(long Id)
|
||||
{
|
||||
CollectionItem collectionItem = GetCollection(Id);
|
||||
|
||||
if (collectionItem.BuildStatus != CollectionItem.CollectionBuildStatus.Building)
|
||||
{
|
||||
// set collection item to waitingforbuild
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE RomCollections SET BuiltStatus=@bs WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
dbDict.Add("bs", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
// start background task
|
||||
foreach (ProcessQueue.QueueItem qi in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (qi.ItemType == ProcessQueue.QueueItemType.CollectionCompiler) {
|
||||
qi.ForceExecute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionContents GetCollectionContent(CollectionItem collectionItem) {
|
||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = new List<CollectionContents.CollectionPlatformItem>();
|
||||
|
||||
// get platforms
|
||||
List<Platform> platforms = new List<Platform>();
|
||||
if (collectionItem.Platforms.Count > 0) {
|
||||
foreach (long PlatformId in collectionItem.Platforms) {
|
||||
platforms.Add(Platforms.GetPlatform(PlatformId));
|
||||
}
|
||||
} else {
|
||||
// get all platforms to pull from
|
||||
FilterController filterController = new FilterController();
|
||||
platforms.AddRange((List<Platform>)filterController.Filter()["platforms"]);
|
||||
}
|
||||
|
||||
// build collection
|
||||
List<CollectionContents.CollectionPlatformItem> platformItems = new List<CollectionContents.CollectionPlatformItem>();
|
||||
|
||||
foreach (Platform platform in platforms) {
|
||||
long TotalRomSize = 0;
|
||||
long TotalGameCount = 0;
|
||||
|
||||
List<Game> games = GamesController.GetGames("",
|
||||
platform.Id.ToString(),
|
||||
string.Join(",", collectionItem.Genres),
|
||||
string.Join(",", collectionItem.Players),
|
||||
string.Join(",", collectionItem.PlayerPerspectives),
|
||||
string.Join(",", collectionItem.Themes),
|
||||
collectionItem.MinimumRating,
|
||||
collectionItem.MaximumRating
|
||||
);
|
||||
|
||||
CollectionContents.CollectionPlatformItem collectionPlatformItem = new CollectionContents.CollectionPlatformItem(platform);
|
||||
collectionPlatformItem.Games = new List<CollectionContents.CollectionPlatformItem.CollectionGameItem>();
|
||||
|
||||
foreach (Game game in games) {
|
||||
CollectionContents.CollectionPlatformItem.CollectionGameItem collectionGameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(game);
|
||||
|
||||
List<Roms.GameRomItem> gameRoms = Roms.GetRoms((long)game.Id, (long)platform.Id);
|
||||
|
||||
bool AddGame = false;
|
||||
|
||||
// calculate total rom size for the game
|
||||
long GameRomSize = 0;
|
||||
foreach (Roms.GameRomItem gameRom in gameRoms) {
|
||||
GameRomSize += gameRom.Size;
|
||||
}
|
||||
if (collectionItem.MaximumBytesPerPlatform > 0) {
|
||||
if ((TotalRomSize + GameRomSize) < collectionItem.MaximumBytesPerPlatform) {
|
||||
AddGame = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddGame = true;
|
||||
}
|
||||
|
||||
if (AddGame == true) {
|
||||
TotalRomSize += GameRomSize;
|
||||
|
||||
bool AddRoms = false;
|
||||
|
||||
if (collectionItem.MaximumRomsPerPlatform > 0) {
|
||||
if (TotalGameCount < collectionItem.MaximumRomsPerPlatform) {
|
||||
AddRoms = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRoms = true;
|
||||
}
|
||||
|
||||
if (AddRoms == true) {
|
||||
TotalGameCount += 1;
|
||||
collectionGameItem.Roms = gameRoms;
|
||||
collectionPlatformItem.Games.Add(collectionGameItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (collectionPlatformItem.Games.Count > 0)
|
||||
{
|
||||
bool AddPlatform = false;
|
||||
if (collectionItem.MaximumCollectionSizeInBytes > 0)
|
||||
{
|
||||
if (TotalRomSize < collectionItem.MaximumCollectionSizeInBytes)
|
||||
{
|
||||
AddPlatform = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPlatform = true;
|
||||
}
|
||||
|
||||
if (AddPlatform == true)
|
||||
{
|
||||
collectionPlatformItems.Add(collectionPlatformItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CollectionContents collectionContents = new CollectionContents();
|
||||
collectionContents.Collection = collectionPlatformItems;
|
||||
return collectionContents;
|
||||
}
|
||||
|
||||
public static void CompileCollections()
|
||||
{
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
List<CollectionItem> collectionItems = GetCollections();
|
||||
foreach (CollectionItem collectionItem in collectionItems)
|
||||
{
|
||||
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
||||
{
|
||||
// set starting
|
||||
string sql = "UPDATE RomCollections SET BuiltStatus=@bs WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", collectionItem.Id);
|
||||
dbDict.Add("bs", CollectionItem.CollectionBuildStatus.Building);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = GetCollectionContent(collectionItem).Collection;
|
||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + ".zip");
|
||||
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// clean up if needed
|
||||
if (File.Exists(ZipFilePath))
|
||||
{
|
||||
File.Delete(ZipFilePath);
|
||||
}
|
||||
|
||||
if (Directory.Exists(ZipFileTempPath))
|
||||
{
|
||||
Directory.Delete(ZipFileTempPath, true);
|
||||
}
|
||||
|
||||
// gather collection files
|
||||
Directory.CreateDirectory(ZipFileTempPath);
|
||||
|
||||
foreach (CollectionContents.CollectionPlatformItem collectionPlatformItem in collectionPlatformItems)
|
||||
{
|
||||
// create platform directory
|
||||
string ZipPlatformPath = Path.Combine(ZipFileTempPath, collectionPlatformItem.Slug);
|
||||
if (!Directory.Exists(ZipPlatformPath))
|
||||
{
|
||||
Directory.CreateDirectory(ZipPlatformPath);
|
||||
}
|
||||
|
||||
foreach (CollectionContents.CollectionPlatformItem.CollectionGameItem collectionGameItem in collectionPlatformItem.Games)
|
||||
{
|
||||
// create game directory
|
||||
string ZipGamePath = Path.Combine(ZipPlatformPath, collectionGameItem.Slug);
|
||||
if (!Directory.Exists(ZipGamePath))
|
||||
{
|
||||
Directory.CreateDirectory(ZipGamePath);
|
||||
}
|
||||
|
||||
// copy in roms
|
||||
foreach (Roms.GameRomItem gameRomItem in collectionGameItem.Roms)
|
||||
{
|
||||
if (File.Exists(gameRomItem.Path))
|
||||
{
|
||||
File.Copy(gameRomItem.Path, Path.Combine(ZipGamePath, gameRomItem.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compress to zip
|
||||
ZipFile.CreateFromDirectory(ZipFileTempPath, ZipFilePath, CompressionLevel.SmallestSize, false);
|
||||
|
||||
// clean up
|
||||
if (Directory.Exists(ZipFileTempPath))
|
||||
{
|
||||
Directory.Delete(ZipFileTempPath, true);
|
||||
}
|
||||
|
||||
// set completed
|
||||
dbDict["bs"] = CollectionItem.CollectionBuildStatus.Completed;
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// clean up
|
||||
if (Directory.Exists(ZipFileTempPath))
|
||||
{
|
||||
Directory.Delete(ZipFileTempPath, true);
|
||||
}
|
||||
|
||||
if (File.Exists(ZipFilePath))
|
||||
{
|
||||
File.Delete(ZipFilePath);
|
||||
}
|
||||
|
||||
// set failed
|
||||
dbDict["bs"] = CollectionItem.CollectionBuildStatus.Failed;
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
Logging.Log(Logging.LogType.Critical, "Collection Builder", "Collection building has failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CollectionItem BuildCollectionItem(DataRow row) {
|
||||
string strPlatforms = (string)Common.ReturnValueIfNull(row["Platforms"], "[ ]");
|
||||
string strGenres = (string)Common.ReturnValueIfNull(row["Genres"], "[ ]");
|
||||
string strPlayers = (string)Common.ReturnValueIfNull(row["Players"], "[ ]");
|
||||
string strPlayerPerspectives = (string)Common.ReturnValueIfNull(row["PlayerPerspectives"], "[ ]");
|
||||
string strThemes = (string)Common.ReturnValueIfNull(row["Themes"], "[ ]");
|
||||
|
||||
CollectionItem item = new CollectionItem();
|
||||
item.Id = (long)row["Id"];
|
||||
item.Name = (string)row["Name"];
|
||||
item.Description = (string)row["Description"];
|
||||
item.Platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(strPlatforms);
|
||||
item.Genres = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(strGenres);
|
||||
item.Players = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(strPlayers);
|
||||
item.PlayerPerspectives = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(strPlayerPerspectives);
|
||||
item.Themes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(strThemes);
|
||||
item.MinimumRating = (int)Common.ReturnValueIfNull(row["MinimumRating"], -1);
|
||||
item.MaximumRating = (int)Common.ReturnValueIfNull(row["MaximumRating"], -1);
|
||||
item.MaximumRomsPerPlatform = (int)Common.ReturnValueIfNull(row["MaximumRomsPerPlatform"], (int)-1);
|
||||
item.MaximumBytesPerPlatform = (long)Common.ReturnValueIfNull(row["MaximumBytesPerPlatform"], (long)-1);
|
||||
item.MaximumCollectionSizeInBytes = (long)Common.ReturnValueIfNull(row["MaximumCollectionSizeInBytes"], (long)-1);
|
||||
item.BuildStatus = (CollectionItem.CollectionBuildStatus)(int)Common.ReturnValueIfNull(row["BuiltStatus"], 0);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public class CollectionItem
|
||||
{
|
||||
public CollectionItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<long>? Platforms { get; set; }
|
||||
public List<long>? Genres { get; set; }
|
||||
public List<long>? Players { get; set; }
|
||||
public List<long>? PlayerPerspectives { get; set; }
|
||||
public List<long>? Themes { get; set; }
|
||||
public int MinimumRating { get; set; }
|
||||
public int MaximumRating { get; set; }
|
||||
public int? MaximumRomsPerPlatform { get; set; }
|
||||
public long? MaximumBytesPerPlatform { get; set; }
|
||||
public long? MaximumCollectionSizeInBytes { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public CollectionBuildStatus BuildStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_BuildStatus == CollectionBuildStatus.Completed)
|
||||
{
|
||||
if (File.Exists(Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip")))
|
||||
{
|
||||
return CollectionBuildStatus.Completed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CollectionBuildStatus.NoStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _BuildStatus;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
_BuildStatus = value;
|
||||
}
|
||||
}
|
||||
private CollectionBuildStatus _BuildStatus { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public long CollectionBuiltSizeBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BuildStatus == CollectionBuildStatus.Completed)
|
||||
{
|
||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
||||
if (File.Exists(ZipFilePath))
|
||||
{
|
||||
FileInfo fi = new FileInfo(ZipFilePath);
|
||||
return fi.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CollectionBuildStatus
|
||||
{
|
||||
NoStatus = 0,
|
||||
WaitingForBuild = 1,
|
||||
Building = 2,
|
||||
Completed = 3,
|
||||
Failed = 4
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectionContents {
|
||||
[JsonIgnore]
|
||||
public List<CollectionPlatformItem> Collection { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public long CollectionProjectedSizeBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
long CollectionSize = 0;
|
||||
|
||||
List<CollectionPlatformItem> collectionPlatformItems = new List<CollectionPlatformItem>();
|
||||
|
||||
if (Collection != null)
|
||||
{
|
||||
collectionPlatformItems = Collection;
|
||||
}
|
||||
|
||||
foreach (CollectionPlatformItem platformItem in collectionPlatformItems)
|
||||
{
|
||||
CollectionSize += platformItem.RomSize;
|
||||
}
|
||||
|
||||
return CollectionSize;
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectionPlatformItem {
|
||||
public CollectionPlatformItem(IGDB.Models.Platform platform) {
|
||||
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug" };
|
||||
|
||||
PropertyInfo[] srcProperties = typeof(IGDB.Models.Platform).GetProperties();
|
||||
PropertyInfo[] dstProperties = typeof(CollectionPlatformItem).GetProperties();
|
||||
foreach (PropertyInfo srcProperty in srcProperties) {
|
||||
if (PropertyWhitelist.Contains<string>(srcProperty.Name))
|
||||
{
|
||||
foreach (PropertyInfo dstProperty in dstProperties)
|
||||
{
|
||||
if (srcProperty.Name == dstProperty.Name)
|
||||
{
|
||||
dstProperty.SetValue(this, srcProperty.GetValue(platform));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
|
||||
public List<CollectionGameItem> Games { get; set; }
|
||||
|
||||
public int RomCount {
|
||||
get {
|
||||
int Counter = 0;
|
||||
foreach (CollectionGameItem Game in Games) {
|
||||
Counter += 1;
|
||||
}
|
||||
|
||||
return Counter;
|
||||
}
|
||||
}
|
||||
|
||||
public long RomSize {
|
||||
get {
|
||||
long Size = 0;
|
||||
foreach (CollectionGameItem Game in Games) {
|
||||
foreach (Roms.GameRomItem Rom in Game.Roms) {
|
||||
Size += Rom.Size;
|
||||
}
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectionGameItem {
|
||||
public CollectionGameItem(IGDB.Models.Game game) {
|
||||
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug", "Cover" };
|
||||
PropertyInfo[] srcProperties = typeof(IGDB.Models.Game).GetProperties();
|
||||
PropertyInfo[] dstProperties = typeof(CollectionPlatformItem.CollectionGameItem).GetProperties();
|
||||
foreach (PropertyInfo srcProperty in srcProperties) {
|
||||
if (PropertyWhitelist.Contains<string>(srcProperty.Name))
|
||||
{
|
||||
foreach (PropertyInfo dstProperty in dstProperties)
|
||||
{
|
||||
if (srcProperty.Name == dstProperty.Name)
|
||||
{
|
||||
if (srcProperty.GetValue(game) != null) {
|
||||
string compareName = srcProperty.PropertyType.Name.ToLower().Split("`")[0];
|
||||
switch(compareName) {
|
||||
case "identityorvalue":
|
||||
string newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(srcProperty.GetValue(game));
|
||||
Dictionary<string, object> newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
||||
dstProperty.SetValue(this, newDict["Id"]);
|
||||
break;
|
||||
default:
|
||||
dstProperty.SetValue(this, srcProperty.GetValue(game));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public long Cover { get; set;}
|
||||
|
||||
public List<Roms.GameRomItem> Roms { get; set; }
|
||||
|
||||
public long RomSize {
|
||||
get {
|
||||
long Size = 0;
|
||||
foreach (Roms.GameRomItem Rom in Roms) {
|
||||
Size += Rom.Size;
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -129,7 +129,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
// file is a zip and less than 1 GiB
|
||||
// extract the zip file and search the contents
|
||||
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "Temp", Path.GetRandomFileName());
|
||||
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, Path.GetRandomFileName());
|
||||
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
||||
ZipFile.ExtractToDirectory(GameFileImportPath, ExtractPath);
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace gaseous_server.Classes
|
||||
if (games.Length == 1)
|
||||
{
|
||||
// exact match!
|
||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false);
|
||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " IGDB game: " + determinedGame.Name);
|
||||
GameFound = true;
|
||||
break;
|
||||
@@ -425,7 +425,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
// get metadata
|
||||
IGDB.Models.Platform platform = gaseous_server.Classes.Metadata.Platforms.GetPlatform(rom.PlatformId);
|
||||
IGDB.Models.Game game = gaseous_server.Classes.Metadata.Games.GetGame(rom.GameId, false, false);
|
||||
IGDB.Models.Game game = gaseous_server.Classes.Metadata.Games.GetGame(rom.GameId, false, false, false);
|
||||
|
||||
// build path
|
||||
string platformSlug = "Unknown Platform";
|
||||
|
110
gaseous-server/Classes/Metadata/GameModes.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using gaseous_tools;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using MySqlX.XDevAPI.Common;
|
||||
using static gaseous_tools.Config.ConfigFile;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class GameModes
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public GameModes()
|
||||
{
|
||||
}
|
||||
|
||||
private static IGDBClient igdb = new IGDBClient(
|
||||
// Found in Twitch Developer portal for your app
|
||||
Config.IGDB.ClientId,
|
||||
Config.IGDB.Secret
|
||||
);
|
||||
|
||||
public static GameMode? GetGame_Modes(long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<GameMode> RetVal = _GetGame_Modes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameMode GetGame_Modes(string Slug)
|
||||
{
|
||||
Task<GameMode> RetVal = _GetGame_Modes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<GameMode> _GetGame_Modes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameMode", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameMode", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
GameMode returnValue = new GameMode();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<GameMode>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<GameMode> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_Modes metadata
|
||||
var results = await igdb.QueryAsync<GameMode>(IGDBClient.Endpoints.GameModes, query: fieldList + " " + WhereClause + ";");
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
Config.IGDB.Secret
|
||||
);
|
||||
|
||||
public static Game? GetGame(long Id, bool followSubGames, bool forceRefresh)
|
||||
public static Game? GetGame(long Id, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
{
|
||||
if (Id == 0)
|
||||
{
|
||||
@@ -45,14 +45,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.id, Id, followSubGames, forceRefresh);
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.id, Id, getAllMetadata, followSubGames, forceRefresh);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static Game GetGame(string Slug, bool followSubGames, bool forceRefresh)
|
||||
public static Game GetGame(string Slug, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
{
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.slug, Slug, followSubGames, forceRefresh);
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.slug, Slug, getAllMetadata, followSubGames, forceRefresh);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
return Storage.BuildCacheObject<Game>(new Game(), dataRow);
|
||||
}
|
||||
|
||||
private static async Task<Game> _GetGame(SearchUsing searchUsing, object searchValue, bool followSubGames = false, bool forceRefresh = false)
|
||||
private static async Task<Game> _GetGame(SearchUsing searchUsing, object searchValue, bool getAllMetadata = true, bool followSubGames = false, bool forceRefresh = false)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
@@ -99,12 +99,12 @@ namespace gaseous_server.Classes.Metadata
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue, followSubGames);
|
||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames);
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(returnValue, followSubGames);
|
||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames);
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Current:
|
||||
return Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
||||
@@ -113,7 +113,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Game Game, bool followSubGames)
|
||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames)
|
||||
{
|
||||
if (Game.Cover != null)
|
||||
{
|
||||
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game));
|
||||
}
|
||||
|
||||
if (getAllMetadata == true)
|
||||
{
|
||||
if (Game.AgeRatings != null)
|
||||
{
|
||||
@@ -152,7 +159,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
foreach (long gameId in gamesToFetch)
|
||||
{
|
||||
Game relatedGame = GetGame(gameId, false, false);
|
||||
Game relatedGame = GetGame(gameId, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,11 +168,6 @@ namespace gaseous_server.Classes.Metadata
|
||||
Collection GameCollection = Collections.GetCollections(Game.Collection.Id);
|
||||
}
|
||||
|
||||
if (Game.Cover != null)
|
||||
{
|
||||
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game));
|
||||
}
|
||||
|
||||
if (Game.ExternalGames != null)
|
||||
{
|
||||
foreach (long ExternalGameId in Game.ExternalGames.Ids)
|
||||
@@ -203,6 +205,22 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.GameModes != null)
|
||||
{
|
||||
foreach (long gameModeId in Game.GameModes.Ids)
|
||||
{
|
||||
GameMode gameMode = GameModes.GetGame_Modes(gameModeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.MultiplayerModes != null)
|
||||
{
|
||||
foreach (long multiplayerModeId in Game.MultiplayerModes.Ids)
|
||||
{
|
||||
MultiplayerMode multiplayerMode = MultiplayerModes.GetGame_MultiplayerModes(multiplayerModeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Platforms != null)
|
||||
{
|
||||
foreach (long PlatformId in Game.Platforms.Ids)
|
||||
@@ -211,6 +229,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.PlayerPerspectives != null)
|
||||
{
|
||||
foreach (long PerspectiveId in Game.PlayerPerspectives.Ids)
|
||||
{
|
||||
PlayerPerspective GamePlayPerspective = PlayerPerspectives.GetGame_PlayerPerspectives(PerspectiveId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Screenshots != null)
|
||||
{
|
||||
foreach (long ScreenshotId in Game.Screenshots.Ids)
|
||||
@@ -219,6 +245,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Themes != null)
|
||||
{
|
||||
foreach (long ThemeId in Game.Themes.Ids)
|
||||
{
|
||||
Theme GameTheme = Themes.GetGame_Themes(ThemeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Videos != null)
|
||||
{
|
||||
foreach (long GameVideoId in Game.Videos.Ids)
|
||||
@@ -227,6 +261,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
|
110
gaseous-server/Classes/Metadata/MultiplayerModes.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using gaseous_tools;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using MySqlX.XDevAPI.Common;
|
||||
using static gaseous_tools.Config.ConfigFile;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class MultiplayerModes
|
||||
{
|
||||
const string fieldList = "fields campaigncoop,checksum,dropin,game,lancoop,offlinecoop,offlinecoopmax,offlinemax,onlinecoop,onlinecoopmax,onlinemax,platform,splitscreen,splitscreenonline;";
|
||||
|
||||
public MultiplayerModes()
|
||||
{
|
||||
}
|
||||
|
||||
private static IGDBClient igdb = new IGDBClient(
|
||||
// Found in Twitch Developer portal for your app
|
||||
Config.IGDB.ClientId,
|
||||
Config.IGDB.Secret
|
||||
);
|
||||
|
||||
public static MultiplayerMode? GetGame_MultiplayerModes(long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<MultiplayerMode> RetVal = _GetGame_MultiplayerModes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiplayerMode GetGame_MultiplayerModes(string Slug)
|
||||
{
|
||||
Task<MultiplayerMode> RetVal = _GetGame_MultiplayerModes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<MultiplayerMode> _GetGame_MultiplayerModes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
MultiplayerMode returnValue = new MultiplayerMode();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<MultiplayerMode>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<MultiplayerMode> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_MultiplayerModes metadata
|
||||
var results = await igdb.QueryAsync<MultiplayerMode>(IGDBClient.Endpoints.MultiplayerModes, query: fieldList + " " + WhereClause + ";");
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
gaseous-server/Classes/Metadata/PlayerPerspectives.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using gaseous_tools;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using MySqlX.XDevAPI.Common;
|
||||
using static gaseous_tools.Config.ConfigFile;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class PlayerPerspectives
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public PlayerPerspectives()
|
||||
{
|
||||
}
|
||||
|
||||
private static IGDBClient igdb = new IGDBClient(
|
||||
// Found in Twitch Developer portal for your app
|
||||
Config.IGDB.ClientId,
|
||||
Config.IGDB.Secret
|
||||
);
|
||||
|
||||
public static PlayerPerspective? GetGame_PlayerPerspectives(long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<PlayerPerspective> RetVal = _GetGame_PlayerPerspectives(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlayerPerspective GetGame_PlayerPerspectives(string Slug)
|
||||
{
|
||||
Task<PlayerPerspective> RetVal = _GetGame_PlayerPerspectives(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<PlayerPerspective> _GetGame_PlayerPerspectives(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
PlayerPerspective returnValue = new PlayerPerspective();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<PlayerPerspective>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<PlayerPerspective> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_PlayerPerspectives metadata
|
||||
var results = await igdb.QueryAsync<PlayerPerspective>(IGDBClient.Endpoints.PlayerPerspectives, query: fieldList + " " + WhereClause + ";");
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
gaseous-server/Classes/Metadata/Themes.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using gaseous_tools;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using MySqlX.XDevAPI.Common;
|
||||
using static gaseous_tools.Config.ConfigFile;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Themes
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public Themes()
|
||||
{
|
||||
}
|
||||
|
||||
private static IGDBClient igdb = new IGDBClient(
|
||||
// Found in Twitch Developer portal for your app
|
||||
Config.IGDB.ClientId,
|
||||
Config.IGDB.Secret
|
||||
);
|
||||
|
||||
public static Theme? GetGame_Themes(long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Theme> RetVal = _GetGame_Themes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static Theme GetGame_Themes(string Slug)
|
||||
{
|
||||
Task<Theme> RetVal = _GetGame_Themes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Theme> _GetGame_Themes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Theme", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Theme", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Theme returnValue = new Theme();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Theme>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Theme> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_Themes metadata
|
||||
var results = await igdb.QueryAsync<Theme>(IGDBClient.Endpoints.Themes, query: fieldList + " " + WhereClause + ";");
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ namespace gaseous_server.Classes
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "Refreshing metadata for game " + dr["name"] + " (" + dr["id"] + ")");
|
||||
Metadata.Games.GetGame((long)dr["id"], true, forceRefresh);
|
||||
Metadata.Games.GetGame((long)dr["id"], true, true, forceRefresh);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -6,12 +6,19 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
public class Roms
|
||||
{
|
||||
public static List<GameRomItem> GetRoms(long GameId)
|
||||
public static List<GameRomItem> GetRoms(long GameId, long PlatformId = -1)
|
||||
{
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Games_Roms WHERE GameId = @id ORDER BY `Name`";
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", GameId);
|
||||
|
||||
if (PlatformId == -1) {
|
||||
sql = "SELECT * FROM Games_Roms WHERE GameId = @id ORDER BY `Name`";
|
||||
} else {
|
||||
sql = "SELECT * FROM Games_Roms WHERE GameId = @id AND PlatformId = @platformid ORDER BY `Name`";
|
||||
dbDict.Add("platformid", PlatformId);
|
||||
}
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
@@ -56,7 +63,7 @@ namespace gaseous_server.Classes
|
||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
// ensure metadata for gameid is present
|
||||
IGDB.Models.Game game = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game game = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid WHERE Id = @id";
|
||||
|
@@ -24,6 +24,8 @@ namespace gaseous_server.Controllers
|
||||
public ActionResult<ProcessQueue.QueueItem> ForceRun(ProcessQueue.QueueItemType TaskType, Boolean ForceRun)
|
||||
{
|
||||
foreach (ProcessQueue.QueueItem qi in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (qi.AllowManualStart == true)
|
||||
{
|
||||
if (TaskType == qi.ItemType)
|
||||
{
|
||||
@@ -34,6 +36,7 @@ namespace gaseous_server.Controllers
|
||||
return qi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
191
gaseous-server/Controllers/CollectionsController.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/v1/[controller]")]
|
||||
public class CollectionsController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all ROM collections
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Classes.Collections.CollectionItem> GetCollections()
|
||||
{
|
||||
return Classes.Collections.GetCollections();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific ROM collection
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <param name="Build">Set to true to begin the collection build process</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetCollection(long CollectionId, bool Build = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Build == true)
|
||||
{
|
||||
Classes.Collections.StartCollectionItemBuild(CollectionId);
|
||||
}
|
||||
|
||||
return Ok(Classes.Collections.GetCollection(CollectionId));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the specified ROM collection
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}/Roms")]
|
||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetCollectionRoms(long CollectionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
|
||||
return Ok(Classes.Collections.GetCollectionContent(collectionItem));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a preview of the provided collection item
|
||||
/// </summary>
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("Preview")]
|
||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetCollectionRomsPreview(Classes.Collections.CollectionItem Item)
|
||||
{
|
||||
//try
|
||||
//{
|
||||
return Ok(Classes.Collections.GetCollectionContent(Item));
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// return NotFound(ex);
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets ROM collection in zip format
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{CollectionId}/Roms/Zip")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetCollectionRomsZip(long CollectionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
|
||||
|
||||
string ZipFilePath = Path.Combine(gaseous_tools.Config.LibraryConfiguration.LibraryCollectionsDirectory, CollectionId + ".zip");
|
||||
|
||||
if (System.IO.File.Exists(ZipFilePath))
|
||||
{
|
||||
var stream = new FileStream(ZipFilePath, FileMode.Open);
|
||||
return File(stream, "application/zip", collectionItem.Name + ".zip");
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ROM collection
|
||||
/// </summary>
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public ActionResult NewCollection(Classes.Collections.CollectionItem Item)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(Classes.Collections.NewCollection(Item));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Edits an existing collection
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
/// <param name="Item"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPatch]
|
||||
[Route("{CollectionId}")]
|
||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult EditCollection(long CollectionId, Classes.Collections.CollectionItem Item)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(Classes.Collections.EditCollection(CollectionId, Item));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified ROM collection
|
||||
/// </summary>
|
||||
/// <param name="CollectionId"></param>
|
||||
[HttpDelete]
|
||||
[Route("{CollectionId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult DeleteCollection(long CollectionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Classes.Collections.DeleteCollection(CollectionId);
|
||||
return Ok();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -45,6 +45,39 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
FilterSet.Add("genres", genres);
|
||||
|
||||
// game modes
|
||||
List<GameMode> gameModes = new List<GameMode>();
|
||||
sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM GameMode AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.GameModes, CAST(t1.Id AS char), '$') ORDER BY t1.Id";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
gameModes.Add(Classes.Metadata.GameModes.GetGame_Modes((long)dr["id"]));
|
||||
}
|
||||
FilterSet.Add("gamemodes", gameModes);
|
||||
|
||||
// player perspectives
|
||||
List<PlayerPerspective> playerPerspectives = new List<PlayerPerspective>();
|
||||
sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM PlayerPerspective AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.PlayerPerspectives, CAST(t1.Id AS char), '$') ORDER BY t1.`Name`";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
playerPerspectives.Add(Classes.Metadata.PlayerPerspectives.GetGame_PlayerPerspectives((long)dr["id"]));
|
||||
}
|
||||
FilterSet.Add("playerperspectives", playerPerspectives);
|
||||
|
||||
// themes
|
||||
List<Theme> themes = new List<Theme>();
|
||||
sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM Theme AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.Themes, CAST(t1.Id AS char), '$') ORDER BY t1.`Name`";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
themes.Add(Classes.Metadata.Themes.GetGame_Themes((long)dr["id"]));
|
||||
}
|
||||
FilterSet.Add("themes", themes);
|
||||
|
||||
return FilterSet;
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,31 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
public ActionResult Game(string name = "", string platform = "", string genre = "", bool sortdescending = false)
|
||||
public ActionResult Game(
|
||||
string name = "",
|
||||
string platform = "",
|
||||
string genre = "",
|
||||
string gamemode = "",
|
||||
string playerperspective = "",
|
||||
string theme = "",
|
||||
int minrating = -1,
|
||||
int maxrating = -1,
|
||||
bool sortdescending = false)
|
||||
{
|
||||
|
||||
return Ok(GetGames(name, platform, genre, gamemode, playerperspective, theme, minrating, maxrating, sortdescending));
|
||||
}
|
||||
|
||||
public static List<Game> GetGames(
|
||||
string name = "",
|
||||
string platform = "",
|
||||
string genre = "",
|
||||
string gamemode = "",
|
||||
string playerperspective = "",
|
||||
string theme = "",
|
||||
int minrating = -1,
|
||||
int maxrating = -1,
|
||||
bool sortdescending = false)
|
||||
{
|
||||
string whereClause = "";
|
||||
string havingClause = "";
|
||||
@@ -41,6 +65,20 @@ namespace gaseous_server.Controllers
|
||||
havingClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (minrating != -1)
|
||||
{
|
||||
string ratingTempMinVal = "totalRating >= @totalMinRating";
|
||||
whereParams.Add("@totalMinRating", minrating);
|
||||
havingClauses.Add(ratingTempMinVal);
|
||||
}
|
||||
|
||||
if (maxrating != -1)
|
||||
{
|
||||
string ratingTempMaxVal = "totalRating <= @totalMaxRating";
|
||||
whereParams.Add("@totalMaxRating", maxrating);
|
||||
havingClauses.Add(ratingTempMaxVal);
|
||||
}
|
||||
|
||||
if (platform.Length > 0)
|
||||
{
|
||||
tempVal = "Games_Roms.PlatformId IN (";
|
||||
@@ -77,6 +115,60 @@ namespace gaseous_server.Controllers
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (gamemode.Length > 0)
|
||||
{
|
||||
tempVal = "(";
|
||||
string[] gameModeClauseItems = gamemode.Split(",");
|
||||
for (int i = 0; i < gameModeClauseItems.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string gameModeLabel = "@GameMode" + i;
|
||||
tempVal += "JSON_CONTAINS(Game.GameModes, " + gameModeLabel + ", '$')";
|
||||
whereParams.Add(gameModeLabel, gameModeClauseItems[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (playerperspective.Length > 0)
|
||||
{
|
||||
tempVal = "(";
|
||||
string[] playerPerspectiveClauseItems = playerperspective.Split(",");
|
||||
for (int i = 0; i < playerPerspectiveClauseItems.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string playerPerspectiveLabel = "@PlayerPerspective" + i;
|
||||
tempVal += "JSON_CONTAINS(Game.PlayerPerspectives, " + playerPerspectiveLabel + ", '$')";
|
||||
whereParams.Add(playerPerspectiveLabel, playerPerspectiveClauseItems[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
if (theme.Length > 0)
|
||||
{
|
||||
tempVal = "(";
|
||||
string[] themeClauseItems = theme.Split(",");
|
||||
for (int i = 0; i < themeClauseItems.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
tempVal += " AND ";
|
||||
}
|
||||
string themeLabel = "@Theme" + i;
|
||||
tempVal += "JSON_CONTAINS(Game.Themes, " + themeLabel + ", '$')";
|
||||
whereParams.Add(themeLabel, themeClauseItems[i]);
|
||||
}
|
||||
tempVal += ")";
|
||||
whereClauses.Add(tempVal);
|
||||
}
|
||||
|
||||
// build where clause
|
||||
if (whereClauses.Count > 0)
|
||||
{
|
||||
@@ -124,7 +216,7 @@ namespace gaseous_server.Controllers
|
||||
RetVal.Add(Classes.Metadata.Games.GetGame(dr));
|
||||
}
|
||||
|
||||
return Ok(RetVal);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -136,7 +228,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, forceRefresh);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, forceRefresh, false, forceRefresh);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
@@ -162,7 +254,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (gameObject.AlternativeNames != null)
|
||||
{
|
||||
@@ -193,7 +285,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (gameObject.AgeRatings != null)
|
||||
{
|
||||
@@ -303,7 +395,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
List<Artwork> artworks = new List<Artwork>();
|
||||
if (gameObject.Artworks != null)
|
||||
@@ -332,7 +424,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -365,7 +457,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -420,7 +512,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null)
|
||||
{
|
||||
IGDB.Models.Cover coverObject = Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
||||
@@ -452,7 +544,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Cover.png");
|
||||
if (System.IO.File.Exists(coverFilePath)) {
|
||||
@@ -492,7 +584,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null)
|
||||
{
|
||||
List<IGDB.Models.Genre> genreObjects = new List<Genre>();
|
||||
@@ -528,7 +620,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null)
|
||||
{
|
||||
List<Dictionary<string, object>> icObjects = new List<Dictionary<string, object>>();
|
||||
@@ -571,7 +663,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null)
|
||||
{
|
||||
List<Dictionary<string, object>> icObjects = new List<Dictionary<string, object>>();
|
||||
@@ -611,7 +703,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
InvolvedCompany involvedCompany = Classes.Metadata.InvolvedCompanies.GetInvolvedCompanies(CompanyId);
|
||||
Company company = Classes.Metadata.Companies.GetCompanies(involvedCompany.Company.Id);
|
||||
@@ -655,7 +747,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
List<Classes.Roms.GameRomItem> roms = Classes.Roms.GetRoms(GameId);
|
||||
|
||||
@@ -676,7 +768,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId == GameId)
|
||||
@@ -702,7 +794,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId == GameId)
|
||||
@@ -729,7 +821,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId == GameId)
|
||||
@@ -757,7 +849,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId != GameId)
|
||||
@@ -792,7 +884,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId != GameId || rom.Name != FileName)
|
||||
@@ -864,7 +956,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
List<Screenshot> screenshots = new List<Screenshot>();
|
||||
if (gameObject.Screenshots != null)
|
||||
@@ -893,7 +985,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null) {
|
||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
||||
if (screenshotObject != null)
|
||||
@@ -924,7 +1016,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
||||
|
||||
@@ -967,7 +1059,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false);
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
List<GameVideo> videos = new List<GameVideo>();
|
||||
if (gameObject.Videos != null)
|
||||
|
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_tools;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -49,6 +51,22 @@ namespace gaseous_server.Controllers
|
||||
return ReturnValue;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Version")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Version GetSystemVersion() {
|
||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("VersionFile")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public FileContentResult GetSystemVersionAsFile() {
|
||||
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\"";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
||||
return File(bytes, "text/javascript");
|
||||
}
|
||||
|
||||
private SystemInfo.PathItem GetDisk(string Path)
|
||||
{
|
||||
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
|
||||
@@ -63,6 +81,12 @@ namespace gaseous_server.Controllers
|
||||
|
||||
public class SystemInfo
|
||||
{
|
||||
public Version ApplicationVersion {
|
||||
get
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||
}
|
||||
}
|
||||
public List<PathItem>? Paths { get; set; }
|
||||
public long DatabaseSize { get; set; }
|
||||
public List<PlatformStatisticsItem>? PlatformStatistics { get; set; }
|
||||
|
@@ -9,20 +9,22 @@ namespace gaseous_server
|
||||
|
||||
public class QueueItem
|
||||
{
|
||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval)
|
||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval, bool AllowManualStart = true)
|
||||
{
|
||||
_ItemType = ItemType;
|
||||
_ItemState = QueueItemState.NeverStarted;
|
||||
_LastRunTime = DateTime.UtcNow.AddMinutes(ExecutionInterval);
|
||||
_Interval = ExecutionInterval;
|
||||
_AllowManualStart = AllowManualStart;
|
||||
}
|
||||
|
||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval, List<QueueItemType> Blocks)
|
||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval, List<QueueItemType> Blocks, bool AllowManualStart = true)
|
||||
{
|
||||
_ItemType = ItemType;
|
||||
_ItemState = QueueItemState.NeverStarted;
|
||||
_LastRunTime = DateTime.UtcNow.AddMinutes(ExecutionInterval);
|
||||
_Interval = ExecutionInterval;
|
||||
_AllowManualStart = AllowManualStart;
|
||||
_Blocks = Blocks;
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ namespace gaseous_server
|
||||
private string _LastResult = "";
|
||||
private string? _LastError = null;
|
||||
private bool _ForceExecute = false;
|
||||
private bool _AllowManualStart = true;
|
||||
private List<QueueItemType> _Blocks = new List<QueueItemType>();
|
||||
|
||||
public QueueItemType ItemType => _ItemType;
|
||||
@@ -50,6 +53,7 @@ namespace gaseous_server
|
||||
public string LastResult => _LastResult;
|
||||
public string? LastError => _LastError;
|
||||
public bool Force => _ForceExecute;
|
||||
public bool AllowManualStart => _AllowManualStart;
|
||||
public List<QueueItemType> Blocks => _Blocks;
|
||||
|
||||
public void Execute()
|
||||
@@ -96,6 +100,10 @@ namespace gaseous_server
|
||||
Classes.ImportGame.LibraryScan();
|
||||
break;
|
||||
|
||||
case QueueItemType.CollectionCompiler:
|
||||
Logging.Log(Logging.LogType.Information, "Timered Event", "Starting Collection Compiler");
|
||||
Classes.Collections.CompileCollections();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -125,7 +133,8 @@ namespace gaseous_server
|
||||
TitleIngestor,
|
||||
MetadataRefresh,
|
||||
OrganiseLibrary,
|
||||
LibraryScan
|
||||
LibraryScan,
|
||||
CollectionCompiler
|
||||
}
|
||||
|
||||
public enum QueueItemState
|
||||
|
@@ -1,11 +1,13 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using gaseous_server;
|
||||
using gaseous_tools;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Startup", "Starting Gaseous Server");
|
||||
Logging.Log(Logging.LogType.Information, "Startup", "Starting Gaseous Server " + Assembly.GetExecutingAssembly().GetName().Version);
|
||||
|
||||
// set up db
|
||||
Database db = new gaseous_tools.Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
@@ -83,7 +85,31 @@ builder.Services.Configure<FormOptions>(options =>
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Version = "v1",
|
||||
Title = "Gaseous Server API",
|
||||
Description = "An API for managing the Gaseous Server",
|
||||
TermsOfService = new Uri("https://github.com/gaseous-project/gaseous-server"),
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "GitHub Repository",
|
||||
Url = new Uri("https://github.com/gaseous-project/gaseous-server")
|
||||
},
|
||||
License = new OpenApiLicense
|
||||
{
|
||||
Name = "Gaseous Server License",
|
||||
Url = new Uri("https://github.com/gaseous-project/gaseous-server/blob/main/LICENSE")
|
||||
}
|
||||
});
|
||||
|
||||
// using System.Reflection;
|
||||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||
}
|
||||
);
|
||||
builder.Services.AddHostedService<TimedHostedService>();
|
||||
|
||||
var app = builder.Build();
|
||||
@@ -114,7 +140,7 @@ app.MapControllers();
|
||||
Config.LibraryConfiguration.InitLibrary();
|
||||
|
||||
// insert unknown platform and game if not present
|
||||
gaseous_server.Classes.Metadata.Games.GetGame(0, false, false);
|
||||
gaseous_server.Classes.Metadata.Games.GetGame(0, false, false, false);
|
||||
gaseous_server.Classes.Metadata.Platforms.GetPlatform(0);
|
||||
|
||||
// organise library
|
||||
@@ -145,6 +171,7 @@ ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary
|
||||
})
|
||||
);
|
||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(ProcessQueue.QueueItemType.CollectionCompiler, 5, false));
|
||||
|
||||
// start the app
|
||||
app.Run();
|
||||
|
@@ -87,7 +87,15 @@
|
||||
],
|
||||
"WebEmulator": {
|
||||
"Type": "EmulatorJS",
|
||||
"Core": "segaMD"
|
||||
"Core": "segaMD",
|
||||
"Bios": [
|
||||
{
|
||||
"hash": "45e298905a08f9cfb38fd504cd6dbc84",
|
||||
"description": "MegaDrive TMSS startup ROM",
|
||||
"filename": "bios_MD.bin",
|
||||
"region": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -98,7 +106,9 @@
|
||||
"N64"
|
||||
],
|
||||
"KnownFileExtensions": [
|
||||
".Z64"
|
||||
".Z64",
|
||||
".V64",
|
||||
".N64"
|
||||
],
|
||||
"WebEmulator": {
|
||||
"Type": "EmulatorJS",
|
||||
@@ -110,20 +120,32 @@
|
||||
"IGDBName": "Nintendo Entertainment System",
|
||||
"AlternateNames": [
|
||||
"Nintendo Entertainment System",
|
||||
"NES"
|
||||
"NES",
|
||||
"Nintendo Famicom & Entertainment System"
|
||||
],
|
||||
"KnownFileExtensions": [
|
||||
".NES",
|
||||
".FDS",
|
||||
".FIG",
|
||||
".MGD",
|
||||
".SFC",
|
||||
".SMC",
|
||||
".SWC"
|
||||
".NEZ",
|
||||
".UNF",
|
||||
".UNIF"
|
||||
],
|
||||
"WebEmulator": {
|
||||
"Type": "EmulatorJS",
|
||||
"Core": "nes"
|
||||
"Core": "nes",
|
||||
"Bios": [
|
||||
{
|
||||
"hash": "ca30b50f880eb660a320674ed365ef7a",
|
||||
"description": "Family Computer Disk System BIOS - Required for Famicom Disk System emulation",
|
||||
"filename": "disksys.rom",
|
||||
"region": ""
|
||||
},
|
||||
{
|
||||
"hash": "7f98d77d7a094ad7d069b74bd553ec98",
|
||||
"description": "Game Genie add-on cartridge - Required for Game Genei Add-on emulation (Only supported on the fceumm core)",
|
||||
"filename": "gamegenie.nes",
|
||||
"region": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -135,7 +157,10 @@
|
||||
"Super Nintendo",
|
||||
"SNES"
|
||||
],
|
||||
"KnownFileExtensions": [],
|
||||
"KnownFileExtensions": [
|
||||
".SFC",
|
||||
".SMC"
|
||||
],
|
||||
"WebEmulator": {
|
||||
"Type": "EmulatorJS",
|
||||
"Core": "snes"
|
||||
|
@@ -13,10 +13,14 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\net7.0\gaseous-server.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\net7.0\gaseous-server.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.8" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.9" />
|
||||
<PackageReference Include="IGDB" Version="2.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -88,24 +92,21 @@
|
||||
<Folder Include="Classes\" />
|
||||
<Folder Include="Classes\SignatureIngestors\" />
|
||||
<Folder Include="Support\" />
|
||||
<Folder Include="wwwroot\" />
|
||||
<Folder Include="Classes\Metadata\" />
|
||||
<Folder Include="Assets\" />
|
||||
<Folder Include="Assets\Ratings\" />
|
||||
<Folder Include="Assets\Ratings\ESRB\" />
|
||||
<Folder Include="Assets\Ratings\ACB\" />
|
||||
<Folder Include="Assets\Ratings\PEGI\" />
|
||||
<Folder Include="wwwroot\scripts\" />
|
||||
<Folder Include="wwwroot\images\" />
|
||||
<Folder Include="wwwroot\styles\" />
|
||||
<Folder Include="wwwroot\pages\" />
|
||||
<Folder Include="Assets\Ratings\CERO\" />
|
||||
<Folder Include="Assets\Ratings\USK\" />
|
||||
<Folder Include="Assets\Ratings\GRAC\" />
|
||||
<Folder Include="Assets\Ratings\CLASS_IND\" />
|
||||
<Folder Include="wwwroot\fonts\" />
|
||||
<Folder Include="wwwroot\pages\dialogs\" />
|
||||
<Folder Include="wwwroot\pages\settings\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wwwroot\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\gaseous-tools\gaseous-tools.csproj">
|
||||
@@ -118,10 +119,6 @@
|
||||
<GlobalPropertiesToRemove></GlobalPropertiesToRemove>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Support\PlatformMap.json" />
|
||||
<Content Remove="wwwroot\pages\settings\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Support\PlatformMap.json" Condition="'$(ExcludeConfigFilesFromBuildOutput)'!='true'">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
|
BIN
gaseous-server/wwwroot/images/CollectionsWallpaper.jpg
Normal file
After Width: | Height: | Size: 408 KiB |
11
gaseous-server/wwwroot/images/IGDB_logo.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="249.44 647.1 1461.24 702.85">
|
||||
<title>IGDB logo</title>
|
||||
<g id="text_logo">
|
||||
<path fill="#000000" d=" M 249.44 647.14 C 736.51 647.13 1223.59 647.21 1710.67 647.10 C 1710.68 881.38 1710.69 1115.67 1710.66 1349.95 C 1615.86 1334.68 1520.63 1321.89 1425.05 1312.53 C 1080.16 1278.28 731.31 1284.02 387.73 1329.60 C 341.52 1335.59 295.47 1342.74 249.44 1349.92 C 249.43 1115.66 249.45 881.40 249.44 647.14 M 292.45 690.16 C 292.47 893.35 292.45 1096.55 292.45 1299.74 C 747.32 1230.12 1212.80 1230.06 1667.66 1299.76 C 1667.69 1096.55 1667.67 893.34 1667.67 690.13 C 1209.26 690.20 750.85 690.15 292.45 690.16 Z"/>
|
||||
<path fill="#000000" d=" M 606.98 849.96 C 636.79 820.94 678.61 805.48 720.03 806.13 C 748.31 806.03 777.18 810.46 802.61 823.37 C 815.72 829.91 827.70 838.49 838.88 847.92 C 824.81 864.91 810.62 881.79 796.71 898.90 C 788.34 892.63 780.20 885.94 770.94 880.98 C 752.35 870.49 730.45 866.86 709.32 868.40 C 683.46 870.61 659.80 886.20 645.79 907.79 C 627.73 934.91 624.92 970.60 635.86 1000.97 C 642.48 1019.42 655.12 1035.79 671.77 1046.24 C 688.33 1056.88 708.44 1061.15 727.96 1059.98 C 747.98 1059.21 768.36 1053.75 784.66 1041.78 C 784.50 1027.38 784.66 1012.97 784.58 998.57 C 762.15 998.63 739.71 998.55 717.28 998.61 C 717.23 979.29 717.40 959.97 717.20 940.66 C 761.32 940.38 805.45 940.76 849.57 940.47 C 849.84 984.58 849.54 1028.70 849.72 1072.81 C 819.35 1099.03 781.02 1116.23 740.99 1120.14 C 701.91 1124.43 660.71 1117.24 627.40 1095.69 C 600.71 1078.68 580.09 1052.59 569.30 1022.87 C 558.65 993.63 556.55 961.41 562.53 930.93 C 568.76 900.29 584.34 871.56 606.98 849.96 Z"/>
|
||||
<path fill="#000000" d=" M 412.22 811.37 C 434.59 811.42 456.96 811.33 479.33 811.42 C 479.28 912.90 479.33 1014.39 479.31 1115.88 C 456.95 1115.87 434.59 1115.84 412.23 1115.89 C 412.22 1014.39 412.24 912.88 412.22 811.37 Z"/>
|
||||
<path fill="#000000" d=" M 931.25 811.38 C 972.17 811.39 1013.09 811.38 1054.01 811.39 C 1091.21 811.80 1128.88 823.34 1157.99 846.93 C 1183.44 867.28 1201.49 896.55 1208.37 928.40 C 1216.70 966.86 1211.27 1008.80 1190.62 1042.63 C 1174.23 1069.90 1148.49 1091.13 1119.07 1103.04 C 1098.46 1111.41 1076.23 1115.81 1053.98 1115.87 C 1013.08 1115.87 972.17 1115.85 931.26 1115.88 C 931.26 1014.38 931.28 912.88 931.25 811.38 M 998.55 871.86 C 998.45 933.04 998.56 994.22 998.49 1055.41 C 1011.33 1055.39 1024.18 1055.40 1037.02 1055.40 C 1047.36 1055.32 1057.79 1055.89 1068.03 1053.99 C 1088.10 1050.87 1107.44 1041.22 1120.71 1025.65 C 1132.31 1012.31 1139.05 995.20 1141.08 977.75 C 1142.97 960.03 1141.47 941.67 1134.60 925.11 C 1127.53 907.51 1114.31 892.45 1097.61 883.42 C 1082.53 875.02 1065.11 871.85 1047.99 871.84 C 1031.51 871.88 1015.03 871.84 998.55 871.86 Z"/>
|
||||
<path fill="#000000" d=" M 1288.80 811.57 C 1330.15 811.13 1371.54 811.51 1412.90 811.38 C 1424.26 811.54 1435.65 810.91 1446.97 812.08 C 1467.08 813.95 1487.46 819.82 1503.55 832.45 C 1517.54 843.24 1527.36 859.35 1530.07 876.86 C 1532.03 893.42 1531.12 911.06 1522.97 925.99 C 1516.04 939.38 1504.10 949.32 1491.26 956.78 C 1508.37 963.22 1525.29 972.72 1535.94 988.04 C 1545.87 1002.19 1548.77 1020.07 1547.80 1037.03 C 1547.40 1054.27 1541.09 1071.56 1529.28 1084.27 C 1517.35 1097.30 1500.95 1105.31 1484.12 1109.96 C 1470.05 1113.75 1455.50 1115.70 1440.94 1115.84 C 1390.26 1115.88 1339.58 1115.89 1288.90 1115.84 C 1288.82 1014.41 1289.01 912.99 1288.80 811.57 M 1354.30 870.27 C 1354.37 891.67 1354.24 913.08 1354.36 934.49 C 1376.56 934.35 1398.76 934.52 1420.96 934.40 C 1431.03 933.86 1441.46 932.43 1450.36 927.35 C 1457.39 923.37 1462.73 916.24 1463.78 908.14 C 1465.26 899.01 1463.69 888.76 1457.02 881.93 C 1449.00 873.67 1437.04 871.03 1425.95 870.37 C 1402.07 870.17 1378.18 870.37 1354.30 870.27 M 1354.29 990.41 C 1354.32 1012.64 1354.35 1034.89 1354.27 1057.13 C 1375.50 1057.33 1396.74 1057.15 1417.98 1057.21 C 1428.58 1057.08 1439.29 1057.80 1449.79 1055.91 C 1458.99 1054.43 1468.48 1050.97 1474.69 1043.71 C 1480.95 1036.44 1482.26 1026.10 1480.69 1016.93 C 1479.44 1009.15 1474.55 1002.16 1467.79 998.15 C 1458.62 992.57 1447.64 990.81 1437.06 990.45 C 1409.47 990.37 1381.88 990.45 1354.29 990.41 Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
BIN
gaseous-server/wwwroot/images/TOSEC_logo.gif
Normal file
After Width: | Height: | Size: 1.4 KiB |
4
gaseous-server/wwwroot/images/collections.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.0656 8.00389L11.25 7.99875H18.75C20.483 7.99875 21.8992 9.3552 21.9949 11.0643L22 11.2487V18.7487C22 20.4818 20.6435 21.898 18.9344 21.9936L18.75 21.9987H11.25C9.51697 21.9987 8.10075 20.6423 8.00515 18.9332L8 18.7487V11.2487C8 9.51571 9.35646 8.0995 11.0656 8.00389ZM18.75 9.49875H11.25C10.3318 9.49875 9.57881 10.2059 9.5058 11.1052L9.5 11.2487V18.7487C9.5 19.6669 10.2071 20.4199 11.1065 20.4929L11.25 20.4987H18.75C19.6682 20.4987 20.4212 19.7916 20.4942 18.8923L20.5 18.7487V11.2487C20.5 10.2822 19.7165 9.49875 18.75 9.49875ZM15 11C15.4142 11 15.75 11.3358 15.75 11.75V14.248L18.25 14.2487C18.6642 14.2487 19 14.5845 19 14.9987C19 15.413 18.6642 15.7487 18.25 15.7487L15.75 15.748V18.25C15.75 18.6642 15.4142 19 15 19C14.5858 19 14.25 18.6642 14.25 18.25V15.748L11.75 15.7487C11.3358 15.7487 11 15.413 11 14.9987C11 14.5845 11.3358 14.2487 11.75 14.2487L14.25 14.248V11.75C14.25 11.3358 14.5858 11 15 11ZM15.5818 4.23284L15.6345 4.40964L16.327 6.998H14.774L14.1856 4.79787C13.9355 3.86431 12.9759 3.31029 12.0423 3.56044L4.79787 5.50158C3.91344 5.73856 3.36966 6.61227 3.52756 7.49737L3.56044 7.64488L5.50158 14.8893C5.69372 15.6064 6.30445 16.0996 7.00045 16.1764L7.00056 17.6816C5.69932 17.6051 4.52962 16.7445 4.10539 15.4544L4.05269 15.2776L2.11155 8.03311C1.66301 6.35913 2.6067 4.6401 4.23284 4.10539L4.40964 4.05269L11.6541 2.11155C13.3281 1.66301 15.0471 2.6067 15.5818 4.23284Z" fill="#212121"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
3
gaseous-server/wwwroot/images/delete.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M960 160h-291.2a160 160 0 0 0-313.6 0H64a32 32 0 0 0 0 64h896a32 32 0 0 0 0-64zM512 96a96 96 0 0 1 90.24 64h-180.48A96 96 0 0 1 512 96zM844.16 290.56a32 32 0 0 0-34.88 6.72A32 32 0 0 0 800 320a32 32 0 1 0 64 0 33.6 33.6 0 0 0-9.28-22.72 32 32 0 0 0-10.56-6.72zM832 416a32 32 0 0 0-32 32v96a32 32 0 0 0 64 0v-96a32 32 0 0 0-32-32zM832 640a32 32 0 0 0-32 32v224a32 32 0 0 1-32 32H256a32 32 0 0 1-32-32V320a32 32 0 0 0-64 0v576a96 96 0 0 0 96 96h512a96 96 0 0 0 96-96v-224a32 32 0 0 0-32-32z" fill="#231815" /><path d="M384 768V352a32 32 0 0 0-64 0v416a32 32 0 0 0 64 0zM544 768V352a32 32 0 0 0-64 0v416a32 32 0 0 0 64 0zM704 768V352a32 32 0 0 0-64 0v416a32 32 0 0 0 64 0z" fill="#231815" /></svg>
|
After Width: | Height: | Size: 946 B |
2
gaseous-server/wwwroot/images/download.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M24 12a5 5 0 0 1-5 5h-2v-1h2a3.99 3.99 0 0 0 .623-7.934l-.79-.124-.052-.798a5.293 5.293 0 0 0-10.214-1.57L8.17 6.59l-.977-.483A2.277 2.277 0 0 0 6.19 5.87a2.18 2.18 0 0 0-1.167.339 2.206 2.206 0 0 0-.98 1.395l-.113.505-.476.2A4 4 0 0 0 5 16h3v1H5a5 5 0 0 1-1.934-9.611 3.21 3.21 0 0 1 1.422-2.025 3.17 3.17 0 0 1 1.702-.493 3.268 3.268 0 0 1 1.446.34 6.293 6.293 0 0 1 12.143 1.867A4.988 4.988 0 0 1 24 12zm-11-1h-1v10.292l-2.646-2.646-.707.707 3.854 3.854 3.853-3.852-.707-.707L13 21.294z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
|
After Width: | Height: | Size: 752 B |
5
gaseous-server/wwwroot/images/edit.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.2799 6.40005L11.7399 15.94C10.7899 16.89 7.96987 17.33 7.33987 16.7C6.70987 16.07 7.13987 13.25 8.08987 12.3L17.6399 2.75002C17.8754 2.49308 18.1605 2.28654 18.4781 2.14284C18.7956 1.99914 19.139 1.92124 19.4875 1.9139C19.8359 1.90657 20.1823 1.96991 20.5056 2.10012C20.8289 2.23033 21.1225 2.42473 21.3686 2.67153C21.6147 2.91833 21.8083 3.21243 21.9376 3.53609C22.0669 3.85976 22.1294 4.20626 22.1211 4.55471C22.1128 4.90316 22.0339 5.24635 21.8894 5.5635C21.7448 5.88065 21.5375 6.16524 21.2799 6.40005V6.40005Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11 4H6C4.93913 4 3.92178 4.42142 3.17163 5.17157C2.42149 5.92172 2 6.93913 2 8V18C2 19.0609 2.42149 20.0783 3.17163 20.8284C3.92178 21.5786 4.93913 22 6 22H17C19.21 22 20 20.2 20 18V13" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
gaseous-server/wwwroot/images/gamebg1.jpg
Normal file
After Width: | Height: | Size: 3.4 MiB |
BIN
gaseous-server/wwwroot/images/gamebg2.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
gaseous-server/wwwroot/images/gamebg3.jpg
Normal file
After Width: | Height: | Size: 262 KiB |
12
gaseous-server/wwwroot/images/library.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>library</title>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Combined-Shape" fill="#000000" transform="translate(42.666667, 85.333333)">
|
||||
<path d="M3.55271368e-14,298.666667 L426.666667,298.666667 L426.666667,341.333333 L3.55271368e-14,341.333333 L3.55271368e-14,298.666667 Z M42.6666667,1.42108547e-14 L106.666667,1.42108547e-14 L106.666667,277.333333 L42.6666667,277.333333 L42.6666667,1.42108547e-14 Z M128,21.3333333 L192,21.3333333 L192,277.333333 L128,277.333333 L128,21.3333333 Z M288.933802,36.9522088 L351.961498,25.8387255 L399.909944,277.333333 L330.641827,277.70319 L288.933802,36.9522088 Z M213.333333,21.3333333 L277.333333,21.3333333 L277.333333,277.333333 L213.333333,277.333333 L213.333333,21.3333333 Z">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
gaseous-server/wwwroot/images/librarybg.jpg
Normal file
After Width: | Height: | Size: 218 KiB |
4
gaseous-server/wwwroot/images/refresh.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 3V8M3 8H8M3 8L6 5.29168C7.59227 3.86656 9.69494 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.71683 21 4.13247 18.008 3.22302 14" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 473 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 20 KiB |
@@ -2,11 +2,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link type="text/css" rel="stylesheet" href="/styles/style.css" />
|
||||
<script src="/api/v1/System/VersionFile"></script>
|
||||
<link type="text/css" rel="stylesheet" dat-href="/styles/style.css" />
|
||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
||||
<script src="/scripts/moment.js"></script>
|
||||
<link href="/styles/select2.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/styles/dropzone.min.css" type="text/css" />
|
||||
<link href="/styles/dropzone.min.css" rel="stylesheet" type="text/css" />
|
||||
<script src="/scripts/jquery.lazy.min.js"></script>
|
||||
<script src="/scripts/jquery.lazy.plugins.min.js"></script>
|
||||
<script src="/scripts/select2.min.js"></script>
|
||||
@@ -19,22 +20,54 @@
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<title>Gaseous Games</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
|
||||
// update links
|
||||
var headLinks = document.getElementsByTagName('link');
|
||||
for (var i = 0; i < headLinks.length; i++) {
|
||||
if (headLinks[i].getAttribute('dat-href') && headLinks[i].rel == "stylesheet") {
|
||||
var newLink = document.createElement('link');
|
||||
newLink.rel = "stylesheet";
|
||||
newLink.href = headLinks[i].getAttribute('dat-href') + '?v=' + AppVersion;
|
||||
newLink.type = "text/css";
|
||||
|
||||
headLinks[i].parentElement.removeChild(headLinks[i]);
|
||||
head.appendChild(newLink);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="banner_icon" onclick="window.location.href = '/index.html';">
|
||||
<img src="/images/logo.png" alt="Gaseous" id="banner_icon_image" />
|
||||
</div>
|
||||
<div id="banner_header">
|
||||
<div id="banner_header_label">Gaseous Games</div>
|
||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';" class="banner_button">
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" class="banner_button_image" />
|
||||
<span id="banner_system_label">Settings</span>
|
||||
</div>
|
||||
<div id="banner_upload" onclick="showDialog('upload');">
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image" />
|
||||
<span id="banner_upload_label">Upload Games</span>
|
||||
|
||||
<div id="banner_upload" onclick="showDialog('upload');" class="banner_button">
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image" class="banner_button_image" />
|
||||
<span id="banner_upload_label">Upload</span>
|
||||
</div>
|
||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';">
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" />
|
||||
|
||||
<div id="banner_collections" onclick="window.location.href = '/index.html?page=collections';" class="banner_button">
|
||||
<img src="/images/collections.svg" alt="Collections" title="Collections" id="banner_collections_image" class="banner_button_image" />
|
||||
<span id="banner_collections_label">Collections</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_library" onclick="window.location.href = '/index.html';" class="banner_button">
|
||||
<img src="/images/library.svg" alt="Library" title="Library" id="banner_library_image" class="banner_button_image" />
|
||||
<span id="banner_library_label">Library</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous Games</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
@@ -64,6 +97,7 @@
|
||||
|
||||
<script type="text/javascript">var modalVariables = null;
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
var myParam = getQueryString('page', 'string');
|
||||
|
||||
@@ -71,7 +105,8 @@
|
||||
myParam = 'home';
|
||||
}
|
||||
|
||||
$('#content').load('/pages/' + myParam + '.html');
|
||||
});</script>
|
||||
$('#content').load('/pages/' + myParam + '.html?v=' + AppVersion);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -23,5 +23,8 @@
|
||||
EJS_DEBUG_XX = false;
|
||||
|
||||
EJS_startOnLoaded = false;
|
||||
|
||||
EJS_backgroundImage = emuBackground;
|
||||
EJS_backgroundBlur = true;
|
||||
</script>
|
||||
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
80
gaseous-server/wwwroot/pages/collections.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<div id="bgImage" style="background-image: url('/images/CollectionsWallpaper.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="gametitle">
|
||||
<h1 id="gametitle_label">Collections</h1>
|
||||
</div>
|
||||
<button id="collection_new" style="float: right;" onclick="showDialog('collectionedit');">New Collection</button>
|
||||
<div id="collection_table_location">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings_photocredit">
|
||||
Wallpaper by <a href="https://wallpapercave.com/u/andrea16" class="romlink">andrea16</a> / <a href="https://wallpapercave.com/w/wp5206111" class="romlink">Wallpaper Cave</a>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
GetCollections();
|
||||
|
||||
function GetCollections() {
|
||||
ajaxCall('/api/v1/Collections', 'GET', function (result) {
|
||||
if (result) {
|
||||
var targetDiv = document.getElementById('collection_table_location');
|
||||
targetDiv.innerHTML = '';
|
||||
|
||||
var newTable = document.createElement('table');
|
||||
newTable.id = 'romtable';
|
||||
newTable.className = 'romtable';
|
||||
newTable.setAttribute('cellspacing', 0);
|
||||
newTable.appendChild(createTableRow(true, [ 'Name', 'Description', 'Download Status', 'Size', '' ]));
|
||||
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var statusText = result[i].buildStatus;
|
||||
var downloadLink = '';
|
||||
var packageSize = '-';
|
||||
switch (result[i].buildStatus) {
|
||||
case 'NoStatus':
|
||||
statusText = '-';
|
||||
break;
|
||||
case "WaitingForBuild":
|
||||
statusText = 'Build pending';
|
||||
break;
|
||||
case "Building":
|
||||
statusText = 'Building';
|
||||
break;
|
||||
case "Completed":
|
||||
statusText = 'Available';
|
||||
downloadLink = '<a href="/api/v1/Collections/' + result[i].id + '/Roms/Zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||
packageSize = formatBytes(result[i].collectionBuiltSizeBytes);
|
||||
break;
|
||||
case "Failed":
|
||||
statusText = 'Build error';
|
||||
break;
|
||||
default:
|
||||
statusText = result[i].buildStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
var editButton = '<a href="#" onclick="showDialog(\'collectionedit\', ' + result[i].id + ');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
||||
|
||||
var deleteButton = '<a href="#" onclick="showSubDialog(\'collectiondelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
||||
|
||||
var newRow = [
|
||||
result[i].name,
|
||||
result[i].description,
|
||||
statusText,
|
||||
packageSize,
|
||||
'<div style="text-align: right;">' + downloadLink + editButton + deleteButton + '</div>'
|
||||
];
|
||||
|
||||
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
|
||||
}
|
||||
|
||||
targetDiv.appendChild(newTable);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
27
gaseous-server/wwwroot/pages/dialogs/collectiondelete.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<p>Are you sure you want to delete this collection?</p>
|
||||
<p><strong>Warning:</strong> This cannot be undone!</p>
|
||||
<div style="width: 100%; text-align: center;">
|
||||
<div style="display: inline-block; margin-right: 20px;">
|
||||
<button class="redbutton" value="Delete" onclick="deleteCollection();">Delete</button>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-left: 20px;">
|
||||
<button value="Cancel" onclick="closeSubDialog();">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function deleteCollection() {
|
||||
ajaxCall(
|
||||
'/api/v1/Collections/' + subModalVariables,
|
||||
'DELETE',
|
||||
function (result) {
|
||||
GetCollections();
|
||||
closeSubDialog();
|
||||
},
|
||||
function (error) {
|
||||
GetCollections();
|
||||
closeSubDialog();
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
494
gaseous-server/wwwroot/pages/dialogs/collectionedit.html
Normal file
@@ -0,0 +1,494 @@
|
||||
<input id="collection_name" type="text" placeholder="Collection Name" style="width: 80%; font-size: 2em;" />
|
||||
<input id="collection_description" type="text" placeholder="Description" style="width: 80%; margin-top: 5px;" />
|
||||
|
||||
<div style="position: absolute; top: 90px; right: 5px; left: 10px; bottom: 5px;">
|
||||
<div style="position: relative; width: 100%; height: 100%;">
|
||||
<table style="position: absolute; top: 0px; left: 0px; bottom: 0px; width: 40%;">
|
||||
<tr>
|
||||
<td>
|
||||
<h3>Filter</h3>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="collection_filter_box" style="position: absolute; top: 40px; left: 0px; bottom: 5px; width: 40%; max-width: 40%; overflow-x: scroll;">
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<th style="width: 25%;">Platforms</th>
|
||||
<td><select id="collection_platform" style="width: 100%;" multiple="multiple"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Genres</th>
|
||||
<td><select id="collection_genres" style="width: 100%;" multiple="multiple"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Players</th>
|
||||
<td><select id="collection_players" style="width: 100%;" multiple="multiple"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Player Perspectives</th>
|
||||
<td><select id="collection_playerperspectives" style="width: 100%;" multiple="multiple"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Themes</th>
|
||||
<td><select id="collection_themes" style="width: 100%;" multiple="multiple"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Rating</th>
|
||||
<td>
|
||||
<input id="collection_userrating_min" type="number" placeholder="0" min="0" max="100">
|
||||
<input id="collection_userrating_max" type="number" placeholder="100" min="0" max="100">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>Options</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Maximum ROMs per platform</th>
|
||||
<td><input id="collection_maxroms" type="number" placeholder="0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Maximum size per platform (bytes)</th>
|
||||
<td><input id="collection_maxplatformsize" type="number" placeholder="0" step="1048576" oninput="DisplayFormattedBytes('collection_maxplatformsize', 'maxplatformsize_label');"><span id="maxplatformsize_label" style="margin-left: 10px;"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Maximum collection size (bytes)</th>
|
||||
<td><input id="collection_maxcollectionsize" type="number" placeholder="0" step="1048576" oninput="DisplayFormattedBytes('collection_maxcollectionsize', 'maxcollectionsize_label');"><span id="maxcollectionsize_label" style="margin-left: 10px;"></span></td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<table style="position: absolute; top: 0px; right: 0px; bottom: 0px; width: 60%;">
|
||||
<tr>
|
||||
<td>
|
||||
<h3>Collection</h3>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="collectionedit_previewbox" style="position: absolute; top: 40px; right: 0px; bottom: 60px; width: 60%; overflow-x: scroll;">
|
||||
<div id="collectionedit_previewbox_content" style="margin: 5px;">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="collectionedit_previewbox_size" style="position: absolute; right: 10px; bottom: 30px; width: 60%; height: 20px; text-align: right;">
|
||||
|
||||
</div>
|
||||
<div id="collectionedit_previewbox_controls" style="position: absolute; right: 10px; bottom: 0px; width: 60%; height: 25px; text-align: right;">
|
||||
<button id="collectionedit_preview" onclick="GetPreview();">Preview</button>
|
||||
<button id="collectionedit_cancel" onclick="closeDialog();">Cancel</button>
|
||||
<button id="collectionedit_ok" onclick="SaveCollection();">Ok</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var headerToRemove = document.getElementById('modal-heading');
|
||||
if (headerToRemove) {
|
||||
headerToRemove.parentNode.removeChild(headerToRemove);
|
||||
}
|
||||
|
||||
var modalContent = document.getElementsByClassName('modal-content');
|
||||
if (!modalContent[0].classList.contains('collections_modal')) {
|
||||
modalContent[0].classList.add('collections_modal');
|
||||
}
|
||||
|
||||
// setup dropdowns
|
||||
$('#collection_platform').select2({
|
||||
ajax: {
|
||||
url: '/api/v1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['platforms'];
|
||||
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < filter.length; i++) {
|
||||
arr.push({
|
||||
id: filter[i].id,
|
||||
text: filter[i].name
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
results: arr
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#collection_genres').select2({
|
||||
ajax: {
|
||||
url: '/api/v1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['genres'];
|
||||
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < filter.length; i++) {
|
||||
arr.push({
|
||||
id: filter[i].id,
|
||||
text: filter[i].name
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
results: arr
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#collection_players').select2({
|
||||
ajax: {
|
||||
url: '/api/v1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['gamemodes'];
|
||||
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < filter.length; i++) {
|
||||
arr.push({
|
||||
id: filter[i].id,
|
||||
text: filter[i].name
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
results: arr
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#collection_playerperspectives').select2({
|
||||
ajax: {
|
||||
url: '/api/v1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['playerperspectives'];
|
||||
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < filter.length; i++) {
|
||||
arr.push({
|
||||
id: filter[i].id,
|
||||
text: filter[i].name
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
results: arr
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#collection_themes').select2({
|
||||
ajax: {
|
||||
url: '/api/v1/Filter',
|
||||
processResults: function (data) {
|
||||
var filter = data['themes'];
|
||||
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < filter.length; i++) {
|
||||
arr.push({
|
||||
id: filter[i].id,
|
||||
text: filter[i].name
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
results: arr
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (modalVariables) {
|
||||
// edit mode
|
||||
ajaxCall(
|
||||
'/api/v1/Collections/' + modalVariables,
|
||||
'GET',
|
||||
function(result) {
|
||||
if (result.name) { document.getElementById('collection_name').value = result.name; }
|
||||
if (result.description) { document.getElementById('collection_description').value = result.description; }
|
||||
if (result.minimumRating != -1) { document.getElementById('collection_userrating_min').value = result.minimumRating; }
|
||||
if (result.maximumRating != -1) { document.getElementById('collection_userrating_max').value = result.maximumRating; }
|
||||
if (result.maximumRomsPerPlatform != -1) { document.getElementById('collection_maxroms').value = result.maximumRomsPerPlatform; }
|
||||
if (result.maximumBytesPerPlatform != -1) { document.getElementById('collection_maxplatformsize').value = result.maximumBytesPerPlatform; }
|
||||
if (result.maximumCollectionSizeInBytes != -1) { document.getElementById('collection_maxcollectionsize').value = result.maximumCollectionSizeInBytes; }
|
||||
|
||||
// fill select2 controls
|
||||
$.ajax(
|
||||
{
|
||||
url: '/api/v1/Filter',
|
||||
type: 'GET',
|
||||
indexValue: result,
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
success: function (data) {
|
||||
// platforms
|
||||
for (var i = 0; i < data.platforms.length; i++) {
|
||||
if (this.indexValue.platforms.includes(data.platforms[i].id)) {
|
||||
var newOption = new Option(data.platforms[i].name, data.platforms[i].id, true, true);
|
||||
$('#collection_platform').append(newOption).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// genres
|
||||
for (var i = 0; i < data.genres.length; i++) {
|
||||
if (this.indexValue.genres.includes(data.genres[i].id)) {
|
||||
var newOption = new Option(data.genres[i].name, data.genres[i].id, true, true);
|
||||
$('#collection_genres').append(newOption).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// players
|
||||
for (var i = 0; i < data.gamemodes.length; i++) {
|
||||
if (this.indexValue.players.includes(data.gamemodes[i].id)) {
|
||||
var newOption = new Option(data.gamemodes[i].name, data.gamemodes[i].id, true, true);
|
||||
$('#collection_players').append(newOption).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// playerperspectives
|
||||
for (var i = 0; i < data.playerperspectives.length; i++) {
|
||||
if (this.indexValue.playerPerspectives.includes(data.playerperspectives[i].id)) {
|
||||
var newOption = new Option(data.playerperspectives[i].name, data.playerperspectives[i].id, true, true);
|
||||
$('#collection_playerperspectives').append(newOption).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// themes
|
||||
for (var i = 0; i < data.themes.length; i++) {
|
||||
if (this.indexValue.themes.includes(data.themes[i].id)) {
|
||||
var newOption = new Option(data.themes[i].name, data.themes[i].id, true, true);
|
||||
$('#collection_themes').append(newOption).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// generate preview
|
||||
GetPreview();
|
||||
},
|
||||
error: function (error) {
|
||||
console.log(`Error ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// new mode
|
||||
}
|
||||
|
||||
function SaveCollection() {
|
||||
var item = GenerateCollectionItem();
|
||||
if (modalVariables) {
|
||||
// existing object - save over the top
|
||||
item.id = modalVariables;
|
||||
ajaxCall(
|
||||
'/api/v1/Collections/' + modalVariables,
|
||||
'PATCH',
|
||||
function(result) {
|
||||
location.reload();
|
||||
},
|
||||
function(error) {
|
||||
alert(error);
|
||||
},
|
||||
JSON.stringify(item)
|
||||
);
|
||||
} else {
|
||||
// new object
|
||||
ajaxCall(
|
||||
'/api/v1/Collections',
|
||||
'POST',
|
||||
function(result) {
|
||||
location.reload();
|
||||
},
|
||||
function(error) {
|
||||
alert(error);
|
||||
},
|
||||
JSON.stringify(item)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function GenerateCollectionItem() {
|
||||
var platforms = GetDropDownIds('#collection_platform');
|
||||
var genres = GetDropDownIds('#collection_genres');
|
||||
var players = GetDropDownIds('#collection_players');
|
||||
var playerperspectives = GetDropDownIds('#collection_playerperspectives');
|
||||
var themes = GetDropDownIds('#collection_themes');
|
||||
|
||||
var item = {
|
||||
"name": document.getElementById('collection_name').value,
|
||||
"description": document.getElementById('collection_description').value,
|
||||
"platforms": platforms,
|
||||
"genres": genres,
|
||||
"players": players,
|
||||
"playerPerspectives": playerperspectives,
|
||||
"themes": themes,
|
||||
"minimumRating": GetNumberFieldValue('collection_userrating_min'),
|
||||
"maximumRating": GetNumberFieldValue('collection_userrating_max'),
|
||||
"maximumRomsPerPlatform": GetNumberFieldValue('collection_maxroms'),
|
||||
"maximumBytesPerPlatform": GetNumberFieldValue('collection_maxplatformsize'),
|
||||
"maximumCollectionSizeInBytes": GetNumberFieldValue('collection_maxcollectionsize')
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
function GetPreview() {
|
||||
var item = GenerateCollectionItem();
|
||||
|
||||
console.log(JSON.stringify(item));
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1/Collections/Preview',
|
||||
'POST',
|
||||
function(result) {
|
||||
DisplayPreview(result, 'collectionedit_previewbox_content');
|
||||
},
|
||||
function(error) {
|
||||
console.log(JSON.stringify(error));
|
||||
},
|
||||
JSON.stringify(item)
|
||||
);
|
||||
}
|
||||
|
||||
function GetDropDownIds(objectName) {
|
||||
var obj = $(objectName).select2('data');
|
||||
|
||||
if (obj.length > 0) {
|
||||
var ids = [];
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
ids.push(obj[i].id);
|
||||
}
|
||||
|
||||
return ids;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function GetNumberFieldValue(objectName) {
|
||||
var obj = document.getElementById(objectName);
|
||||
var objVal = obj.value;
|
||||
|
||||
if (objVal) {
|
||||
return objVal;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayPreview(data, targetDiv) {
|
||||
var container = document.getElementById(targetDiv);
|
||||
container.innerHTML = '';
|
||||
|
||||
if (data.collection) {
|
||||
var collectionTable = document.createElement('table');
|
||||
collectionTable.setAttribute('cellspacing', 0);
|
||||
collectionTable.style.width = '100%';
|
||||
|
||||
// loop the platforms
|
||||
for (var p = 0; p < data.collection.length; p++) {
|
||||
var platformItem = data.collection[p];
|
||||
|
||||
var platformLabelRow = document.createElement('tr');
|
||||
var platformLabelCell = document.createElement('th');
|
||||
platformLabelCell.setAttribute('colspan', 2);
|
||||
platformLabelCell.className = 'collections_preview_platform_header';
|
||||
platformLabelCell.innerHTML = '<span style="float: right;">' + formatBytes(platformItem.romSize) + '</span>' + platformItem.name;
|
||||
|
||||
platformLabelRow.appendChild(platformLabelCell);
|
||||
collectionTable.appendChild(platformLabelRow);
|
||||
|
||||
var bgaltindex = 0;
|
||||
|
||||
// loop the games
|
||||
for (var g = 0; g < platformItem.games.length; g++) {
|
||||
var gameItem = platformItem.games[g];
|
||||
|
||||
var bgalt = '';
|
||||
if (bgaltindex == 1) {
|
||||
bgaltindex = 0;
|
||||
bgalt = 'bgalt1';
|
||||
} else {
|
||||
bgaltindex = 1;
|
||||
bgalt = 'bgalt0';
|
||||
}
|
||||
|
||||
var gameItemRow = document.createElement('tr');
|
||||
gameItemRow.className = bgalt;
|
||||
|
||||
// game title
|
||||
var gameTitleCell = document.createElement('th');
|
||||
gameTitleCell.setAttribute('colspan', 2);
|
||||
gameTitleCell.className = 'collections_preview_gametitlecell';
|
||||
gameTitleCell.innerHTML = gameItem.name;
|
||||
|
||||
gameItemRow.appendChild(gameTitleCell);
|
||||
|
||||
// game cover
|
||||
var gameDetailRow = document.createElement('tr');
|
||||
gameDetailRow.className = bgalt;
|
||||
|
||||
var gameCoverCell = document.createElement('td');
|
||||
gameCoverCell.className = 'collections_preview_gamecovercell';
|
||||
|
||||
var gameImage = document.createElement('img');
|
||||
gameImage.className = 'game_tile_image game_tile_image_small';
|
||||
if (gameItem.cover) {
|
||||
gameImage.src = '/api/v1/Games/' + gameItem.id + '/cover/image';
|
||||
} else {
|
||||
gameImage.src = '/images/unknowngame.png';
|
||||
gameImage.className = 'game_tile_image game_tile_image_small unknown';
|
||||
}
|
||||
gameCoverCell.appendChild(gameImage);
|
||||
|
||||
gameDetailRow.appendChild(gameCoverCell);
|
||||
|
||||
// game detail
|
||||
var gameDetailCell = document.createElement('td');
|
||||
gameDetailCell.className = 'collections_preview_gamedetailcell';
|
||||
|
||||
// loop roms
|
||||
for (var r = 0; r < gameItem.roms.length; r++) {
|
||||
var romItem = gameItem.roms[r];
|
||||
|
||||
var romLabel = document.createElement('p');
|
||||
romLabel.innerHTML = romItem.name;
|
||||
|
||||
gameDetailCell.appendChild(romLabel);
|
||||
}
|
||||
|
||||
gameDetailRow.appendChild(gameDetailCell);
|
||||
|
||||
collectionTable.appendChild(gameItemRow);
|
||||
collectionTable.appendChild(gameDetailRow);
|
||||
}
|
||||
}
|
||||
|
||||
container.appendChild(collectionTable);
|
||||
|
||||
var collectionSize = document.getElementById('collectionedit_previewbox_size');
|
||||
collectionSize.innerHTML = "Collection size: " + formatBytes(data.collectionProjectedSizeBytes);
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayFormattedBytes(inputElement, labelElement) {
|
||||
var src = document.getElementById(inputElement);
|
||||
var label = document.getElementById(labelElement);
|
||||
|
||||
if (src.value) {
|
||||
label.innerHTML = formatBytes(src.value);
|
||||
} else {
|
||||
label.innerHTML = '';
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -55,7 +55,7 @@
|
||||
|
||||
subModalVariables = modalVariables;
|
||||
|
||||
$('#modal-content-sub').load('/pages/dialogs/' + dialogPage + '.html');
|
||||
$('#modal-content-sub').load('/pages/dialogs/' + dialogPage + '.html?v=' + AppVersion);
|
||||
}
|
||||
|
||||
function closeSubDialog() {
|
||||
|
@@ -12,6 +12,7 @@
|
||||
var artworksPosition = 0;
|
||||
|
||||
var emuBios = '';
|
||||
var emuBackground = '';
|
||||
|
||||
ajaxCall('/api/v1/Games/' + gameId, 'GET', function (result) {
|
||||
gameData = result;
|
||||
@@ -28,6 +29,10 @@
|
||||
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);');
|
||||
}
|
||||
}
|
||||
|
||||
if (result.cover) {
|
||||
emuBackground = '/api/v1/Games/' + gameId + '/cover/image';
|
||||
}
|
||||
});
|
||||
|
||||
ajaxCall('/api/v1/Bios/' + platformId, 'GET', function (result) {
|
||||
@@ -39,7 +44,7 @@
|
||||
|
||||
switch (getQueryString('engine', 'string')) {
|
||||
case 'EmulatorJS':
|
||||
$('#emulator').load('/pages/EmulatorJS.html');
|
||||
$('#emulator').load('/pages/EmulatorJS.html?v=' + AppVersion);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@@ -2,13 +2,34 @@
|
||||
<div id="bgImage_Opacity"></div>
|
||||
</div>
|
||||
|
||||
<!-- The Modal -->
|
||||
<div id="myModalProgress" class="modal">
|
||||
|
||||
<!-- Modal content -->
|
||||
<div class="modal-content-sub">
|
||||
<div id="modal-content-sub-progress">
|
||||
<h1>In Progress...</h1>
|
||||
<progress style="width: 100%;"></progress>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="gamepage">
|
||||
<div id="gametitle">
|
||||
<div id="gametitle_criticrating">
|
||||
<div>
|
||||
<span id="gametitle_criticrating_value"></span>
|
||||
<span id="gametitle_criticrating_label"></span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 id="gametitle_label"></h1>
|
||||
<p id="gamedeveloper_label"></p>
|
||||
|
||||
<p id="gametitle_alts">
|
||||
<span>Also known as: </span><span id="gametitle_alts_label"></span>
|
||||
</p>
|
||||
|
||||
<p id="gamedeveloper_label"></p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -59,9 +80,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gameId = getQueryString('id', 'int');
|
||||
var gameData;
|
||||
@@ -78,6 +98,17 @@
|
||||
var gameTitleLabel = document.getElementById('gametitle_label');
|
||||
gameTitleLabel.innerHTML = result.name;
|
||||
|
||||
// get critic rating
|
||||
if (gameData.totalRating) {
|
||||
var criticscoreval = document.getElementById('gametitle_criticrating_value');
|
||||
criticscoreval.innerHTML = Math.floor(gameData.totalRating) + '%';
|
||||
|
||||
if (gameData.totalRatingCount) {
|
||||
var criticscorelabel = document.getElementById('gametitle_criticrating_label');
|
||||
criticscorelabel.innerHTML = '<img src="/images/IGDB_logo.svg" style="filter: invert(100%); height: 13px; margin-bottom: -5px;" /><span style="font-size: 10px;"> User Rating<br />' + "based on " + gameData.totalRatingCount + " votes</span>"
|
||||
}
|
||||
}
|
||||
|
||||
// get alt name
|
||||
var gameTitleAltLabel = document.getElementById('gametitle_alts');
|
||||
if (result.alternativeNames) {
|
||||
@@ -124,9 +155,12 @@
|
||||
artworksPosition = startPos;
|
||||
rotateBackground();
|
||||
} else {
|
||||
if (result.cover) {
|
||||
var bg = document.getElementById('bgImage');
|
||||
if (result.cover) {
|
||||
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);');
|
||||
} else {
|
||||
var randomInt = randomIntFromInterval(1, 3);
|
||||
bg.setAttribute('style', 'background-image: url("/images/gamebg' + randomInt + '.jpg"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +329,8 @@
|
||||
gameScreenshots_vGallery.appendChild(itemsArr[i]);
|
||||
}
|
||||
|
||||
selectScreenshot(0);
|
||||
}, function(error) {
|
||||
selectScreenshot(0);
|
||||
});
|
||||
} else {
|
||||
@@ -344,7 +380,7 @@
|
||||
|
||||
var newRow = [
|
||||
['<input type="checkbox" name="rom_checkbox" data-romid="' + result[i].id + '" />', 'rom_checkbox_box_hidden', 'rom_edit_checkbox'],
|
||||
'<a href="/api/v1/Games/' + gameId + '/roms/' + result[i].id + '/' + encodeURIComponent(result[i].name) +'" class="romlink">' + result[i].name + '</a>',
|
||||
'<a href="/api/v1/Games/' + gameId + '/roms/' + result[i].id + '/' + encodeURIComponent(result[i].name) + '" class="romlink">' + result[i].name + '</a>',
|
||||
formatBytes(result[i].size, 2),
|
||||
result[i].romTypeMedia,
|
||||
result[i].mediaLabel,
|
||||
@@ -545,29 +581,47 @@
|
||||
});
|
||||
|
||||
var remapCallCounter = 0;
|
||||
var remapCallCounterMax = 0;
|
||||
|
||||
function remapTitles() {
|
||||
var fixplatform = $('#rom_edit_fixplatform').select2('data');
|
||||
var fixgame = $('#rom_edit_fixgame').select2('data');
|
||||
|
||||
if (fixplatform[0] && fixgame[0]) {
|
||||
var rom_checks = document.getElementsByName('rom_checkbox');
|
||||
|
||||
for (var i = 0; i < rom_checks.length; i++) {
|
||||
if (rom_checks[i].checked == true) {
|
||||
remapCallCounterMax += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (remapCallCounterMax > 0) {
|
||||
showProgress();
|
||||
|
||||
for (var i = 0; i < rom_checks.length; i++) {
|
||||
if (rom_checks[i].checked == true) {
|
||||
var romId = rom_checks[i].getAttribute('data-romid');
|
||||
remapCallCounter += 1;
|
||||
ajaxCall('/api/v1/Games/' + gameId + '/roms/' + romId + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
remapTitlesCallback();
|
||||
}, function (result) {
|
||||
remapTitlesCallback();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function remapTitlesCallback() {
|
||||
remapCallCounter = remapCallCounter - 1;
|
||||
|
||||
if (remapCallCounter <= 0) {
|
||||
closeProgress();
|
||||
loadRoms(true);
|
||||
remapCallCounter = 0;
|
||||
remapCallCounterMax = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,4 +651,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showProgress() {
|
||||
// Get the modal
|
||||
var submodal = document.getElementById("myModalProgress");
|
||||
|
||||
// When the user clicks on the button, open the modal
|
||||
submodal.style.display = "block";
|
||||
}
|
||||
|
||||
function closeProgress() {
|
||||
// Get the modal
|
||||
var submodal = document.getElementById("myModalProgress");
|
||||
|
||||
submodal.style.display = "none";
|
||||
}
|
||||
</script>
|
@@ -1,4 +1,8 @@
|
||||
<div id="games_home">
|
||||
<div id="bgImage" style="background-image: url('/images/librarybg.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="games_home">
|
||||
<div id="games_filter"></div>
|
||||
<div id="games_library"></div>
|
||||
</div>
|
||||
@@ -7,10 +11,7 @@
|
||||
ajaxCall('/api/v1/Filter', 'GET', function (result) {
|
||||
var filterElement = document.getElementById('games_filter');
|
||||
formatFilterPanel(filterElement, result);
|
||||
});
|
||||
|
||||
ajaxCall('/api/v1/Games', 'GET', function (result) {
|
||||
var gameElement = document.getElementById('games_library');
|
||||
formatGamesPanel(gameElement, result);
|
||||
executeFilter();
|
||||
});
|
||||
</script>
|
@@ -42,6 +42,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$('#properties_bodypanel').load('/pages/settings/' + TabName + '.html');
|
||||
$('#properties_bodypanel').load('/pages/settings/' + TabName + '.html?v=' + AppVersion);
|
||||
}
|
||||
</script>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<h1 id="gametitle_label">About Gaseous</h1>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<table style="width: 100%;">
|
||||
<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>
|
||||
@@ -11,4 +11,44 @@
|
||||
<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>
|
||||
<tr>
|
||||
<th>Server Version</th>
|
||||
<td id="settings_appversion"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>Data Sources</h2>
|
||||
<h4>Game data</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.igdb.com/" target="_blank"><img src="/images/IGDB_logo.svg" style="filter: invert(100%); height: 36px;" /></a>
|
||||
</td>
|
||||
<td>
|
||||
The Internet Game Database
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h4>Signature data sources</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.tosecdev.org/" target="_blank"><img src="/images/TOSEC_logo.gif" style="height: 36px;" /></a>
|
||||
</td>
|
||||
<td>
|
||||
The Old School Emulation Center
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
ajaxCall('/api/v1/System/Version', 'GET', function (result) {
|
||||
if (result) {
|
||||
var versionBox = document.getElementById('settings_appversion');
|
||||
versionBox.innerHTML = result;
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -51,6 +51,9 @@
|
||||
case 'LibraryScan':
|
||||
itemTypeName = "Library scan";
|
||||
break;
|
||||
case 'CollectionCompiler':
|
||||
itemTypeName = "Compress collections";
|
||||
break;
|
||||
default:
|
||||
itemTypeName = result[i].itemType;
|
||||
break;
|
||||
@@ -78,7 +81,7 @@
|
||||
}
|
||||
|
||||
var startButton = '';
|
||||
if (result[i].itemState != "Running") {
|
||||
if (result[i].allowManualStart == true && result[i].itemState != "Running") {
|
||||
startButton = "<span id='startProcess' class='romstart' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,10 @@
|
||||
var containerPanelSearch = document.createElement('div');
|
||||
containerPanelSearch.className = 'filter_panel_box';
|
||||
var containerPanelSearchField = document.createElement('input');
|
||||
var searchCookie = getCookie('filter_panel_search');
|
||||
if (searchCookie) {
|
||||
containerPanelSearchField.value = searchCookie;
|
||||
}
|
||||
containerPanelSearchField.id = 'filter_panel_search';
|
||||
containerPanelSearchField.type = 'text';
|
||||
containerPanelSearchField.placeholder = 'Search';
|
||||
@@ -15,45 +19,136 @@
|
||||
|
||||
panel.appendChild(containerPanelSearch);
|
||||
|
||||
if (result.platforms) {
|
||||
panel.appendChild(buildFilterPanelHeader('platforms', 'Platforms'));
|
||||
|
||||
var containerPanelPlatform = document.createElement('div');
|
||||
containerPanelPlatform.className = 'filter_panel_box';
|
||||
for (var i = 0; i < result.platforms.length; i++) {
|
||||
containerPanelPlatform.appendChild(buildFilterPanelItem('platforms', result.platforms[i].id, result.platforms[i].name));
|
||||
panel.appendChild(buildFilterPanelHeader('userrating', 'User Rating'));
|
||||
var containerPanelUserRating = document.createElement('div');
|
||||
containerPanelUserRating.className = 'filter_panel_box';
|
||||
var containerPanelUserRatingMinField = document.createElement('input');
|
||||
var minRatingCookie = getCookie('filter_panel_userrating_min');
|
||||
if (minRatingCookie) {
|
||||
containerPanelUserRatingMinField.value = minRatingCookie;
|
||||
}
|
||||
panel.appendChild(containerPanelPlatform);
|
||||
containerPanelUserRatingMinField.id = 'filter_panel_userrating_min';
|
||||
containerPanelUserRatingMinField.type = 'number';
|
||||
containerPanelUserRatingMinField.placeholder = '0';
|
||||
containerPanelUserRatingMinField.setAttribute('onchange', 'executeFilterDelayed();');
|
||||
containerPanelUserRatingMinField.setAttribute('onkeydown', 'executeFilterDelayed();');
|
||||
containerPanelUserRatingMinField.setAttribute('min', '0');
|
||||
containerPanelUserRatingMinField.setAttribute('max', '100');
|
||||
containerPanelUserRating.appendChild(containerPanelUserRatingMinField);
|
||||
|
||||
targetElement.appendChild(panel);
|
||||
var containerPanelUserRatingMaxField = document.createElement('input');
|
||||
var maxRatingCookie = getCookie('filter_panel_userrating_max');
|
||||
if (maxRatingCookie) {
|
||||
containerPanelUserRatingMaxField.value = maxRatingCookie;
|
||||
}
|
||||
containerPanelUserRatingMaxField.id = 'filter_panel_userrating_max';
|
||||
containerPanelUserRatingMaxField.type = 'number';
|
||||
containerPanelUserRatingMaxField.placeholder = '100';
|
||||
containerPanelUserRatingMaxField.setAttribute('onchange', 'executeFilterDelayed();');
|
||||
containerPanelUserRatingMaxField.setAttribute('onkeydown', 'executeFilterDelayed();');
|
||||
containerPanelUserRatingMaxField.setAttribute('min', '0');
|
||||
containerPanelUserRatingMaxField.setAttribute('max', '100');
|
||||
containerPanelUserRating.appendChild(containerPanelUserRatingMaxField);
|
||||
|
||||
panel.appendChild(containerPanelUserRating);
|
||||
|
||||
if (result.platforms) {
|
||||
buildFilterPanel(panel, 'platform', 'Platforms', result.platforms, true, true);
|
||||
}
|
||||
|
||||
if (result.genres) {
|
||||
panel.appendChild(buildFilterPanelHeader('genres', 'Genres'));
|
||||
|
||||
var containerPanelGenres = document.createElement('div');
|
||||
containerPanelGenres.className = 'filter_panel_box';
|
||||
for (var i = 0; i < result.genres.length; i++) {
|
||||
containerPanelGenres.appendChild(buildFilterPanelItem('genres', result.genres[i].id, result.genres[i].name));
|
||||
buildFilterPanel(panel, 'genre', 'Genres', result.genres, true, false);
|
||||
}
|
||||
|
||||
if (result.gamemodes) {
|
||||
buildFilterPanel(panel, 'gamemode', 'Players', result.gamemodes, true, false);
|
||||
}
|
||||
|
||||
if (result.playerperspectives) {
|
||||
buildFilterPanel(panel, 'playerperspective', 'Player Perspectives', result.playerperspectives, true, false);
|
||||
}
|
||||
|
||||
if (result.themes) {
|
||||
buildFilterPanel(panel, 'theme', 'Themes', result.themes, true, false);
|
||||
}
|
||||
panel.appendChild(containerPanelGenres);
|
||||
|
||||
targetElement.appendChild(panel);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function buildFilterPanelHeader(headerString, friendlyHeaderString) {
|
||||
function buildFilterPanel(targetElement, headerString, friendlyHeaderString, valueList, showToggle, initialDisplay) {
|
||||
if (showToggle == false) { initialDisplay = true; }
|
||||
var displayCookie = getCookie('filter_panel_box_' + headerString);
|
||||
if (displayCookie) {
|
||||
initialDisplay = (displayCookie === 'true');
|
||||
console.log(displayCookie);
|
||||
}
|
||||
targetElement.appendChild(buildFilterPanelHeader(headerString, friendlyHeaderString, showToggle, initialDisplay));
|
||||
|
||||
var containerPanel = document.createElement('div');
|
||||
containerPanel.className = 'filter_panel_box';
|
||||
containerPanel.id = 'filter_panel_box_' + headerString;
|
||||
if (initialDisplay == false) {
|
||||
containerPanel.setAttribute('style', 'display: none;');
|
||||
}
|
||||
for (var i = 0; i < valueList.length; i++) {
|
||||
containerPanel.appendChild(buildFilterPanelItem(headerString, valueList[i].id, valueList[i].name));
|
||||
}
|
||||
targetElement.appendChild(containerPanel);
|
||||
}
|
||||
|
||||
function buildFilterPanelHeader(headerString, friendlyHeaderString, showVisibleToggle, toggleInitialValue) {
|
||||
var headerToggle = document.createElement('div');
|
||||
headerToggle.setAttribute('style', 'float: right;');
|
||||
headerToggle.id = 'filter_panel_header_toggle_' + headerString;
|
||||
if (toggleInitialValue == true) {
|
||||
headerToggle.innerHTML = '-';
|
||||
} else {
|
||||
headerToggle.innerHTML = '+';
|
||||
}
|
||||
|
||||
var headerLabel = document.createElement('span');
|
||||
headerLabel.innerHTML = friendlyHeaderString;
|
||||
|
||||
var header = document.createElement('div');
|
||||
header.id = 'filter_panel_header_' + headerString;
|
||||
header.className = 'filter_header';
|
||||
header.innerHTML = friendlyHeaderString;
|
||||
|
||||
if (showVisibleToggle == true) {
|
||||
header.appendChild(headerToggle);
|
||||
header.setAttribute('onclick', 'toggleFilterPanel("' + headerString + '");');
|
||||
header.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
header.appendChild(headerLabel);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
function toggleFilterPanel(panelName) {
|
||||
var filterPanel = document.getElementById('filter_panel_box_' + panelName);
|
||||
var filterPanelToggle = document.getElementById('filter_panel_header_toggle_' + panelName);
|
||||
|
||||
var cookieVal = '';
|
||||
if (filterPanel.style.display == 'none') {
|
||||
filterPanelToggle.innerHTML = '-';
|
||||
filterPanel.style.display = '';
|
||||
cookieVal = "true";
|
||||
} else {
|
||||
filterPanelToggle.innerHTML = '+';
|
||||
filterPanel.style.display = 'none';
|
||||
cookieVal = "false";
|
||||
}
|
||||
|
||||
setCookie("filter_panel_box_" + panelName, cookieVal);
|
||||
}
|
||||
|
||||
function buildFilterPanelItem(filterType, itemString, friendlyItemString) {
|
||||
var checkCookie = getCookie('filter_panel_item_' + filterType + '_checkbox_' + itemString);
|
||||
var checkState = false;
|
||||
if (checkCookie) {
|
||||
checkState = (checkCookie === 'true');
|
||||
}
|
||||
|
||||
var filterPanelItem = document.createElement('div');
|
||||
filterPanelItem.id = 'filter_panel_item_' + itemString;
|
||||
filterPanelItem.className = 'filter_panel_item';
|
||||
@@ -61,12 +156,15 @@ function buildFilterPanelItem(filterType, itemString, friendlyItemString) {
|
||||
var filterPanelItemCheckBox = document.createElement('div');
|
||||
|
||||
var filterPanelItemCheckBoxItem = document.createElement('input');
|
||||
filterPanelItemCheckBoxItem.id = 'filter_panel_item_checkbox_' + itemString;
|
||||
filterPanelItemCheckBoxItem.id = 'filter_panel_item_' + filterType + '_checkbox_' + itemString;
|
||||
filterPanelItemCheckBoxItem.type = 'checkbox';
|
||||
filterPanelItemCheckBoxItem.className = 'filter_panel_item_checkbox';
|
||||
filterPanelItemCheckBoxItem.name = 'filter_' + filterType;
|
||||
filterPanelItemCheckBoxItem.setAttribute('filter_id', itemString);
|
||||
filterPanelItemCheckBoxItem.setAttribute('oninput' , 'executeFilter();');
|
||||
if (checkState == true) {
|
||||
filterPanelItemCheckBoxItem.checked = true;
|
||||
}
|
||||
filterPanelItemCheckBox.appendChild(filterPanelItemCheckBoxItem);
|
||||
|
||||
var filterPanelItemLabel = document.createElement('label');
|
||||
@@ -92,33 +190,79 @@ function executeFilterDelayed() {
|
||||
|
||||
function executeFilter() {
|
||||
// build filter lists
|
||||
var queries = [];
|
||||
|
||||
var platforms = '';
|
||||
var genres = '';
|
||||
|
||||
var searchString = document.getElementById('filter_panel_search').value;
|
||||
var platformFilters = document.getElementsByName('filter_platforms');
|
||||
var genreFilters = document.getElementsByName('filter_genres');
|
||||
|
||||
for (var i = 0; i < platformFilters.length; i++) {
|
||||
if (platformFilters[i].checked) {
|
||||
if (platforms.length > 0) {
|
||||
platforms += ',';
|
||||
var searchString = document.getElementById('filter_panel_search');
|
||||
if (searchString.value.length > 0) {
|
||||
queries.push('name=' + searchString.value);
|
||||
}
|
||||
platforms += platformFilters[i].getAttribute('filter_id');
|
||||
setCookie(searchString.id, searchString.value);
|
||||
|
||||
var minUserRating = 0;
|
||||
var minUserRatingInput = document.getElementById('filter_panel_userrating_min');
|
||||
if (minUserRatingInput.value) {
|
||||
minUserRating = minUserRatingInput.value;
|
||||
queries.push('minrating=' + minUserRating);
|
||||
}
|
||||
setCookie(minUserRatingInput.id, minUserRatingInput.value);
|
||||
|
||||
var maxUserRating = 100;
|
||||
var maxUserRatingInput = document.getElementById('filter_panel_userrating_max');
|
||||
if (maxUserRatingInput.value) {
|
||||
maxUserRating = maxUserRatingInput.value;
|
||||
queries.push('maxrating=' + maxUserRating);
|
||||
}
|
||||
setCookie(maxUserRatingInput.id, maxUserRatingInput.value);
|
||||
|
||||
queries.push(GetFilterQuery('platform'));
|
||||
queries.push(GetFilterQuery('genre'));
|
||||
queries.push(GetFilterQuery('gamemode'));
|
||||
queries.push(GetFilterQuery('playerperspective'));
|
||||
queries.push(GetFilterQuery('theme'));
|
||||
|
||||
var queryString = '';
|
||||
for (var i = 0; i < queries.length; i++) {
|
||||
if (queries[i].length > 0) {
|
||||
if (queryString.length == 0) {
|
||||
queryString = '?';
|
||||
} else {
|
||||
queryString += '&';
|
||||
}
|
||||
|
||||
queryString += queries[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < genreFilters.length; i++) {
|
||||
if (genreFilters[i].checked) {
|
||||
if (genres.length > 0) {
|
||||
genres += ',';
|
||||
}
|
||||
genres += genreFilters[i].getAttribute('filter_id');
|
||||
}
|
||||
}
|
||||
console.log('Query string = ' + queryString);
|
||||
|
||||
ajaxCall('/api/v1/Games?name=' + searchString + '&platform=' + platforms + '&genre=' + genres, 'GET', function (result) {
|
||||
ajaxCall('/api/v1/Games' + queryString, 'GET', function (result) {
|
||||
var gameElement = document.getElementById('games_library');
|
||||
formatGamesPanel(gameElement, result);
|
||||
});
|
||||
}
|
||||
|
||||
function GetFilterQuery(filterName) {
|
||||
var Filters = document.getElementsByName('filter_' + filterName);
|
||||
var queryString = '';
|
||||
|
||||
for (var i = 0; i < Filters.length; i++) {
|
||||
if (Filters[i].checked) {
|
||||
setCookie(Filters[i].id, true);
|
||||
if (queryString.length > 0) {
|
||||
queryString += ',';
|
||||
}
|
||||
queryString += Filters[i].getAttribute('filter_id');
|
||||
} else {
|
||||
setCookie(Filters[i].id, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (queryString.length > 0) {
|
||||
queryString = filterName + '=' + queryString;
|
||||
}
|
||||
|
||||
return queryString;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
function ajaxCall(endpoint, method, successFunction) {
|
||||
function ajaxCall(endpoint, method, successFunction, errorFunction, body) {
|
||||
$.ajax({
|
||||
|
||||
// Our sample url to make request
|
||||
@@ -8,17 +8,27 @@
|
||||
// Type of Request
|
||||
type: method,
|
||||
|
||||
// data to send to the server
|
||||
data: body,
|
||||
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
|
||||
// Function to call when to
|
||||
// request is ok
|
||||
success: function (data) {
|
||||
var x = JSON.stringify(data);
|
||||
console.log(x);
|
||||
//var x = JSON.stringify(data);
|
||||
//console.log(x);
|
||||
successFunction(data);
|
||||
},
|
||||
|
||||
// Error handling
|
||||
error: function (error) {
|
||||
console.log(`Error ${error}`);
|
||||
console.log(`Error ${JSON.stringify(error)}`);
|
||||
|
||||
if (errorFunction) {
|
||||
errorFunction(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -47,6 +57,33 @@ function getQueryString(stringName, type) {
|
||||
}
|
||||
}
|
||||
|
||||
function setCookie(cname, cvalue, exdays) {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + (exdays*24*60*60*1000));
|
||||
if (exdays) {
|
||||
let expires = "expires="+ d.toUTCString();
|
||||
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
||||
} else {
|
||||
document.cookie = cname + "=" + cvalue + ";path=/";
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for(let i = 0; i <ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (!+bytes) return '0 Bytes'
|
||||
|
||||
@@ -93,7 +130,19 @@ function showDialog(dialogPage, variables) {
|
||||
|
||||
modalVariables = variables;
|
||||
|
||||
$('#modal-content').load('/pages/dialogs/' + dialogPage + '.html');
|
||||
$('#modal-content').load('/pages/dialogs/' + dialogPage + '.html?v=' + AppVersion);
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
// Get the modal
|
||||
var modal = document.getElementById("myModal");
|
||||
|
||||
// Get the modal content
|
||||
var modalContent = document.getElementById("modal-content");
|
||||
|
||||
modal.style.display = "none";
|
||||
modalContent.innerHTML = "";
|
||||
modalVariables = null;
|
||||
}
|
||||
|
||||
var subModalVariables;
|
||||
@@ -121,9 +170,9 @@ function showSubDialog(dialogPage, variables) {
|
||||
subModalVariables = null;
|
||||
}
|
||||
|
||||
subModalVariables = modalVariables;
|
||||
subModalVariables = variables;
|
||||
|
||||
$('#modal-content-sub').load('/pages/dialogs/' + dialogPage + '.html');
|
||||
$('#modal-content-sub').load('/pages/dialogs/' + dialogPage + '.html?v=' + AppVersion);
|
||||
}
|
||||
|
||||
function closeSubDialog() {
|
||||
|
@@ -13,6 +13,10 @@
|
||||
src: url('/fonts/Commodore Pixelized v1.2.ttf');
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: unset;
|
||||
}
|
||||
|
||||
h3 {
|
||||
border-bottom-style: solid;
|
||||
/*border-bottom-color: #916b01;*/
|
||||
@@ -66,6 +70,9 @@ h3 {
|
||||
|
||||
border-image: linear-gradient(to right, rgba(255,0,0,1) 0%, rgba(251,255,0,1) 16%, rgba(0,255,250,1) 30%, rgba(0,16,255,1) 46%, rgba(250,0,255,1) 62%, rgba(255,0,0,1) 78%, rgba(255,237,0,1) 90%, rgba(20,255,0,1) 100%) 5;
|
||||
}
|
||||
#modal-content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* The Close Button */
|
||||
.close {
|
||||
@@ -105,11 +112,10 @@ h3 {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#banner_upload {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
.banner_button {
|
||||
background-color: transparent;
|
||||
float: right;
|
||||
top: 0px;
|
||||
right: 41px;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -117,44 +123,24 @@ h3 {
|
||||
padding-right: 10px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
margin: 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
display: flex;
|
||||
color: black;
|
||||
color: white;
|
||||
border-left-color: black;
|
||||
border-left-width: 1px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
#banner_upload:hover {
|
||||
.banner_button:hover {
|
||||
cursor: pointer;
|
||||
background-color: lightgrey;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#banner_cog {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#banner_cog:hover {
|
||||
cursor: pointer;
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
#banner_system_image {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
#banner_upload_image {
|
||||
.banner_button_image {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 5px;
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
#banner_header {
|
||||
@@ -167,12 +153,11 @@ h3 {
|
||||
height: 40px;
|
||||
right: 0px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#banner_header_label {
|
||||
font-family: Commodore64;
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
font-size: 16pt;
|
||||
vertical-align: top;
|
||||
@@ -180,6 +165,10 @@ h3 {
|
||||
color: #7c70da;
|
||||
}
|
||||
|
||||
#banner_header_label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin-top: 35px;
|
||||
padding-top: 5px;
|
||||
@@ -206,7 +195,7 @@ h3 {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
input[type='text'], input[type='number'] {
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
@@ -225,6 +214,15 @@ input[id='filter_panel_search'] {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
input[id='filter_panel_userrating_min'] {
|
||||
width: 50px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
input[id='filter_panel_userrating_max'] {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
@@ -286,12 +284,20 @@ input[id='filter_panel_search'] {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px 10px 10px 10px;
|
||||
-webkit-border-radius: 10px 10px 10px 10px;
|
||||
-moz-border-radius: 10px 10px 10px 10px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.game_tile:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
background-color: #2b2b2b;
|
||||
border-radius: 10px 10px 10px 10px;
|
||||
-webkit-border-radius: 10px 10px 10px 10px;
|
||||
-moz-border-radius: 10px 10px 10px 10px;
|
||||
border: 1px solid #2b2b2b;
|
||||
}
|
||||
|
||||
.game_tile_image {
|
||||
@@ -306,6 +312,11 @@ input[id='filter_panel_search'] {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.game_tile_image_small {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
}
|
||||
|
||||
#bgImage {
|
||||
position: fixed;
|
||||
top: -30px;
|
||||
@@ -619,6 +630,11 @@ div[name="properties_toc_item"]:hover {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: #2b2b2b !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.select2-container--open .select2-dropdown--below,
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
background: #2b2b2b;
|
||||
@@ -628,6 +644,29 @@ div[name="properties_toc_item"]:hover {
|
||||
border: 1px solid #2b2b2b;
|
||||
}
|
||||
|
||||
.select2-selection__choice {
|
||||
background-color: #2b2b2b !important;
|
||||
}
|
||||
|
||||
.select2-selection__choice__display {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.select2-results__option--selected {
|
||||
background-color: black !important;
|
||||
}
|
||||
|
||||
.select2-selection--single .select2-selection__rendered {
|
||||
background-color: #2b2b2b;
|
||||
color: white !important;
|
||||
border: 1px solid #2b2b2b;
|
||||
}
|
||||
|
||||
.select2-search__field {
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dropdown-div {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -771,3 +810,71 @@ button:disabled {
|
||||
-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);
|
||||
}
|
||||
|
||||
#gametitle_criticrating {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#gametitle_alts {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
#gametitle_criticrating_value {
|
||||
display: inline-block;
|
||||
font-family: Commodore64;
|
||||
font-size: 36px;
|
||||
text-align: center;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
#gametitle_criticrating_label {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#rom_edit_progressbar {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background-color: lightgray;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#rom_edit_progressbar_progress {
|
||||
height: 10px;
|
||||
background-color: cyan;
|
||||
}
|
||||
|
||||
.collections_modal {
|
||||
width: 1000px;
|
||||
height: 90%;
|
||||
margin: 25px auto;
|
||||
/* overflow-x: scroll;*/
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.collections_preview_platform_header {
|
||||
background-color: #2b2b2b;
|
||||
}
|
||||
|
||||
.collections_preview_gamecovercell {
|
||||
text-align: center;
|
||||
width: 110px;
|
||||
vertical-align: top;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.collections_preview_gametitlecell {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.collections_preview_gamedetailcell {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.bgalt0 {
|
||||
background-color: #414040;
|
||||
}
|
||||
|
||||
.bgalt1 {
|
||||
background-color: transparent;;
|
||||
}
|
@@ -13,7 +13,7 @@ namespace gaseous_tools
|
||||
/// <returns></returns>
|
||||
static public object ReturnValueIfNull(object? ObjectToCheck, object IfNullValue)
|
||||
{
|
||||
if (ObjectToCheck == null)
|
||||
if (ObjectToCheck == null || ObjectToCheck == System.DBNull.Value)
|
||||
{
|
||||
return IfNullValue;
|
||||
} else
|
||||
|
@@ -359,6 +359,22 @@ namespace gaseous_tools
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryTempDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryRootDirectory, "Temp");
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryCollectionsDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryRootDirectory, "Collections");
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryMetadataDirectory_Platform(Platform platform)
|
||||
{
|
||||
string MetadataPath = Path.Combine(LibraryMetadataDirectory, "Platforms", platform.Slug);
|
||||
@@ -404,6 +420,8 @@ namespace gaseous_tools
|
||||
if (!Directory.Exists(LibraryBIOSDirectory)) { Directory.CreateDirectory(LibraryBIOSDirectory); }
|
||||
if (!Directory.Exists(LibraryUploadDirectory)) { Directory.CreateDirectory(LibraryUploadDirectory); }
|
||||
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
|
||||
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }
|
||||
if (!Directory.Exists(LibraryCollectionsDirectory)) { Directory.CreateDirectory(LibraryCollectionsDirectory); }
|
||||
if (!Directory.Exists(LibrarySignatureImportDirectory)) { Directory.CreateDirectory(LibrarySignatureImportDirectory); }
|
||||
if (!Directory.Exists(LibrarySignatureImportDirectory_TOSEC)) { Directory.CreateDirectory(LibrarySignatureImportDirectory_TOSEC); }
|
||||
}
|
||||
|
86
gaseous-tools/Database/MySQL/gaseous-1001.sql
Normal file
@@ -0,0 +1,86 @@
|
||||
DROP TABLE IF EXISTS `GameMode`;
|
||||
CREATE TABLE `gaseous`.`GameMode` (
|
||||
`Id` BIGINT NOT NULL,
|
||||
`CreatedAt` DATETIME NULL,
|
||||
`Checksum` VARCHAR(45) NULL,
|
||||
`Name` VARCHAR(100) NULL,
|
||||
`Slug` VARCHAR(100) NULL,
|
||||
`UpdatedAt` DATETIME NULL,
|
||||
`Url` VARCHAR(255) NULL,
|
||||
`dateAdded` DATETIME NULL,
|
||||
`lastUpdated` DATETIME NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `MultiplayerMode`;
|
||||
CREATE TABLE `MultiplayerMode` (
|
||||
`Id` bigint NOT NULL,
|
||||
`CreatedAt` datetime DEFAULT NULL,
|
||||
`Checksum` varchar(45) DEFAULT NULL,
|
||||
`CampaignCoop` boolean DEFAULT NULL,
|
||||
`DropIn` boolean DEFAULT NULL,
|
||||
`Game` bigint DEFAULT NULL,
|
||||
`LanCoop` boolean DEFAULT NULL,
|
||||
`OfflineCoop` boolean DEFAULT NULL,
|
||||
`OfflineCoopMax` int DEFAULT NULL,
|
||||
`OfflineMax` int DEFAULT NULL,
|
||||
`OnlineCoop` boolean DEFAULT NULL,
|
||||
`OnlineCoopMax` int DEFAULT NULL,
|
||||
`OnlineMax` int DEFAULT NULL,
|
||||
`Platform` bigint DEFAULT NULL,
|
||||
`SplitScreen` boolean DEFAULT NULL,
|
||||
`SplitScreenOnline` boolean DEFAULT NULL,
|
||||
`UpdatedAt` datetime DEFAULT NULL,
|
||||
`dateAdded` datetime DEFAULT NULL,
|
||||
`lastUpdated` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `PlayerPerspective`;
|
||||
CREATE TABLE `PlayerPerspective` (
|
||||
`Id` bigint NOT NULL,
|
||||
`CreatedAt` datetime DEFAULT NULL,
|
||||
`Checksum` varchar(45) DEFAULT NULL,
|
||||
`Name` varchar(100) DEFAULT NULL,
|
||||
`Slug` varchar(45) DEFAULT NULL,
|
||||
`UpdatedAt` datetime DEFAULT NULL,
|
||||
`Url` varchar(255) DEFAULT NULL,
|
||||
`dateAdded` datetime DEFAULT NULL,
|
||||
`lastUpdated` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `Theme`;
|
||||
CREATE TABLE `Theme` (
|
||||
`Id` bigint NOT NULL,
|
||||
`CreatedAt` datetime DEFAULT NULL,
|
||||
`Checksum` varchar(45) DEFAULT NULL,
|
||||
`Name` varchar(100) DEFAULT NULL,
|
||||
`Slug` varchar(45) DEFAULT NULL,
|
||||
`UpdatedAt` datetime DEFAULT NULL,
|
||||
`Url` varchar(255) DEFAULT NULL,
|
||||
`dateAdded` datetime DEFAULT NULL,
|
||||
`lastUpdated` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `RomCollections`;
|
||||
CREATE TABLE `RomCollections` (
|
||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`Name` VARCHAR(255) NULL,
|
||||
`Description` LONGTEXT NULL,
|
||||
`Platforms` JSON NULL,
|
||||
`Genres` JSON NULL,
|
||||
`Players` JSON NULL,
|
||||
`PlayerPerspectives` JSON NULL,
|
||||
`Themes` JSON NULL,
|
||||
`MinimumRating` INT NULL,
|
||||
`MaximumRating` INT NULL,
|
||||
`MaximumRomsPerPlatform` INT NULL,
|
||||
`MaximumBytesPerPlatform` BIGINT NULL,
|
||||
`MaximumCollectionSizeInBytes` BIGINT NULL,
|
||||
`BuiltStatus` INT NULL,
|
||||
PRIMARY KEY (`Id`));
|
||||
|
||||
ALTER TABLE `gaseous`.`Signatures_Sources`
|
||||
CHANGE COLUMN `Author` `Author` LONGTEXT NULL DEFAULT NULL ;
|
@@ -16,6 +16,7 @@
|
||||
<None Remove="Database\" />
|
||||
<None Remove="Database\MySQL\" />
|
||||
<None Remove="Database\MySQL\gaseous-1000.sql" />
|
||||
<None Remove="Database\MySQL\gaseous-1001.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Database\" />
|
||||
@@ -23,5 +24,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Database\MySQL\gaseous-1000.sql" />
|
||||
<EmbeddedResource Include="Database\MySQL\gaseous-1001.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
BIN
screenshots/Emulator.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 3.8 MiB After Width: | Height: | Size: 3.9 MiB |
Before Width: | Height: | Size: 6.6 MiB After Width: | Height: | Size: 7.4 MiB |