diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 10292d1..8c23067 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,9 +9,3 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" - - package-ecosystem: "gitsubmodule" - directory: "/" - allow: - - dependency-name: "gaseous-server/wwwroot/emulators/EmulatorJS" - schedule: - interval: "weekly" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5d44f11..c608dca 100644 --- a/.gitignore +++ b/.gitignore @@ -404,3 +404,4 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ gaseous-server/.DS_Store +gaseous-server/wwwroot/emulators/EmulatorJS diff --git a/.gitmodules b/.gitmodules index fc7ecb4..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "gaseous-server/wwwroot/emulators/EmulatorJS"] - path = gaseous-server/wwwroot/emulators/EmulatorJS - url = https://github.com/EmulatorJS/EmulatorJS.git diff --git a/Dockerfile b/Dockerfile index 8c3a6e2..9a45994 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,12 @@ RUN dotnet restore "gaseous-server/gaseous-server.csproj" # Build and publish a release RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o out +# download and unzip EmulatorJS from CDN +RUN apt-get update && apt-get install -y p7zip-full +RUN mkdir -p out/wwwroot/emulators/EmulatorJS +RUN wget https://cdn.emulatorjs.org/releases/4.0.9.7z +RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.9.7z + # Build runtime image FROM mcr.microsoft.com/dotnet/aspnet:7.0 WORKDIR /App diff --git a/README.MD b/README.MD index 724cdd5..56440e7 100644 --- a/README.MD +++ b/README.MD @@ -85,10 +85,9 @@ Dockerfile and docker-compose.yml files have been provided to make deployment of Dockerfile and docker-compose-build.yml files have been provided to make deployment of the server as easy as possible. 1. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git``` 2. Change into the gaseous-server directory -3. Clone the submodules with the command ```git submodule update --init``` -4. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account -5. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d``` -6. Connect to the host on port 5198 +3. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account +4. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d``` +5. Connect to the host on port 5198 ## Source ### Build and deploy @@ -100,8 +99,7 @@ Dockerfile and docker-compose-build.yml files have been provided to make deploym 5. Change into the gaseous-server directory 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``` * Check the releases page for the version you would like to run: https://github.com/gaseous-project/gaseous-server/releases -7. Clone the submodules with the command ```git submodule update --init --recursive``` - * This command will clone the code that the server uses from other projects (currently only EmulatorJS) +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``` 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``` 9. Change into the ```.gaseous-server``` directory created in the previous step 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 **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. -If the git submodule commands aren't working, you can: -1. change to the ```gaseous-server/wwwroot/emulators``` directory -2. delete the ```EmulatorJS``` directory -3. clone the EmulatorJS repository with ```git clone https://github.com/EmulatorJS/EmulatorJS.git``` - ### Updating from source 1. Stop the server 2. Switch to the source directory @@ -128,8 +121,7 @@ If the git submodule commands aren't working, you can: * If running from another branch or tag, run: * ```git fetch``` * ```git checkout ``` -4. Update the submodules with ```git submodule update --recursive``` -5. Run steps 12 and 13 from the above Build guide +4. Run steps 12 and 13 from the above Build guide # Adding Content 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. diff --git a/gaseous-server/.DS_Store b/gaseous-server/.DS_Store index e33e0ab..fc2bf7c 100644 Binary files a/gaseous-server/.DS_Store and b/gaseous-server/.DS_Store differ diff --git a/gaseous-server/Classes/Auth/Classes/UserTable.cs b/gaseous-server/Classes/Auth/Classes/UserTable.cs index 02c887e..af02b03 100644 --- a/gaseous-server/Classes/Auth/Classes/UserTable.cs +++ b/gaseous-server/Classes/Auth/Classes/UserTable.cs @@ -289,7 +289,7 @@ namespace Authentication /// private int Delete(string userId) { - string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId;"; + string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from GameState where UserId = @userId;"; Dictionary parameters = new Dictionary(); parameters.Add("@userId", userId); diff --git a/gaseous-server/Classes/Metadata/Games.cs b/gaseous-server/Classes/Metadata/Games.cs index c13a671..77c0be5 100644 --- a/gaseous-server/Classes/Metadata/Games.cs +++ b/gaseous-server/Classes/Metadata/Games.cs @@ -529,6 +529,11 @@ namespace gaseous_server.Classes.Metadata public class MinimalGameItem { + public MinimalGameItem() + { + + } + public MinimalGameItem(Game gameObject) { this.Id = gameObject.Id; @@ -558,6 +563,7 @@ namespace gaseous_server.Classes.Metadata public string Name { get; set; } public double? TotalRating { get; set; } public int? TotalRatingCount { get; set; } + public bool HasSavedGame { get; set; } = false; public DateTimeOffset? FirstReleaseDate { get; set; } public IGDB.IdentityOrValue Cover { get; set; } public IGDB.IdentitiesOrValues Artworks { get; set; } diff --git a/gaseous-server/Classes/RomMediaGroup.cs b/gaseous-server/Classes/RomMediaGroup.cs index f8f2f78..b24c4b1 100644 --- a/gaseous-server/Classes/RomMediaGroup.cs +++ b/gaseous-server/Classes/RomMediaGroup.cs @@ -55,12 +55,15 @@ namespace gaseous_server.Classes return GetMediaGroup(mgId); } - public static GameRomMediaGroupItem GetMediaGroup(long Id) + public static GameRomMediaGroupItem GetMediaGroup(long Id, string userid = "") { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - 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;"; - Dictionary dbDict = new Dictionary(); - dbDict.Add("id", Id); + 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;"; + Dictionary dbDict = new Dictionary + { + { "id", Id }, + { "userid", userid } + }; DataTable dataTable = db.ExecuteCMD(sql, dbDict); @@ -75,12 +78,15 @@ namespace gaseous_server.Classes } } - public static List GetMediaGroupsFromGameId(long GameId) + public static List GetMediaGroupsFromGameId(long GameId, string userid = "") { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - 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;"; - Dictionary dbDict = new Dictionary(); - dbDict.Add("gameid", GameId); + 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;"; + Dictionary dbDict = new Dictionary + { + { "gameid", GameId }, + { "userid", userid } + }; DataTable dataTable = db.ExecuteCMD(sql, dbDict); diff --git a/gaseous-server/Controllers/V1.0/GamesController.cs b/gaseous-server/Controllers/V1.0/GamesController.cs index 228adfd..df14fbd 100644 --- a/gaseous-server/Controllers/V1.0/GamesController.cs +++ b/gaseous-server/Controllers/V1.0/GamesController.cs @@ -1034,13 +1034,15 @@ namespace gaseous_server.Controllers [ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] //[ResponseCache(CacheProfileName = "5Minute")] - public ActionResult GameRomGroup(long GameId, long RomGroupId) + public async Task GameRomGroupAsync(long GameId, long RomGroupId) { + var user = await _userManager.GetUserAsync(User); + try { Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false); - Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId); + Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id); if (rom.GameId == GameId) { return Ok(rom); @@ -1063,15 +1065,17 @@ namespace gaseous_server.Controllers [Route("{GameId}/romgroup")] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetGameRomGroup(long GameId) + public async Task GetGameRomGroupAsync(long GameId) { + var user = await _userManager.GetUserAsync(User); + try { Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false); try { - return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId)); + return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id)); } catch (Exception ex) { @@ -1121,13 +1125,15 @@ namespace gaseous_server.Controllers [Route("{GameId}/romgroup/{RomId}")] [ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GameRomGroupMembers(long GameId, long RomGroupId, [FromBody] List RomIds) + public async Task GameRomGroupMembersAsync(long GameId, long RomGroupId, [FromBody] List RomIds) { + var user = await _userManager.GetUserAsync(User); + try { Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false); - Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId); + Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id); if (rom.GameId == GameId) { rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds); diff --git a/gaseous-server/Controllers/V1.0/PlatformMapsController.cs b/gaseous-server/Controllers/V1.0/PlatformMapsController.cs index 7d5f055..18304a3 100644 --- a/gaseous-server/Controllers/V1.0/PlatformMapsController.cs +++ b/gaseous-server/Controllers/V1.0/PlatformMapsController.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; using Microsoft.AspNetCore.Authorization; +using System.Text; namespace gaseous_server.Controllers { @@ -37,6 +38,32 @@ namespace gaseous_server.Controllers return Ok(PlatformMapping.PlatformMap); } + [MapToApiVersion("1.0")] + [MapToApiVersion("1.1")] + [HttpGet] + [Route("PlatformMap.json")] + [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult DownloadPlatformMap() + { + string srcJson = Newtonsoft.Json.JsonConvert.SerializeObject(PlatformMapping.PlatformMap, Newtonsoft.Json.Formatting.Indented); + + string filename = "PlatformMap.json"; + byte[] bytes = Encoding.UTF8.GetBytes(srcJson); + string contentType = "application/json"; + + var cd = new System.Net.Mime.ContentDisposition + { + FileName = filename, + Inline = true, + DispositionType = "attachment" + }; + + Response.Headers.Add("Content-Disposition", cd.ToString()); + + return File(bytes, contentType); + } + [MapToApiVersion("1.0")] [MapToApiVersion("1.1")] [HttpGet] diff --git a/gaseous-server/Controllers/V1.1/GamesController.cs b/gaseous-server/Controllers/V1.1/GamesController.cs index c85a457..516c0ef 100644 --- a/gaseous-server/Controllers/V1.1/GamesController.cs +++ b/gaseous-server/Controllers/V1.1/GamesController.cs @@ -85,7 +85,7 @@ namespace gaseous_server.Controllers.v1_1 model.GameAgeRating.IncludeUnrated = false; } - return Ok(GetGames(model, pageNumber, pageSize)); + return Ok(GetGames(model, user.Id, pageNumber, pageSize)); } else { @@ -144,6 +144,7 @@ namespace gaseous_server.Controllers.v1_1 public GameRatingItem GameRating { get; set; } = new GameRatingItem(); public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem(); public GameSortingItem Sorting { get; set; } = new GameSortingItem(); + public bool HasSavedGame { get; set; } public class GameRatingItem @@ -181,11 +182,12 @@ namespace gaseous_server.Controllers.v1_1 } } - public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber = 0, int pageSize = 0) + public static GameReturnPackage GetGames(GameSearchModel model, string userid, int pageNumber = 0, int pageSize = 0) { string whereClause = ""; string havingClause = ""; Dictionary whereParams = new Dictionary(); + whereParams.Add("userid", userid); List whereClauses = new List(); List havingClauses = new List(); @@ -202,6 +204,12 @@ namespace gaseous_server.Controllers.v1_1 whereParams.Add("@Name", "(*" + model.Name + "*) (" + model.Name + ") "); } + if (model.HasSavedGame == true) + { + string hasSavesTemp = "(RomSavedStates.RomSaveCount IS NOT NULL OR RomGroupSavedStates.MediaGroupSaveCount IS NOT NULL)"; + whereClauses.Add(hasSavesTemp); + } + if (model.GameRating != null) { List ratingClauses = new List(); @@ -444,9 +452,71 @@ namespace gaseous_server.Controllers.v1_1 string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder; Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - 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; - - List RetVal = new List(); + + 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, + RomSavedStates.RomSaveCount, + RomGroupSavedStates.MediaGroupSaveCount +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 + (SELECT + Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount + FROM + GameState + JOIN Games_Roms ON GameState.RomId = Games_Roms.Id + WHERE + GameState.IsMediaGroup = 0 + AND GameState.UserId = @userid + GROUP BY Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId + LEFT JOIN + (SELECT + RomMediaGroup.GameId, + COUNT(RomMediaGroup.GameId) AS MediaGroupSaveCount + FROM + RomMediaGroup + JOIN GameState ON RomMediaGroup.Id = GameState.RomId + AND GameState.IsMediaGroup = 1 + AND GameState.UserId = @userid + GROUP BY RomMediaGroup.GameId) RomGroupSavedStates ON Game.Id = RomGroupSavedStates.GameId + 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; + List RetVal = new List(); DataTable dbResponse = db.ExecuteCMD(sql, whereParams); @@ -463,10 +533,24 @@ namespace gaseous_server.Controllers.v1_1 } Game retGame = Storage.BuildCacheObject(new Game() , dbResponse.Rows[i]); - RetVal.Add(retGame); + Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame); + if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value) + { + retMinGame.HasSavedGame = true; + } + else + { + retMinGame.HasSavedGame = false; + } + + RetVal.Add(retMinGame); } - GameReturnPackage gameReturn = new GameReturnPackage(RecordCount, RetVal); + GameReturnPackage gameReturn = new GameReturnPackage + { + Count = RecordCount, + Games = RetVal + }; return gameReturn; } diff --git a/gaseous-server/Models/GaseousGame.cs b/gaseous-server/Models/GaseousGame.cs index 8f6e053..150f108 100644 --- a/gaseous-server/Models/GaseousGame.cs +++ b/gaseous-server/Models/GaseousGame.cs @@ -29,6 +29,8 @@ namespace gaseous_server.Models } } + public bool HasSavedGame { get; set; } = false; + public IGDB.Models.Cover? CoverItem { get @@ -46,49 +48,5 @@ namespace gaseous_server.Models return null; } } - - // public List? ArtworksItem - // { - // get - // { - // if (this.Artworks != null) - // { - // if (this.Artworks.Ids != null) - // { - // List artworks = new List(); - // foreach (long id in this.Artworks.Ids) - // { - // artworks.Add(gaseous_server.Classes.Metadata.Artworks.GetArtwork(id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false)); - // } - - // return artworks; - // } - // } - - // return null; - // } - // } - - // public List? ScreenshotsItem - // { - // get - // { - // if (this.Screenshots != null) - // { - // if (this.Screenshots.Ids != null) - // { - // List screenshots = new List(); - // foreach (long id in this.Screenshots.Ids) - // { - // screenshots.Add(gaseous_server.Classes.Metadata.Screenshots.GetScreenshot(id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false)); - // } - - // return screenshots; - // } - // } - - // return null; - // } - // } } } \ No newline at end of file diff --git a/gaseous-server/wwwroot/.DS_Store b/gaseous-server/wwwroot/.DS_Store index c037546..e145abe 100644 Binary files a/gaseous-server/wwwroot/.DS_Store and b/gaseous-server/wwwroot/.DS_Store differ diff --git a/gaseous-server/wwwroot/emulators/EmulatorJS b/gaseous-server/wwwroot/emulators/EmulatorJS deleted file mode 160000 index c1a9d9b..0000000 --- a/gaseous-server/wwwroot/emulators/EmulatorJS +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c1a9d9b266bbd59b90753d2d6af93bb06204f94a diff --git a/gaseous-server/wwwroot/pages/EmulatorJS.html b/gaseous-server/wwwroot/emulators/EmulatorJS.html similarity index 100% rename from gaseous-server/wwwroot/pages/EmulatorJS.html rename to gaseous-server/wwwroot/emulators/EmulatorJS.html diff --git a/gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html b/gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html index b0ed4e9..33ee3a5 100644 --- a/gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html +++ b/gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html @@ -102,7 +102,7 @@ stateControlsDownload.id = 'stateControlsDownload_' + result[i].id; stateControlsDownload.className = 'saved_state_buttonlink'; stateControlsDownload.href = '/api/v1.1/StateManager/' + modalVariables.romId + '/' + result[i].id + '/State/savestate.state?IsMediaGroup=' + modalVariables.IsMediaGroup; - stateControlsDownload.innerHTML = ''; + stateControlsDownload.innerHTML = ''; stateControls.appendChild(stateControlsDownload); var stateControlsDelete = document.createElement('span'); diff --git a/gaseous-server/wwwroot/pages/emulator.html b/gaseous-server/wwwroot/pages/emulator.html index 60889b2..27182d2 100644 --- a/gaseous-server/wwwroot/pages/emulator.html +++ b/gaseous-server/wwwroot/pages/emulator.html @@ -55,7 +55,7 @@ switch (getQueryString('engine', 'string')) { case 'EmulatorJS': - $('#emulator').load('/pages/EmulatorJS.html?v=' + AppVersion); + $('#emulator').load('/emulators/EmulatorJS.html?v=' + AppVersion); break; } }); diff --git a/gaseous-server/wwwroot/pages/game.html b/gaseous-server/wwwroot/pages/game.html index c6b92df..31feafb 100644 --- a/gaseous-server/wwwroot/pages/game.html +++ b/gaseous-server/wwwroot/pages/game.html @@ -500,8 +500,7 @@ "mediagroup": 1, "rompath": romPath }; - saveStatesButton = document.createElement('a'); - saveStatesButton.href = '#'; + saveStatesButton = document.createElement('div'); saveStatesButton.setAttribute('onclick', 'showDialog("emulatorloadstate", ' + JSON.stringify(modalVariables) + ');'); saveStatesButton.innerHTML = ''; } @@ -672,8 +671,7 @@ "mediagroup": 0, "rompath": romPath }; - saveStatesButton = document.createElement('a'); - saveStatesButton.href = '#'; + saveStatesButton = document.createElement('div'); saveStatesButton.setAttribute('onclick', 'showDialog("emulatorloadstate", ' + JSON.stringify(modalVariables) + ');'); saveStatesButton.innerHTML = ''; } diff --git a/gaseous-server/wwwroot/pages/settings/mapping.html b/gaseous-server/wwwroot/pages/settings/mapping.html index f0feacb..0a18090 100644 --- a/gaseous-server/wwwroot/pages/settings/mapping.html +++ b/gaseous-server/wwwroot/pages/settings/mapping.html @@ -72,7 +72,7 @@ } function DownloadJSON() { - window.open('/api/v1.1/PlatformMaps', '_blank'); + window.location = '/api/v1.1/PlatformMaps/PlatformMap.json'; } document.getElementById('importjson').addEventListener('click', openDialog); diff --git a/gaseous-server/wwwroot/scripts/filterformating.js b/gaseous-server/wwwroot/scripts/filterformating.js index 54fbd83..a756cbd 100644 --- a/gaseous-server/wwwroot/scripts/filterformating.js +++ b/gaseous-server/wwwroot/scripts/filterformating.js @@ -21,6 +21,14 @@ function formatFilterPanel(containerElement, result) { containerPanelSearchField.id = 'filter_panel_search'; containerPanelSearchField.type = 'text'; containerPanelSearchField.placeholder = 'Search'; + containerPanelSearchField.addEventListener("keypress", function(event) { + if (event.key === "Enter") { + // Cancel the default action, if needed + event.preventDefault(); + // Trigger the button element with a click + executeFilter1_1(); + } + }); containerPanelSearch.appendChild(containerPanelSearchField); panel.appendChild(containerPanelSearch); @@ -73,6 +81,8 @@ function formatFilterPanel(containerElement, result) { panel.appendChild(containerPanelUserRating); + buildFilterPanel(panel, 'settings', 'Settings', [{ "id": "savestatesavailable", "name": "Game has save states avaialble", "gameCount": 0 }], true, true); + if (result.platforms) { buildFilterPanel(panel, 'platform', 'Platforms', result.platforms, true, true); } @@ -350,6 +360,9 @@ function executeFilter1_1(pageNumber, pageSize) { setCookie('games_library_orderby_direction_select', orderByDirectionSelect); if (existingSearchModel == undefined || freshSearch == true) { + // search name + setCookie('filter_panel_search', document.getElementById('filter_panel_search').value); + // user ratings var userRatingEnabled = document.getElementById('filter_panel_userrating_enabled'); @@ -386,6 +399,9 @@ function executeFilter1_1(pageNumber, pageSize) { setCookie("filter_panel_userrating_enabled", true); } + // save cookies for settings + GetFilterQuery1_1('settings'); + // build filter model var ratingAgeGroups = GetFilterQuery1_1('agegroupings'); var ratingIncludeUnrated = false; @@ -395,6 +411,7 @@ function executeFilter1_1(pageNumber, pageSize) { model = { "Name": document.getElementById('filter_panel_search').value, + "HasSavedGame": document.getElementById('filter_panel_item_settings_checkbox_savestatesavailable').checked, "Platform": GetFilterQuery1_1('platform'), "Genre": GetFilterQuery1_1('genre'), "GameMode": GetFilterQuery1_1('gamemode'), diff --git a/gaseous-server/wwwroot/scripts/gamesformating.js b/gaseous-server/wwwroot/scripts/gamesformating.js index 8024d3b..b032446 100644 --- a/gaseous-server/wwwroot/scripts/gamesformating.js +++ b/gaseous-server/wwwroot/scripts/gamesformating.js @@ -283,6 +283,14 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification, } } + // add save game icon + if (gameObject.hasSavedGame == true) { + var gameSaveIcon = document.createElement('img'); + gameSaveIcon.src = '/images/SaveStates.png'; + gameSaveIcon.className = 'game_tile_box_savedgame savedstateicon'; + gameImageBox.appendChild(gameSaveIcon); + } + if (gameObject.totalRating || displayClassification == true) { var gameImageRatingBanner = document.createElement('div'); gameImageRatingBanner.className = 'game_tile_box_ratingbanner'; diff --git a/gaseous-server/wwwroot/styles/style.css b/gaseous-server/wwwroot/styles/style.css index 6bb38df..34d1015 100644 --- a/gaseous-server/wwwroot/styles/style.css +++ b/gaseous-server/wwwroot/styles/style.css @@ -213,13 +213,13 @@ h3 { position: -webkit-sticky; bottom: 0; width: 180px; - height: 18px; + height: 15px; padding: 10px; background-color: #352879; color: white; text-align: center; font-family: Commodore64; - font-size: 16px; + font-size: 13px; } #games_library_searchbutton:hover { @@ -232,13 +232,13 @@ h3 { position: -webkit-sticky; bottom: 0; width: 180px; - height: 18px; + height: 15px; padding: 10px; background-color: #646464; color: white; text-align: center; font-family: Commodore64; - font-size: 16px; + font-size: 13px; } #games_library_resetbutton:hover { @@ -557,6 +557,12 @@ input[id='filter_panel_userrating_max'] { -webkit-backdrop-filter: blur(8px); } +.game_tile_box_savedgame { + position: absolute; + top: 1px; + right: 5px; +} + .game_tile_image { max-width: 200px; min-width: 150px; @@ -804,6 +810,7 @@ table .romrow:nth-child(odd) { height: 24px; width: 24px; margin-top: 4px; + cursor: pointer; } th {