Skip to content

Commit 9b88749

Browse files
Migrate to new EJS CDN, and save state tweaks (#264)
* Saved game icon now displays on game cover art in library * Fixed casing error on save state download icon * Migrate EJS from submodule to 7z download during docker build * Updated README and gitignore * Resized library search buttons * Export to JSON now triggers the download rather than display of a formatted platform map
1 parent 127eab6 commit 9b88749

23 files changed

+206
-100
lines changed

.github/dependabot.yml

-6
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,3 @@ updates:
99
directory: "/" # Location of package manifests
1010
schedule:
1111
interval: "weekly"
12-
- package-ecosystem: "gitsubmodule"
13-
directory: "/"
14-
allow:
15-
- dependency-name: "gaseous-server/wwwroot/emulators/EmulatorJS"
16-
schedule:
17-
interval: "weekly"

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,4 @@ ASALocalRun/
404404
# Local History for Visual Studio
405405
.localhistory/
406406
gaseous-server/.DS_Store
407+
gaseous-server/wwwroot/emulators/EmulatorJS

.gitmodules

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

Dockerfile

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ RUN dotnet restore "gaseous-server/gaseous-server.csproj"
99
# Build and publish a release
1010
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o out
1111

12+
# download and unzip EmulatorJS from CDN
13+
RUN apt-get update && apt-get install -y p7zip-full
14+
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
15+
RUN wget https://cdn.emulatorjs.org/releases/4.0.9.7z
16+
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.9.7z
17+
1218
# Build runtime image
1319
FROM mcr.microsoft.com/dotnet/aspnet:7.0
1420
WORKDIR /App

README.MD

+5-13
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,9 @@ Dockerfile and docker-compose.yml files have been provided to make deployment of
8585
Dockerfile and docker-compose-build.yml files have been provided to make deployment of the server as easy as possible.
8686
1. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
8787
2. Change into the gaseous-server directory
88-
3. Clone the submodules with the command ```git submodule update --init```
89-
4. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
90-
5. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d```
91-
6. Connect to the host on port 5198
88+
3. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
89+
4. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d```
90+
5. Connect to the host on port 5198
9291

9392
## Source
9493
### Build and deploy
@@ -100,8 +99,7 @@ Dockerfile and docker-compose-build.yml files have been provided to make deploym
10099
5. Change into the gaseous-server directory
101100
6. As the main branch is the development branch, you might want to change to a stable version - these are tagged with a version number. For example to change to the 1.5.0 release, use the command ```git checkout v1.5.0```
102101
* Check the releases page for the version you would like to run: https://github.com/gaseous-project/gaseous-server/releases
103-
7. Clone the submodules with the command ```git submodule update --init --recursive```
104-
* This command will clone the code that the server uses from other projects (currently only EmulatorJS)
102+
7. Download the emulator files from ```https://cdn.emulatorjs.org/releases/4.0.9.zip``` and extract the files to ```gaseous-server/wwwroot/emulators/EmulatorJS```
105103
8. Create a directory in the home directory of the user that will run the server. For example, if running as the user ```gaseous```, create the directory ```/home/gaseous/.gaseous-server```
106104
9. Change into the ```.gaseous-server``` directory created in the previous step
107105
10. Copy the JSON from the config file above into a new file named ```config.json```
@@ -115,11 +113,6 @@ Dockerfile and docker-compose-build.yml files have been provided to make deploym
115113

116114
**Note**: The above instructions were tested on macOS Ventura, and Ubuntu 22.04.3. There was a report that Debian 11 had an issue with the git submodule commands (see: https://github.com/gaseous-project/gaseous-server/issues/71). This was possibly due to an older git package.
117115

118-
If the git submodule commands aren't working, you can:
119-
1. change to the ```gaseous-server/wwwroot/emulators``` directory
120-
2. delete the ```EmulatorJS``` directory
121-
3. clone the EmulatorJS repository with ```git clone https://github.com/EmulatorJS/EmulatorJS.git```
122-
123116
### Updating from source
124117
1. Stop the server
125118
2. Switch to the source directory
@@ -128,8 +121,7 @@ If the git submodule commands aren't working, you can:
128121
* If running from another branch or tag, run:
129122
* ```git fetch```
130123
* ```git checkout <branch or tag name>```
131-
4. Update the submodules with ```git submodule update --recursive```
132-
5. Run steps 12 and 13 from the above Build guide
124+
4. Run steps 12 and 13 from the above Build guide
133125

134126
# Adding Content
135127
While games can be added to the server without them, it is recommended adding some signature DAT files beforehand to allow for better matching of ROMs to games.

gaseous-server/.DS_Store

0 Bytes
Binary file not shown.

gaseous-server/Classes/Auth/Classes/UserTable.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ public int Insert(TUser user)
289289
/// <returns></returns>
290290
private int Delete(string userId)
291291
{
292-
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId;";
292+
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from GameState where UserId = @userId;";
293293
Dictionary<string, object> parameters = new Dictionary<string, object>();
294294
parameters.Add("@userId", userId);
295295

gaseous-server/Classes/Metadata/Games.cs

+6
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,11 @@ public enum SearchType
529529

530530
public class MinimalGameItem
531531
{
532+
public MinimalGameItem()
533+
{
534+
535+
}
536+
532537
public MinimalGameItem(Game gameObject)
533538
{
534539
this.Id = gameObject.Id;
@@ -558,6 +563,7 @@ public MinimalGameItem(Game gameObject)
558563
public string Name { get; set; }
559564
public double? TotalRating { get; set; }
560565
public int? TotalRatingCount { get; set; }
566+
public bool HasSavedGame { get; set; } = false;
561567
public DateTimeOffset? FirstReleaseDate { get; set; }
562568
public IGDB.IdentityOrValue<IGDB.Models.Cover> Cover { get; set; }
563569
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }

gaseous-server/Classes/RomMediaGroup.cs

+14-8
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ public static GameRomMediaGroupItem CreateMediaGroup(long GameId, long PlatformI
5555
return GetMediaGroup(mgId);
5656
}
5757

58-
public static GameRomMediaGroupItem GetMediaGroup(long Id)
58+
public static GameRomMediaGroupItem GetMediaGroup(long Id, string userid = "")
5959
{
6060
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
61-
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 WHERE RomMediaGroup.Id=@id;";
62-
Dictionary<string, object> dbDict = new Dictionary<string, object>();
63-
dbDict.Add("id", Id);
61+
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid WHERE RomMediaGroup.Id=@id;";
62+
Dictionary<string, object> dbDict = new Dictionary<string, object>
63+
{
64+
{ "id", Id },
65+
{ "userid", userid }
66+
};
6467

6568
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
6669

@@ -75,12 +78,15 @@ public static GameRomMediaGroupItem GetMediaGroup(long Id)
7578
}
7679
}
7780

78-
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId)
81+
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "")
7982
{
8083
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
81-
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 WHERE RomMediaGroup.GameId=@gameid;";
82-
Dictionary<string, object> dbDict = new Dictionary<string, object>();
83-
dbDict.Add("gameid", GameId);
84+
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid WHERE RomMediaGroup.GameId=@gameid;";
85+
Dictionary<string, object> dbDict = new Dictionary<string, object>
86+
{
87+
{ "gameid", GameId },
88+
{ "userid", userid }
89+
};
8490

8591
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
8692

gaseous-server/Controllers/V1.0/GamesController.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1034,13 +1034,15 @@ public ActionResult GameRomFile(long GameId, long RomId, string FileName)
10341034
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
10351035
[ProducesResponseType(StatusCodes.Status404NotFound)]
10361036
//[ResponseCache(CacheProfileName = "5Minute")]
1037-
public ActionResult GameRomGroup(long GameId, long RomGroupId)
1037+
public async Task<ActionResult> GameRomGroupAsync(long GameId, long RomGroupId)
10381038
{
1039+
var user = await _userManager.GetUserAsync(User);
1040+
10391041
try
10401042
{
10411043
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
10421044

1043-
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId);
1045+
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id);
10441046
if (rom.GameId == GameId)
10451047
{
10461048
return Ok(rom);
@@ -1063,15 +1065,17 @@ public ActionResult GameRomGroup(long GameId, long RomGroupId)
10631065
[Route("{GameId}/romgroup")]
10641066
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
10651067
[ProducesResponseType(StatusCodes.Status404NotFound)]
1066-
public ActionResult GetGameRomGroup(long GameId)
1068+
public async Task<ActionResult> GetGameRomGroupAsync(long GameId)
10671069
{
1070+
var user = await _userManager.GetUserAsync(User);
1071+
10681072
try
10691073
{
10701074
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
10711075

10721076
try
10731077
{
1074-
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId));
1078+
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id));
10751079
}
10761080
catch (Exception ex)
10771081
{
@@ -1121,13 +1125,15 @@ public ActionResult NewGameRomGroup(long GameId, long PlatformId, [FromBody] Lis
11211125
[Route("{GameId}/romgroup/{RomId}")]
11221126
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
11231127
[ProducesResponseType(StatusCodes.Status404NotFound)]
1124-
public ActionResult GameRomGroupMembers(long GameId, long RomGroupId, [FromBody] List<long> RomIds)
1128+
public async Task<ActionResult> GameRomGroupMembersAsync(long GameId, long RomGroupId, [FromBody] List<long> RomIds)
11251129
{
1130+
var user = await _userManager.GetUserAsync(User);
1131+
11261132
try
11271133
{
11281134
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
11291135

1130-
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId);
1136+
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id);
11311137
if (rom.GameId == GameId)
11321138
{
11331139
rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds);

gaseous-server/Controllers/V1.0/PlatformMapsController.cs

+27
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.AspNetCore.Mvc;
1414
using Microsoft.CodeAnalysis.Scripting;
1515
using Microsoft.AspNetCore.Authorization;
16+
using System.Text;
1617

1718
namespace gaseous_server.Controllers
1819
{
@@ -37,6 +38,32 @@ public ActionResult GetPlatformMap(bool ResetToDefault = false)
3738
return Ok(PlatformMapping.PlatformMap);
3839
}
3940

41+
[MapToApiVersion("1.0")]
42+
[MapToApiVersion("1.1")]
43+
[HttpGet]
44+
[Route("PlatformMap.json")]
45+
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
46+
[ProducesResponseType(StatusCodes.Status404NotFound)]
47+
public ActionResult DownloadPlatformMap()
48+
{
49+
string srcJson = Newtonsoft.Json.JsonConvert.SerializeObject(PlatformMapping.PlatformMap, Newtonsoft.Json.Formatting.Indented);
50+
51+
string filename = "PlatformMap.json";
52+
byte[] bytes = Encoding.UTF8.GetBytes(srcJson);
53+
string contentType = "application/json";
54+
55+
var cd = new System.Net.Mime.ContentDisposition
56+
{
57+
FileName = filename,
58+
Inline = true,
59+
DispositionType = "attachment"
60+
};
61+
62+
Response.Headers.Add("Content-Disposition", cd.ToString());
63+
64+
return File(bytes, contentType);
65+
}
66+
4067
[MapToApiVersion("1.0")]
4168
[MapToApiVersion("1.1")]
4269
[HttpGet]

gaseous-server/Controllers/V1.1/GamesController.cs

+91-7
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public async Task<IActionResult> Game_v1_1(GameSearchModel model, int pageNumber
8585
model.GameAgeRating.IncludeUnrated = false;
8686
}
8787

88-
return Ok(GetGames(model, pageNumber, pageSize));
88+
return Ok(GetGames(model, user.Id, pageNumber, pageSize));
8989
}
9090
else
9191
{
@@ -144,6 +144,7 @@ public class GameSearchModel
144144
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
145145
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
146146
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
147+
public bool HasSavedGame { get; set; }
147148

148149

149150
public class GameRatingItem
@@ -181,11 +182,12 @@ public enum SortField
181182
}
182183
}
183184

184-
public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber = 0, int pageSize = 0)
185+
public static GameReturnPackage GetGames(GameSearchModel model, string userid, int pageNumber = 0, int pageSize = 0)
185186
{
186187
string whereClause = "";
187188
string havingClause = "";
188189
Dictionary<string, object> whereParams = new Dictionary<string, object>();
190+
whereParams.Add("userid", userid);
189191

190192
List<string> whereClauses = new List<string>();
191193
List<string> havingClauses = new List<string>();
@@ -202,6 +204,12 @@ public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber =
202204
whereParams.Add("@Name", "(*" + model.Name + "*) (" + model.Name + ") ");
203205
}
204206

207+
if (model.HasSavedGame == true)
208+
{
209+
string hasSavesTemp = "(RomSavedStates.RomSaveCount IS NOT NULL OR RomGroupSavedStates.MediaGroupSaveCount IS NOT NULL)";
210+
whereClauses.Add(hasSavesTemp);
211+
}
212+
205213
if (model.GameRating != null)
206214
{
207215
List<string> ratingClauses = new List<string>();
@@ -444,9 +452,71 @@ public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber =
444452
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
445453

446454
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
447-
string sql = "SELECT DISTINCT Game.Id, Game.`Name`, Game.NameThe, Game.PlatformId, Game.TotalRating, Game.TotalRatingCount, Game.Cover, Game.Artworks, Game.FirstReleaseDate, Game.Category, Game.ParentGame, Game.AgeRatings, Game.AgeGroupId, Game.RomCount FROM (SELECT DISTINCT Game.*, CASE WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The') ELSE Game.`Name` END AS NameThe, Games_Roms.PlatformId, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId" + platformWhereClause + " LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + " GROUP BY Game.Id HAVING RomCount > 0) Game LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
448-
449-
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
455+
456+
string sql = @"
457+
SELECT DISTINCT
458+
Game.Id,
459+
Game.`Name`,
460+
Game.NameThe,
461+
Game.PlatformId,
462+
Game.TotalRating,
463+
Game.TotalRatingCount,
464+
Game.Cover,
465+
Game.Artworks,
466+
Game.FirstReleaseDate,
467+
Game.Category,
468+
Game.ParentGame,
469+
Game.AgeRatings,
470+
Game.AgeGroupId,
471+
Game.RomCount,
472+
RomSavedStates.RomSaveCount,
473+
RomGroupSavedStates.MediaGroupSaveCount
474+
FROM
475+
(SELECT DISTINCT
476+
Game.*,
477+
CASE
478+
WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The')
479+
ELSE Game.`Name`
480+
END AS NameThe,
481+
Games_Roms.PlatformId,
482+
AgeGroup.AgeGroupId,
483+
COUNT(Games_Roms.Id) AS RomCount
484+
FROM
485+
Game
486+
LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId
487+
LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId" + platformWhereClause + @"
488+
LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + @"
489+
GROUP BY Game.Id
490+
HAVING RomCount > 0) Game
491+
LEFT JOIN
492+
(SELECT
493+
Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount
494+
FROM
495+
GameState
496+
JOIN Games_Roms ON GameState.RomId = Games_Roms.Id
497+
WHERE
498+
GameState.IsMediaGroup = 0
499+
AND GameState.UserId = @userid
500+
GROUP BY Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId
501+
LEFT JOIN
502+
(SELECT
503+
RomMediaGroup.GameId,
504+
COUNT(RomMediaGroup.GameId) AS MediaGroupSaveCount
505+
FROM
506+
RomMediaGroup
507+
JOIN GameState ON RomMediaGroup.Id = GameState.RomId
508+
AND GameState.IsMediaGroup = 1
509+
AND GameState.UserId = @userid
510+
GROUP BY RomMediaGroup.GameId) RomGroupSavedStates ON Game.Id = RomGroupSavedStates.GameId
511+
LEFT JOIN
512+
Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId
513+
LEFT JOIN
514+
Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId
515+
LEFT JOIN
516+
Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId
517+
LEFT JOIN
518+
Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
519+
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
450520

451521
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
452522

@@ -463,10 +533,24 @@ public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber =
463533
}
464534

465535
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
466-
RetVal.Add(retGame);
536+
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
537+
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
538+
{
539+
retMinGame.HasSavedGame = true;
540+
}
541+
else
542+
{
543+
retMinGame.HasSavedGame = false;
544+
}
545+
546+
RetVal.Add(retMinGame);
467547
}
468548

469-
GameReturnPackage gameReturn = new GameReturnPackage(RecordCount, RetVal);
549+
GameReturnPackage gameReturn = new GameReturnPackage
550+
{
551+
Count = RecordCount,
552+
Games = RetVal
553+
};
470554

471555
return gameReturn;
472556
}

0 commit comments

Comments
 (0)