Compare commits
3 Commits
v1.7.0-pre
...
v1.7.0-pre
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9b8874902a | ||
![]() |
127eab683b | ||
![]() |
1efc47f9cd |
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -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"
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -404,3 +404,4 @@ ASALocalRun/
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
gaseous-server/.DS_Store
|
||||
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "gaseous-server/wwwroot/emulators/EmulatorJS"]
|
||||
path = gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
url = https://github.com/EmulatorJS/EmulatorJS.git
|
||||
|
@@ -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
|
||||
|
18
README.MD
18
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 <branch or tag name>```
|
||||
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.
|
||||
|
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/.DS_Store
vendored
Binary file not shown.
@@ -289,7 +289,7 @@ namespace Authentication
|
||||
/// <returns></returns>
|
||||
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<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
|
@@ -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<IGDB.Models.Cover> Cover { get; set; }
|
||||
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
||||
|
@@ -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 * FROM RomMediaGroup WHERE Id=@id;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
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<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", Id },
|
||||
{ "userid", userid }
|
||||
};
|
||||
|
||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
@@ -75,12 +78,15 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId)
|
||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "")
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM RomMediaGroup WHERE GameId=@gameid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
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<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", userid }
|
||||
};
|
||||
|
||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
@@ -156,7 +162,7 @@ namespace gaseous_server.Classes
|
||||
public static void DeleteMediaGroup(long Id)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id;";
|
||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState WHERE RomId=@id AND IsMediaGroup=1;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -170,6 +176,15 @@ namespace gaseous_server.Classes
|
||||
|
||||
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
||||
{
|
||||
bool hasSaveStates = false;
|
||||
if (row.Table.Columns.Contains("GameStateRomId"))
|
||||
{
|
||||
if (row["GameStateRomId"] != DBNull.Value)
|
||||
{
|
||||
hasSaveStates = true;
|
||||
}
|
||||
}
|
||||
|
||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
||||
mediaGroupItem.Id = (long)row["Id"];
|
||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
||||
@@ -177,6 +192,7 @@ namespace gaseous_server.Classes
|
||||
mediaGroupItem.GameId = (long)row["GameId"];
|
||||
mediaGroupItem.RomIds = new List<long>();
|
||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
||||
mediaGroupItem.HasSaveStates = hasSaveStates;
|
||||
|
||||
// get members
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
@@ -397,6 +413,7 @@ namespace gaseous_server.Classes
|
||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||
public List<long> RomIds { get; set; }
|
||||
public List<Roms.GameRomItem> Roms { get; set; }
|
||||
public bool HasSaveStates { get; set; } = false;
|
||||
private GroupBuildStatus _Status { get; set; }
|
||||
public GroupBuildStatus Status {
|
||||
get
|
||||
|
@@ -15,7 +15,7 @@ namespace gaseous_server.Classes
|
||||
{}
|
||||
}
|
||||
|
||||
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0)
|
||||
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
||||
{
|
||||
GameRomObject GameRoms = new GameRomObject();
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace gaseous_server.Classes
|
||||
string sqlPlatform = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", GameId);
|
||||
dbDict.Add("userid", userid);
|
||||
|
||||
string NameSearchWhere = "";
|
||||
if (NameSearch.Length > 0)
|
||||
@@ -38,13 +39,13 @@ namespace gaseous_server.Classes
|
||||
|
||||
if (PlatformId == -1) {
|
||||
// data query
|
||||
sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, GameState.RomId AS SavedStateRomId FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
|
||||
// count query
|
||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
||||
} else {
|
||||
// data query
|
||||
sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, GameState.RomId AS SavedStateRomId FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
|
||||
// count query
|
||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
||||
@@ -131,7 +132,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM Games_Roms WHERE Id = @id";
|
||||
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @id;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -140,6 +141,15 @@ namespace gaseous_server.Classes
|
||||
|
||||
private static GameRomItem BuildRom(DataRow romDR)
|
||||
{
|
||||
bool hasSaveStates = false;
|
||||
if (romDR.Table.Columns.Contains("SavedStateRomId"))
|
||||
{
|
||||
if (romDR["SavedStateRomId"] != DBNull.Value)
|
||||
{
|
||||
hasSaveStates = true;
|
||||
}
|
||||
}
|
||||
|
||||
GameRomItem romItem = new GameRomItem
|
||||
{
|
||||
Id = (long)romDR["id"],
|
||||
@@ -159,6 +169,7 @@ namespace gaseous_server.Classes
|
||||
Path = (string)romDR["path"],
|
||||
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
|
||||
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
||||
HasSaveStates = hasSaveStates,
|
||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||
};
|
||||
|
||||
@@ -191,6 +202,7 @@ namespace gaseous_server.Classes
|
||||
public long GameId { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public string? SignatureSourceGameTitle { get; set;}
|
||||
public bool HasSaveStates { get; set; } = false;
|
||||
public GameLibrary.LibraryItem Library { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -6,12 +6,14 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
@@ -25,6 +27,18 @@ namespace gaseous_server.Controllers
|
||||
[ApiController]
|
||||
public class GamesController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public GamesController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
@@ -830,13 +844,15 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||
public ActionResult GameRom(long GameId, int pageNumber = 0, int pageSize = 0, long PlatformId = -1, string NameSearch = "")
|
||||
public async Task<ActionResult> GameRomAsync(long GameId, int pageNumber = 0, int pageSize = 0, long PlatformId = -1, string NameSearch = "")
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
try
|
||||
{
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
return Ok(Classes.Roms.GetRoms(GameId, PlatformId, NameSearch, pageNumber, pageSize));
|
||||
return Ok(Classes.Roms.GetRoms(GameId, PlatformId, NameSearch, pageNumber, pageSize, user.Id));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -1018,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<ActionResult> 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);
|
||||
@@ -1047,15 +1065,17 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/romgroup")]
|
||||
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetGameRomGroup(long GameId)
|
||||
public async Task<ActionResult> 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)
|
||||
{
|
||||
@@ -1105,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<long> RomIds)
|
||||
public async Task<ActionResult> GameRomGroupMembersAsync(long GameId, long RomGroupId, [FromBody] List<long> 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);
|
||||
|
@@ -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]
|
||||
|
@@ -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<string, object> whereParams = new Dictionary<string, object>();
|
||||
whereParams.Add("userid", userid);
|
||||
|
||||
List<string> whereClauses = new List<string>();
|
||||
List<string> havingClauses = new List<string>();
|
||||
@@ -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<string> ratingClauses = new List<string>();
|
||||
@@ -444,11 +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 view_Games.* FROM view_Games LEFT JOIN Relation_Game_Platforms ON view_Games.Id = Relation_Game_Platforms.GameId AND (Relation_Game_Platforms.PlatformsId IN (SELECT DISTINCT PlatformId FROM Games_Roms WHERE Games_Roms.GameId = view_Games.Id)) LEFT JOIN Relation_Game_Genres ON view_Games.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON view_Games.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON view_Games.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON view_Games.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
|
||||
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<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
||||
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<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||
|
||||
@@ -465,10 +533,24 @@ namespace gaseous_server.Controllers.v1_1
|
||||
}
|
||||
|
||||
Game retGame = Storage.BuildCacheObject<Game>(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;
|
||||
}
|
||||
|
||||
GameReturnPackage gameReturn = new GameReturnPackage(RecordCount, RetVal);
|
||||
RetVal.Add(retMinGame);
|
||||
}
|
||||
|
||||
GameReturnPackage gameReturn = new GameReturnPackage
|
||||
{
|
||||
Count = RecordCount,
|
||||
Games = RetVal
|
||||
};
|
||||
|
||||
return gameReturn;
|
||||
}
|
||||
|
279
gaseous-server/Controllers/V1.1/StateManagerController.cs
Normal file
279
gaseous-server/Controllers/V1.1/StateManagerController.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using gaseous_server.Models;
|
||||
using gaseous_server.Classes;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.Data;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class StateManagerController: ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public StateManagerController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.GameStateItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}")]
|
||||
public async Task<ActionResult> SaveStateAsync(long RomId, UploadStateModel uploadState, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state); SELECT LAST_INSERT_ID();";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", user.Id },
|
||||
{ "romid", RomId },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "statedatetime", DateTime.UtcNow },
|
||||
{ "name", "" },
|
||||
{ "screenshot", uploadState.ScreenshotByteArray },
|
||||
{ "state", uploadState.StateByteArray }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return Ok(await GetStateAsync(RomId, (long)(ulong)data.Rows[0][0], IsMediaGroup));
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(List<Models.GameStateItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}")]
|
||||
public async Task<ActionResult> GetAllStateAsync(long RomId, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id, StateDateTime, `Name`, Screenshot FROM GameState WHERE RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid ORDER BY StateDateTime DESC;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
List<Models.GameStateItem> gameStates = new List<GameStateItem>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
gameStates.Add(BuildGameStateItem(row));
|
||||
}
|
||||
|
||||
return Ok(gameStates);
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.GameStateItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}/{StateId}")]
|
||||
public async Task<ActionResult> GetStateAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id, StateDateTime, `Name`, Screenshot FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
// invalid match - return not found
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameStateItem stateItem = BuildGameStateItem(data.Rows[0]);
|
||||
|
||||
return Ok(stateItem);
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}/{StateId}")]
|
||||
public async Task<ActionResult> DeleteStateAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPut]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}/{StateId}")]
|
||||
public async Task<ActionResult> EditStateAsync(long RomId, long StateId, GameStateItemUpdateModel model, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE GameState SET `Name` = @name WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "name", model.Name }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}/{StateId}/Screenshot/")]
|
||||
[Route("{RomId}/{StateId}/Screenshot/image.png")]
|
||||
public async Task<ActionResult> GetStateScreenshotAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Screenshot FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
// invalid match - return not found
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
string filename = "image.jpg";
|
||||
byte[] bytes = (byte[])data.Rows[0][0];
|
||||
string contentType = "image/png";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = filename,
|
||||
Inline = true,
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
return File(bytes, contentType);
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("{RomId}/{StateId}/State/")]
|
||||
[Route("{RomId}/{StateId}/State/savestate.state")]
|
||||
public async Task<ActionResult> GetStateDataAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT State FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
{ "romid", RomId },
|
||||
{ "userid", user.Id },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
// invalid match - return not found
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
string filename = "savestate.state";
|
||||
byte[] bytes = (byte[])data.Rows[0][0];
|
||||
string contentType = "application/octet-stream";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = filename,
|
||||
Inline = true,
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
return File(bytes, contentType);
|
||||
}
|
||||
}
|
||||
|
||||
private Models.GameStateItem BuildGameStateItem(DataRow dr)
|
||||
{
|
||||
bool HasScreenshot = true;
|
||||
if (dr["Screenshot"] == DBNull.Value)
|
||||
{
|
||||
HasScreenshot = false;
|
||||
}
|
||||
GameStateItem stateItem = new GameStateItem
|
||||
{
|
||||
Id = (long)dr["Id"],
|
||||
Name = (string)dr["Name"],
|
||||
SaveTime = DateTime.Parse(((DateTime)dr["StateDateTime"]).ToString("yyyy-MM-ddThh:mm:ss") + 'Z'),
|
||||
HasScreenshot = HasScreenshot
|
||||
};
|
||||
|
||||
return stateItem;
|
||||
}
|
||||
}
|
||||
}
|
35
gaseous-server/Models/GameState.cs
Normal file
35
gaseous-server/Models/GameState.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class UploadStateModel
|
||||
{
|
||||
public string ScreenshotByteArrayBase64 { get; set; }
|
||||
public string StateByteArrayBase64 { get; set; }
|
||||
public byte[] ScreenshotByteArray
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.FromBase64String(ScreenshotByteArrayBase64);
|
||||
}
|
||||
}
|
||||
public byte[] StateByteArray
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.FromBase64String(StateByteArrayBase64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GameStateItem
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public DateTime SaveTime { get; set; }
|
||||
public bool HasScreenshot { get; set; }
|
||||
}
|
||||
|
||||
public class GameStateItemUpdateModel
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
}
|
||||
}
|
@@ -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<IGDB.Models.Artwork>? ArtworksItem
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (this.Artworks != null)
|
||||
// {
|
||||
// if (this.Artworks.Ids != null)
|
||||
// {
|
||||
// List<IGDB.Models.Artwork> artworks = new List<IGDB.Models.Artwork>();
|
||||
// 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<IGDB.Models.Screenshot>? ScreenshotsItem
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (this.Screenshots != null)
|
||||
// {
|
||||
// if (this.Screenshots.Ids != null)
|
||||
// {
|
||||
// List<IGDB.Models.Screenshot> screenshots = new List<IGDB.Models.Screenshot>();
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
11
gaseous-server/Support/Database/MySQL/gaseous-1015.sql
Normal file
11
gaseous-server/Support/Database/MySQL/gaseous-1015.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE `GameState` (
|
||||
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`UserId` VARCHAR(45) NULL,
|
||||
`RomId` BIGINT NULL,
|
||||
`IsMediaGroup` INT NULL,
|
||||
`StateDateTime` DATETIME NULL,
|
||||
`Name` VARCHAR(100) NULL,
|
||||
`Screenshot` LONGBLOB NULL,
|
||||
`State` LONGBLOB NULL,
|
||||
PRIMARY KEY (`Id`),
|
||||
INDEX `idx_UserId` (`UserId` ASC) VISIBLE);
|
@@ -59,6 +59,7 @@
|
||||
<None Remove="Support\Database\MySQL\gaseous-1012.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1013.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1014.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1015.sql" />
|
||||
<None Remove="Classes\Metadata\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -95,5 +96,6 @@
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1012.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1013.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1014.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1015.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
BIN
gaseous-server/wwwroot/.DS_Store
vendored
Binary file not shown.
Submodule gaseous-server/wwwroot/emulators/EmulatorJS deleted from c1a9d9b266
73
gaseous-server/wwwroot/emulators/EmulatorJS.html
Normal file
73
gaseous-server/wwwroot/emulators/EmulatorJS.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!-- <div style='width:640px;height:480px;max-width:100%'> -->
|
||||
<div style='width:100%;height:100%;'>
|
||||
<div id='game'></div>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
EJS_player = '#game';
|
||||
|
||||
// Can also be fceumm or nestopia
|
||||
EJS_core = getQueryString('core', 'string');
|
||||
|
||||
// Lightgun
|
||||
EJS_lightgun = false; // can be true or false
|
||||
|
||||
// URL to BIOS file
|
||||
EJS_biosUrl = emuBios;
|
||||
|
||||
// URL to Game rom
|
||||
EJS_gameUrl = decodeURIComponent(getQueryString('rompath', 'string'));
|
||||
|
||||
// load state if defined
|
||||
if (StateUrl) {
|
||||
console.log('Loading saved state from: ' + StateUrl);
|
||||
EJS_loadStateURL = StateUrl;
|
||||
EJS_startOnLoaded = true;
|
||||
}
|
||||
|
||||
// Path to the data directory
|
||||
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
||||
|
||||
EJS_DEBUG_XX = false;
|
||||
|
||||
EJS_backgroundImage = emuBackground;
|
||||
EJS_backgroundBlur = true;
|
||||
|
||||
EJS_fullscreenOnLoaded = false;
|
||||
|
||||
EJS_gameName = emuGameTitle;
|
||||
|
||||
EJS_threads = false;
|
||||
|
||||
EJS_onSaveState = function(e) {
|
||||
var returnValue = {
|
||||
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
||||
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
||||
};
|
||||
|
||||
var url = '/api/v1.1/StateManager/' + romId + '?IsMediaGroup=' + IsMediaGroup;
|
||||
|
||||
ajaxCall(
|
||||
url,
|
||||
'POST',
|
||||
function (result) {
|
||||
console.log("Upload complete");
|
||||
console.log(result);
|
||||
|
||||
displayNotification('State Saved', 'Game state has been saved.', '/api/v1.1/StateManager/' + romId + '/' + result.value.id + '/Screenshot/image.png?IsMediaGroup=' + IsMediaGroup);
|
||||
},
|
||||
function (error) {
|
||||
console.log("An error occurred");
|
||||
console.log(error);
|
||||
},
|
||||
JSON.stringify(returnValue)
|
||||
);
|
||||
|
||||
returnValue = undefined;
|
||||
}
|
||||
|
||||
EJS_onLoadState = function(e) {
|
||||
showDialog('emulatorloadstate', { "romId": romId, "IsMediaGroup": IsMediaGroup });
|
||||
}
|
||||
</script>
|
||||
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
BIN
gaseous-server/wwwroot/images/SaveStates.png
Normal file
BIN
gaseous-server/wwwroot/images/SaveStates.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
@@ -4,6 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
<link type="text/css" rel="stylesheet" href="/styles/style.css" dat-href="/styles/style.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/styles/notifications.css" dat-href="/styles/notifications.css" />
|
||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
||||
<script src="/scripts/moment-with-locales.min.js"></script>
|
||||
<link href="/styles/select2.min.css" rel="stylesheet" />
|
||||
@@ -14,6 +15,7 @@
|
||||
<script src="/scripts/dropzone.min.js"></script>
|
||||
<script src="/scripts/simpleUpload.min.js"></script>
|
||||
<script src="/scripts/main.js" type="text/javascript"></script>
|
||||
<script src="/scripts/notifications.js" type="text/javascript"></script>
|
||||
<script src="/scripts/filterformating.js" type="text/javascript"></script>
|
||||
<script src="/scripts/gamesformating.js" type="text/javascript"></script>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
@@ -43,6 +45,9 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Notifications -->
|
||||
<div id="notifications_target"></div>
|
||||
|
||||
<div id="banner_icon" onclick="window.location.href = '/index.html';">
|
||||
<img src="/images/logo.png" alt="Gaseous" id="banner_icon_image" />
|
||||
</div>
|
||||
|
@@ -1,35 +0,0 @@
|
||||
<!-- <div style='width:640px;height:480px;max-width:100%'> -->
|
||||
<div style='width:100%;height:100%;'>
|
||||
<div id='game'></div>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
EJS_player = '#game';
|
||||
|
||||
// Can also be fceumm or nestopia
|
||||
EJS_core = getQueryString('core', 'string');
|
||||
|
||||
// Lightgun
|
||||
EJS_lightgun = false; // can be true or false
|
||||
|
||||
// URL to BIOS file
|
||||
EJS_biosUrl = emuBios;
|
||||
|
||||
// URL to Game rom
|
||||
EJS_gameUrl = decodeURIComponent(getQueryString('rompath', 'string'));
|
||||
|
||||
// Path to the data directory
|
||||
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
||||
|
||||
EJS_DEBUG_XX = false;
|
||||
|
||||
EJS_startOnLoaded = false;
|
||||
|
||||
EJS_backgroundImage = emuBackground;
|
||||
EJS_backgroundBlur = true;
|
||||
|
||||
EJS_gameName = emuGameTitle;
|
||||
|
||||
EJS_threads = false;
|
||||
</script>
|
||||
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
159
gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html
Normal file
159
gaseous-server/wwwroot/pages/dialogs/emulatorloadstate.html
Normal file
@@ -0,0 +1,159 @@
|
||||
<div id="saved_states">
|
||||
|
||||
</div>
|
||||
|
||||
<script text="text/javascript">
|
||||
document.getElementById('modal-heading').innerHTML = "Load saved state";
|
||||
|
||||
console.log(modalVariables);
|
||||
|
||||
var statesUrl = '/api/v1.1/StateManager/' + modalVariables.romId + '?IsMediaGroup=' + modalVariables.IsMediaGroup;
|
||||
console.log(statesUrl);
|
||||
function LoadStates() {
|
||||
ajaxCall(
|
||||
statesUrl,
|
||||
'GET',
|
||||
function(result) {
|
||||
var statesBox = document.getElementById('saved_states');
|
||||
statesBox.innerHTML = '';
|
||||
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var stateBox = document.createElement('div');
|
||||
stateBox.id = 'stateBox_' + result[i].id;
|
||||
stateBox.className = 'saved_state_box';
|
||||
|
||||
// screenshot panel
|
||||
var stateImageBox = document.createElement('div');
|
||||
stateImageBox.id = 'stateImageBox_' + result[i].id;
|
||||
stateImageBox.className = 'saved_state_image_box';
|
||||
|
||||
if (result[i].hasScreenshot == true) {
|
||||
var stateImage = document.createElement('img');
|
||||
stateImage.className = 'saved_state_image_image';
|
||||
stateImage.src = '/api/v1.1/StateManager/' + modalVariables.romId + '/' + result[i].id + '/Screenshot/image.png?IsMediaGroup=' + modalVariables.IsMediaGroup;
|
||||
stateImageBox.appendChild(stateImage);
|
||||
}
|
||||
stateBox.appendChild(stateImageBox);
|
||||
|
||||
// main panel
|
||||
var stateMainPanel = document.createElement('div');
|
||||
stateMainPanel.id = 'stateMainPanel_' + result[i].id;
|
||||
stateMainPanel.className = 'saved_state_main_box';
|
||||
|
||||
var stateName = document.createElement('input');
|
||||
stateName.id = 'stateName_' + result[i].id;
|
||||
stateName.type = 'text';
|
||||
stateName.className = 'saved_state_name';
|
||||
stateName.setAttribute('onblur', 'UpdateStateSave(' + result[i].id + ', ' + modalVariables.IsMediaGroup + ');');
|
||||
if (result[i].name) {
|
||||
stateName.value = result[i].name;
|
||||
} else {
|
||||
stateName.setAttribute('placeholder', "Untitled");
|
||||
}
|
||||
stateMainPanel.appendChild(stateName);
|
||||
|
||||
var stateTime = document.createElement('div');
|
||||
stateTime.id = 'stateTime_' + result[i].id;
|
||||
stateTime.className = 'saved_state_date';
|
||||
stateTime.innerHTML = moment(result[i].saveTime).format("YYYY-MM-DD h:mm:ss a");
|
||||
stateMainPanel.appendChild(stateTime);
|
||||
|
||||
var stateControls = document.createElement('div');
|
||||
stateControls.id = 'stateControls_' + result[i].id;
|
||||
stateControls.className = 'saved_state_controls';
|
||||
|
||||
var stateControlsLaunch= document.createElement('span');
|
||||
stateControlsLaunch.id = 'stateControlsLaunch_' + result[i].id;
|
||||
stateControlsLaunch.className = 'romstart';
|
||||
var emulatorTarget = '/index.html?page=emulator&engine=@engine&core=@core&platformid=@platformid&gameid=@gameid&romid=@romid&mediagroup=@mediagroup&rompath=@rompath&stateid=' + result[i].id;
|
||||
switch (getQueryString('page', 'string')) {
|
||||
case 'emulator':
|
||||
var mediagroupint = 0;
|
||||
if (modalVariables.IsMediaGroup == true) {
|
||||
mediagroupint = 1;
|
||||
}
|
||||
emulatorTarget = emulatorTarget.replaceAll('@engine', getQueryString('engine', 'string'));
|
||||
emulatorTarget = emulatorTarget.replaceAll('@core', getQueryString('core', 'string'));
|
||||
emulatorTarget = emulatorTarget.replaceAll('@platformid', getQueryString('platformid', 'string'));
|
||||
emulatorTarget = emulatorTarget.replaceAll('@gameid', getQueryString('gameid', 'string'));
|
||||
emulatorTarget = emulatorTarget.replaceAll('@romid', getQueryString('romid', 'string'));
|
||||
emulatorTarget = emulatorTarget.replaceAll('@mediagroup', mediagroupint);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@rompath', getQueryString('rompath', 'string'));
|
||||
stateControlsLaunch.setAttribute("onclick", 'window.location.replace("' + emulatorTarget + '")');
|
||||
break;
|
||||
case 'game':
|
||||
console.log(modalVariables);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@engine', modalVariables.engine);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@core', modalVariables.core);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@platformid', modalVariables.platformid);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@gameid', modalVariables.gameid);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@romid', modalVariables.romId);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@mediagroup', modalVariables.mediagroup);
|
||||
emulatorTarget = emulatorTarget.replaceAll('@rompath', modalVariables.rompath);
|
||||
stateControlsLaunch.setAttribute("onclick", 'window.location.href = "' + emulatorTarget + '"');
|
||||
break;
|
||||
}
|
||||
|
||||
stateControlsLaunch.innerHTML = 'Launch';
|
||||
stateControlsLaunch.style.float = 'right';
|
||||
stateControls.appendChild(stateControlsLaunch);
|
||||
|
||||
var stateControlsDownload = document.createElement('a');
|
||||
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 = '<img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" />';
|
||||
stateControls.appendChild(stateControlsDownload);
|
||||
|
||||
var stateControlsDelete = document.createElement('span');
|
||||
stateControlsDelete.id = 'stateControlsDelete_' + result[i].id;
|
||||
stateControlsDelete.className = 'saved_state_buttonlink';
|
||||
stateControlsDelete.setAttribute('onclick', 'DeleteStateSave(' + result[i].id + ', ' + modalVariables.IsMediaGroup + ');');
|
||||
stateControlsDelete.innerHTML = '<img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" />';
|
||||
stateControls.appendChild(stateControlsDelete);
|
||||
|
||||
stateMainPanel.appendChild(stateControls);
|
||||
|
||||
stateBox.appendChild(stateMainPanel);
|
||||
|
||||
statesBox.appendChild(stateBox);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
LoadStates();
|
||||
|
||||
function DeleteStateSave(StateId, IsMediaGroup) {
|
||||
ajaxCall(
|
||||
'/api/v1.1/StateManager/' + modalVariables.romId + '/' + StateId + '?IsMediaGroup=' + IsMediaGroup,
|
||||
'DELETE',
|
||||
function(success) {
|
||||
LoadStates();
|
||||
},
|
||||
function (error) {
|
||||
LoadStates();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function UpdateStateSave(StateId, IsMediaGroup) {
|
||||
var stateName = document.getElementById('stateName_' + StateId);
|
||||
|
||||
var model = {
|
||||
"name": stateName.value
|
||||
};
|
||||
|
||||
ajaxCall(
|
||||
'/api/v1.1/StateManager/' + modalVariables.romId + '/' + StateId + '?IsMediaGroup=' + IsMediaGroup,
|
||||
'PUT',
|
||||
function(success) {
|
||||
LoadStates();
|
||||
},
|
||||
function (error) {
|
||||
LoadStates();
|
||||
},
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
</script>
|
@@ -1,4 +1,4 @@
|
||||
<p>Are you sure you want to delete this media group?</p>
|
||||
<p>Are you sure you want to delete this media group and all associated saved states?</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;">
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<p>Are you sure you want to delete this ROM?</p>
|
||||
<p>Are you sure you want to delete this ROM and all associated saved states?</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;">
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<p>Are you sure you want to delete the selected ROMs?</p>
|
||||
<p>Are you sure you want to delete the selected ROMs and any associated saved states?</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;">
|
||||
|
@@ -6,7 +6,15 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
var gameId = getQueryString('gameid', 'int');
|
||||
var romId = getQueryString('romid', 'int');
|
||||
var platformId = getQueryString('platformid', 'int');
|
||||
var IsMediaGroupInt = getQueryString('mediagroup', 'int');
|
||||
var IsMediaGroup = false;
|
||||
if (IsMediaGroupInt == 1) { IsMediaGroup = true; }
|
||||
var StateUrl = undefined;
|
||||
if (getQueryString('stateid', 'int')) {
|
||||
StateUrl = '/api/v1.1/StateManager/' + romId + '/' + getQueryString('stateid', 'int') + '/State/savestate.state?IsMediaGroup=' + IsMediaGroup;
|
||||
}
|
||||
var gameData;
|
||||
var artworks = null;
|
||||
var artworksPosition = 0;
|
||||
@@ -47,7 +55,7 @@
|
||||
|
||||
switch (getQueryString('engine', 'string')) {
|
||||
case 'EmulatorJS':
|
||||
$('#emulator').load('/pages/EmulatorJS.html?v=' + AppVersion);
|
||||
$('#emulator').load('/emulators/EmulatorJS.html?v=' + AppVersion);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@@ -97,7 +97,7 @@
|
||||
<button value="Search" onclick="loadRoms();">Search</button>
|
||||
</div>
|
||||
<div class="games_library_controlblock">
|
||||
<span class="games_library_label">0 ROMs</span>
|
||||
<span id="games_roms_count" class="games_library_label">0 ROMs</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="gamesummaryromscontent"></div>
|
||||
@@ -476,7 +476,7 @@
|
||||
mgTable.id = 'mediagrouptable';
|
||||
mgTable.className = 'romtable';
|
||||
mgTable.setAttribute('cellspacing', 0);
|
||||
mgTable.appendChild(createTableRow(true, ['Platform', 'Images', 'Size', '', '', '']));
|
||||
mgTable.appendChild(createTableRow(true, ['Platform', 'Images', 'Size', '', '', '', '']));
|
||||
|
||||
lastPlatform = '';
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
@@ -484,9 +484,28 @@
|
||||
|
||||
// get rom details including emulator and friendly platform name
|
||||
var launchButton = '';
|
||||
var saveStatesButton = '';
|
||||
if (mediaGroup.emulator) {
|
||||
if (mediaGroup.emulator.type.length > 0) {
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + mediaGroup.emulator.type + '&core=' + mediaGroup.emulator.core + '&platformid=' + mediaGroup.platformId + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip') + '" class="romstart">Launch</a>';
|
||||
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip');
|
||||
|
||||
if (mediaGroup.hasSaveStates == true) {
|
||||
var modalVariables = {
|
||||
"romId": mediaGroup.id,
|
||||
"IsMediaGroup": true,
|
||||
"engine": mediaGroup.emulator.type,
|
||||
"core": mediaGroup.emulator.core,
|
||||
"platformid": mediaGroup.platformId,
|
||||
"gameid": gameId,
|
||||
"mediagroup": 1,
|
||||
"rompath": romPath
|
||||
};
|
||||
saveStatesButton = document.createElement('div');
|
||||
saveStatesButton.setAttribute('onclick', 'showDialog("emulatorloadstate", ' + JSON.stringify(modalVariables) + ');');
|
||||
saveStatesButton.innerHTML = '<img src="/images/SaveStates.png" class="savedstateicon" />';
|
||||
}
|
||||
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + mediaGroup.emulator.type + '&core=' + mediaGroup.emulator.core + '&platformid=' + mediaGroup.platformId + '&gameid=' + gameId + '&romid=' + mediaGroup.id + '&mediagroup=1&rompath=' + romPath + '" class="romstart">Launch</a>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,15 +551,19 @@
|
||||
mediaGroup.romIds.length,
|
||||
packageSize,
|
||||
statusText,
|
||||
saveStatesButton,
|
||||
launchButtonContent,
|
||||
'<div style="text-align: right;">' + downloadLink + deleteButton + '</div>'
|
||||
]
|
||||
|
||||
mgTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
|
||||
var mgRowBody = document.createElement('tbody');
|
||||
mgRowBody.className = 'romrow';
|
||||
|
||||
mgRowBody.appendChild(createTableRow(false, newRow, '', 'romcell'));
|
||||
|
||||
var mgRomRow = document.createElement('tr');
|
||||
var mgRomCell = document.createElement('td');
|
||||
mgRomCell.setAttribute('colspan', 6);
|
||||
mgRomCell.setAttribute('colspan', 7);
|
||||
mgRomCell.className = 'romGroupTitles';
|
||||
|
||||
|
||||
@@ -557,7 +580,9 @@
|
||||
}
|
||||
mgRomCell.innerHTML = groupMemberNames.join("<br />");
|
||||
mgRomRow.appendChild(mgRomCell);
|
||||
mgTable.appendChild(mgRomRow);
|
||||
mgRowBody.appendChild(mgRomRow);
|
||||
|
||||
mgTable.appendChild(mgRowBody);
|
||||
}
|
||||
|
||||
mediaGroupDiv.appendChild(mgTable);
|
||||
@@ -600,6 +625,13 @@
|
||||
var gameRoms = document.getElementById('gamesummaryromscontent');
|
||||
var pageSize = 20;
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms?pageNumber=' + pageNumber + '&pageSize=' + pageSize + '&platformId=' + selectedPlatform + nameSearchQuery, 'GET', function (result) {
|
||||
var romCount = document.getElementById('games_roms_count');
|
||||
if (result.count != 1) {
|
||||
romCount.innerHTML = result.count + ' ROMs';
|
||||
} else {
|
||||
romCount.innerHTML = result.count + ' ROM';
|
||||
}
|
||||
|
||||
if (result.gameRomItems) {
|
||||
var gameRomItems = result.gameRomItems;
|
||||
|
||||
@@ -608,7 +640,7 @@
|
||||
newTable.id = 'romtable';
|
||||
newTable.className = 'romtable';
|
||||
newTable.setAttribute('cellspacing', 0);
|
||||
newTable.appendChild(createTableRow(true, [['<input id="rom_mastercheck" type="checkbox" onclick="selectAllChecks(); handleChecks();"/>', 'rom_checkbox_box_hidden', 'rom_edit_checkbox'], 'Name', 'Size', 'Media', '', '', '']));
|
||||
newTable.appendChild(createTableRow(true, [['<input id="rom_mastercheck" type="checkbox" onclick="selectAllChecks(); handleChecks();"/>', 'rom_checkbox_box_hidden', 'rom_edit_checkbox'], 'Name', 'Size', 'Media', '', '', '', '']));
|
||||
|
||||
var lastPlatform = '';
|
||||
for (var i = 0; i < gameRomItems.length; i++) {
|
||||
@@ -622,11 +654,28 @@
|
||||
newTable.appendChild(platformRow);
|
||||
}
|
||||
|
||||
var saveStatesButton = '';
|
||||
var launchButton = '';
|
||||
if (result.gameRomItems[i].emulator) {
|
||||
if (gameRomItems[i].emulator.type) {
|
||||
if (gameRomItems[i].emulator.type.length > 0) {
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItems[i].emulator.type + '&core=' + gameRomItems[i].emulator.core + '&platformid=' + gameRomItems[i].platformId + '&gameid=' + gameId + '&rompath=' + encodeURIComponent('/api/v1.1/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + encodeURIComponent(gameRomItems[i].name)) + '" class="romstart">Launch</a>';
|
||||
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/roms/' + gameRomItems[i].id + '/' + gameRomItems[i].name);
|
||||
if (gameRomItems[i].hasSaveStates == true) {
|
||||
var modalVariables = {
|
||||
"romId": gameRomItems[i].id,
|
||||
"IsMediaGroup": false,
|
||||
"engine": gameRomItems[i].emulator.type,
|
||||
"core": gameRomItems[i].emulator.core,
|
||||
"platformid": gameRomItems[i].platformId,
|
||||
"gameid": gameId,
|
||||
"mediagroup": 0,
|
||||
"rompath": romPath
|
||||
};
|
||||
saveStatesButton = document.createElement('div');
|
||||
saveStatesButton.setAttribute('onclick', 'showDialog("emulatorloadstate", ' + JSON.stringify(modalVariables) + ');');
|
||||
saveStatesButton.innerHTML = '<img src="/images/SaveStates.png" class="savedstateicon" />';
|
||||
}
|
||||
launchButton = '<a href="/index.html?page=emulator&engine=' + gameRomItems[i].emulator.type + '&core=' + gameRomItems[i].emulator.core + '&platformid=' + gameRomItems[i].platformId + '&gameid=' + gameId + '&romid=' + gameRomItems[i].id + '&mediagroup=0&rompath=' + romPath + '" class="romstart">Launch</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,10 +686,11 @@
|
||||
formatBytes(gameRomItems[i].size, 2),
|
||||
gameRomItems[i].romTypeMedia,
|
||||
gameRomItems[i].mediaLabel,
|
||||
saveStatesButton,
|
||||
launchButton,
|
||||
'<div class="properties_button" onclick="showDialog(\'rominfo\', ' + gameRomItems[i].id + ');">i</div>'
|
||||
];
|
||||
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
|
||||
newTable.appendChild(createTableRow(false, newRow, 'romrow romrowgamepage', 'romcell'));
|
||||
}
|
||||
|
||||
gameRoms.appendChild(newTable);
|
||||
@@ -713,15 +763,17 @@
|
||||
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);');
|
||||
}
|
||||
|
||||
// // load artwork
|
||||
// if (game.artworks) {
|
||||
// ajaxCall('/api/v1.1/games/' + gameId + '/artwork', 'GET', function (result) {
|
||||
// artworks = result;
|
||||
// var startPos = randomIntFromInterval(0, result.length);
|
||||
// artworksPosition = startPos;
|
||||
// rotateBackground();
|
||||
// });
|
||||
// }
|
||||
// load artwork
|
||||
if (!artworks) {
|
||||
if (game.artworks) {
|
||||
ajaxCall('/api/v1.1/games/' + gameId + '/artwork', 'GET', function (result) {
|
||||
artworks = result;
|
||||
var startPos = randomIntFromInterval(0, result.length);
|
||||
artworksPosition = startPos;
|
||||
rotateBackground();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rotateBackground() {
|
||||
|
@@ -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);
|
||||
|
@@ -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'),
|
||||
|
@@ -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';
|
||||
|
@@ -496,3 +496,12 @@ function SetPreference_Local(Setting, Value) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Uint8ToString(u8a){
|
||||
var CHUNK_SZ = 0x8000;
|
||||
var c = [];
|
||||
for (var i=0; i < u8a.length; i+=CHUNK_SZ) {
|
||||
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
|
||||
}
|
||||
return c.join("");
|
||||
}
|
58
gaseous-server/wwwroot/scripts/notifications.js
Normal file
58
gaseous-server/wwwroot/scripts/notifications.js
Normal file
@@ -0,0 +1,58 @@
|
||||
function displayNotification(heading, message, image, link) {
|
||||
var noteId = Math.random().toString(36).substr(2, 9);
|
||||
|
||||
var noteBox = document.createElement('div');
|
||||
noteBox.id = noteId;
|
||||
noteBox.className = 'notification';
|
||||
noteBox.style.display = 'none;'
|
||||
|
||||
if (link) {
|
||||
noteBox.setAttribute('onclick', 'window.location.href = "' + link + '"');
|
||||
} else {
|
||||
noteBox.setAttribute('onclick', 'closeNotification("' + noteId + '");');
|
||||
}
|
||||
|
||||
if (image) {
|
||||
var noteImageBox = document.createElement('div');
|
||||
noteImageBox.className = 'notification_imagebox';
|
||||
|
||||
var noteImage = document.createElement('img');
|
||||
noteImage.className = 'notification_image';
|
||||
noteImage.src = image;
|
||||
noteImageBox.appendChild(noteImage);
|
||||
|
||||
noteBox.appendChild(noteImageBox);
|
||||
}
|
||||
|
||||
var noteMessageBox = document.createElement('div');
|
||||
noteMessageBox.className = 'notification_messagebox';
|
||||
|
||||
if (heading) {
|
||||
var noteMessageHeading = document.createElement('div');
|
||||
noteMessageHeading.className = 'notification_title';
|
||||
noteMessageHeading.innerHTML = heading;
|
||||
noteMessageBox.appendChild(noteMessageHeading);
|
||||
}
|
||||
|
||||
var noteMessageBody = document.createElement('div');
|
||||
noteMessageBody.className = 'notification_message';
|
||||
noteMessageBody.innerHTML = message;
|
||||
noteMessageBox.appendChild(noteMessageBody);
|
||||
|
||||
noteBox.appendChild(noteMessageBox);
|
||||
|
||||
document.getElementById('notifications_target').appendChild(noteBox);
|
||||
|
||||
$(noteBox).hide().fadeIn(500);
|
||||
|
||||
setTimeout(function() {
|
||||
closeNotification(noteId);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function closeNotification(id) {
|
||||
var notificationObj = document.getElementById(id);
|
||||
$(notificationObj).fadeOut(1000, function() {
|
||||
notificationObj.parentElement.removeChild(notificationObj);
|
||||
});
|
||||
}
|
58
gaseous-server/wwwroot/styles/notifications.css
Normal file
58
gaseous-server/wwwroot/styles/notifications.css
Normal file
@@ -0,0 +1,58 @@
|
||||
#notification_target {
|
||||
position: fixed;
|
||||
top: 40px;
|
||||
width: 400px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column nowrap;
|
||||
top: 55px;
|
||||
right: 15px;
|
||||
width: 350px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 7px;
|
||||
border-color: rgba(0, 22, 56, 0.7);
|
||||
padding-left: 15px;
|
||||
padding-right: 20px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 10px;
|
||||
background-color: rgba(0, 22, 56, 0.6);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
-webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
-moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.notification_imagebox {
|
||||
flex-basis: 70px;
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.notification_image {
|
||||
width: 80px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.notification_messagebox {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.notification_title {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 5px;
|
||||
font-size: 14px;
|
||||
color: rgb(160, 160, 186);
|
||||
}
|
||||
|
||||
.notification_message {
|
||||
|
||||
}
|
@@ -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;
|
||||
@@ -792,10 +798,21 @@ table .romrow:nth-child(odd) {
|
||||
background: rgba(56, 56, 56, 0.3);
|
||||
}
|
||||
|
||||
.romrow.romrowgamepage {
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.romcell {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.savedstateicon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-top: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 5px;
|
||||
@@ -1417,3 +1434,48 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#saved_states {
|
||||
overflow-x: scroll;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.saved_state_box {
|
||||
display: flex;
|
||||
flex-direction: column nowrap;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.saved_state_image_box {
|
||||
flex-basis: 128px;
|
||||
}
|
||||
|
||||
.saved_state_image_image {
|
||||
width: 128px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.saved_state_main_box {
|
||||
flex-grow: 1;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.saved_state_name {
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.saved_state_date {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.saved_state_controls {
|
||||
margin-top: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.saved_state_buttonlink {
|
||||
cursor: pointer;
|
||||
}
|
Reference in New Issue
Block a user