Compare commits
20 Commits
v1.7.0-pre
...
v1.7.0-pre
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9b8874902a | ||
![]() |
127eab683b | ||
![]() |
1efc47f9cd | ||
![]() |
7f2e186d06 | ||
![]() |
7d5419d33c | ||
![]() |
ce9ab91e5b | ||
![]() |
eac35ee8a3 | ||
![]() |
49f36a2b99 | ||
![]() |
47c2fc8069 | ||
![]() |
9a215123f6 | ||
![]() |
40597b4386 | ||
![]() |
eb9c1ce1a4 | ||
![]() |
7be1ec7080 | ||
![]() |
311c7733fa | ||
![]() |
ea0a5a6a71 | ||
![]() |
d014a176ce | ||
![]() |
b9d9b0ea16 | ||
![]() |
7e3e4991dc | ||
![]() |
57248cd467 | ||
![]() |
722c153e40 |
6
.github/dependabot.yml
vendored
@@ -9,9 +9,3 @@ updates:
|
|||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
- package-ecosystem: "gitsubmodule"
|
|
||||||
directory: "/"
|
|
||||||
allow:
|
|
||||||
- dependency-name: "gaseous-server/wwwroot/emulators/EmulatorJS"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
2
.gitignore
vendored
@@ -403,3 +403,5 @@ ASALocalRun/
|
|||||||
|
|
||||||
# Local History for Visual Studio
|
# Local History for Visual Studio
|
||||||
.localhistory/
|
.localhistory/
|
||||||
|
gaseous-server/.DS_Store
|
||||||
|
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||||
|
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
|
# Build and publish a release
|
||||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o out
|
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
|
# Build runtime image
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0
|
FROM mcr.microsoft.com/dotnet/aspnet:7.0
|
||||||
WORKDIR /App
|
WORKDIR /App
|
||||||
|
20
README.MD
@@ -1,6 +1,6 @@
|
|||||||
# Gaseous Server
|
# Gaseous Server
|
||||||
|
|
||||||
This is the server for the Gaseous system. It offers ROM and title management, as well as some basic in browser emulation of those ROM's.
|
This is the server for the Gaseous system. It offers ROM and title management, as well as some basic in browser emulation of those ROMs.
|
||||||
|
|
||||||
## Warning
|
## Warning
|
||||||
|
|
||||||
@@ -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.
|
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```
|
1. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
|
||||||
2. Change into the gaseous-server directory
|
2. Change into the gaseous-server directory
|
||||||
3. Clone the submodules with the command ```git submodule update --init```
|
3. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
|
||||||
4. 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. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d```
|
5. Connect to the host on port 5198
|
||||||
6. Connect to the host on port 5198
|
|
||||||
|
|
||||||
## Source
|
## Source
|
||||||
### Build and deploy
|
### 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
|
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```
|
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
|
* 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```
|
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```
|
||||||
* This command will clone the code that the server uses from other projects (currently only 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```
|
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
|
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```
|
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.
|
**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
|
### Updating from source
|
||||||
1. Stop the server
|
1. Stop the server
|
||||||
2. Switch to the source directory
|
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:
|
* If running from another branch or tag, run:
|
||||||
* ```git fetch```
|
* ```git fetch```
|
||||||
* ```git checkout <branch or tag name>```
|
* ```git checkout <branch or tag name>```
|
||||||
4. Update the submodules with ```git submodule update --recursive```
|
4. Run steps 12 and 13 from the above Build guide
|
||||||
5. Run steps 12 and 13 from the above Build guide
|
|
||||||
|
|
||||||
# Adding Content
|
# 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.
|
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/Assets/.DS_Store
vendored
BIN
gaseous-server/Assets/Ratings/.DS_Store
vendored
@@ -289,7 +289,7 @@ namespace Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private int Delete(string userId)
|
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>();
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
parameters.Add("@userId", userId);
|
parameters.Add("@userId", userId);
|
||||||
|
|
||||||
|
@@ -5,13 +5,13 @@ namespace Authentication
|
|||||||
public class SecurityProfileViewModel
|
public class SecurityProfileViewModel
|
||||||
{
|
{
|
||||||
public AgeRestrictionItem AgeRestrictionPolicy { get; set; } = new AgeRestrictionItem{
|
public AgeRestrictionItem AgeRestrictionPolicy { get; set; } = new AgeRestrictionItem{
|
||||||
MaximumAgeRestriction = gaseous_server.Classes.Metadata.AgeRatings.AgeGroups.AgeRestrictionGroupings.Adult,
|
MaximumAgeRestriction = gaseous_server.Classes.Metadata.AgeGroups.AgeRestrictionGroupings.Adult,
|
||||||
IncludeUnrated = true
|
IncludeUnrated = true
|
||||||
};
|
};
|
||||||
|
|
||||||
public class AgeRestrictionItem
|
public class AgeRestrictionItem
|
||||||
{
|
{
|
||||||
public gaseous_server.Classes.Metadata.AgeRatings.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction { get; set; }
|
public gaseous_server.Classes.Metadata.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction { get; set; }
|
||||||
public bool IncludeUnrated { get; set; }
|
public bool IncludeUnrated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ using IGDB.Models;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -66,7 +67,7 @@ namespace gaseous_server.Classes
|
|||||||
public static CollectionItem NewCollection(CollectionItem item)
|
public static CollectionItem NewCollection(CollectionItem item)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "INSERT INTO RomCollections (`Name`, Description, Platforms, Genres, Players, PlayerPerspectives, Themes, MinimumRating, MaximumRating, MaximumRomsPerPlatform, MaximumBytesPerPlatform, MaximumCollectionSizeInBytes, FolderStructure, IncludeBIOSFiles, AlwaysInclude, BuiltStatus) VALUES (@name, @description, @platforms, @genres, @players, @playerperspectives, @themes, @minimumrating, @maximumrating, @maximumromsperplatform, @maximumbytesperplatform, @maximumcollectionsizeinbytes, @folderstructure, @includebiosfiles, @alwaysinclude, @builtstatus); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
string sql = "INSERT INTO RomCollections (`Name`, Description, Platforms, Genres, Players, PlayerPerspectives, Themes, MinimumRating, MaximumRating, MaximumRomsPerPlatform, MaximumBytesPerPlatform, MaximumCollectionSizeInBytes, FolderStructure, IncludeBIOSFiles, ArchiveType, AlwaysInclude, BuiltStatus) VALUES (@name, @description, @platforms, @genres, @players, @playerperspectives, @themes, @minimumrating, @maximumrating, @maximumromsperplatform, @maximumbytesperplatform, @maximumcollectionsizeinbytes, @folderstructure, @includebiosfiles, @archivetype, @alwaysinclude, @builtstatus); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("name", item.Name);
|
dbDict.Add("name", item.Name);
|
||||||
dbDict.Add("description", item.Description);
|
dbDict.Add("description", item.Description);
|
||||||
@@ -82,6 +83,7 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
||||||
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
||||||
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
||||||
|
dbDict.Add("archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip));
|
||||||
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
||||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -97,7 +99,7 @@ namespace gaseous_server.Classes
|
|||||||
public static CollectionItem EditCollection(long Id, CollectionItem item, bool ForceRebuild = true)
|
public static CollectionItem EditCollection(long Id, CollectionItem item, bool ForceRebuild = true)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "UPDATE RomCollections SET `Name`=@name, Description=@description, Platforms=@platforms, Genres=@genres, Players=@players, PlayerPerspectives=@playerperspectives, Themes=@themes, MinimumRating=@minimumrating, MaximumRating=@maximumrating, MaximumRomsPerPlatform=@maximumromsperplatform, MaximumBytesPerPlatform=@maximumbytesperplatform, MaximumCollectionSizeInBytes=@maximumcollectionsizeinbytes, FolderStructure=@folderstructure, IncludeBIOSFiles=@includebiosfiles, AlwaysInclude=@alwaysinclude, BuiltStatus=@builtstatus WHERE Id=@id";
|
string sql = "UPDATE RomCollections SET `Name`=@name, Description=@description, Platforms=@platforms, Genres=@genres, Players=@players, PlayerPerspectives=@playerperspectives, Themes=@themes, MinimumRating=@minimumrating, MaximumRating=@maximumrating, MaximumRomsPerPlatform=@maximumromsperplatform, MaximumBytesPerPlatform=@maximumbytesperplatform, MaximumCollectionSizeInBytes=@maximumcollectionsizeinbytes, FolderStructure=@folderstructure, IncludeBIOSFiles=@includebiosfiles, ArchiveType=@archivetype, AlwaysInclude=@alwaysinclude, BuiltStatus=@builtstatus WHERE Id=@id";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", Id);
|
dbDict.Add("id", Id);
|
||||||
dbDict.Add("name", item.Name);
|
dbDict.Add("name", item.Name);
|
||||||
@@ -115,8 +117,9 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
||||||
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
||||||
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
||||||
|
dbDict.Add("archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip));
|
||||||
|
|
||||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + item.ArchiveExtension);
|
||||||
if (ForceRebuild == true)
|
if (ForceRebuild == true)
|
||||||
{
|
{
|
||||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||||
@@ -220,7 +223,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get all platforms to pull from
|
// get all platforms to pull from
|
||||||
Dictionary<string, object> FilterDict = Filters.Filter(AgeRatings.AgeGroups.AgeRestrictionGroupings.Adult, true);
|
Dictionary<string, List<Filters.FilterItem>> FilterDict = Filters.Filter(AgeGroups.AgeRestrictionGroupings.Adult, true);
|
||||||
List<Classes.Filters.FilterItem> filteredPlatforms = (List<Classes.Filters.FilterItem>)FilterDict["platforms"];
|
List<Classes.Filters.FilterItem> filteredPlatforms = (List<Classes.Filters.FilterItem>)FilterDict["platforms"];
|
||||||
foreach (Filters.FilterItem filterItem in filteredPlatforms) {
|
foreach (Filters.FilterItem filterItem in filteredPlatforms) {
|
||||||
platforms.Add(Platforms.GetPlatform(filterItem.Id));
|
platforms.Add(Platforms.GetPlatform(filterItem.Id));
|
||||||
@@ -304,7 +307,7 @@ namespace gaseous_server.Classes
|
|||||||
// calculate total rom size for the game
|
// calculate total rom size for the game
|
||||||
long GameRomSize = 0;
|
long GameRomSize = 0;
|
||||||
foreach (Roms.GameRomItem gameRom in gameRoms) {
|
foreach (Roms.GameRomItem gameRom in gameRoms) {
|
||||||
GameRomSize += gameRom.Size;
|
GameRomSize += (long)gameRom.Size;
|
||||||
}
|
}
|
||||||
if (collectionItem.MaximumBytesPerPlatform > 0) {
|
if (collectionItem.MaximumBytesPerPlatform > 0) {
|
||||||
if ((TotalRomSize + GameRomSize) < collectionItem.MaximumBytesPerPlatform) {
|
if ((TotalRomSize + GameRomSize) < collectionItem.MaximumBytesPerPlatform) {
|
||||||
@@ -389,7 +392,7 @@ namespace gaseous_server.Classes
|
|||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = GetCollectionContent(collectionItem).Collection;
|
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = GetCollectionContent(collectionItem).Collection;
|
||||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + ".zip");
|
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + collectionItem.ArchiveExtension);
|
||||||
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -499,7 +502,7 @@ namespace gaseous_server.Classes
|
|||||||
if (File.Exists(gameRomItem.Path))
|
if (File.Exists(gameRomItem.Path))
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Collections", "Copying ROM: " + gameRomItem.Name);
|
Logging.Log(Logging.LogType.Information, "Collections", "Copying ROM: " + gameRomItem.Name);
|
||||||
File.Copy(gameRomItem.Path, Path.Combine(ZipGamePath, gameRomItem.Name));
|
File.Copy(gameRomItem.Path, Path.Combine(ZipGamePath, gameRomItem.Name), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,7 +511,21 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// compress to zip
|
// compress to zip
|
||||||
Logging.Log(Logging.LogType.Information, "Collections", "Compressing collection");
|
Logging.Log(Logging.LogType.Information, "Collections", "Compressing collection");
|
||||||
ZipFile.CreateFromDirectory(ZipFileTempPath, ZipFilePath, CompressionLevel.SmallestSize, false);
|
switch(collectionItem.ArchiveType)
|
||||||
|
{
|
||||||
|
case CollectionItem.ArchiveTypes.Zip:
|
||||||
|
ZipFile.CreateFromDirectory(ZipFileTempPath, ZipFilePath, CompressionLevel.SmallestSize, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionItem.ArchiveTypes.RAR:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionItem.ArchiveTypes.SevenZip:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
if (Directory.Exists(ZipFileTempPath))
|
if (Directory.Exists(ZipFileTempPath))
|
||||||
@@ -567,6 +584,7 @@ namespace gaseous_server.Classes
|
|||||||
item.MaximumCollectionSizeInBytes = (long)Common.ReturnValueIfNull(row["MaximumCollectionSizeInBytes"], (long)-1);
|
item.MaximumCollectionSizeInBytes = (long)Common.ReturnValueIfNull(row["MaximumCollectionSizeInBytes"], (long)-1);
|
||||||
item.FolderStructure = (CollectionItem.FolderStructures)(int)Common.ReturnValueIfNull(row["FolderStructure"], 0);
|
item.FolderStructure = (CollectionItem.FolderStructures)(int)Common.ReturnValueIfNull(row["FolderStructure"], 0);
|
||||||
item.IncludeBIOSFiles = (bool)row["IncludeBIOSFiles"];
|
item.IncludeBIOSFiles = (bool)row["IncludeBIOSFiles"];
|
||||||
|
item.ArchiveType = (CollectionItem.ArchiveTypes)(int)Common.ReturnValueIfNull(row["ArchiveType"], 0);
|
||||||
item.AlwaysInclude = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CollectionItem.AlwaysIncludeItem>>(strAlwaysInclude);
|
item.AlwaysInclude = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CollectionItem.AlwaysIncludeItem>>(strAlwaysInclude);
|
||||||
item.BuildStatus = (CollectionItem.CollectionBuildStatus)(int)Common.ReturnValueIfNull(row["BuiltStatus"], 0);
|
item.BuildStatus = (CollectionItem.CollectionBuildStatus)(int)Common.ReturnValueIfNull(row["BuiltStatus"], 0);
|
||||||
|
|
||||||
@@ -595,6 +613,32 @@ namespace gaseous_server.Classes
|
|||||||
public long? MaximumCollectionSizeInBytes { get; set; }
|
public long? MaximumCollectionSizeInBytes { get; set; }
|
||||||
public FolderStructures FolderStructure { get; set; } = FolderStructures.Gaseous;
|
public FolderStructures FolderStructure { get; set; } = FolderStructures.Gaseous;
|
||||||
public bool IncludeBIOSFiles { get; set; } = true;
|
public bool IncludeBIOSFiles { get; set; } = true;
|
||||||
|
public ArchiveTypes ArchiveType { get; set; } = CollectionItem.ArchiveTypes.Zip;
|
||||||
|
public string ArchiveExtension
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (ArchiveType != null)
|
||||||
|
{
|
||||||
|
switch (ArchiveType)
|
||||||
|
{
|
||||||
|
case ArchiveTypes.Zip:
|
||||||
|
default:
|
||||||
|
return ".zip";
|
||||||
|
|
||||||
|
case ArchiveTypes.RAR:
|
||||||
|
return ".rar";
|
||||||
|
|
||||||
|
case ArchiveTypes.SevenZip:
|
||||||
|
return ".7z";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ".zip";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public List<AlwaysIncludeItem> AlwaysInclude { get; set; }
|
public List<AlwaysIncludeItem> AlwaysInclude { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@@ -604,7 +648,7 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
if (_BuildStatus == CollectionBuildStatus.Completed)
|
if (_BuildStatus == CollectionBuildStatus.Completed)
|
||||||
{
|
{
|
||||||
if (File.Exists(Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip")))
|
if (File.Exists(Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ArchiveExtension)))
|
||||||
{
|
{
|
||||||
return CollectionBuildStatus.Completed;
|
return CollectionBuildStatus.Completed;
|
||||||
}
|
}
|
||||||
@@ -632,7 +676,7 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
if (BuildStatus == CollectionBuildStatus.Completed)
|
if (BuildStatus == CollectionBuildStatus.Completed)
|
||||||
{
|
{
|
||||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ArchiveExtension);
|
||||||
if (File.Exists(ZipFilePath))
|
if (File.Exists(ZipFilePath))
|
||||||
{
|
{
|
||||||
FileInfo fi = new FileInfo(ZipFilePath);
|
FileInfo fi = new FileInfo(ZipFilePath);
|
||||||
@@ -665,6 +709,13 @@ namespace gaseous_server.Classes
|
|||||||
RetroPie = 1
|
RetroPie = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ArchiveTypes
|
||||||
|
{
|
||||||
|
Zip = 0,
|
||||||
|
RAR = 1,
|
||||||
|
SevenZip = 2
|
||||||
|
}
|
||||||
|
|
||||||
public class AlwaysIncludeItem
|
public class AlwaysIncludeItem
|
||||||
{
|
{
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
@@ -749,7 +800,7 @@ namespace gaseous_server.Classes
|
|||||||
long Size = 0;
|
long Size = 0;
|
||||||
foreach (CollectionGameItem Game in Games) {
|
foreach (CollectionGameItem Game in Games) {
|
||||||
foreach (Roms.GameRomItem Rom in Game.Roms) {
|
foreach (Roms.GameRomItem Rom in Game.Roms) {
|
||||||
Size += Rom.Size;
|
Size += (long)Rom.Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,6 +843,15 @@ namespace gaseous_server.Classes
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public long Cover { get; set;}
|
public long Cover { get; set;}
|
||||||
|
public IGDB.Models.Cover CoverItem
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IGDB.Models.Cover cover = Covers.GetCover(Cover, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory, "Games", Slug), false);
|
||||||
|
|
||||||
|
return cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CollectionItem.AlwaysIncludeItem InclusionStatus { get; set; }
|
public CollectionItem.AlwaysIncludeItem InclusionStatus { get; set; }
|
||||||
|
|
||||||
@@ -801,7 +861,7 @@ namespace gaseous_server.Classes
|
|||||||
get {
|
get {
|
||||||
long Size = 0;
|
long Size = 0;
|
||||||
foreach (Roms.GameRomItem Rom in Roms) {
|
foreach (Roms.GameRomItem Rom in Roms) {
|
||||||
Size += Rom.Size;
|
Size += (long)Rom.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Size;
|
return Size;
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class Common
|
public static class Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns IfNullValue if the ObjectToCheck is null
|
/// Returns IfNullValue if the ObjectToCheck is null
|
||||||
@@ -110,6 +112,14 @@ namespace gaseous_server.Classes
|
|||||||
return Path.GetFullPath(new Uri(path).LocalPath)
|
return Path.GetFullPath(new Uri(path).LocalPath)
|
||||||
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetDescription(this Enum value)
|
||||||
|
{
|
||||||
|
return ((DescriptionAttribute)Attribute.GetCustomAttribute(
|
||||||
|
value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||||
|
.Single(x => x.GetValue(null).Equals(value)),
|
||||||
|
typeof(DescriptionAttribute)))?.Description ?? value.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -473,22 +473,66 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public class MetadataAPI
|
public class MetadataAPI
|
||||||
{
|
{
|
||||||
private static Communications.MetadataSources _Source
|
private static HasheousClient.Models.MetadataModel.MetadataSources _MetadataSource
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("metadatasource")))
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("metadatasource")))
|
||||||
{
|
{
|
||||||
return (Communications.MetadataSources)Enum.Parse(typeof(Communications.MetadataSources), Environment.GetEnvironmentVariable("metadatasource"));
|
return (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), Environment.GetEnvironmentVariable("metadatasource"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Communications.MetadataSources.IGDB;
|
return HasheousClient.Models.MetadataModel.MetadataSources.IGDB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Communications.MetadataSources Source = _Source;
|
private static HasheousClient.Models.MetadataModel.SignatureSources _SignatureSource
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("signaturesource")))
|
||||||
|
{
|
||||||
|
return (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), Environment.GetEnvironmentVariable("signaturesource"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int _MaxLibraryScanWorkers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string _HasheousHost
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("hasheoushoust")))
|
||||||
|
{
|
||||||
|
return Environment.GetEnvironmentVariable("hasheoushoust");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "https://hasheous.org/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HasheousClient.Models.MetadataModel.MetadataSources MetadataSource = _MetadataSource;
|
||||||
|
|
||||||
|
public HasheousClient.Models.MetadataModel.SignatureSources SignatureSource = _SignatureSource;
|
||||||
|
|
||||||
|
public int MaxLibraryScanWorkers = _MaxLibraryScanWorkers;
|
||||||
|
|
||||||
|
public string HasheousHost = _HasheousHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IGDB
|
public class IGDB
|
||||||
|
@@ -107,20 +107,28 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
||||||
if (SchemaVer < i)
|
if (SchemaVer < i)
|
||||||
{
|
{
|
||||||
// run pre-upgrade code
|
try
|
||||||
DatabaseMigration.PreUpgradeScript(i, _ConnectorType);
|
{
|
||||||
|
// run pre-upgrade code
|
||||||
// apply schema!
|
DatabaseMigration.PreUpgradeScript(i, _ConnectorType);
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
|
||||||
ExecuteCMD(dbScript, dbDict);
|
// apply schema!
|
||||||
|
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
||||||
|
ExecuteCMD(dbScript, dbDict, 180);
|
||||||
|
|
||||||
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("schemaver", i);
|
dbDict.Add("schemaver", i);
|
||||||
ExecuteCMD(sql, dbDict);
|
ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
// run post-upgrade code
|
// run post-upgrade code
|
||||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Database", "Schema upgrade failed! Unable to continue.", ex);
|
||||||
|
System.Environment.Exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +235,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||||
return (int)conn.ExecNonQuery(Command, Parameters, Timeout);
|
int retVal = conn.ExecNonQuery(Command, Parameters, Timeout);
|
||||||
|
return retVal;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -321,38 +330,40 @@ namespace gaseous_server.Classes
|
|||||||
DataTable RetTable = new DataTable();
|
DataTable RetTable = new DataTable();
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||||
MySqlConnection conn = new MySqlConnection(DBConn);
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
MySqlCommand cmd = new MySqlCommand
|
|
||||||
{
|
{
|
||||||
Connection = conn,
|
conn.Open();
|
||||||
CommandText = SQL,
|
|
||||||
CommandTimeout = Timeout
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (string Parameter in Parameters.Keys)
|
MySqlCommand cmd = new MySqlCommand
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue(Parameter, Parameters[Parameter]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Executing sql: '" + SQL + "'", null, true);
|
|
||||||
if (Parameters.Count > 0)
|
|
||||||
{
|
{
|
||||||
string dictValues = string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
Connection = conn,
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
CommandText = SQL,
|
||||||
}
|
CommandTimeout = Timeout
|
||||||
RetTable.Load(cmd.ExecuteReader());
|
};
|
||||||
} catch (Exception ex) {
|
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Closing database connection", null, true);
|
foreach (string Parameter in Parameters.Keys)
|
||||||
conn.Close();
|
{
|
||||||
|
cmd.Parameters.AddWithValue(Parameter, Parameters[Parameter]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Executing sql: '" + SQL + "'", null, true);
|
||||||
|
if (Parameters.Count > 0)
|
||||||
|
{
|
||||||
|
string dictValues = string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
|
}
|
||||||
|
RetTable.Load(cmd.ExecuteReader());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Closing database connection", null, true);
|
||||||
|
conn.Close();
|
||||||
|
}
|
||||||
|
|
||||||
return RetTable;
|
return RetTable;
|
||||||
}
|
}
|
||||||
@@ -362,60 +373,64 @@ namespace gaseous_server.Classes
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||||
MySqlConnection conn = new MySqlConnection(DBConn);
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
MySqlCommand cmd = new MySqlCommand
|
|
||||||
{
|
{
|
||||||
Connection = conn,
|
conn.Open();
|
||||||
CommandText = SQL,
|
|
||||||
CommandTimeout = Timeout
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (string Parameter in Parameters.Keys)
|
MySqlCommand cmd = new MySqlCommand
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue(Parameter, Parameters[Parameter]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Executing sql: '" + SQL + "'", null, true);
|
|
||||||
if (Parameters.Count > 0)
|
|
||||||
{
|
{
|
||||||
string dictValues = string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
Connection = conn,
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
CommandText = SQL,
|
||||||
}
|
CommandTimeout = Timeout
|
||||||
result = cmd.ExecuteNonQuery();
|
};
|
||||||
} catch (Exception ex) {
|
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Closing database connection", null, true);
|
foreach (string Parameter in Parameters.Keys)
|
||||||
conn.Close();
|
{
|
||||||
|
cmd.Parameters.AddWithValue(Parameter, Parameters[Parameter]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Executing sql: '" + SQL + "'", null, true);
|
||||||
|
if (Parameters.Count > 0)
|
||||||
|
{
|
||||||
|
string dictValues = string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
|
}
|
||||||
|
result = cmd.ExecuteNonQuery();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Closing database connection", null, true);
|
||||||
|
conn.Close();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
||||||
{
|
{
|
||||||
var conn = new MySqlConnection(DBConn);
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
conn.Open();
|
|
||||||
var command = conn.CreateCommand();
|
|
||||||
MySqlTransaction transaction;
|
|
||||||
transaction = conn.BeginTransaction();
|
|
||||||
command.Connection = conn;
|
|
||||||
command.Transaction = transaction;
|
|
||||||
foreach (Dictionary<string, object> Parameter in Parameters)
|
|
||||||
{
|
{
|
||||||
var cmd = buildcommand(conn, Parameter["sql"].ToString(), (Dictionary<string, object>)Parameter["values"], Timeout);
|
conn.Open();
|
||||||
cmd.Transaction = transaction;
|
var command = conn.CreateCommand();
|
||||||
cmd.ExecuteNonQuery();
|
MySqlTransaction transaction;
|
||||||
}
|
transaction = conn.BeginTransaction();
|
||||||
|
command.Connection = conn;
|
||||||
|
command.Transaction = transaction;
|
||||||
|
foreach (Dictionary<string, object> Parameter in Parameters)
|
||||||
|
{
|
||||||
|
var cmd = buildcommand(conn, Parameter["sql"].ToString(), (Dictionary<string, object>)Parameter["values"], Timeout);
|
||||||
|
cmd.Transaction = transaction;
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
conn.Close();
|
conn.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||||
@@ -441,16 +456,18 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public bool TestConnection()
|
public bool TestConnection()
|
||||||
{
|
{
|
||||||
MySqlConnection conn = new MySqlConnection(DBConn);
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
try
|
|
||||||
{
|
{
|
||||||
conn.Open();
|
try
|
||||||
conn.Close();
|
{
|
||||||
return true;
|
conn.Open();
|
||||||
}
|
conn.Close();
|
||||||
catch
|
return true;
|
||||||
{
|
}
|
||||||
return false;
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
373
gaseous-server/Classes/FileSignature.cs
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using HasheousClient.Models;
|
||||||
|
using NuGet.Common;
|
||||||
|
using SevenZip;
|
||||||
|
using SharpCompress.Archives;
|
||||||
|
using SharpCompress.Archives.Rar;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes
|
||||||
|
{
|
||||||
|
public class FileSignature
|
||||||
|
{
|
||||||
|
public gaseous_server.Models.Signatures_Games GetFileSignature(GameLibrary.LibraryItem library, Common.hashObject hash, FileInfo fi, string GameFileImportPath)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Getting signature for file: " + GameFileImportPath);
|
||||||
|
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
||||||
|
discoveredSignature = _GetFileSignature(hash, fi.Name, fi.Extension, fi.Length, GameFileImportPath, false);
|
||||||
|
|
||||||
|
string[] CompressionExts = { ".zip", ".rar", ".7z" };
|
||||||
|
string ImportedFileExtension = Path.GetExtension(GameFileImportPath);
|
||||||
|
|
||||||
|
if (CompressionExts.Contains(ImportedFileExtension) && (fi.Length < 1073741824))
|
||||||
|
{
|
||||||
|
// file is a zip and less than 1 GiB
|
||||||
|
// extract the zip file and search the contents
|
||||||
|
|
||||||
|
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, library.Id.ToString(), Path.GetRandomFileName());
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing " + GameFileImportPath + " to " + ExtractPath + " examine contents");
|
||||||
|
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch(ImportedFileExtension)
|
||||||
|
{
|
||||||
|
case ".zip":
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using zip");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(GameFileImportPath))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Unzip error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".rar":
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using rar");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = RarArchive.Open(GameFileImportPath))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Unrar error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".7z":
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using 7z");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(GameFileImportPath))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "7z error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Processing decompressed files for signature matches");
|
||||||
|
// loop through contents until we find the first signature match
|
||||||
|
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||||
|
bool signatureFound = false;
|
||||||
|
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
FileInfo zfi = new FileInfo(file);
|
||||||
|
Common.hashObject zhash = new Common.hashObject(file);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking signature of decompressed file " + file);
|
||||||
|
|
||||||
|
if (zfi != null)
|
||||||
|
{
|
||||||
|
ArchiveData archiveData = new ArchiveData{
|
||||||
|
FileName = Path.GetFileName(file),
|
||||||
|
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||||
|
Size = zfi.Length,
|
||||||
|
MD5 = hash.md5hash,
|
||||||
|
SHA1 = hash.sha1hash
|
||||||
|
};
|
||||||
|
archiveFiles.Add(archiveData);
|
||||||
|
|
||||||
|
if (signatureFound == false)
|
||||||
|
{
|
||||||
|
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi.Name, zfi.Extension, zfi.Length, file, true);
|
||||||
|
zDiscoveredSignature.Rom.Name = Path.ChangeExtension(zDiscoveredSignature.Rom.Name, ImportedFileExtension);
|
||||||
|
|
||||||
|
if (zDiscoveredSignature.Score > discoveredSignature.Score)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEArcade ||
|
||||||
|
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEMess
|
||||||
|
)
|
||||||
|
{
|
||||||
|
zDiscoveredSignature.Rom.Name = zDiscoveredSignature.Game.Description + ImportedFileExtension;
|
||||||
|
}
|
||||||
|
zDiscoveredSignature.Rom.Crc = discoveredSignature.Rom.Crc;
|
||||||
|
zDiscoveredSignature.Rom.Md5 = discoveredSignature.Rom.Md5;
|
||||||
|
zDiscoveredSignature.Rom.Sha1 = discoveredSignature.Rom.Sha1;
|
||||||
|
zDiscoveredSignature.Rom.Size = discoveredSignature.Rom.Size;
|
||||||
|
discoveredSignature = zDiscoveredSignature;
|
||||||
|
|
||||||
|
signatureFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveredSignature.Rom.Attributes.Add(new KeyValuePair<string, object>(
|
||||||
|
"ZipContents", Newtonsoft.Json.JsonConvert.SerializeObject(archiveFiles)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Get Signature", "Error processing compressed file: " + GameFileImportPath, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private gaseous_server.Models.Signatures_Games _GetFileSignature(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath, bool IsInZip)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Checking signature for file: " + GameFileImportPath + "\nMD5 hash: " + hash.md5hash + "\nSHA1 hash: " + hash.sha1hash);
|
||||||
|
|
||||||
|
|
||||||
|
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
||||||
|
|
||||||
|
// do database search first
|
||||||
|
gaseous_server.Models.Signatures_Games? dbSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
|
||||||
|
if (dbSignature != null)
|
||||||
|
{
|
||||||
|
// local signature found
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
||||||
|
discoveredSignature = dbSignature;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no local signature attempt to pull from Hasheous
|
||||||
|
dbSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
|
||||||
|
if (dbSignature != null)
|
||||||
|
{
|
||||||
|
// signature retrieved from Hasheous
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
||||||
|
|
||||||
|
discoveredSignature = dbSignature;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// construct a signature from file data
|
||||||
|
dbSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
||||||
|
|
||||||
|
discoveredSignature = dbSignature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", " Determined import file as: " + discoveredSignature.Game.Name + " (" + discoveredSignature.Game.Year + ") " + discoveredSignature.Game.System);
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", " Platform determined to be: " + discoveredSignature.Flags.IGDBPlatformName + " (" + discoveredSignature.Flags.IGDBPlatformId + ")");
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private gaseous_server.Models.Signatures_Games? _GetFileSignatureFromDatabase(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking local database for MD5: " + hash.md5hash);
|
||||||
|
|
||||||
|
// check 1: do we have a signature for it?
|
||||||
|
gaseous_server.Classes.SignatureManagement sc = new SignatureManagement();
|
||||||
|
List<gaseous_server.Models.Signatures_Games> signatures = sc.GetSignature(hash.md5hash);
|
||||||
|
if (signatures == null || signatures.Count == 0)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking local database for SHA1: " + hash.sha1hash);
|
||||||
|
|
||||||
|
// no md5 signature found - try sha1
|
||||||
|
signatures = sc.GetSignature("", hash.sha1hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
gaseous_server.Models.Signatures_Games? discoveredSignature = null;
|
||||||
|
if (signatures.Count == 1)
|
||||||
|
{
|
||||||
|
// only 1 signature found!
|
||||||
|
discoveredSignature = signatures.ElementAt(0);
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
else if (signatures.Count > 1)
|
||||||
|
{
|
||||||
|
// more than one signature found - find one with highest score
|
||||||
|
// start with first returned element
|
||||||
|
discoveredSignature = signatures.First();
|
||||||
|
foreach (gaseous_server.Models.Signatures_Games Sig in signatures)
|
||||||
|
{
|
||||||
|
if (Sig.Score > discoveredSignature.Score)
|
||||||
|
{
|
||||||
|
discoveredSignature = Sig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private gaseous_server.Models.Signatures_Games? _GetFileSignatureFromHasheous(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath)
|
||||||
|
{
|
||||||
|
// check if hasheous is enabled, and if so use it's signature database
|
||||||
|
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||||
|
{
|
||||||
|
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||||
|
SignatureLookupItem? HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel{
|
||||||
|
MD5 = hash.md5hash,
|
||||||
|
SHA1 = hash.sha1hash
|
||||||
|
});
|
||||||
|
|
||||||
|
if (HasheousResult != null)
|
||||||
|
{
|
||||||
|
if (HasheousResult.Signature != null)
|
||||||
|
{
|
||||||
|
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
||||||
|
signature.Game = HasheousResult.Signature.Game;
|
||||||
|
signature.Rom = HasheousResult.Signature.Rom;
|
||||||
|
|
||||||
|
if (HasheousResult.MetadataResults != null)
|
||||||
|
{
|
||||||
|
if (HasheousResult.MetadataResults.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (SignatureLookupItem.MetadataResult metadataResult in HasheousResult.MetadataResults)
|
||||||
|
{
|
||||||
|
if (metadataResult.Source == MetadataModel.MetadataSources.IGDB)
|
||||||
|
{
|
||||||
|
signature.Flags.IGDBPlatformId = (long)metadataResult.PlatformId;
|
||||||
|
signature.Flags.IGDBGameId = (long)metadataResult.GameId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private gaseous_server.Models.Signatures_Games _GetFileSignatureFromFileData(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath)
|
||||||
|
{
|
||||||
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
|
|
||||||
|
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
||||||
|
|
||||||
|
// no signature match found - try name search
|
||||||
|
List<gaseous_server.Models.Signatures_Games> signatures = signatureManagement.GetByTosecName(ImageName);
|
||||||
|
|
||||||
|
if (signatures.Count == 1)
|
||||||
|
{
|
||||||
|
// only 1 signature found!
|
||||||
|
discoveredSignature = signatures.ElementAt(0);
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
else if (signatures.Count > 1)
|
||||||
|
{
|
||||||
|
// more than one signature found - find one with highest score
|
||||||
|
foreach (gaseous_server.Models.Signatures_Games Sig in signatures)
|
||||||
|
{
|
||||||
|
if (Sig.Score > discoveredSignature.Score)
|
||||||
|
{
|
||||||
|
discoveredSignature = Sig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// still no search - try alternate method
|
||||||
|
gaseous_server.Models.Signatures_Games.GameItem gi = new gaseous_server.Models.Signatures_Games.GameItem();
|
||||||
|
gaseous_server.Models.Signatures_Games.RomItem ri = new gaseous_server.Models.Signatures_Games.RomItem();
|
||||||
|
|
||||||
|
discoveredSignature.Game = gi;
|
||||||
|
discoveredSignature.Rom = ri;
|
||||||
|
|
||||||
|
// game title is the file name without the extension or path
|
||||||
|
gi.Name = Path.GetFileNameWithoutExtension(GameFileImportPath);
|
||||||
|
|
||||||
|
// remove everything after brackets - leaving (hopefully) only the name
|
||||||
|
if (gi.Name.Contains("("))
|
||||||
|
{
|
||||||
|
gi.Name = gi.Name.Substring(0, gi.Name.IndexOf("(")).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove special characters like dashes
|
||||||
|
gi.Name = gi.Name.Replace("-", "").Trim();
|
||||||
|
|
||||||
|
// get rom data
|
||||||
|
ri.Name = Path.GetFileName(GameFileImportPath);
|
||||||
|
ri.Md5 = hash.md5hash;
|
||||||
|
ri.Sha1 = hash.sha1hash;
|
||||||
|
ri.Size = ImageSize;
|
||||||
|
ri.SignatureSource = gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.None;
|
||||||
|
|
||||||
|
return discoveredSignature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArchiveData
|
||||||
|
{
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
public long Size { get; set; }
|
||||||
|
public string MD5 { get; set; }
|
||||||
|
public string SHA1 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,24 +7,24 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
public class Filters
|
public class Filters
|
||||||
{
|
{
|
||||||
public static Dictionary<string, object> Filter(Metadata.AgeRatings.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction, bool IncludeUnrated)
|
public static Dictionary<string, List<FilterItem>> Filter(Metadata.AgeGroups.AgeRestrictionGroupings MaximumAgeRestriction, bool IncludeUnrated)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
Dictionary<string, object> FilterSet = new Dictionary<string, object>();
|
Dictionary<string, List<FilterItem>> FilterSet = new Dictionary<string, List<FilterItem>>();
|
||||||
|
|
||||||
// platforms
|
// platforms
|
||||||
List<FilterItem> platforms = new List<FilterItem>();
|
List<FilterItem> platforms = new List<FilterItem>();
|
||||||
|
|
||||||
string ageRestriction_Platform = "Game.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
string ageRestriction_Platform = "AgeGroup.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
||||||
string ageRestriction_Generic = "view_Games.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
string ageRestriction_Generic = "view_Games.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
||||||
if (IncludeUnrated == true)
|
if (IncludeUnrated == true)
|
||||||
{
|
{
|
||||||
ageRestriction_Platform += " OR Game.AgeGroupId IS NULL";
|
ageRestriction_Platform += " OR AgeGroup.AgeGroupId IS NULL";
|
||||||
ageRestriction_Generic += " OR view_Games.AgeGroupId IS NULL";
|
ageRestriction_Generic += " OR view_Games.AgeGroupId IS NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
string sql = "SELECT DISTINCT Platform.Id, Platform.Abbreviation, Platform.AlternativeName, Platform.`Name`, Platform.PlatformLogo, (SELECT COUNT(*) AS GameCount FROM (SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Games_Roms.PlatformId, view_Games.AgeGroupId FROM Games_Roms LEFT JOIN view_Games ON view_Games.Id = Games_Roms.GameId) Game WHERE Game.PlatformId = Platform.Id AND (" + ageRestriction_Platform + ")) AS GameCount FROM Platform LEFT JOIN Relation_Game_Platforms ON Relation_Game_Platforms.PlatformsId = Platform.Id LEFT JOIN view_Games ON view_Games.Id = Relation_Game_Platforms.GameId HAVING GameCount > 0 ORDER BY Platform.`Name`;";
|
string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, Games_Roms.PlatformId, 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 WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id GROUP BY Platform.`Name`;";
|
||||||
|
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql);
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// genres
|
// genres
|
||||||
List<FilterItem> genres = new List<FilterItem>();
|
List<FilterItem> genres = new List<FilterItem>();
|
||||||
dbResponse = GetGenericFilterItem(db, "Genre", ageRestriction_Generic);
|
dbResponse = GetGenericFilterItem(db, "Genre", ageRestriction_Platform);
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -49,7 +49,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// game modes
|
// game modes
|
||||||
List<FilterItem> gameModes = new List<FilterItem>();
|
List<FilterItem> gameModes = new List<FilterItem>();
|
||||||
dbResponse = GetGenericFilterItem(db, "GameMode", ageRestriction_Generic);
|
dbResponse = GetGenericFilterItem(db, "GameMode", ageRestriction_Platform);
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// player perspectives
|
// player perspectives
|
||||||
List<FilterItem> playerPerspectives = new List<FilterItem>();
|
List<FilterItem> playerPerspectives = new List<FilterItem>();
|
||||||
dbResponse = GetGenericFilterItem(db, "PlayerPerspective", ageRestriction_Generic);
|
dbResponse = GetGenericFilterItem(db, "PlayerPerspective", ageRestriction_Platform);
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -71,7 +71,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// themes
|
// themes
|
||||||
List<FilterItem> themes = new List<FilterItem>();
|
List<FilterItem> themes = new List<FilterItem>();
|
||||||
dbResponse = GetGenericFilterItem(db, "Theme", ageRestriction_Generic);
|
dbResponse = GetGenericFilterItem(db, "Theme", ageRestriction_Platform);
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -81,22 +81,24 @@ namespace gaseous_server.Classes
|
|||||||
FilterSet.Add("themes", themes);
|
FilterSet.Add("themes", themes);
|
||||||
|
|
||||||
// age groups
|
// age groups
|
||||||
List<FilterAgeGrouping> agegroupings = new List<FilterAgeGrouping>();
|
List<FilterItem> agegroupings = new List<FilterItem>();
|
||||||
sql = "SELECT view_Games.Id, view_Games.AgeGroupId, COUNT(view_Games.Id) AS GameCount FROM view_Games WHERE (" + ageRestriction_Generic + ") GROUP BY view_Games.AgeGroupId ORDER BY view_Games.AgeGroupId DESC;";
|
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, 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 WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id HAVING RomCount > 0) Game GROUP BY Game.AgeGroupId ORDER BY Game.AgeGroupId DESC";
|
||||||
dbResponse = db.ExecuteCMD(sql);
|
dbResponse = db.ExecuteCMD(sql);
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
FilterAgeGrouping filterAgeGrouping = new FilterAgeGrouping();
|
FilterItem filterAgeGrouping = new FilterItem();
|
||||||
if (dr["AgeGroupId"] == DBNull.Value)
|
if (dr["AgeGroupId"] == DBNull.Value)
|
||||||
{
|
{
|
||||||
filterAgeGrouping.Id = (long)AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified;
|
filterAgeGrouping.Id = (int)(long)AgeGroups.AgeRestrictionGroupings.Unclassified;
|
||||||
filterAgeGrouping.AgeGroup = AgeRatings.AgeGroups.AgeRestrictionGroupings.Unclassified;
|
filterAgeGrouping.Name = AgeGroups.AgeRestrictionGroupings.Unclassified.ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filterAgeGrouping.Id = (long)(AgeRatings.AgeGroups.AgeRestrictionGroupings)dr["AgeGroupId"];
|
int ageGroupLong = (int)dr["AgeGroupId"];
|
||||||
filterAgeGrouping.AgeGroup = (AgeRatings.AgeGroups.AgeRestrictionGroupings)dr["AgeGroupId"];
|
AgeGroups.AgeRestrictionGroupings ageGroup = (AgeGroups.AgeRestrictionGroupings)ageGroupLong;
|
||||||
|
filterAgeGrouping.Id = ageGroupLong;
|
||||||
|
filterAgeGrouping.Name = ageGroup.ToString();
|
||||||
}
|
}
|
||||||
filterAgeGrouping.GameCount = (int)(long)dr["GameCount"];
|
filterAgeGrouping.GameCount = (int)(long)dr["GameCount"];
|
||||||
agegroupings.Add(filterAgeGrouping);
|
agegroupings.Add(filterAgeGrouping);
|
||||||
@@ -106,9 +108,11 @@ namespace gaseous_server.Classes
|
|||||||
return FilterSet;
|
return FilterSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DataTable GetGenericFilterItem(Database db, string Name, string AgeRestriction_Generic)
|
private static DataTable GetGenericFilterItem(Database db, string Name, string AgeRestriction)
|
||||||
{
|
{
|
||||||
string sql = "SELECT DISTINCT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(view_Games.Id) AS GameCount FROM <ITEMNAME> LEFT JOIN Relation_Game_<ITEMNAME>s ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id LEFT JOIN view_Games ON view_Games.Id = Relation_Game_<ITEMNAME>s.GameId WHERE (" + AgeRestriction_Generic + ") GROUP BY <ITEMNAME>.Id ORDER BY <ITEMNAME>.`Name`;";
|
//string sql = "SELECT DISTINCT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(view_Games.Id) AS GameCount FROM <ITEMNAME> LEFT JOIN Relation_Game_<ITEMNAME>s ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id LEFT JOIN view_Games ON view_Games.Id = Relation_Game_<ITEMNAME>s.GameId WHERE (" + AgeRestriction_Generic + ") GROUP BY <ITEMNAME>.Id HAVING GameCount > 0 ORDER BY <ITEMNAME>.`Name`;";
|
||||||
|
|
||||||
|
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, 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 WHERE (" + AgeRestriction + ") GROUP BY Game.Id HAVING RomCount > 0) Game JOIN Relation_Game_<ITEMNAME>s ON Game.Id = Relation_Game_<ITEMNAME>s.GameId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
|
||||||
sql = sql.Replace("<ITEMNAME>", Name);
|
sql = sql.Replace("<ITEMNAME>", Name);
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql);
|
||||||
|
|
||||||
@@ -117,6 +121,11 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public class FilterItem
|
public class FilterItem
|
||||||
{
|
{
|
||||||
|
public FilterItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public FilterItem(DataRow dr)
|
public FilterItem(DataRow dr)
|
||||||
{
|
{
|
||||||
this.Id = (long)dr["Id"];
|
this.Id = (long)dr["Id"];
|
||||||
@@ -130,22 +139,5 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public int GameCount { get; set; }
|
public int GameCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FilterAgeGrouping
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public AgeRatings.AgeGroups.AgeRestrictionGroupings AgeGroup { get ; set; }
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.AgeGroup.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GameCount { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -34,6 +34,12 @@ namespace gaseous_server
|
|||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
||||||
|
{
|
||||||
|
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
// code
|
// code
|
||||||
public static LibraryItem GetDefaultLibrary
|
public static LibraryItem GetDefaultLibrary
|
||||||
{
|
{
|
||||||
@@ -110,21 +116,42 @@ namespace gaseous_server
|
|||||||
|
|
||||||
int newLibraryId = (int)(long)data.Rows[0][0];
|
int newLibraryId = (int)(long)data.Rows[0][0];
|
||||||
|
|
||||||
return GetLibrary(newLibraryId);
|
Logging.Log(Logging.LogType.Information, "Library Management", "Created library " + Name + " at directory " + PathName);
|
||||||
|
|
||||||
|
LibraryItem library = GetLibrary(newLibraryId);
|
||||||
|
|
||||||
|
return library;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeleteLibrary(int LibraryId)
|
public static void DeleteLibrary(int LibraryId)
|
||||||
{
|
{
|
||||||
if (GetLibrary(LibraryId).IsDefaultLibrary == false)
|
LibraryItem library = GetLibrary(LibraryId);
|
||||||
|
if (library.IsDefaultLibrary == false)
|
||||||
{
|
{
|
||||||
|
// check for active library scans
|
||||||
|
foreach(ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
||||||
|
(item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker && item.ItemState == ProcessQueue.QueueItemState.Running)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Library Management", "Unable to delete libraries while a library scan is running. Wait until the the library scan is completed and try again.");
|
||||||
|
throw new CannotDeleteLibraryWhileScanIsActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "DELETE FROM Games_Roms WHERE LibraryId=@id; DELETE FROM GameLibraries WHERE Id=@id;";
|
string sql = "DELETE FROM Games_Roms WHERE LibraryId=@id; DELETE FROM GameLibraries WHERE Id=@id;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", LibraryId);
|
dbDict.Add("id", LibraryId);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Management", "Deleted library " + library.Name + " at path " + library.Path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Library Management", "Unable to delete the default library.");
|
||||||
throw new CannotDeleteDefaultLibrary();
|
throw new CannotDeleteDefaultLibrary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,51 +6,47 @@ using System.Security.Policy;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using NuGet.Common;
|
using NuGet.Common;
|
||||||
using NuGet.LibraryModel;
|
using NuGet.LibraryModel;
|
||||||
using static gaseous_server.Classes.Metadata.Games;
|
using static gaseous_server.Classes.Metadata.Games;
|
||||||
|
using static gaseous_server.Classes.FileSignature;
|
||||||
|
using HasheousClient.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class ImportGames : QueueItemStatus
|
public class ImportGame : QueueItemStatus
|
||||||
{
|
{
|
||||||
public ImportGames(string ImportPath)
|
public void ProcessDirectory(string ImportPath)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(ImportPath))
|
if (Directory.Exists(ImportPath))
|
||||||
{
|
{
|
||||||
string[] importContents_Files = Directory.GetFiles(ImportPath);
|
string[] importContents = Directory.GetFiles(ImportPath, "*.*", SearchOption.AllDirectories);
|
||||||
string[] importContents_Directories = Directory.GetDirectories(ImportPath);
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Games", "Found " + importContents.Length + " files to process in import directory: " + ImportPath);
|
||||||
|
|
||||||
// import files first
|
// import files first
|
||||||
int importCount = 1;
|
int importCount = 1;
|
||||||
foreach (string importContent in importContents_Files) {
|
foreach (string importContent in importContents) {
|
||||||
SetStatus(importCount, importContents_Files.Length, "Importing file: " + importContent);
|
SetStatus(importCount, importContents.Length, "Importing file: " + importContent);
|
||||||
|
|
||||||
ImportGame.ImportGameFile(importContent, null);
|
ImportGameFile(importContent, null);
|
||||||
|
|
||||||
importCount += 1;
|
importCount += 1;
|
||||||
}
|
}
|
||||||
ClearStatus();
|
ClearStatus();
|
||||||
|
|
||||||
// import sub directories
|
DeleteOrphanedDirectories(ImportPath);
|
||||||
foreach (string importDir in importContents_Directories) {
|
|
||||||
Classes.ImportGames importGames = new Classes.ImportGames(importDir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
||||||
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||||
}
|
|
||||||
|
|
||||||
public class ImportGame : QueueItemStatus
|
|
||||||
{
|
|
||||||
public static void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
@@ -102,7 +98,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " not in database - processing");
|
Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " not in database - processing");
|
||||||
|
|
||||||
Models.Signatures_Games discoveredSignature = GetFileSignature(hash, fi, GameFileImportPath);
|
FileSignature fileSignature = new FileSignature();
|
||||||
|
gaseous_server.Models.Signatures_Games discoveredSignature = fileSignature.GetFileSignature(GameLibrary.GetDefaultLibrary, hash, fi, GameFileImportPath);
|
||||||
|
|
||||||
// get discovered platform
|
// get discovered platform
|
||||||
IGDB.Models.Platform? determinedPlatform = null;
|
IGDB.Models.Platform? determinedPlatform = null;
|
||||||
@@ -121,7 +118,7 @@ namespace gaseous_server.Classes
|
|||||||
discoveredSignature.Flags.IGDBPlatformName = determinedPlatform.Name;
|
discoveredSignature.Flags.IGDBPlatformName = determinedPlatform.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature.Game.Name, discoveredSignature.Flags.IGDBPlatformId);
|
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
||||||
|
|
||||||
// add to database
|
// add to database
|
||||||
StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
||||||
@@ -152,155 +149,29 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Models.Signatures_Games GetFileSignature(Common.hashObject hash, FileInfo fi, string GameFileImportPath)
|
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||||
{
|
{
|
||||||
Models.Signatures_Games discoveredSignature = _GetFileSignature(hash, fi, GameFileImportPath);
|
if (Signature.Flags != null)
|
||||||
|
|
||||||
if ((Path.GetExtension(GameFileImportPath) == ".zip") && (fi.Length < 1073741824))
|
|
||||||
{
|
{
|
||||||
// file is a zip and less than 1 GiB
|
if (Signature.Flags.IGDBGameId != null && Signature.Flags.IGDBGameId != 0)
|
||||||
// extract the zip file and search the contents
|
|
||||||
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, Path.GetRandomFileName());
|
|
||||||
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
ZipFile.ExtractToDirectory(GameFileImportPath, ExtractPath);
|
// game was determined elsewhere - probably a Hasheous server
|
||||||
|
try
|
||||||
// loop through contents until we find the first signature match
|
|
||||||
foreach (string file in Directory.GetFiles(ExtractPath))
|
|
||||||
{
|
{
|
||||||
FileInfo zfi = new FileInfo(file);
|
return Games.GetGame(Signature.Flags.IGDBGameId, false, false, FullDownload);
|
||||||
Common.hashObject zhash = new Common.hashObject(file);
|
|
||||||
|
|
||||||
Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi, file);
|
|
||||||
zDiscoveredSignature.Rom.Name = Path.ChangeExtension(zDiscoveredSignature.Rom.Name, ".zip");
|
|
||||||
|
|
||||||
if (zDiscoveredSignature.Score > discoveredSignature.Score)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType.MAMEArcade ||
|
|
||||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType.MAMEMess
|
|
||||||
)
|
|
||||||
{
|
|
||||||
zDiscoveredSignature.Rom.Name = zDiscoveredSignature.Game.Description + ".zip";
|
|
||||||
}
|
|
||||||
zDiscoveredSignature.Rom.Crc = discoveredSignature.Rom.Crc;
|
|
||||||
zDiscoveredSignature.Rom.Md5 = discoveredSignature.Rom.Md5;
|
|
||||||
zDiscoveredSignature.Rom.Sha1 = discoveredSignature.Rom.Sha1;
|
|
||||||
zDiscoveredSignature.Rom.Size = discoveredSignature.Rom.Size;
|
|
||||||
discoveredSignature = zDiscoveredSignature;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.Log(Logging.LogType.Critical, "Get Signature", "Error processing zip file: " + GameFileImportPath, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Directory.Exists(ExtractPath)) { Directory.Delete(ExtractPath, true); }
|
|
||||||
}
|
|
||||||
|
|
||||||
return discoveredSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Models.Signatures_Games _GetFileSignature(Common.hashObject hash, FileInfo fi, string GameFileImportPath)
|
|
||||||
{
|
|
||||||
// check 1: do we have a signature for it?
|
|
||||||
gaseous_server.Controllers.SignaturesController sc = new Controllers.SignaturesController();
|
|
||||||
List<Models.Signatures_Games> signatures = sc.GetSignature(hash.md5hash);
|
|
||||||
if (signatures.Count == 0)
|
|
||||||
{
|
|
||||||
// no md5 signature found - try sha1
|
|
||||||
signatures = sc.GetSignature("", hash.sha1hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
Models.Signatures_Games discoveredSignature = new Models.Signatures_Games();
|
|
||||||
if (signatures.Count == 1)
|
|
||||||
{
|
|
||||||
// only 1 signature found!
|
|
||||||
discoveredSignature = signatures.ElementAt(0);
|
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, fi, false);
|
|
||||||
}
|
|
||||||
else if (signatures.Count > 1)
|
|
||||||
{
|
|
||||||
// more than one signature found - find one with highest score
|
|
||||||
foreach (Models.Signatures_Games Sig in signatures)
|
|
||||||
{
|
|
||||||
if (Sig.Score > discoveredSignature.Score)
|
|
||||||
{
|
{
|
||||||
discoveredSignature = Sig;
|
Logging.Log(Logging.LogType.Warning, "Import Game", "Provided game id resulted in a failed game lookup", ex);
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, fi, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// no signature match found - try name search
|
|
||||||
signatures = sc.GetByTosecName(fi.Name);
|
|
||||||
|
|
||||||
if (signatures.Count == 1)
|
|
||||||
{
|
|
||||||
// only 1 signature found!
|
|
||||||
discoveredSignature = signatures.ElementAt(0);
|
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, fi, false);
|
|
||||||
}
|
|
||||||
else if (signatures.Count > 1)
|
|
||||||
{
|
|
||||||
// more than one signature found - find one with highest score
|
|
||||||
foreach (Models.Signatures_Games Sig in signatures)
|
|
||||||
{
|
|
||||||
if (Sig.Score > discoveredSignature.Score)
|
|
||||||
{
|
|
||||||
discoveredSignature = Sig;
|
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, fi, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// still no search - try alternate method
|
|
||||||
Models.Signatures_Games.GameItem gi = new Models.Signatures_Games.GameItem();
|
|
||||||
Models.Signatures_Games.RomItem ri = new Models.Signatures_Games.RomItem();
|
|
||||||
|
|
||||||
discoveredSignature.Game = gi;
|
|
||||||
discoveredSignature.Rom = ri;
|
|
||||||
|
|
||||||
// game title is the file name without the extension or path
|
|
||||||
gi.Name = Path.GetFileNameWithoutExtension(GameFileImportPath);
|
|
||||||
|
|
||||||
// remove everything after brackets - leaving (hopefully) only the name
|
|
||||||
if (gi.Name.Contains("("))
|
|
||||||
{
|
|
||||||
gi.Name = gi.Name.Substring(0, gi.Name.IndexOf("("));
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove special characters like dashes
|
|
||||||
gi.Name = gi.Name.Replace("-", "");
|
|
||||||
|
|
||||||
// guess platform
|
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, fi, true);
|
|
||||||
|
|
||||||
// get rom data
|
|
||||||
ri.Name = Path.GetFileName(GameFileImportPath);
|
|
||||||
ri.Md5 = hash.md5hash;
|
|
||||||
ri.Sha1 = hash.sha1hash;
|
|
||||||
ri.Size = fi.Length;
|
|
||||||
ri.SignatureSource = gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", " Determined import file as: " + discoveredSignature.Game.Name + " (" + discoveredSignature.Game.Year + ") " + discoveredSignature.Game.System);
|
|
||||||
|
|
||||||
return discoveredSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IGDB.Models.Game SearchForGame(string GameName, long PlatformId)
|
|
||||||
{
|
|
||||||
// search discovered game - case insensitive exact match first
|
// search discovered game - case insensitive exact match first
|
||||||
IGDB.Models.Game determinedGame = new IGDB.Models.Game();
|
IGDB.Models.Game determinedGame = new IGDB.Models.Game();
|
||||||
|
|
||||||
|
string GameName = Signature.Game.Name;
|
||||||
|
|
||||||
List<string> SearchCandidates = GetSearchCandidates(GameName);
|
List<string> SearchCandidates = GetSearchCandidates(GameName);
|
||||||
|
|
||||||
foreach (string SearchCandidate in SearchCandidates)
|
foreach (string SearchCandidate in SearchCandidates)
|
||||||
@@ -423,7 +294,7 @@ namespace gaseous_server.Classes
|
|||||||
return SearchCandidates;
|
return SearchCandidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0)
|
public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, gaseous_server.Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
@@ -566,7 +437,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OrganiseLibrary()
|
public void OrganiseLibrary()
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Organise Library", "Starting default library organisation");
|
Logging.Log(Logging.LogType.Information, "Organise Library", "Starting default library organisation");
|
||||||
|
|
||||||
@@ -600,161 +471,253 @@ namespace gaseous_server.Classes
|
|||||||
foreach (var directory in Directory.GetDirectories(startLocation))
|
foreach (var directory in Directory.GetDirectories(startLocation))
|
||||||
{
|
{
|
||||||
DeleteOrphanedDirectories(directory);
|
DeleteOrphanedDirectories(directory);
|
||||||
if (Directory.GetFiles(directory).Length == 0 &&
|
|
||||||
Directory.GetDirectories(directory).Length == 0)
|
string[] files = Directory.GetFiles(directory);
|
||||||
|
string[] directories = Directory.GetDirectories(directory);
|
||||||
|
|
||||||
|
if (files.Length == 0 &&
|
||||||
|
directories.Length == 0)
|
||||||
{
|
{
|
||||||
Directory.Delete(directory, false);
|
Directory.Delete(directory, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LibraryScan()
|
public void LibraryScan(GameLibrary.LibraryItem? singleLibrary = null)
|
||||||
{
|
{
|
||||||
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
int maxWorkers = Config.MetadataConfiguration.MaxLibraryScanWorkers;
|
||||||
|
|
||||||
|
List<GameLibrary.LibraryItem> libraries = new List<GameLibrary.LibraryItem>();
|
||||||
|
if (singleLibrary == null)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting library scan. Library " + library.Name);
|
libraries.AddRange(GameLibrary.GetLibraries);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
libraries.Add(singleLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
// setup background tasks for each library
|
||||||
|
foreach (GameLibrary.LibraryItem library in libraries)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name);
|
||||||
|
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
||||||
|
ProcessQueue.QueueItemType.LibraryScanWorker,
|
||||||
|
1,
|
||||||
|
new List<ProcessQueue.QueueItemType>
|
||||||
|
{
|
||||||
|
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||||
|
ProcessQueue.QueueItemType.Rematcher
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true);
|
||||||
|
queue.Options = library;
|
||||||
|
queue.ForceExecute();
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Looking for duplicate library files to clean up");
|
ProcessQueue.QueueItems.Add(queue);
|
||||||
string duplicateSql = "DELETE r1 FROM Games_Roms r1 INNER JOIN Games_Roms r2 WHERE r1.Id > r2.Id AND r1.MD5 = r2.MD5 AND r1.LibraryId=@libraryid AND r2.LibraryId=@libraryid;";
|
|
||||||
Dictionary<string, object> dupDict = new Dictionary<string, object>();
|
|
||||||
dupDict.Add("libraryid", library.Id);
|
|
||||||
db.ExecuteCMD(duplicateSql, dupDict);
|
|
||||||
|
|
||||||
string sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
// check number of running tasks is less than maxWorkers
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
bool allowContinue;
|
||||||
dbDict.Add("libraryid", library.Id);
|
do
|
||||||
DataTable dtRoms = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
|
||||||
// clean out database entries in the import folder
|
|
||||||
if (dtRoms.Rows.Count > 0)
|
|
||||||
{
|
{
|
||||||
|
allowContinue = true;
|
||||||
|
int currentWorkerCount = 0;
|
||||||
|
List<ProcessQueue.QueueItem> queueItems = new List<ProcessQueue.QueueItem>();
|
||||||
|
queueItems.AddRange(ProcessQueue.QueueItems);
|
||||||
|
foreach (ProcessQueue.QueueItem item in queueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||||
|
{
|
||||||
|
currentWorkerCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentWorkerCount >= maxWorkers)
|
||||||
|
{
|
||||||
|
allowContinue = false;
|
||||||
|
Thread.Sleep(60000);
|
||||||
|
}
|
||||||
|
} while (allowContinue == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorkersStillWorking;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
WorkersStillWorking = false;
|
||||||
|
List<ProcessQueue.QueueItem> queueItems = new List<ProcessQueue.QueueItem>();
|
||||||
|
queueItems.AddRange(ProcessQueue.QueueItems);
|
||||||
|
foreach (ProcessQueue.QueueItem item in queueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||||
|
{
|
||||||
|
// workers are still running - sleep and keep looping
|
||||||
|
WorkersStillWorking = true;
|
||||||
|
Thread.Sleep(30000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (WorkersStillWorking == true);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan complete. All workers stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LibrarySpecificScan(GameLibrary.LibraryItem library)
|
||||||
|
{
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting scan of library: " + library.Name);
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Looking for duplicate library files to clean up");
|
||||||
|
string duplicateSql = "DELETE r1 FROM Games_Roms r1 INNER JOIN Games_Roms r2 WHERE r1.Id > r2.Id AND r1.MD5 = r2.MD5 AND r1.LibraryId=@libraryid AND r2.LibraryId=@libraryid;";
|
||||||
|
Dictionary<string, object> dupDict = new Dictionary<string, object>();
|
||||||
|
dupDict.Add("libraryid", library.Id);
|
||||||
|
db.ExecuteCMD(duplicateSql, dupDict);
|
||||||
|
|
||||||
|
string sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("libraryid", library.Id);
|
||||||
|
DataTable dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
// clean out database entries in the import folder
|
||||||
|
if (dtRoms.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
||||||
|
{
|
||||||
|
long romId = (long)dtRoms.Rows[i]["Id"];
|
||||||
|
string romPath = (string)dtRoms.Rows[i]["Path"];
|
||||||
|
|
||||||
|
if (!romPath.StartsWith(library.Path))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Deleting database entry for files with incorrect directory " + romPath);
|
||||||
|
string deleteSql = "DELETE FROM Games_Roms WHERE Id=@id AND LibraryId=@libraryid";
|
||||||
|
Dictionary<string, object> deleteDict = new Dictionary<string, object>();
|
||||||
|
deleteDict.Add("Id", romId);
|
||||||
|
deleteDict.Add("libraryid", library.Id);
|
||||||
|
db.ExecuteCMD(deleteSql, deleteDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||||
|
dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
// search for files in the library that aren't in the database
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Looking for orphaned library files to add");
|
||||||
|
string[] LibraryFiles = Directory.GetFiles(library.Path, "*.*", SearchOption.AllDirectories);
|
||||||
|
int StatusCount = 0;
|
||||||
|
foreach (string LibraryFile in LibraryFiles)
|
||||||
|
{
|
||||||
|
SetStatus(StatusCount, LibraryFiles.Length, "Processing file " + LibraryFile);
|
||||||
|
if (!Common.SkippableFiles.Contains<string>(Path.GetFileName(LibraryFile), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Common.hashObject LibraryFileHash = new Common.hashObject(LibraryFile);
|
||||||
|
|
||||||
|
// check if file is in database
|
||||||
|
bool romFound = false;
|
||||||
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
||||||
{
|
{
|
||||||
long romId = (long)dtRoms.Rows[i]["Id"];
|
long romId = (long)dtRoms.Rows[i]["Id"];
|
||||||
string romPath = (string)dtRoms.Rows[i]["Path"];
|
string romPath = (string)dtRoms.Rows[i]["Path"];
|
||||||
|
string romMd5 = (string)dtRoms.Rows[i]["MD5"];
|
||||||
|
|
||||||
if (!romPath.StartsWith(library.Path))
|
if ((LibraryFile == romPath) || (LibraryFileHash.md5hash == romMd5))
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", " Deleting database entry for files with incorrect directory " + romPath);
|
romFound = true;
|
||||||
string deleteSql = "DELETE FROM Games_Roms WHERE Id=@id AND LibraryId=@libraryid";
|
break;
|
||||||
Dictionary<string, object> deleteDict = new Dictionary<string, object>();
|
|
||||||
deleteDict.Add("Id", romId);
|
|
||||||
deleteDict.Add("libraryid", library.Id);
|
|
||||||
db.ExecuteCMD(deleteSql, deleteDict);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sql = "SELECT * FROM Games_Roms ORDER BY `name`";
|
if (romFound == false)
|
||||||
dtRoms = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
|
||||||
// search for files in the library that aren't in the database
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Looking for orphaned library files to add");
|
|
||||||
string[] LibraryFiles = Directory.GetFiles(library.Path, "*.*", SearchOption.AllDirectories);
|
|
||||||
int StatusCount = 0;
|
|
||||||
foreach (string LibraryFile in LibraryFiles)
|
|
||||||
{
|
|
||||||
SetStatus(StatusCount, LibraryFiles.Length, "Processing file " + LibraryFile);
|
|
||||||
if (!Common.SkippableFiles.Contains<string>(Path.GetFileName(LibraryFile), StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
Common.hashObject LibraryFileHash = new Common.hashObject(LibraryFile);
|
// file is not in database - process it
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Orphaned file found in library: " + LibraryFile);
|
||||||
|
|
||||||
|
Common.hashObject hash = new Common.hashObject(LibraryFile);
|
||||||
|
FileInfo fi = new FileInfo(LibraryFile);
|
||||||
|
|
||||||
// check if file is in database
|
FileSignature fileSignature = new FileSignature();
|
||||||
bool romFound = false;
|
gaseous_server.Models.Signatures_Games sig = fileSignature.GetFileSignature(library, hash, fi, LibraryFile);
|
||||||
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
long romId = (long)dtRoms.Rows[i]["Id"];
|
|
||||||
string romPath = (string)dtRoms.Rows[i]["Path"];
|
|
||||||
string romMd5 = (string)dtRoms.Rows[i]["MD5"];
|
|
||||||
|
|
||||||
if ((LibraryFile == romPath) || (LibraryFileHash.md5hash == romMd5))
|
|
||||||
{
|
|
||||||
romFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (romFound == false)
|
|
||||||
{
|
|
||||||
// file is not in database - process it
|
|
||||||
Common.hashObject hash = new Common.hashObject(LibraryFile);
|
|
||||||
FileInfo fi = new FileInfo(LibraryFile);
|
|
||||||
|
|
||||||
Models.Signatures_Games sig = GetFileSignature(hash, fi, LibraryFile);
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", " Orphaned file found in library: " + LibraryFile);
|
|
||||||
|
|
||||||
// get discovered platform
|
// get discovered platform
|
||||||
IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(sig.Flags.IGDBPlatformId);
|
long PlatformId;
|
||||||
|
IGDB.Models.Platform determinedPlatform;
|
||||||
IGDB.Models.Game determinedGame = new Game();
|
|
||||||
if (determinedPlatform == null)
|
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
||||||
{
|
{
|
||||||
if (library.DefaultPlatformId == 0)
|
// no platform discovered in the signature
|
||||||
{
|
PlatformId = library.DefaultPlatformId;
|
||||||
determinedPlatform = new IGDB.Models.Platform();
|
|
||||||
determinedGame = SearchForGame(sig.Game.Name, sig.Flags.IGDBPlatformId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
determinedPlatform = Platforms.GetPlatform(library.DefaultPlatformId);
|
|
||||||
determinedGame = SearchForGame(sig.Game.Name, library.DefaultPlatformId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
determinedGame = SearchForGame(sig.Game.Name, (long)determinedPlatform.Id);
|
// use the platform discovered in the signature
|
||||||
|
PlatformId = sig.Flags.IGDBPlatformId;
|
||||||
}
|
}
|
||||||
|
determinedPlatform = Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
|
IGDB.Models.Game determinedGame = SearchForGame(sig, PlatformId, true);
|
||||||
|
|
||||||
StoreROM(library, hash, determinedGame, determinedPlatform, sig, LibraryFile);
|
StoreROM(library, hash, determinedGame, determinedPlatform, sig, LibraryFile);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Library Scan", "An error occurred while matching orphaned file: " + LibraryFile + ". Skipping.", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClearStatus();
|
StatusCount += 1;
|
||||||
|
}
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||||
dtRoms = db.ExecuteCMD(sql, dbDict);
|
dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
// check all roms to see if their local file still exists
|
// check all roms to see if their local file still exists
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Checking library files exist on disk");
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Checking library files exist on disk");
|
||||||
if (dtRoms.Rows.Count > 0)
|
StatusCount = 0;
|
||||||
|
if (dtRoms.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < dtRoms.Rows.Count; i++)
|
long romId = (long)dtRoms.Rows[i]["Id"];
|
||||||
|
string romPath = (string)dtRoms.Rows[i]["Path"];
|
||||||
|
gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType romMetadataSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(int)dtRoms.Rows[i]["MetadataSource"];
|
||||||
|
|
||||||
|
SetStatus(StatusCount, dtRoms.Rows.Count, "Processing file " + romPath);
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Processing ROM at path " + romPath);
|
||||||
|
|
||||||
|
if (File.Exists(romPath))
|
||||||
{
|
{
|
||||||
long romId = (long)dtRoms.Rows[i]["Id"];
|
if (library.IsDefaultLibrary == true)
|
||||||
string romPath = (string)dtRoms.Rows[i]["Path"];
|
|
||||||
gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType romMetadataSource = (gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType)(int)dtRoms.Rows[i]["MetadataSource"];
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", " Processing ROM at path " + romPath);
|
|
||||||
|
|
||||||
if (File.Exists(romPath))
|
|
||||||
{
|
{
|
||||||
if (library.IsDefaultLibrary == true)
|
if (romPath != ComputeROMPath(romId))
|
||||||
{
|
{
|
||||||
if (romPath != ComputeROMPath(romId))
|
Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found, but needs to be moved");
|
||||||
{
|
MoveGameFile(romId);
|
||||||
MoveGameFile(romId);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// file doesn't exist where it's supposed to be! delete it from the db
|
|
||||||
Logging.Log(Logging.LogType.Warning, "Library Scan", " Deleting orphaned database entry for " + romPath);
|
|
||||||
|
|
||||||
string deleteSql = "DELETE FROM Games_Roms WHERE Id = @id AND LibraryId = @libraryid";
|
|
||||||
Dictionary<string, object> deleteDict = new Dictionary<string, object>();
|
|
||||||
deleteDict.Add("id", romId);
|
|
||||||
deleteDict.Add("libraryid", library.Id);
|
|
||||||
db.ExecuteCMD(deleteSql, deleteDict);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
// file doesn't exist where it's supposed to be! delete it from the db
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Library Scan", "Deleting orphaned database entry for " + romPath);
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan completed");
|
string deleteSql = "DELETE FROM Games_Roms WHERE Id = @id AND LibraryId = @libraryid";
|
||||||
|
Dictionary<string, object> deleteDict = new Dictionary<string, object>();
|
||||||
|
deleteDict.Add("id", romId);
|
||||||
|
deleteDict.Add("libraryid", library.Id);
|
||||||
|
db.ExecuteCMD(deleteSql, deleteDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusCount += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Rematcher(bool ForceExecute = false)
|
public void Rematcher(bool ForceExecute = false)
|
||||||
@@ -763,64 +726,78 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan starting");
|
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan starting");
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
|
||||||
if (ForceExecute == false)
|
|
||||||
{
|
|
||||||
sql = "SELECT * FROM Games_Roms WHERE ((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) AND (LastMatchAttemptDate IS NULL OR LastMatchAttemptDate < @lastmatchattemptdate) LIMIT 100;";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sql = "SELECT * FROM Games_Roms WHERE ((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0);";
|
|
||||||
}
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
|
||||||
dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7));
|
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
|
||||||
int StatusCount = -0;
|
|
||||||
foreach (DataRow row in data.Rows)
|
|
||||||
{
|
|
||||||
SetStatus(StatusCount, data.Rows.Count, "Running rematcher");
|
|
||||||
|
|
||||||
// get library
|
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||||
GameLibrary.LibraryItem library = GameLibrary.GetLibrary((int)row["LibraryId"]);
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch on library " + library.Name);
|
||||||
|
|
||||||
// get rom info
|
string sql = "";
|
||||||
long romId = (long)row["Id"];
|
if (ForceExecute == false)
|
||||||
string romPath = (string)row["Path"];
|
|
||||||
Common.hashObject hash = new Common.hashObject
|
|
||||||
{
|
{
|
||||||
md5hash = (string)row["MD5"],
|
sql = "SELECT * FROM Games_Roms WHERE (PlatformId = 0 AND GameId <> 0) OR (((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) OR (PlatformId = 0 AND GameId = 0)) AND (LastMatchAttemptDate IS NULL OR LastMatchAttemptDate < @lastmatchattemptdate) AND LibraryId = @libraryid LIMIT 100;";
|
||||||
sha1hash = (string)row["SHA1"]
|
|
||||||
};
|
|
||||||
FileInfo fi = new FileInfo(romPath);
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Running rematch against " + romPath);
|
|
||||||
|
|
||||||
// determine rom signature
|
|
||||||
Models.Signatures_Games sig = GetFileSignature(hash, fi, romPath);
|
|
||||||
|
|
||||||
// determine rom platform
|
|
||||||
IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(sig.Flags.IGDBPlatformId);
|
|
||||||
if (determinedPlatform == null)
|
|
||||||
{
|
|
||||||
determinedPlatform = new IGDB.Models.Platform();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql = "SELECT * FROM Games_Roms WHERE (PlatformId = 0 AND GameId <> 0) OR (((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) OR (PlatformId = 0 AND GameId = 0)) AND LibraryId = @libraryid;";
|
||||||
|
}
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7));
|
||||||
|
dbDict.Add("libraryid", library.Id);
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
int StatusCount = -0;
|
||||||
|
foreach (DataRow row in data.Rows)
|
||||||
|
{
|
||||||
|
SetStatus(StatusCount, data.Rows.Count, "Running rematcher");
|
||||||
|
|
||||||
IGDB.Models.Game determinedGame = SearchForGame(sig.Game.Name, sig.Flags.IGDBPlatformId);
|
// get rom info
|
||||||
|
long romId = (long)row["Id"];
|
||||||
|
string romPath = (string)row["Path"];
|
||||||
|
Common.hashObject hash = new Common.hashObject
|
||||||
|
{
|
||||||
|
md5hash = (string)row["MD5"],
|
||||||
|
sha1hash = (string)row["SHA1"]
|
||||||
|
};
|
||||||
|
FileInfo fi = new FileInfo(romPath);
|
||||||
|
|
||||||
StoreROM(library, hash, determinedGame, determinedPlatform, sig, romPath, romId);
|
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Running rematch against " + romPath);
|
||||||
|
|
||||||
string attemptSql = "UPDATE Games_Roms SET LastMatchAttemptDate=@lastmatchattemptdate WHERE Id=@id;";
|
// determine rom signature
|
||||||
Dictionary<string, object> dbLastAttemptDict = new Dictionary<string, object>();
|
FileSignature fileSignature = new FileSignature();
|
||||||
dbLastAttemptDict.Add("id", romId);
|
gaseous_server.Models.Signatures_Games sig = fileSignature.GetFileSignature(library, hash, fi, romPath);
|
||||||
dbLastAttemptDict.Add("lastmatchattemptdate", DateTime.UtcNow);
|
|
||||||
db.ExecuteCMD(attemptSql, dbLastAttemptDict);
|
|
||||||
|
|
||||||
StatusCount += 1;
|
// get discovered platform
|
||||||
|
long PlatformId;
|
||||||
|
IGDB.Models.Platform determinedPlatform;
|
||||||
|
|
||||||
|
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
||||||
|
{
|
||||||
|
// no platform discovered in the signature
|
||||||
|
PlatformId = library.DefaultPlatformId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// use the platform discovered in the signature
|
||||||
|
PlatformId = sig.Flags.IGDBPlatformId;
|
||||||
|
}
|
||||||
|
determinedPlatform = Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
|
IGDB.Models.Game determinedGame = SearchForGame(sig, PlatformId, true);
|
||||||
|
|
||||||
|
StoreROM(library, hash, determinedGame, determinedPlatform, sig, romPath, romId);
|
||||||
|
|
||||||
|
string attemptSql = "UPDATE Games_Roms SET LastMatchAttemptDate=@lastmatchattemptdate WHERE Id=@id;";
|
||||||
|
Dictionary<string, object> dbLastAttemptDict = new Dictionary<string, object>();
|
||||||
|
dbLastAttemptDict.Add("id", romId);
|
||||||
|
dbLastAttemptDict.Add("lastmatchattemptdate", DateTime.UtcNow);
|
||||||
|
db.ExecuteCMD(attemptSql, dbLastAttemptDict);
|
||||||
|
|
||||||
|
StatusCount += 1;
|
||||||
|
}
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan completed");
|
||||||
|
ClearStatus();
|
||||||
}
|
}
|
||||||
ClearStatus();
|
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan completed");
|
|
||||||
ClearStatus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,10 +109,26 @@ namespace gaseous_server.Classes
|
|||||||
callingProcess = "";
|
callingProcess = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string callingUser;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (CallContext.GetData("CallingUser").ToString() == null)
|
||||||
|
{
|
||||||
|
callingUser = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callingUser = CallContext.GetData("CallingUser").ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
callingUser = "";
|
||||||
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate; INSERT INTO ServerLogs (EventTime, EventType, Process, Message, Exception, CorrelationId, CallingProcess) VALUES (@EventTime, @EventType, @Process, @Message, @Exception, @correlationid, @callingprocess);";
|
string sql = "INSERT INTO ServerLogs (EventTime, EventType, Process, Message, Exception, CorrelationId, CallingProcess, CallingUser) VALUES (@EventTime, @EventType, @Process, @Message, @Exception, @correlationid, @callingprocess, @callinguser);";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("EventRententionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
|
||||||
dbDict.Add("EventTime", logItem.EventTime);
|
dbDict.Add("EventTime", logItem.EventTime);
|
||||||
dbDict.Add("EventType", logItem.EventType);
|
dbDict.Add("EventType", logItem.EventType);
|
||||||
dbDict.Add("Process", logItem.Process);
|
dbDict.Add("Process", logItem.Process);
|
||||||
@@ -120,6 +136,7 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("Exception", Common.ReturnValueIfNull(logItem.ExceptionValue, "").ToString());
|
dbDict.Add("Exception", Common.ReturnValueIfNull(logItem.ExceptionValue, "").ToString());
|
||||||
dbDict.Add("correlationid", correlationId);
|
dbDict.Add("correlationid", correlationId);
|
||||||
dbDict.Add("callingprocess", callingProcess);
|
dbDict.Add("callingprocess", callingProcess);
|
||||||
|
dbDict.Add("callinguser", callingUser);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -238,6 +255,15 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model.CallingUser != null)
|
||||||
|
{
|
||||||
|
if (model.CallingUser.Length > 0)
|
||||||
|
{
|
||||||
|
dbDict.Add("callingUser", model.CallingUser);
|
||||||
|
whereClauses.Add("CallingUser = @callingUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compile WHERE clause
|
// compile WHERE clause
|
||||||
string whereClause = "";
|
string whereClause = "";
|
||||||
if (whereClauses.Count > 0)
|
if (whereClauses.Count > 0)
|
||||||
@@ -252,7 +278,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
whereClause = "WHERE " + whereClause;
|
whereClause = "WHERE " + whereClause;
|
||||||
}
|
}
|
||||||
sql = "SELECT * FROM ServerLogs " + whereClause + " ORDER BY Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
|
||||||
|
sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -260,7 +287,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
whereClause = "AND " + whereClause;
|
whereClause = "AND " + whereClause;
|
||||||
}
|
}
|
||||||
sql = "SELECT * FROM ServerLogs WHERE Id < @StartIndex " + whereClause + " ORDER BY Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
|
||||||
|
sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id WHERE ServerLogs.Id < @StartIndex " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
||||||
}
|
}
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
@@ -275,8 +303,9 @@ namespace gaseous_server.Classes
|
|||||||
Process = (string)row["Process"],
|
Process = (string)row["Process"],
|
||||||
Message = (string)row["Message"],
|
Message = (string)row["Message"],
|
||||||
ExceptionValue = (string)row["Exception"],
|
ExceptionValue = (string)row["Exception"],
|
||||||
CorrelationId = (string)row["CorrelationId"],
|
CorrelationId = (string)Common.ReturnValueIfNull(row["CorrelationId"], ""),
|
||||||
CallingProcess = (string)row["CallingProcess"]
|
CallingProcess = (string)Common.ReturnValueIfNull(row["CallingProcess"], ""),
|
||||||
|
CallingUser = (string)Common.ReturnValueIfNull(row["Email"], "")
|
||||||
};
|
};
|
||||||
|
|
||||||
logs.Add(log);
|
logs.Add(log);
|
||||||
@@ -301,6 +330,7 @@ namespace gaseous_server.Classes
|
|||||||
public string Process { get; set; } = "";
|
public string Process { get; set; } = "";
|
||||||
public string CorrelationId { get; set; } = "";
|
public string CorrelationId { get; set; } = "";
|
||||||
public string? CallingProcess { get; set; } = "";
|
public string? CallingProcess { get; set; } = "";
|
||||||
|
public string? CallingUser { get; set; } = "";
|
||||||
private string _Message = "";
|
private string _Message = "";
|
||||||
public string Message
|
public string Message
|
||||||
{
|
{
|
||||||
@@ -327,6 +357,7 @@ namespace gaseous_server.Classes
|
|||||||
public string? SearchText { get; set; }
|
public string? SearchText { get; set; }
|
||||||
public string? CorrelationId { get; set; }
|
public string? CorrelationId { get; set; }
|
||||||
public string? CallingProcess { get; set; }
|
public string? CallingProcess { get; set; }
|
||||||
|
public string? CallingUser { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,32 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public void RunMaintenance()
|
public void RunMaintenance()
|
||||||
{
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
// remove any entries from the library that have an invalid id
|
||||||
|
string LibraryWhereClause = "";
|
||||||
|
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||||
|
{
|
||||||
|
if (LibraryWhereClause.Length > 0)
|
||||||
|
{
|
||||||
|
LibraryWhereClause += ", ";
|
||||||
|
}
|
||||||
|
LibraryWhereClause += library.Id;
|
||||||
|
}
|
||||||
|
string sqlLibraryWhereClause = "";
|
||||||
|
if (LibraryWhereClause.Length > 0)
|
||||||
|
{
|
||||||
|
sqlLibraryWhereClause = "DELETE FROM Games_Roms WHERE LibraryId NOT IN ( " + LibraryWhereClause + " );";
|
||||||
|
db.ExecuteCMD(sqlLibraryWhereClause);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete old logs
|
||||||
|
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate;";
|
||||||
|
dbDict.Add("EventRententionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
// delete files and directories older than 7 days in PathsToClean
|
// delete files and directories older than 7 days in PathsToClean
|
||||||
List<string> PathsToClean = new List<string>();
|
List<string> PathsToClean = new List<string>();
|
||||||
PathsToClean.Add(Config.LibraryConfiguration.LibraryUploadDirectory);
|
PathsToClean.Add(Config.LibraryConfiguration.LibraryUploadDirectory);
|
||||||
@@ -45,8 +71,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Optimising database tables");
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Optimising database tables");
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
sql = "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE';";
|
||||||
string sql = "SHOW TABLES;";
|
|
||||||
DataTable tables = db.ExecuteCMD(sql);
|
DataTable tables = db.ExecuteCMD(sql);
|
||||||
|
|
||||||
int StatusCounter = 1;
|
int StatusCounter = 1;
|
||||||
|
304
gaseous-server/Classes/Metadata/AgeGroups.cs
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using IGDB;
|
||||||
|
using IGDB.Models;
|
||||||
|
using Microsoft.CodeAnalysis.Classification;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes.Metadata
|
||||||
|
{
|
||||||
|
public class AgeGroups
|
||||||
|
{
|
||||||
|
public AgeGroups()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AgeGroup? GetAgeGroup(Game? game)
|
||||||
|
{
|
||||||
|
if (game == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
|
cacheStatus = Storage.GetCacheStatus("AgeGroup", (long)game.Id);
|
||||||
|
|
||||||
|
AgeGroup? RetVal = new AgeGroup();
|
||||||
|
|
||||||
|
switch (cacheStatus)
|
||||||
|
{
|
||||||
|
case Storage.CacheStatus.NotPresent:
|
||||||
|
RetVal = _GetAgeGroup(game);
|
||||||
|
Storage.NewCacheValue(RetVal, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Storage.CacheStatus.Expired:
|
||||||
|
RetVal = _GetAgeGroup(game);
|
||||||
|
Storage.NewCacheValue(RetVal, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Storage.CacheStatus.Current:
|
||||||
|
RetVal = Storage.GetCacheValue<AgeGroup>(RetVal, "Id", game.Id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception("How did you get here?");
|
||||||
|
}
|
||||||
|
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AgeGroup? _GetAgeGroup(Game game)
|
||||||
|
{
|
||||||
|
// compile the maximum age group for the given game
|
||||||
|
if (game != null)
|
||||||
|
{
|
||||||
|
if (game.AgeRatings != null)
|
||||||
|
{
|
||||||
|
if (game.AgeRatings.Ids != null)
|
||||||
|
{
|
||||||
|
// collect ratings values from metadata
|
||||||
|
List<AgeRating> ageRatings = new List<AgeRating>();
|
||||||
|
foreach (long ratingId in game.AgeRatings.Ids)
|
||||||
|
{
|
||||||
|
AgeRating? rating = AgeRatings.GetAgeRatings(ratingId);
|
||||||
|
if (rating != null)
|
||||||
|
{
|
||||||
|
ageRatings.Add(rating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile the ratings values into the ratings groups
|
||||||
|
AgeRestrictionGroupings highestAgeGroup = AgeRestrictionGroupings.Unclassified;
|
||||||
|
foreach (AgeRating ageRating in ageRatings)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<AgeRestrictionGroupings, AgeGroupItem> ageGroupItem in AgeGroupingsFlat)
|
||||||
|
{
|
||||||
|
|
||||||
|
PropertyInfo[] groupProps = typeof(AgeGroupItem).GetProperties();
|
||||||
|
foreach (PropertyInfo property in groupProps)
|
||||||
|
{
|
||||||
|
if (RatingsBoards.Contains(property.Name))
|
||||||
|
{
|
||||||
|
List<AgeRatingTitle> ratingBoard = (List<AgeRatingTitle>)property.GetValue(ageGroupItem.Value);
|
||||||
|
foreach (AgeRatingTitle ratingTitle in ratingBoard)
|
||||||
|
{
|
||||||
|
if (ageRating.Rating == ratingTitle)
|
||||||
|
{
|
||||||
|
if (highestAgeGroup < ageGroupItem.Key)
|
||||||
|
{
|
||||||
|
highestAgeGroup = ageGroupItem.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the compiled ratings group
|
||||||
|
AgeGroup ageGroup = new AgeGroup();
|
||||||
|
ageGroup.Id = game.Id;
|
||||||
|
ageGroup.GameId = game.Id;
|
||||||
|
if (highestAgeGroup == 0)
|
||||||
|
{
|
||||||
|
ageGroup.AgeGroupId = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ageGroup.AgeGroupId = highestAgeGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ageGroup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AgeGroup ageGroup = new AgeGroup();
|
||||||
|
ageGroup.Id = game.Id;
|
||||||
|
ageGroup.GameId = game.Id;
|
||||||
|
ageGroup.AgeGroupId = null;
|
||||||
|
|
||||||
|
return ageGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AgeGroup ageGroup = new AgeGroup();
|
||||||
|
ageGroup.Id = game.Id;
|
||||||
|
ageGroup.GameId = game.Id;
|
||||||
|
ageGroup.AgeGroupId = null;
|
||||||
|
|
||||||
|
return ageGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AgeGroup
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
public long? GameId { get; set; }
|
||||||
|
public AgeRestrictionGroupings? AgeGroupId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<AgeRestrictionGroupings, List<AgeGroupItem>> AgeGroupings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Dictionary<AgeRestrictionGroupings, List<AgeGroupItem>>{
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Adult, new List<AgeGroupItem>{ Adult_Item, Mature_Item, Teen_Item, Child_Item }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Mature, new List<AgeGroupItem>{ Mature_Item, Teen_Item, Child_Item }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Teen, new List<AgeGroupItem>{ Teen_Item, Child_Item }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Child, new List<AgeGroupItem>{ Child_Item }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<AgeRestrictionGroupings, AgeGroupItem> AgeGroupingsFlat
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Dictionary<AgeRestrictionGroupings, AgeGroupItem>{
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Adult, Adult_Item
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Mature, Mature_Item
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Teen, Teen_Item
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AgeRestrictionGroupings.Child, Child_Item
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AgeRestrictionGroupings
|
||||||
|
{
|
||||||
|
Adult = 4,
|
||||||
|
Mature = 3,
|
||||||
|
Teen = 2,
|
||||||
|
Child = 1,
|
||||||
|
Unclassified = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> RatingsBoards
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<string> boards = new List<string>{
|
||||||
|
"ACB", "CERO", "CLASS_IND", "ESRB", "GRAC", "PEGI", "USK"
|
||||||
|
};
|
||||||
|
|
||||||
|
return boards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
||||||
|
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||||
|
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
||||||
|
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
||||||
|
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||||
|
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
||||||
|
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
||||||
|
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
||||||
|
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||||
|
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||||
|
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
||||||
|
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
||||||
|
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
||||||
|
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
||||||
|
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
||||||
|
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
||||||
|
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
||||||
|
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||||
|
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
||||||
|
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
||||||
|
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
||||||
|
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
||||||
|
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
||||||
|
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
||||||
|
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||||
|
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||||
|
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
||||||
|
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
||||||
|
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
||||||
|
};
|
||||||
|
|
||||||
|
public class AgeGroupItem
|
||||||
|
{
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> ACB { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> CERO { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> CLASS_IND { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> ESRB { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> GRAC { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> PEGI { get; set; }
|
||||||
|
public List<IGDB.Models.AgeRatingTitle> USK { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Newtonsoft.Json.JsonIgnore]
|
||||||
|
public List<long> AgeGroupItemValues
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<long> values = new List<long>();
|
||||||
|
{
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in ACB)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in CERO)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in CLASS_IND)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in ESRB)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in GRAC)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in PEGI)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
foreach (AgeRatingTitle ageRatingTitle in USK)
|
||||||
|
{
|
||||||
|
values.Add((long)ageRatingTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -186,158 +186,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AgeGroups
|
|
||||||
{
|
|
||||||
public AgeGroups()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<AgeRestrictionGroupings, List<AgeGroupItem>> AgeGroupings
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new Dictionary<AgeRestrictionGroupings, List<AgeGroupItem>>{
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Adult, new List<AgeGroupItem>{ Adult_Item, Mature_Item, Teen_Item, Child_Item }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Mature, new List<AgeGroupItem>{ Mature_Item, Teen_Item, Child_Item }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Teen, new List<AgeGroupItem>{ Teen_Item, Child_Item }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Child, new List<AgeGroupItem>{ Child_Item }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<AgeRestrictionGroupings, AgeGroupItem> AgeGroupingsFlat
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new Dictionary<AgeRestrictionGroupings, AgeGroupItem>{
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Adult, Adult_Item
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Mature, Mature_Item
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Teen, Teen_Item
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AgeRestrictionGroupings.Child, Child_Item
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AgeRestrictionGroupings
|
|
||||||
{
|
|
||||||
Adult = 4,
|
|
||||||
Mature = 3,
|
|
||||||
Teen = 2,
|
|
||||||
Child = 1,
|
|
||||||
Unclassified = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
|
||||||
};
|
|
||||||
|
|
||||||
public class AgeGroupItem
|
|
||||||
{
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> ACB { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> CERO { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> CLASS_IND { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> ESRB { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> GRAC { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> PEGI { get; set; }
|
|
||||||
public List<IGDB.Models.AgeRatingTitle> USK { get; set; }
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
[Newtonsoft.Json.JsonIgnore]
|
|
||||||
public List<long> AgeGroupItemValues
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
List<long> values = new List<long>();
|
|
||||||
{
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in ACB)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in CERO)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in CLASS_IND)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in ESRB)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in GRAC)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in PEGI)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
foreach (AgeRatingTitle ageRatingTitle in USK)
|
|
||||||
{
|
|
||||||
values.Add((long)ageRatingTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Artwork? GetArtwork(long? Id, string LogoPath)
|
public static Artwork? GetArtwork(long? Id, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
if ((Id == 0) || (Id == null))
|
if ((Id == 0) || (Id == null))
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<Artwork> RetVal = _GetArtwork(SearchUsing.id, Id, LogoPath);
|
Task<Artwork> RetVal = _GetArtwork(SearchUsing.id, Id, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Artwork GetArtwork(string Slug, string LogoPath)
|
public static Artwork GetArtwork(string Slug, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
Task<Artwork> RetVal = _GetArtwork(SearchUsing.slug, Slug, LogoPath);
|
Task<Artwork> RetVal = _GetArtwork(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Artwork> _GetArtwork(SearchUsing searchUsing, object searchValue, string LogoPath)
|
private static async Task<Artwork> _GetArtwork(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -61,19 +61,20 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
Artwork returnValue = new Artwork();
|
Artwork returnValue = new Artwork();
|
||||||
bool forceImageDownload = false;
|
bool forceImageDownload = false;
|
||||||
LogoPath = Path.Combine(LogoPath, "Artwork");
|
ImagePath = Path.Combine(ImagePath, "Artwork");
|
||||||
switch (cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
break;
|
break;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -88,11 +89,17 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!File.Exists(Path.Combine(LogoPath, returnValue.ImageId + ".jpg"))) || forceImageDownload == true)
|
// check for presence of "original" quality file - download if absent or force download is true
|
||||||
|
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_thumb, returnValue.ImageId);
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_logo_med, returnValue.ImageId);
|
{
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_original, returnValue.ImageId);
|
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Artwork download forced.");
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -104,65 +111,15 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Artwork> GetObjectFromServer(string WhereClause, string LogoPath)
|
private static async Task<Artwork> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||||
{
|
{
|
||||||
// get Artwork metadata
|
// get Artwork metadata
|
||||||
Communications comms = new Communications();
|
Communications comms = new Communications();
|
||||||
var results = await comms.APIComm<Artwork>(IGDBClient.Endpoints.Artworks, fieldList, WhereClause);
|
var results = await comms.APIComm<Artwork>(IGDBClient.Endpoints.Artworks, fieldList, WhereClause);
|
||||||
var result = results.First();
|
var result = results.First();
|
||||||
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_thumb, result.ImageId);
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_logo_med, result.ImageId);
|
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_original, result.ImageId);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetImageFromServer(string Url, string LogoPath, LogoSize logoSize, string ImageId)
|
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
string fileName = "Artwork.jpg";
|
|
||||||
string extension = "jpg";
|
|
||||||
switch (logoSize)
|
|
||||||
{
|
|
||||||
case LogoSize.t_thumb:
|
|
||||||
fileName = "_Thumb";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_logo_med:
|
|
||||||
fileName = "_Medium";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_original:
|
|
||||||
fileName = "";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = "Artwork";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileName = ImageId + fileName;
|
|
||||||
string imageUrl = Url.Replace(LogoSize.t_thumb.ToString(), logoSize.ToString()).Replace("jpg", extension);
|
|
||||||
|
|
||||||
using (var s = client.GetStreamAsync("https:" + imageUrl))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(LogoPath)) { Directory.CreateDirectory(LogoPath); }
|
|
||||||
using (var fs = new FileStream(Path.Combine(LogoPath, fileName + "." + extension), FileMode.OpenOrCreate))
|
|
||||||
{
|
|
||||||
s.Result.CopyTo(fs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LogoSize
|
|
||||||
{
|
|
||||||
t_thumb,
|
|
||||||
t_logo_med,
|
|
||||||
t_original
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Humanizer;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using RestEase;
|
using RestEase;
|
||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
@@ -9,16 +14,28 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Communications
|
public class Communications
|
||||||
{
|
{
|
||||||
|
static Communications()
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler();
|
||||||
|
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||||
|
client = new HttpClient(handler);
|
||||||
|
|
||||||
|
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
|
||||||
|
client.DefaultRequestHeaders.Add("Accept-Encoding", "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
private static IGDBClient igdb = new IGDBClient(
|
private static IGDBClient igdb = new IGDBClient(
|
||||||
// Found in Twitch Developer portal for your app
|
// Found in Twitch Developer portal for your app
|
||||||
Config.IGDB.ClientId,
|
Config.IGDB.ClientId,
|
||||||
Config.IGDB.Secret
|
Config.IGDB.Secret
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static HttpClient client = new HttpClient();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure metadata API communications
|
/// Configure metadata API communications
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static MetadataSources MetadataSource
|
public static HasheousClient.Models.MetadataModel.MetadataSources MetadataSource
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -30,7 +47,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case MetadataSources.IGDB:
|
case HasheousClient.Models.MetadataModel.MetadataSources.IGDB:
|
||||||
// set rate limiter avoidance values
|
// set rate limiter avoidance values
|
||||||
RateLimitAvoidanceWait = 1500;
|
RateLimitAvoidanceWait = 1500;
|
||||||
RateLimitAvoidanceThreshold = 3;
|
RateLimitAvoidanceThreshold = 3;
|
||||||
@@ -46,7 +63,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static MetadataSources _MetadataSource = MetadataSources.None;
|
private static HasheousClient.Models.MetadataModel.MetadataSources _MetadataSource = HasheousClient.Models.MetadataModel.MetadataSources.None;
|
||||||
|
|
||||||
// rate limit avoidance - what can we do to ensure that rate limiting is avoided?
|
// rate limit avoidance - what can we do to ensure that rate limiting is avoided?
|
||||||
// these values affect all communications
|
// these values affect all communications
|
||||||
@@ -142,22 +159,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
private int RetryAttempts = 0;
|
private int RetryAttempts = 0;
|
||||||
private int RetryAttemptsMax = 3;
|
private int RetryAttemptsMax = 3;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Supported metadata sources
|
|
||||||
/// </summary>
|
|
||||||
public enum MetadataSources
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// None - always returns null for metadata requests - should not really be using this source
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IGDB - queries the IGDB service for metadata
|
|
||||||
/// </summary>
|
|
||||||
IGDB
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request data from the metadata API
|
/// Request data from the metadata API
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -170,9 +171,9 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
switch (_MetadataSource)
|
switch (_MetadataSource)
|
||||||
{
|
{
|
||||||
case MetadataSources.None:
|
case HasheousClient.Models.MetadataModel.MetadataSources.None:
|
||||||
return null;
|
return null;
|
||||||
case MetadataSources.IGDB:
|
case HasheousClient.Models.MetadataModel.MetadataSources.IGDB:
|
||||||
return await IGDBAPI<T>(Endpoint, Fields, Query);
|
return await IGDBAPI<T>(Endpoint, Fields, Query);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@@ -234,5 +235,343 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Download from the specified uri
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uri">The uri to download from</param>
|
||||||
|
/// <param name="DestinationFile">The file name and path the download should be stored as</param>
|
||||||
|
public Task<bool?> DownloadFile(Uri uri, string DestinationFile)
|
||||||
|
{
|
||||||
|
var result = _DownloadFile(uri, DestinationFile);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool?> _DownloadFile(Uri uri, string DestinationFile)
|
||||||
|
{
|
||||||
|
string DestinationDirectory = new FileInfo(DestinationFile).Directory.FullName;
|
||||||
|
if (!Directory.Exists(DestinationDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(DestinationDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Communications", "Downloading from " + uri.ToString() + " to " + DestinationFile);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (HttpResponseMessage response = client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||||
|
{
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
using (Stream contentStream = await response.Content.ReadAsStreamAsync(), fileStream = new FileStream(DestinationFile, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
|
||||||
|
{
|
||||||
|
var totalRead = 0L;
|
||||||
|
var totalReads = 0L;
|
||||||
|
var buffer = new byte[8192];
|
||||||
|
var isMoreToRead = true;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var read = await contentStream.ReadAsync(buffer, 0, buffer.Length);
|
||||||
|
if (read == 0)
|
||||||
|
{
|
||||||
|
isMoreToRead = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await fileStream.WriteAsync(buffer, 0, read);
|
||||||
|
|
||||||
|
totalRead += read;
|
||||||
|
totalReads += 1;
|
||||||
|
|
||||||
|
if (totalReads % 2000 == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(string.Format("total bytes downloaded so far: {0:n0}", totalRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (isMoreToRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
if (ex.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
if (File.Exists(DestinationFile))
|
||||||
|
{
|
||||||
|
FileInfo fi = new FileInfo(DestinationFile);
|
||||||
|
if (fi.Length == 0)
|
||||||
|
{
|
||||||
|
File.Delete(DestinationFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Download Images", "Error downloading file: ", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetSpecificImageFromServer(string ImagePath, string ImageId, IGDBAPI_ImageSize size, List<IGDBAPI_ImageSize>? FallbackSizes = null)
|
||||||
|
{
|
||||||
|
string returnPath = "";
|
||||||
|
|
||||||
|
// check for artificial sizes first
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case IGDBAPI_ImageSize.screenshot_small:
|
||||||
|
case IGDBAPI_ImageSize.screenshot_thumb:
|
||||||
|
string BasePath = Path.Combine(ImagePath, size.ToString());
|
||||||
|
if (!Directory.Exists(BasePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(BasePath);
|
||||||
|
}
|
||||||
|
returnPath = Path.Combine(BasePath, ImageId + ".jpg");
|
||||||
|
if (!File.Exists(returnPath))
|
||||||
|
{
|
||||||
|
// get original size image and resize
|
||||||
|
string originalSizePath = await GetSpecificImageFromServer(ImagePath, ImageId, IGDBAPI_ImageSize.original, null);
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case IGDBAPI_ImageSize.screenshot_small:
|
||||||
|
// 235x128
|
||||||
|
width = 235;
|
||||||
|
height = 128;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IGDBAPI_ImageSize.screenshot_thumb:
|
||||||
|
// 165x90
|
||||||
|
width = 165;
|
||||||
|
height = 90;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var image = new ImageMagick.MagickImage(originalSizePath))
|
||||||
|
{
|
||||||
|
image.Resize(width, height);
|
||||||
|
image.Strip();
|
||||||
|
image.Write(returnPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// these sizes are IGDB native
|
||||||
|
if (RateLimitResumeTime > DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "API Connection", "IGDB rate limit hit. Pausing API communications until " + RateLimitResumeTime.ToString() + ". Attempt " + RetryAttempts + " of " + RetryAttemptsMax + " retries.");
|
||||||
|
Thread.Sleep(RateLimitRecoveryWaitTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InRateLimitAvoidanceMode == true)
|
||||||
|
{
|
||||||
|
// sleep for a moment to help avoid hitting the rate limiter
|
||||||
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
List<IGDBAPI_ImageSize> imageSizes = new List<IGDBAPI_ImageSize>
|
||||||
|
{
|
||||||
|
size
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the image
|
||||||
|
try
|
||||||
|
{
|
||||||
|
returnPath = Path.Combine(ImagePath, size.ToString(), ImageId + ".jpg");
|
||||||
|
|
||||||
|
// fail early if the file is already downloaded
|
||||||
|
if (!File.Exists(returnPath))
|
||||||
|
{
|
||||||
|
await comms.IGDBAPI_GetImage(imageSizes, ImageId, ImagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
if (ex.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Image Download", "Image not found, trying a different size.");
|
||||||
|
|
||||||
|
if (FallbackSizes != null)
|
||||||
|
{
|
||||||
|
foreach (Communications.IGDBAPI_ImageSize imageSize in FallbackSizes)
|
||||||
|
{
|
||||||
|
returnPath = await GetSpecificImageFromServer(ImagePath, ImageId, imageSize, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment rate limiter avoidance call count
|
||||||
|
RateLimitAvoidanceCallCount += 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? GetSearchCache<T>(string SearchFields, string SearchString)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM SearchCache WHERE SearchFields = @searchfields AND SearchString = @searchstring;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "searchfields", SearchFields },
|
||||||
|
{ "searchstring", SearchString }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
if (data.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
// cache hit
|
||||||
|
string rawString = data.Rows[0]["Content"].ToString();
|
||||||
|
T ReturnValue = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(rawString);
|
||||||
|
if (ReturnValue != null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Found search result in cache. Search string: " + SearchString);
|
||||||
|
return ReturnValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Search result not found in cache.");
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Search result not found in cache.");
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetSearchCache<T>(string SearchFields, string SearchString, T SearchResult)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Storing search results in cache. Search string: " + SearchString);
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "INSERT INTO SearchCache (SearchFields, SearchString, Content, LastSearch) VALUES (@searchfields, @searchstring, @content, @lastsearch);";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "searchfields", SearchFields },
|
||||||
|
{ "searchstring", SearchString },
|
||||||
|
{ "content", Newtonsoft.Json.JsonConvert.SerializeObject(SearchResult) },
|
||||||
|
{ "lastsearch", DateTime.UtcNow }
|
||||||
|
};
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See https://api-docs.igdb.com/?javascript#images for more information about the image url structure
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ImageId"></param>
|
||||||
|
/// <param name="outputPath">The path to save the downloaded files to
|
||||||
|
public async Task IGDBAPI_GetImage(List<IGDBAPI_ImageSize> ImageSizes, string ImageId, string OutputPath)
|
||||||
|
{
|
||||||
|
string urlTemplate = "https://images.igdb.com/igdb/image/upload/t_{size}/{hash}.jpg";
|
||||||
|
|
||||||
|
foreach (IGDBAPI_ImageSize ImageSize in ImageSizes)
|
||||||
|
{
|
||||||
|
string url = urlTemplate.Replace("{size}", Common.GetDescription(ImageSize)).Replace("{hash}", ImageId);
|
||||||
|
string newOutputPath = Path.Combine(OutputPath, Common.GetDescription(ImageSize));
|
||||||
|
string OutputFile = ImageId + ".jpg";
|
||||||
|
string fullPath = Path.Combine(newOutputPath, OutputFile);
|
||||||
|
|
||||||
|
await _DownloadFile(new Uri(url), fullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum IGDBAPI_ImageSize
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 90x128 Fit
|
||||||
|
/// </summary>
|
||||||
|
[Description("cover_small")]
|
||||||
|
cover_small,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 264x374 Fit
|
||||||
|
/// </summary>
|
||||||
|
[Description("cover_big")]
|
||||||
|
cover_big,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 165x90 Lfill, Centre gravity - resized by Gaseous and is not a real IGDB size
|
||||||
|
/// </summary>
|
||||||
|
[Description("screenshot_thumb")]
|
||||||
|
screenshot_thumb,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 235x128 Lfill, Centre gravity - resized by Gaseous and is not a real IGDB size
|
||||||
|
/// </summary>
|
||||||
|
[Description("screenshot_small")]
|
||||||
|
screenshot_small,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 589x320 Lfill, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("screenshot_med")]
|
||||||
|
screenshot_med,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 889x500 Lfill, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("screenshot_big")]
|
||||||
|
screenshot_big,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1280x720 Lfill, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("screenshot_huge")]
|
||||||
|
screenshot_huge,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 284x160 Fit
|
||||||
|
/// </summary>
|
||||||
|
[Description("logo_med")]
|
||||||
|
logo_med,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 90x90 Thumb, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("thumb")]
|
||||||
|
thumb,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 35x35 Thumb, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("micro")]
|
||||||
|
micro,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1280x720 Fit, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("720p")]
|
||||||
|
r720p,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1920x1080 Fit, Centre gravity
|
||||||
|
/// </summary>
|
||||||
|
[Description("1080p")]
|
||||||
|
r1080p,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The originally uploaded image
|
||||||
|
/// </summary>
|
||||||
|
[Description("original")]
|
||||||
|
original
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompanyLogo? GetCompanyLogo(long? Id, string LogoPath)
|
public static CompanyLogo? GetCompanyLogo(long? Id, string ImagePath)
|
||||||
{
|
{
|
||||||
if ((Id == 0) || (Id == null))
|
if ((Id == 0) || (Id == null))
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.id, Id, LogoPath);
|
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.id, Id, ImagePath);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompanyLogo GetCompanyLogo(string Slug, string LogoPath)
|
public static CompanyLogo GetCompanyLogo(string Slug, string ImagePath)
|
||||||
{
|
{
|
||||||
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.slug, Slug, LogoPath);
|
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.slug, Slug, ImagePath);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<CompanyLogo> _GetCompanyLogo(SearchUsing searchUsing, object searchValue, string LogoPath)
|
private static async Task<CompanyLogo> _GetCompanyLogo(SearchUsing searchUsing, object searchValue, string ImagePath)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -64,7 +64,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
switch (cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
if (returnValue != null)
|
if (returnValue != null)
|
||||||
{
|
{
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
@@ -74,7 +74,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
@@ -91,13 +91,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnValue != null)
|
// check for presence of "original" quality file - download if absent or force download is true
|
||||||
|
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
{
|
{
|
||||||
if ((!File.Exists(Path.Combine(LogoPath, "Logo.jpg"))) || forceImageDownload == true)
|
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Company logo download forced.");
|
||||||
{
|
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_thumb);
|
Communications comms = new Communications();
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_logo_med);
|
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -109,64 +110,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<CompanyLogo?> GetObjectFromServer(string WhereClause, string LogoPath)
|
private static async Task<CompanyLogo> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||||
{
|
{
|
||||||
// get CompanyLogo metadata
|
// get Artwork metadata
|
||||||
Communications comms = new Communications();
|
Communications comms = new Communications();
|
||||||
var results = await comms.APIComm<CompanyLogo>(IGDBClient.Endpoints.CompanyLogos, fieldList, WhereClause);
|
var results = await comms.APIComm<CompanyLogo>(IGDBClient.Endpoints.CompanyLogos, fieldList, WhereClause);
|
||||||
if (results.Length > 0)
|
var result = results.First();
|
||||||
{
|
|
||||||
var result = results.First();
|
|
||||||
|
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_thumb);
|
return result;
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_logo_med);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetImageFromServer(string Url, string LogoPath, LogoSize logoSize)
|
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
string fileName = "Logo.jpg";
|
|
||||||
string extension = "jpg";
|
|
||||||
switch (logoSize)
|
|
||||||
{
|
|
||||||
case LogoSize.t_thumb:
|
|
||||||
fileName = "Logo_Thumb";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_logo_med:
|
|
||||||
fileName = "Logo_Medium";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = "Logo";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string imageUrl = Url.Replace(LogoSize.t_thumb.ToString(), logoSize.ToString()).Replace("jpg", extension);
|
|
||||||
|
|
||||||
using (var s = client.GetStreamAsync("https:" + imageUrl))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(LogoPath)) { Directory.CreateDirectory(LogoPath); }
|
|
||||||
using (var fs = new FileStream(Path.Combine(LogoPath, fileName + "." + extension), FileMode.OpenOrCreate))
|
|
||||||
{
|
|
||||||
s.Result.CopyTo(fs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LogoSize
|
|
||||||
{
|
|
||||||
t_thumb,
|
|
||||||
t_logo_med
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Net;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
|
using Microsoft.CodeAnalysis.Elfie.Model.Strings;
|
||||||
|
|
||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
@@ -13,7 +15,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cover? GetCover(long? Id, string LogoPath)
|
public static Cover? GetCover(long? Id, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
if ((Id == 0) || (Id == null))
|
if ((Id == 0) || (Id == null))
|
||||||
{
|
{
|
||||||
@@ -21,18 +23,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<Cover> RetVal = _GetCover(SearchUsing.id, Id, LogoPath);
|
Task<Cover> RetVal = _GetCover(SearchUsing.id, Id, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cover GetCover(string Slug, string LogoPath)
|
public static Cover GetCover(string Slug, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
Task<Cover> RetVal = _GetCover(SearchUsing.slug, Slug, LogoPath);
|
Task<Cover> RetVal = _GetCover(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Cover> _GetCover(SearchUsing searchUsing, object searchValue, string LogoPath)
|
private static async Task<Cover> _GetCover(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -61,17 +63,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
Cover returnValue = new Cover();
|
Cover returnValue = new Cover();
|
||||||
bool forceImageDownload = false;
|
bool forceImageDownload = false;
|
||||||
|
ImagePath = Path.Combine(ImagePath, "Covers");
|
||||||
switch (cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
break;
|
break;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
@@ -88,11 +91,30 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!File.Exists(Path.Combine(LogoPath, "Cover.jpg"))) || forceImageDownload == true)
|
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_thumb, returnValue.ImageId);
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_logo_med, returnValue.ImageId);
|
{
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_original, returnValue.ImageId);
|
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Cover download forced.");
|
||||||
|
|
||||||
|
// check for presence of image file - download if absent or force download is true
|
||||||
|
List<Communications.IGDBAPI_ImageSize> imageSizes = new List<Communications.IGDBAPI_ImageSize>{
|
||||||
|
Communications.IGDBAPI_ImageSize.cover_big,
|
||||||
|
Communications.IGDBAPI_ImageSize.cover_small,
|
||||||
|
Communications.IGDBAPI_ImageSize.original
|
||||||
|
};
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
foreach (Communications.IGDBAPI_ImageSize size in imageSizes)
|
||||||
|
{
|
||||||
|
localFile = Path.Combine(ImagePath, size.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
|
{
|
||||||
|
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, size, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -104,64 +126,15 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Cover> GetObjectFromServer(string WhereClause, string LogoPath)
|
private static async Task<Cover> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||||
{
|
{
|
||||||
// get Cover metadata
|
// get Cover metadata
|
||||||
Communications comms = new Communications();
|
Communications comms = new Communications();
|
||||||
var results = await comms.APIComm<Cover>(IGDBClient.Endpoints.Covers, fieldList, WhereClause);
|
var results = await comms.APIComm<Cover>(IGDBClient.Endpoints.Covers, fieldList, WhereClause);
|
||||||
var result = results.First();
|
var result = results.First();
|
||||||
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_thumb, result.ImageId);
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_logo_med, result.ImageId);
|
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_original, result.ImageId);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetImageFromServer(string Url, string LogoPath, LogoSize logoSize, string ImageId)
|
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
string fileName = "Cover.jpg";
|
|
||||||
string extension = "jpg";
|
|
||||||
switch (logoSize)
|
|
||||||
{
|
|
||||||
case LogoSize.t_thumb:
|
|
||||||
fileName = "Cover_Thumb";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_logo_med:
|
|
||||||
fileName = "Cover_Medium";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_original:
|
|
||||||
fileName = "Cover";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = "Cover";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string imageUrl = Url.Replace(LogoSize.t_thumb.ToString(), logoSize.ToString()).Replace("jpg", extension);
|
|
||||||
|
|
||||||
using (var s = client.GetStreamAsync("https:" + imageUrl))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(LogoPath)) { Directory.CreateDirectory(LogoPath); }
|
|
||||||
using (var fs = new FileStream(Path.Combine(LogoPath, fileName + "." + extension), FileMode.OpenOrCreate))
|
|
||||||
{
|
|
||||||
s.Result.CopyTo(fs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LogoSize
|
|
||||||
{
|
|
||||||
t_thumb,
|
|
||||||
t_logo_med,
|
|
||||||
t_original
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -98,14 +98,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames);
|
UpdateSubClasses(returnValue, getAllMetadata, followSubGames, forceRefresh);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames);
|
UpdateSubClasses(returnValue, getAllMetadata, followSubGames, forceRefresh);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -114,18 +114,27 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Current:
|
case Storage.CacheStatus.Current:
|
||||||
return Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
returnValue = Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
||||||
|
UpdateSubClasses(returnValue, false, false, false);
|
||||||
|
return returnValue;
|
||||||
default:
|
default:
|
||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames)
|
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||||
{
|
{
|
||||||
// required metadata
|
// required metadata
|
||||||
if (Game.Cover != null)
|
if (Game.Cover != null)
|
||||||
{
|
{
|
||||||
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game));
|
try
|
||||||
|
{
|
||||||
|
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Game.Genres != null)
|
if (Game.Genres != null)
|
||||||
@@ -175,6 +184,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
AgeRating GameAgeRating = AgeRatings.GetAgeRatings(AgeRatingId);
|
AgeRating GameAgeRating = AgeRatings.GetAgeRatings(AgeRatingId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AgeGroups.GetAgeGroup(Game);
|
||||||
|
|
||||||
if (Game.ReleaseDates != null)
|
if (Game.ReleaseDates != null)
|
||||||
{
|
{
|
||||||
@@ -199,7 +209,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
foreach (long ArtworkId in Game.Artworks.Ids)
|
foreach (long ArtworkId in Game.Artworks.Ids)
|
||||||
{
|
{
|
||||||
Artwork GameArtwork = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game));
|
try
|
||||||
|
{
|
||||||
|
Artwork GameArtwork = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch artwork id: " + ArtworkId, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +283,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
foreach (long ScreenshotId in Game.Screenshots.Ids)
|
foreach (long ScreenshotId in Game.Screenshots.Ids)
|
||||||
{
|
{
|
||||||
Screenshot GameScreenshot = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game));
|
try
|
||||||
|
{
|
||||||
|
Screenshot GameScreenshot = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch screenshot id: " + ScreenshotId, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,44 +317,208 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, fieldList, WhereClause);
|
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, fieldList, WhereClause);
|
||||||
var result = results.First();
|
var result = results.First();
|
||||||
|
|
||||||
|
// add artificial unknown platform mapping
|
||||||
|
List<long> platformIds = new List<long>();
|
||||||
|
platformIds.Add(0);
|
||||||
|
if (result.Platforms != null)
|
||||||
|
{
|
||||||
|
if (result.Platforms.Ids != null)
|
||||||
|
{
|
||||||
|
platformIds.AddRange(result.Platforms.Ids.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Platforms = new IdentitiesOrValues<Platform>(
|
||||||
|
ids: platformIds.ToArray<long>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// get cover art from parent if this has no cover
|
||||||
|
if (result.Cover == null)
|
||||||
|
{
|
||||||
|
if (result.ParentGame != null)
|
||||||
|
{
|
||||||
|
if (result.ParentGame.Id != null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no cover art, fetching cover art from parent game");
|
||||||
|
Game parentGame = GetGame((long)result.ParentGame.Id, false, false, false);
|
||||||
|
result.Cover = parentGame.Cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get missing metadata from parent if this is a port
|
||||||
|
if (result.Category == Category.Port)
|
||||||
|
{
|
||||||
|
if (result.Summary == null)
|
||||||
|
{
|
||||||
|
if (result.ParentGame != null)
|
||||||
|
{
|
||||||
|
if (result.ParentGame.Id != null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no summary, fetching summary from parent game");
|
||||||
|
Game parentGame = GetGame((long)result.ParentGame.Id, false, false, false);
|
||||||
|
result.Summary = parentGame.Summary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AssignAllGamesToPlatformIdZero()
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM Game;";
|
||||||
|
DataTable gamesTable = db.ExecuteCMD(sql);
|
||||||
|
foreach (DataRow gameRow in gamesTable.Rows)
|
||||||
|
{
|
||||||
|
sql = "DELETE FROM Relation_Game_Platforms WHERE PlatformsId = 0 AND GameId = @Id; INSERT INTO Relation_Game_Platforms (GameId, PlatformsId) VALUES (@Id, 0);";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("Id", (long)gameRow["Id"]);
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AllowNoPlatformSearch = false;
|
||||||
|
|
||||||
public static Game[] SearchForGame(string SearchString, long PlatformId, SearchType searchType)
|
public static Game[] SearchForGame(string SearchString, long PlatformId, SearchType searchType)
|
||||||
{
|
{
|
||||||
Task<Game[]> games = _SearchForGame(SearchString, PlatformId, searchType);
|
// search local first
|
||||||
|
Logging.Log(Logging.LogType.Information, "Game Search", "Attempting local search of type '" + searchType.ToString() + "' for " + SearchString);
|
||||||
|
Task<Game[]> games = _SearchForGameDatabase(SearchString, PlatformId, searchType);
|
||||||
|
if (games.Result.Length == 0)
|
||||||
|
{
|
||||||
|
// fall back to online search
|
||||||
|
Logging.Log(Logging.LogType.Information, "Game Search", "Falling back to remote search of type '" + searchType.ToString() + "' for " + SearchString);
|
||||||
|
games = _SearchForGameRemote(SearchString, PlatformId, searchType);
|
||||||
|
}
|
||||||
return games.Result;
|
return games.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Game[]> _SearchForGame(string SearchString, long PlatformId, SearchType searchType)
|
private static async Task<Game[]> _SearchForGameDatabase(string SearchString, long PlatformId, SearchType searchType)
|
||||||
{
|
{
|
||||||
string searchBody = "";
|
string whereClause = "";
|
||||||
string searchFields = "fields id,name,slug,platforms,summary; ";
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
bool allowSearch = true;
|
||||||
switch (searchType)
|
switch (searchType)
|
||||||
{
|
{
|
||||||
case SearchType.searchNoPlatform:
|
case SearchType.searchNoPlatform:
|
||||||
searchBody += "search \"" + SearchString + "\"; ";
|
whereClause = "MATCH(`Name`) AGAINST (@gamename)";
|
||||||
|
dbDict.Add("platformid", PlatformId);
|
||||||
|
dbDict.Add("gamename", SearchString);
|
||||||
|
|
||||||
|
allowSearch = AllowNoPlatformSearch;
|
||||||
break;
|
break;
|
||||||
case SearchType.search:
|
case SearchType.search:
|
||||||
searchBody += "search \"" + SearchString + "\"; ";
|
whereClause = "PlatformsId = @platformid AND MATCH(`Name`) AGAINST (@gamename)";
|
||||||
searchBody += "where platforms = (" + PlatformId + ");";
|
dbDict.Add("platformid", PlatformId);
|
||||||
|
dbDict.Add("gamename", SearchString);
|
||||||
break;
|
break;
|
||||||
case SearchType.wherefuzzy:
|
case SearchType.wherefuzzy:
|
||||||
searchBody += "where platforms = (" + PlatformId + ") & name ~ *\"" + SearchString + "\"*;";
|
whereClause = "PlatformsId = @platformid AND `Name` LIKE @gamename";
|
||||||
|
dbDict.Add("platformid", PlatformId);
|
||||||
|
dbDict.Add("gamename", "%" + SearchString + "%");
|
||||||
break;
|
break;
|
||||||
case SearchType.where:
|
case SearchType.where:
|
||||||
searchBody += "where platforms = (" + PlatformId + ") & name ~ \"" + SearchString + "\";";
|
whereClause = "PlatformsId = @platformid AND `Name` = @gamename";
|
||||||
|
dbDict.Add("platformid", PlatformId);
|
||||||
|
dbDict.Add("gamename", SearchString);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string sql = "SELECT Game.Id, Game.`Name`, Game.Slug, Relation_Game_Platforms.PlatformsId AS PlatformsId, Game.Summary FROM gaseous.Game JOIN Relation_Game_Platforms ON Game.Id = Relation_Game_Platforms.GameId WHERE " + whereClause + ";";
|
||||||
|
|
||||||
|
|
||||||
// get Game metadata
|
// get Game metadata
|
||||||
Communications comms = new Communications();
|
Game[]? results = new Game[0];
|
||||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
if (allowSearch == true)
|
||||||
|
{
|
||||||
|
List<Game> searchResults = new List<Game>();
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
foreach (DataRow row in data.Rows)
|
||||||
|
{
|
||||||
|
Game game = new Game{
|
||||||
|
Id = (long)row["Id"],
|
||||||
|
Name = (string)Common.ReturnValueIfNull(row["Name"], ""),
|
||||||
|
Slug = (string)Common.ReturnValueIfNull(row["Slug"], ""),
|
||||||
|
Summary = (string)Common.ReturnValueIfNull(row["Summary"], "")
|
||||||
|
};
|
||||||
|
searchResults.Add(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
results = searchResults.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<Game[]> _SearchForGameRemote(string SearchString, long PlatformId, SearchType searchType)
|
||||||
|
{
|
||||||
|
string searchBody = "";
|
||||||
|
string searchFields = "fields id,name,slug,platforms,summary; ";
|
||||||
|
bool allowSearch = true;
|
||||||
|
switch (searchType)
|
||||||
|
{
|
||||||
|
case SearchType.searchNoPlatform:
|
||||||
|
searchBody = "search \"" + SearchString + "\"; ";
|
||||||
|
|
||||||
|
allowSearch = AllowNoPlatformSearch;
|
||||||
|
break;
|
||||||
|
case SearchType.search:
|
||||||
|
searchBody = "search \"" + SearchString + "\"; where platforms = (" + PlatformId + ");";
|
||||||
|
break;
|
||||||
|
case SearchType.wherefuzzy:
|
||||||
|
searchBody = "where platforms = (" + PlatformId + ") & name ~ *\"" + SearchString + "\"*;";
|
||||||
|
break;
|
||||||
|
case SearchType.where:
|
||||||
|
searchBody = "where platforms = (" + PlatformId + ") & name ~ \"" + SearchString + "\";";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check search cache
|
||||||
|
Game[]? games = Communications.GetSearchCache<Game[]?>(searchFields, searchBody);
|
||||||
|
|
||||||
|
if (games == null)
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
// get Game metadata
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Game[]? results = new Game[0];
|
||||||
|
if (allowSearch == true)
|
||||||
|
{
|
||||||
|
results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||||
|
|
||||||
|
Communications.SetSearchCache<Game[]?>(searchFields, searchBody, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return games.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<KeyValuePair<long, string>> GetAvailablePlatforms(long GameId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @gameid ORDER BY Platform.`Name`;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("gameid", GameId);
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
List<KeyValuePair<long, string>> platforms = new List<KeyValuePair<long, string>>();
|
||||||
|
foreach (DataRow row in data.Rows)
|
||||||
|
{
|
||||||
|
KeyValuePair<long, string> valuePair = new KeyValuePair<long, string>((long)row["PlatformId"], (string)row["Name"]);
|
||||||
|
platforms.Add(valuePair);
|
||||||
|
}
|
||||||
|
|
||||||
|
return platforms;
|
||||||
|
}
|
||||||
|
|
||||||
public enum SearchType
|
public enum SearchType
|
||||||
{
|
{
|
||||||
where = 0,
|
where = 0,
|
||||||
@@ -341,6 +529,11 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
public class MinimalGameItem
|
public class MinimalGameItem
|
||||||
{
|
{
|
||||||
|
public MinimalGameItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public MinimalGameItem(Game gameObject)
|
public MinimalGameItem(Game gameObject)
|
||||||
{
|
{
|
||||||
this.Id = gameObject.Id;
|
this.Id = gameObject.Id;
|
||||||
@@ -349,6 +542,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||||
this.Cover = gameObject.Cover;
|
this.Cover = gameObject.Cover;
|
||||||
this.Artworks = gameObject.Artworks;
|
this.Artworks = gameObject.Artworks;
|
||||||
|
this.FirstReleaseDate = gameObject.FirstReleaseDate;
|
||||||
|
|
||||||
// compile age ratings
|
// compile age ratings
|
||||||
this.AgeRatings = new List<AgeRating>();
|
this.AgeRatings = new List<AgeRating>();
|
||||||
@@ -369,6 +563,8 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public double? TotalRating { get; set; }
|
public double? TotalRating { get; set; }
|
||||||
public int? TotalRatingCount { 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.IdentityOrValue<IGDB.Models.Cover> Cover { get; set; }
|
||||||
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
||||||
public List<IGDB.Models.AgeRating> AgeRatings { get; set; }
|
public List<IGDB.Models.AgeRating> AgeRatings { get; set; }
|
||||||
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformLogo? GetPlatformLogo(long? Id, string LogoPath)
|
public static PlatformLogo? GetPlatformLogo(long? Id, string ImagePath)
|
||||||
{
|
{
|
||||||
if ((Id == 0) || (Id == null))
|
if ((Id == 0) || (Id == null))
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.id, Id, LogoPath);
|
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.id, Id, ImagePath);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformLogo GetPlatformLogo(string Slug, string LogoPath)
|
public static PlatformLogo GetPlatformLogo(string Slug, string ImagePath)
|
||||||
{
|
{
|
||||||
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.slug, Slug, LogoPath);
|
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.slug, Slug, ImagePath);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<PlatformLogo> _GetPlatformLogo(SearchUsing searchUsing, object searchValue, string LogoPath)
|
private static async Task<PlatformLogo> _GetPlatformLogo(SearchUsing searchUsing, object searchValue, string ImagePath)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -64,7 +64,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
switch (cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
if (returnValue != null)
|
if (returnValue != null)
|
||||||
{
|
{
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
@@ -74,7 +74,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
@@ -93,10 +93,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
if (returnValue != null)
|
if (returnValue != null)
|
||||||
{
|
{
|
||||||
if ((!File.Exists(Path.Combine(LogoPath, "Logo.jpg"))) || forceImageDownload == true)
|
// check for presence of "original" quality file - download if absent or force download is true
|
||||||
|
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
{
|
{
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_thumb);
|
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Platform logo download forced.");
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_logo_med);
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,64 +113,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<PlatformLogo?> GetObjectFromServer(string WhereClause, string LogoPath)
|
private static async Task<PlatformLogo> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||||
{
|
{
|
||||||
// get PlatformLogo metadata
|
// get Artwork metadata
|
||||||
Communications comms = new Communications();
|
Communications comms = new Communications();
|
||||||
var results = await comms.APIComm<PlatformLogo>(IGDBClient.Endpoints.PlatformLogos, fieldList, WhereClause);
|
var results = await comms.APIComm<PlatformLogo>(IGDBClient.Endpoints.PlatformLogos, fieldList, WhereClause);
|
||||||
if (results.Length > 0)
|
var result = results.First();
|
||||||
{
|
|
||||||
var result = results.First();
|
|
||||||
|
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_thumb);
|
return result;
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_logo_med);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetImageFromServer(string Url, string LogoPath, LogoSize logoSize)
|
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
string fileName = "Logo.jpg";
|
|
||||||
string extension = "jpg";
|
|
||||||
switch (logoSize)
|
|
||||||
{
|
|
||||||
case LogoSize.t_thumb:
|
|
||||||
fileName = "Logo_Thumb";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_logo_med:
|
|
||||||
fileName = "Logo_Medium";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = "Logo";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string imageUrl = Url.Replace(LogoSize.t_thumb.ToString(), logoSize.ToString()).Replace("jpg", extension);
|
|
||||||
|
|
||||||
using (var s = client.GetStreamAsync("https:" + imageUrl))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(LogoPath)) { Directory.CreateDirectory(LogoPath); }
|
|
||||||
using (var fs = new FileStream(Path.Combine(LogoPath, fileName + "." + extension), FileMode.OpenOrCreate))
|
|
||||||
{
|
|
||||||
s.Result.CopyTo(fs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LogoSize
|
|
||||||
{
|
|
||||||
t_thumb,
|
|
||||||
t_logo_med
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -94,7 +94,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
if (platformVersion.PlatformLogo != null)
|
if (platformVersion.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(ParentPlatform), "Versions", platformVersion.Slug));
|
try
|
||||||
|
{
|
||||||
|
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(ParentPlatform), "Versions", platformVersion.Slug));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,8 +39,16 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh);
|
try
|
||||||
return RetVal.Result;
|
{
|
||||||
|
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh);
|
||||||
|
return RetVal.Result;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Metadata", "An error occurred fetching Platform Id " + Id, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +132,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
if (platform.PlatformLogo != null)
|
if (platform.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platform.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platform));
|
try
|
||||||
|
{
|
||||||
|
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platform.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platform));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +183,20 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AssignAllPlatformsToGameIdZero()
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM Platform;";
|
||||||
|
DataTable platformsTable = db.ExecuteCMD(sql);
|
||||||
|
foreach (DataRow platformRow in platformsTable.Rows)
|
||||||
|
{
|
||||||
|
sql = "DELETE FROM Relation_Game_Platforms WHERE GameId = 0 AND PlatformsId = @Id; INSERT INTO Relation_Game_Platforms (GameId, PlatformsId) VALUES (0, @Id);";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("Id", (long)platformRow["Id"]);
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Screenshot? GetScreenshot(long? Id, string LogoPath)
|
public static Screenshot? GetScreenshot(long? Id, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
if ((Id == 0) || (Id == null))
|
if ((Id == 0) || (Id == null))
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.id, Id, LogoPath);
|
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.id, Id, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Screenshot GetScreenshot(string Slug, string LogoPath)
|
public static Screenshot GetScreenshot(string Slug, string ImagePath, bool GetImages)
|
||||||
{
|
{
|
||||||
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.slug, Slug, LogoPath);
|
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Screenshot> _GetScreenshot(SearchUsing searchUsing, object searchValue, string LogoPath)
|
private static async Task<Screenshot> _GetScreenshot(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -61,18 +61,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
Screenshot returnValue = new Screenshot();
|
Screenshot returnValue = new Screenshot();
|
||||||
bool forceImageDownload = false;
|
bool forceImageDownload = false;
|
||||||
LogoPath = Path.Combine(LogoPath, "Screenshots");
|
ImagePath = Path.Combine(ImagePath, "Screenshots");
|
||||||
switch (cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
break;
|
break;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, LogoPath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
@@ -89,11 +89,17 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!File.Exists(Path.Combine(LogoPath, "Screenshot.jpg"))) || forceImageDownload == true)
|
// check for presence of "original" quality file - download if absent or force download is true
|
||||||
|
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||||
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_thumb, returnValue.ImageId);
|
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||||
//GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_logo_med, returnValue.ImageId);
|
{
|
||||||
GetImageFromServer(returnValue.Url, LogoPath, LogoSize.t_original, returnValue.ImageId);
|
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Screenshot download forced.");
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -105,65 +111,15 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Screenshot> GetObjectFromServer(string WhereClause, string LogoPath)
|
private static async Task<Screenshot> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||||
{
|
{
|
||||||
// get Screenshot metadata
|
// get Screenshot metadata
|
||||||
Communications comms = new Communications();
|
Communications comms = new Communications();
|
||||||
var results = await comms.APIComm<Screenshot>(IGDBClient.Endpoints.Screenshots, fieldList, WhereClause);
|
var results = await comms.APIComm<Screenshot>(IGDBClient.Endpoints.Screenshots, fieldList, WhereClause);
|
||||||
var result = results.First();
|
var result = results.First();
|
||||||
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_thumb, result.ImageId);
|
|
||||||
//GetImageFromServer(result.Url, LogoPath, LogoSize.t_logo_med, result.ImageId);
|
|
||||||
GetImageFromServer(result.Url, LogoPath, LogoSize.t_original, result.ImageId);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetImageFromServer(string Url, string LogoPath, LogoSize logoSize, string ImageId)
|
|
||||||
{
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
string fileName = "Artwork.jpg";
|
|
||||||
string extension = "jpg";
|
|
||||||
switch (logoSize)
|
|
||||||
{
|
|
||||||
case LogoSize.t_thumb:
|
|
||||||
fileName = "_Thumb";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_logo_med:
|
|
||||||
fileName = "_Medium";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
case LogoSize.t_original:
|
|
||||||
fileName = "";
|
|
||||||
extension = "png";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = "Artwork";
|
|
||||||
extension = "jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileName = ImageId + fileName;
|
|
||||||
string imageUrl = Url.Replace(LogoSize.t_thumb.ToString(), logoSize.ToString()).Replace("jpg", extension);
|
|
||||||
|
|
||||||
using (var s = client.GetStreamAsync("https:" + imageUrl))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(LogoPath)) { Directory.CreateDirectory(LogoPath); }
|
|
||||||
using (var fs = new FileStream(Path.Combine(LogoPath, fileName + "." + extension), FileMode.OpenOrCreate))
|
|
||||||
{
|
|
||||||
s.Result.CopyTo(fs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LogoSize
|
|
||||||
{
|
|
||||||
t_thumb,
|
|
||||||
t_logo_med,
|
|
||||||
t_original
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,32 +16,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
Expired
|
Expired
|
||||||
}
|
}
|
||||||
|
|
||||||
//private static Dictionary<string, MemoryCacheObject> ObjectCache = new Dictionary<string, MemoryCacheObject>();
|
|
||||||
|
|
||||||
public static CacheStatus GetCacheStatus(string Endpoint, string Slug)
|
public static CacheStatus GetCacheStatus(string Endpoint, string Slug)
|
||||||
{
|
{
|
||||||
// CacheClean();
|
return _GetCacheStatus(Endpoint, "slug", Slug);
|
||||||
// if (ObjectCache.ContainsKey(Endpoint + Slug))
|
|
||||||
// {
|
|
||||||
// return CacheStatus.Current;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
return _GetCacheStatus(Endpoint, "slug", Slug);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CacheStatus GetCacheStatus(string Endpoint, long Id)
|
public static CacheStatus GetCacheStatus(string Endpoint, long Id)
|
||||||
{
|
{
|
||||||
// CacheClean();
|
return _GetCacheStatus(Endpoint, "id", Id);
|
||||||
// if (ObjectCache.ContainsKey(Endpoint + Id))
|
|
||||||
// {
|
|
||||||
// return CacheStatus.Current;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
return _GetCacheStatus(Endpoint, "id", Id);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CacheStatus GetCacheStatus(DataRow Row)
|
public static CacheStatus GetCacheStatus(DataRow Row)
|
||||||
@@ -185,21 +167,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
string Endpoint = EndpointType.GetType().Name;
|
string Endpoint = EndpointType.GetType().Name;
|
||||||
|
|
||||||
// if (ObjectCache.ContainsKey(Endpoint + SearchValue))
|
|
||||||
// {
|
|
||||||
// MemoryCacheObject cacheObject = ObjectCache[Endpoint + SearchValue];
|
|
||||||
// if (cacheObject.ExpiryTime < DateTime.UtcNow)
|
|
||||||
// {
|
|
||||||
// // object has expired, remove it
|
|
||||||
// ObjectCache.Remove(Endpoint + SearchValue);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // object is valid, return it
|
|
||||||
// return (T)cacheObject.Object;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
string sql = "SELECT * FROM " + Endpoint + " WHERE " + SearchField + " = @" + SearchField;
|
string sql = "SELECT * FROM " + Endpoint + " WHERE " + SearchField + " = @" + SearchField;
|
||||||
@@ -218,19 +185,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
DataRow dataRow = dt.Rows[0];
|
DataRow dataRow = dt.Rows[0];
|
||||||
object returnObject = BuildCacheObject<T>(EndpointType, dataRow);
|
object returnObject = BuildCacheObject<T>(EndpointType, dataRow);
|
||||||
// try {
|
|
||||||
// if (!ObjectCache.ContainsKey(Endpoint + SearchValue))
|
|
||||||
// {
|
|
||||||
// ObjectCache.Add(Endpoint + SearchValue, new MemoryCacheObject{
|
|
||||||
// Object = returnObject
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch
|
|
||||||
// {
|
|
||||||
// // unable add item to cache
|
|
||||||
// ObjectCache.Clear();
|
|
||||||
// }
|
|
||||||
return (T)returnObject;
|
return (T)returnObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,9 +372,12 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case "[igdb.models.releasedateregion":
|
case "[igdb.models.releasedateregion":
|
||||||
property.SetValue(EndpointType, (ReleaseDateRegion)dataRow[property.Name]);
|
property.SetValue(EndpointType, (ReleaseDateRegion)dataRow[property.Name]);
|
||||||
break;
|
break;
|
||||||
case "[igdb.models.releasedatecategory":
|
case "[igdb.models.releasedatecategory":
|
||||||
property.SetValue(EndpointType, (ReleaseDateCategory)dataRow[property.Name]);
|
property.SetValue(EndpointType, (ReleaseDateCategory)dataRow[property.Name]);
|
||||||
break;
|
break;
|
||||||
|
case "[gaseous_server.classes.metadata.agegroups+agerestrictiongroupings":
|
||||||
|
property.SetValue(EndpointType, (AgeGroups.AgeRestrictionGroupings)dataRow[property.Name]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
property.SetValue(EndpointType, dataRow[property.Name]);
|
property.SetValue(EndpointType, dataRow[property.Name]);
|
||||||
break;
|
break;
|
||||||
@@ -470,29 +428,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static void CacheClean()
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// if (ObjectCache == null)
|
|
||||||
// {
|
|
||||||
// ObjectCache = new Dictionary<string, MemoryCacheObject>();
|
|
||||||
// }
|
|
||||||
// Dictionary<string, MemoryCacheObject> workCache = ObjectCache;
|
|
||||||
// foreach (KeyValuePair<string, MemoryCacheObject> objectCache in workCache)
|
|
||||||
// {
|
|
||||||
// if (objectCache.Value.ExpiryTime < DateTime.UtcNow)
|
|
||||||
// {
|
|
||||||
// ObjectCache.Remove(objectCache.Key);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch
|
|
||||||
// {
|
|
||||||
// ObjectCache = new Dictionary<string, MemoryCacheObject>();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private class MemoryCacheObject
|
private class MemoryCacheObject
|
||||||
{
|
{
|
||||||
public object Object { get; set; }
|
public object Object { get; set; }
|
||||||
|
@@ -59,7 +59,7 @@ namespace gaseous_server.Classes
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing metadata for game " + dr["name"] + " (" + dr["id"] + ")");
|
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing metadata for game " + dr["name"] + " (" + dr["id"] + ")");
|
||||||
Metadata.Games.GetGame((long)dr["id"], true, false, forceRefresh);
|
Metadata.Games.GetGame((long)dr["id"], true, false, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -55,12 +55,15 @@ namespace gaseous_server.Classes
|
|||||||
return GetMediaGroup(mgId);
|
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);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomMediaGroup WHERE 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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("id", Id);
|
{
|
||||||
|
{ "id", Id },
|
||||||
|
{ "userid", userid }
|
||||||
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
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);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomMediaGroup WHERE 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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("gameid", GameId);
|
{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", userid }
|
||||||
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
@@ -91,7 +97,7 @@ namespace gaseous_server.Classes
|
|||||||
mediaGroupItems.Add(BuildMediaGroupFromRow(row));
|
mediaGroupItems.Add(BuildMediaGroupFromRow(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaGroupItems.Sort((x, y) => x.PlatformName.CompareTo(y.PlatformName));
|
mediaGroupItems.Sort((x, y) => x.Platform.CompareTo(y.Platform));
|
||||||
|
|
||||||
return mediaGroupItems;
|
return mediaGroupItems;
|
||||||
}
|
}
|
||||||
@@ -156,7 +162,7 @@ namespace gaseous_server.Classes
|
|||||||
public static void DeleteMediaGroup(long Id)
|
public static void DeleteMediaGroup(long Id)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", Id);
|
dbDict.Add("id", Id);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -170,12 +176,23 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
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();
|
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
||||||
mediaGroupItem.Id = (long)row["Id"];
|
mediaGroupItem.Id = (long)row["Id"];
|
||||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
||||||
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
||||||
mediaGroupItem.GameId = (long)row["GameId"];
|
mediaGroupItem.GameId = (long)row["GameId"];
|
||||||
mediaGroupItem.RomIds = new List<long>();
|
mediaGroupItem.RomIds = new List<long>();
|
||||||
|
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
||||||
|
mediaGroupItem.HasSaveStates = hasSaveStates;
|
||||||
|
|
||||||
// get members
|
// get members
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
@@ -186,8 +203,28 @@ namespace gaseous_server.Classes
|
|||||||
foreach (DataRow dataRow in data.Rows)
|
foreach (DataRow dataRow in data.Rows)
|
||||||
{
|
{
|
||||||
mediaGroupItem.RomIds.Add((long)dataRow["RomId"]);
|
mediaGroupItem.RomIds.Add((long)dataRow["RomId"]);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mediaGroupItem.Roms.Add(Roms.GetRom((long)dataRow["RomId"]));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Rom Group", "Unable to load ROM data", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a web emulator and update the romItem
|
||||||
|
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
||||||
|
{
|
||||||
|
if (platformMapping.IGDBId == mediaGroupItem.PlatformId)
|
||||||
|
{
|
||||||
|
if (platformMapping.WebEmulator != null)
|
||||||
|
{
|
||||||
|
mediaGroupItem.Emulator = platformMapping.WebEmulator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return mediaGroupItem;
|
return mediaGroupItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +397,7 @@ namespace gaseous_server.Classes
|
|||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
public string PlatformName {
|
public string Platform {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -373,7 +410,10 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||||
public List<long> RomIds { 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; }
|
private GroupBuildStatus _Status { get; set; }
|
||||||
public GroupBuildStatus Status {
|
public GroupBuildStatus Status {
|
||||||
get
|
get
|
||||||
|
@@ -3,6 +3,7 @@ using System.Data;
|
|||||||
using gaseous_signature_parser.models.RomSignatureObject;
|
using gaseous_signature_parser.models.RomSignatureObject;
|
||||||
using static gaseous_server.Classes.RomMediaGroup;
|
using static gaseous_server.Classes.RomMediaGroup;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using IGDB.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -14,32 +15,62 @@ namespace gaseous_server.Classes
|
|||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameRomObject GetRoms(long GameId, long PlatformId = -1)
|
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
||||||
{
|
{
|
||||||
GameRomObject GameRoms = new GameRomObject();
|
GameRomObject GameRoms = new GameRomObject();
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
|
string sqlCount = "";
|
||||||
|
string sqlPlatform = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", GameId);
|
dbDict.Add("id", GameId);
|
||||||
|
dbDict.Add("userid", userid);
|
||||||
|
|
||||||
|
string NameSearchWhere = "";
|
||||||
|
if (NameSearch.Length > 0)
|
||||||
|
{
|
||||||
|
NameSearchWhere = " AND Games_Roms.`Name` LIKE @namesearch";
|
||||||
|
dbDict.Add("namesearch", '%' + NameSearch + '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// platform query
|
||||||
|
sqlPlatform = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;";
|
||||||
|
|
||||||
if (PlatformId == -1) {
|
if (PlatformId == -1) {
|
||||||
sql = "SELECT * FROM Games_Roms WHERE GameId = @id ORDER BY `Name`";
|
// data query
|
||||||
|
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 {
|
} else {
|
||||||
sql = "SELECT * FROM Games_Roms WHERE GameId = @id AND PlatformId = @platformid ORDER BY `Name`";
|
// data query
|
||||||
|
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 + ";";
|
||||||
|
|
||||||
dbDict.Add("platformid", PlatformId);
|
dbDict.Add("platformid", PlatformId);
|
||||||
}
|
}
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
|
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict)[0];
|
||||||
|
DataTable platformDT = db.ExecuteCMD(sqlPlatform, dbDict);
|
||||||
|
|
||||||
if (romDT.Rows.Count > 0)
|
if (romDT.Rows.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (DataRow romDR in romDT.Rows)
|
// set count of roms
|
||||||
{
|
GameRoms.Count = int.Parse((string)rowCount["RomCount"]);
|
||||||
GameRoms.GameRomItems.Add(BuildRom(romDR));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get rom media groups
|
int pageOffset = pageSize * (pageNumber - 1);
|
||||||
GameRoms.MediaGroups = Classes.RomMediaGroup.GetMediaGroupsFromGameId(GameId);
|
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||||
|
{
|
||||||
|
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||||
|
|
||||||
|
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
||||||
|
{
|
||||||
|
GameRoms.GameRomItems.Add(gameRomItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return GameRoms;
|
return GameRoms;
|
||||||
}
|
}
|
||||||
@@ -52,7 +83,7 @@ namespace gaseous_server.Classes
|
|||||||
public static GameRomItem GetRom(long RomId)
|
public static GameRomItem GetRom(long RomId)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM Games_Roms WHERE Id = @id";
|
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.Id = @id";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -101,7 +132,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -110,25 +141,35 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
private static GameRomItem BuildRom(DataRow romDR)
|
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
|
GameRomItem romItem = new GameRomItem
|
||||||
{
|
{
|
||||||
Id = (long)romDR["id"],
|
Id = (long)romDR["id"],
|
||||||
PlatformId = (long)romDR["platformid"],
|
PlatformId = (long)romDR["platformid"],
|
||||||
Platform = Classes.Metadata.Platforms.GetPlatform((long)romDR["platformid"]),
|
Platform = (string)romDR["platformname"],
|
||||||
GameId = (long)romDR["gameid"],
|
GameId = (long)romDR["gameid"],
|
||||||
Name = (string)romDR["name"],
|
Name = (string)romDR["name"],
|
||||||
Size = (long)romDR["size"],
|
Size = (long)romDR["size"],
|
||||||
CRC = ((string)romDR["crc"]).ToLower(),
|
Crc = ((string)romDR["crc"]).ToLower(),
|
||||||
MD5 = ((string)romDR["md5"]).ToLower(),
|
Md5 = ((string)romDR["md5"]).ToLower(),
|
||||||
SHA1 = ((string)romDR["sha1"]).ToLower(),
|
Sha1 = ((string)romDR["sha1"]).ToLower(),
|
||||||
DevelopmentStatus = (string)romDR["developmentstatus"],
|
DevelopmentStatus = (string)romDR["developmentstatus"],
|
||||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(romDR["attributes"], "[ ]")),
|
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(romDR["attributes"], "[ ]")),
|
||||||
RomType = (int)romDR["romtype"],
|
RomType = (HasheousClient.Models.LookupResponseModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||||
RomTypeMedia = (string)romDR["romtypemedia"],
|
RomTypeMedia = (string)romDR["romtypemedia"],
|
||||||
MediaLabel = (string)romDR["medialabel"],
|
MediaLabel = (string)romDR["medialabel"],
|
||||||
Path = (string)romDR["path"],
|
Path = (string)romDR["path"],
|
||||||
Source = (gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType)(Int32)romDR["metadatasource"],
|
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
|
||||||
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
||||||
|
HasSaveStates = hasSaveStates,
|
||||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,134 +190,21 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public class GameRomObject
|
public class GameRomObject
|
||||||
{
|
{
|
||||||
public List<GameRomMediaGroupItem> MediaGroups { get; set; } = new List<GameRomMediaGroupItem>();
|
|
||||||
public List<GameRomItem> GameRomItems { get; set; } = new List<GameRomItem>();
|
public List<GameRomItem> GameRomItems { get; set; } = new List<GameRomItem>();
|
||||||
|
public int Count { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameRomItem
|
public class GameRomItem : HasheousClient.Models.LookupResponseModel.RomItem
|
||||||
{
|
{
|
||||||
public long Id { get; set; }
|
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
public IGDB.Models.Platform Platform { get; set; }
|
public string Platform { get; set; }
|
||||||
//public Dictionary<string, object>? Emulator { get; set; }
|
|
||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
public string? Name { get; set; }
|
|
||||||
public long Size { get; set; }
|
|
||||||
public string? CRC { get; set; }
|
|
||||||
public string? MD5 { get; set; }
|
|
||||||
public string? SHA1 { get; set; }
|
|
||||||
public string? DevelopmentStatus { get; set; }
|
|
||||||
public string[]? Flags { get; set; }
|
|
||||||
public List<KeyValuePair<string, object>>? Attributes { get; set;}
|
|
||||||
public int RomType { get; set; }
|
|
||||||
public string? RomTypeMedia { get; set; }
|
|
||||||
public MediaType? MediaDetail {
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (RomTypeMedia != null)
|
|
||||||
{
|
|
||||||
return new MediaType(Source, RomTypeMedia);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string? MediaLabel { get; set; }
|
|
||||||
public string? Path { get; set; }
|
public string? Path { get; set; }
|
||||||
public RomSignatureObject.Game.Rom.SignatureSourceType Source { get; set; }
|
|
||||||
public string? SignatureSourceGameTitle { get; set;}
|
public string? SignatureSourceGameTitle { get; set;}
|
||||||
|
public bool HasSaveStates { get; set; } = false;
|
||||||
public GameLibrary.LibraryItem Library { get; set; }
|
public GameLibrary.LibraryItem Library { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MediaType
|
|
||||||
{
|
|
||||||
public MediaType(RomSignatureObject.Game.Rom.SignatureSourceType Source, string MediaTypeString)
|
|
||||||
{
|
|
||||||
switch (Source)
|
|
||||||
{
|
|
||||||
case RomSignatureObject.Game.Rom.SignatureSourceType.TOSEC:
|
|
||||||
string[] typeString = MediaTypeString.Split(" ");
|
|
||||||
|
|
||||||
string inType = "";
|
|
||||||
foreach (string typeStringVal in typeString)
|
|
||||||
{
|
|
||||||
if (inType == "")
|
|
||||||
{
|
|
||||||
switch (typeStringVal.ToLower())
|
|
||||||
{
|
|
||||||
case "disk":
|
|
||||||
Media = RomSignatureObject.Game.Rom.RomTypes.Disk;
|
|
||||||
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "disc":
|
|
||||||
Media = RomSignatureObject.Game.Rom.RomTypes.Disc;
|
|
||||||
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "file":
|
|
||||||
Media = RomSignatureObject.Game.Rom.RomTypes.File;
|
|
||||||
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "part":
|
|
||||||
Media = RomSignatureObject.Game.Rom.RomTypes.Part;
|
|
||||||
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "tape":
|
|
||||||
Media = RomSignatureObject.Game.Rom.RomTypes.Tape;
|
|
||||||
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "of":
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
case "side":
|
|
||||||
inType = typeStringVal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switch (inType.ToLower())
|
|
||||||
{
|
|
||||||
case "disk":
|
|
||||||
case "disc":
|
|
||||||
case "file":
|
|
||||||
case "part":
|
|
||||||
case "tape":
|
|
||||||
Number = int.Parse(typeStringVal);
|
|
||||||
break;
|
|
||||||
case "of":
|
|
||||||
Count = int.Parse(typeStringVal);
|
|
||||||
break;
|
|
||||||
case "side":
|
|
||||||
Side = typeStringVal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
inType = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RomSignatureObject.Game.Rom.RomTypes? Media { get; set; }
|
|
||||||
|
|
||||||
public int? Number { get; set; }
|
|
||||||
|
|
||||||
public int? Count { get; set; }
|
|
||||||
|
|
||||||
public string? Side { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
gaseous-server/Classes/SignatureManagement.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using System.Data;
|
||||||
|
using gaseous_signature_parser.models.RomSignatureObject;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes
|
||||||
|
{
|
||||||
|
public class SignatureManagement
|
||||||
|
{
|
||||||
|
public List<gaseous_server.Models.Signatures_Games> GetSignature(string md5 = "", string sha1 = "")
|
||||||
|
{
|
||||||
|
if (md5.Length > 0)
|
||||||
|
{
|
||||||
|
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<gaseous_server.Models.Signatures_Games> GetByTosecName(string TosecName = "")
|
||||||
|
{
|
||||||
|
if (TosecName.Length > 0)
|
||||||
|
{
|
||||||
|
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<gaseous_server.Models.Signatures_Games> _GetSignature(string sqlWhere, string searchString)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT view_Signatures_Games.*, Signatures_Roms.Id AS romid, Signatures_Roms.Name AS romname, Signatures_Roms.Size, Signatures_Roms.CRC, Signatures_Roms.MD5, Signatures_Roms.SHA1, Signatures_Roms.DevelopmentStatus, Signatures_Roms.Attributes, Signatures_Roms.RomType, Signatures_Roms.RomTypeMedia, Signatures_Roms.MediaLabel, Signatures_Roms.MetadataSource FROM Signatures_Roms INNER JOIN view_Signatures_Games ON Signatures_Roms.GameId = view_Signatures_Games.Id WHERE " + sqlWhere;
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("searchString", searchString);
|
||||||
|
|
||||||
|
DataTable sigDb = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
List<gaseous_server.Models.Signatures_Games> GamesList = new List<gaseous_server.Models.Signatures_Games>();
|
||||||
|
|
||||||
|
foreach (DataRow sigDbRow in sigDb.Rows)
|
||||||
|
{
|
||||||
|
gaseous_server.Models.Signatures_Games gameItem = new gaseous_server.Models.Signatures_Games
|
||||||
|
{
|
||||||
|
Game = new gaseous_server.Models.Signatures_Games.GameItem
|
||||||
|
{
|
||||||
|
Id = (Int32)sigDbRow["Id"],
|
||||||
|
Name = (string)sigDbRow["Name"],
|
||||||
|
Description = (string)sigDbRow["Description"],
|
||||||
|
Year = (string)sigDbRow["Year"],
|
||||||
|
Publisher = (string)sigDbRow["Publisher"],
|
||||||
|
Demo = (gaseous_server.Models.Signatures_Games.GameItem.DemoTypes)(int)sigDbRow["Demo"],
|
||||||
|
System = (string)sigDbRow["Platform"],
|
||||||
|
SystemVariant = (string)sigDbRow["SystemVariant"],
|
||||||
|
Video = (string)sigDbRow["Video"],
|
||||||
|
Country = (string)sigDbRow["Country"],
|
||||||
|
Language = (string)sigDbRow["Language"],
|
||||||
|
Copyright = (string)sigDbRow["Copyright"]
|
||||||
|
},
|
||||||
|
Rom = new gaseous_server.Models.Signatures_Games.RomItem
|
||||||
|
{
|
||||||
|
Id = (Int32)sigDbRow["romid"],
|
||||||
|
Name = (string)sigDbRow["romname"],
|
||||||
|
Size = (Int64)sigDbRow["Size"],
|
||||||
|
Crc = (string)sigDbRow["CRC"],
|
||||||
|
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
||||||
|
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
||||||
|
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
|
||||||
|
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
||||||
|
RomType = (gaseous_server.Models.Signatures_Games.RomItem.RomTypes)(int)sigDbRow["RomType"],
|
||||||
|
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
||||||
|
MediaLabel = (string)sigDbRow["MediaLabel"],
|
||||||
|
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)sigDbRow["MetadataSource"]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GamesList.Add(gameItem);
|
||||||
|
}
|
||||||
|
return GamesList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,11 +6,14 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Authentication;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||||
@@ -24,6 +27,18 @@ namespace gaseous_server.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class GamesController : Controller
|
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")]
|
[MapToApiVersion("1.0")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||||
@@ -287,15 +302,15 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "5Minute")]
|
[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult Game(long GameId, bool forceRefresh = false)
|
public ActionResult Game(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, forceRefresh, false, forceRefresh);
|
Game game = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
if (gameObject != null)
|
if (game != null)
|
||||||
{
|
{
|
||||||
return Ok(gameObject);
|
return Ok(game);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -374,87 +389,6 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
|
||||||
[MapToApiVersion("1.1")]
|
|
||||||
[HttpGet]
|
|
||||||
[Route("{GameId}/agerating/{RatingId}/image")]
|
|
||||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public ActionResult GameAgeClassification(long GameId, long RatingId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
GameAgeRating gameAgeRating = GetConsolidatedAgeRating(RatingId);
|
|
||||||
|
|
||||||
string fileExtension = "";
|
|
||||||
string fileType = "";
|
|
||||||
switch (gameAgeRating.RatingBoard)
|
|
||||||
{
|
|
||||||
case AgeRatingCategory.ESRB:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.PEGI:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.ACB:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.CERO:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.USK:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.GRAC:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
case AgeRatingCategory.CLASS_IND:
|
|
||||||
fileExtension = "svg";
|
|
||||||
fileType = "image/svg+xml";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string resourceName = "gaseous_server.Assets.Ratings." + gameAgeRating.RatingBoard.ToString() + "." + gameAgeRating.RatingTitle.ToString() + "." + fileExtension;
|
|
||||||
|
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
|
||||||
string[] resources = assembly.GetManifestResourceNames();
|
|
||||||
if (resources.Contains(resourceName))
|
|
||||||
{
|
|
||||||
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
|
||||||
using (StreamReader reader = new StreamReader(stream))
|
|
||||||
{
|
|
||||||
byte[] filedata = new byte[stream.Length];
|
|
||||||
stream.Read(filedata, 0, filedata.Length);
|
|
||||||
|
|
||||||
string filename = gameAgeRating.RatingBoard.ToString() + "-" + gameAgeRating.RatingTitle.ToString() + "." + fileExtension;
|
|
||||||
string contentType = fileType;
|
|
||||||
|
|
||||||
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(filedata, contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -473,7 +407,7 @@ namespace gaseous_server.Controllers
|
|||||||
{
|
{
|
||||||
foreach (long ArtworkId in gameObject.Artworks.Ids)
|
foreach (long ArtworkId in gameObject.Artworks.Ids)
|
||||||
{
|
{
|
||||||
Artwork GameArtwork = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
Artwork GameArtwork = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
artworks.Add(GameArtwork);
|
artworks.Add(GameArtwork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -501,7 +435,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
if (artworkObject != null)
|
if (artworkObject != null)
|
||||||
{
|
{
|
||||||
return Ok(artworkObject);
|
return Ok(artworkObject);
|
||||||
@@ -525,10 +459,11 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/artwork/{ArtworkId}/image")]
|
[Route("{GameId}/artwork/{ArtworkId}/image/{size}")]
|
||||||
|
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameCoverImage(long GameId, long ArtworkId)
|
public ActionResult GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -536,15 +471,25 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||||
|
|
||||||
if (artworkObject != null) {
|
if (artworkObject != null) {
|
||||||
string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork", artworkObject.ImageId + ".png");
|
//string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork", size.ToString(), artworkObject.ImageId + ".jpg");
|
||||||
|
|
||||||
|
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork");
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, artworkObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
string coverFilePath = ImgFetch.Result;
|
||||||
|
|
||||||
|
|
||||||
if (System.IO.File.Exists(coverFilePath))
|
if (System.IO.File.Exists(coverFilePath))
|
||||||
{
|
{
|
||||||
string filename = artworkObject.ImageId + ".png";
|
string filename = artworkObject.ImageId + ".jpg";
|
||||||
string filepath = coverFilePath;
|
string filepath = coverFilePath;
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||||
string contentType = "image/png";
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
{
|
||||||
@@ -592,7 +537,7 @@ namespace gaseous_server.Controllers
|
|||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
if (gameObject != null)
|
if (gameObject != null)
|
||||||
{
|
{
|
||||||
IGDB.Models.Cover coverObject = Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
IGDB.Models.Cover coverObject = Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
if (coverObject != null)
|
if (coverObject != null)
|
||||||
{
|
{
|
||||||
return Ok(coverObject);
|
return Ok(coverObject);
|
||||||
@@ -616,37 +561,48 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/cover/image")]
|
[Route("{GameId}/cover/image/{size}")]
|
||||||
|
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameCoverImage(long GameId)
|
public ActionResult GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Cover.png");
|
if (gameObject.Cover != null)
|
||||||
if (System.IO.File.Exists(coverFilePath)) {
|
|
||||||
string filename = "Cover.png";
|
|
||||||
string filepath = coverFilePath;
|
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
|
||||||
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(filedata, contentType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return NotFound();
|
if (gameObject.Cover.Id != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Cover cover = Classes.Metadata.Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
|
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Covers");
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, cover.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
string coverFilePath = ImgFetch.Result;
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(coverFilePath)) {
|
||||||
|
string filename = cover.ImageId + ".jpg";
|
||||||
|
string filepath = coverFilePath;
|
||||||
|
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||||
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
|
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(filedata, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return NotFound();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -825,6 +781,24 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{GameId}/platforms")]
|
||||||
|
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public ActionResult GamePlatforms(long GameId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(Games.GetAvailablePlatforms(GameId));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -870,13 +844,15 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult GameRom(long GameId)
|
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
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
return Ok(Classes.Roms.GetRoms(GameId));
|
return Ok(Classes.Roms.GetRoms(GameId, PlatformId, NameSearch, pageNumber, pageSize, user.Id));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -1058,13 +1034,15 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
//[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
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
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)
|
if (rom.GameId == GameId)
|
||||||
{
|
{
|
||||||
return Ok(rom);
|
return Ok(rom);
|
||||||
@@ -1080,6 +1058,37 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
|
[Route("{GameId}/romgroup")]
|
||||||
|
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
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, user.Id));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Rom Group", "An error occurred", ex);
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -1116,13 +1125,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/romgroup/{RomId}")]
|
[Route("{GameId}/romgroup/{RomId}")]
|
||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[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
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
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)
|
if (rom.GameId == GameId)
|
||||||
{
|
{
|
||||||
rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds);
|
rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds);
|
||||||
@@ -1232,7 +1243,8 @@ namespace gaseous_server.Controllers
|
|||||||
{
|
{
|
||||||
Classes.Roms.GameRomItem romItem = Classes.Roms.GetRom(RomId);
|
Classes.Roms.GameRomItem romItem = Classes.Roms.GetRom(RomId);
|
||||||
Common.hashObject hash = new Common.hashObject(romItem.Path);
|
Common.hashObject hash = new Common.hashObject(romItem.Path);
|
||||||
Models.Signatures_Games romSig = Classes.ImportGame.GetFileSignature(hash, new FileInfo(romItem.Path), romItem.Path);
|
FileSignature fileSignature = new FileSignature();
|
||||||
|
gaseous_server.Models.Signatures_Games romSig = fileSignature.GetFileSignature(romItem.Library, hash, new FileInfo(romItem.Path), romItem.Path);
|
||||||
List<Game> searchResults = Classes.ImportGame.SearchForGame_GetAll(romSig.Game.Name, romSig.Flags.IGDBPlatformId);
|
List<Game> searchResults = Classes.ImportGame.SearchForGame_GetAll(romSig.Game.Name, romSig.Flags.IGDBPlatformId);
|
||||||
|
|
||||||
return Ok(searchResults);
|
return Ok(searchResults);
|
||||||
@@ -1275,7 +1287,7 @@ namespace gaseous_server.Controllers
|
|||||||
{
|
{
|
||||||
foreach (long ScreenshotId in gameObject.Screenshots.Ids)
|
foreach (long ScreenshotId in gameObject.Screenshots.Ids)
|
||||||
{
|
{
|
||||||
Screenshot GameScreenshot = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
Screenshot GameScreenshot = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
screenshots.Add(GameScreenshot);
|
screenshots.Add(GameScreenshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1301,7 +1313,7 @@ namespace gaseous_server.Controllers
|
|||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
if (gameObject != null) {
|
if (gameObject != null) {
|
||||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
if (screenshotObject != null)
|
if (screenshotObject != null)
|
||||||
{
|
{
|
||||||
return Ok(screenshotObject);
|
return Ok(screenshotObject);
|
||||||
@@ -1325,24 +1337,31 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/screenshots/{ScreenshotId}/image")]
|
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
||||||
|
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameScreenshotImage(long GameId, long ScreenshotId)
|
public ActionResult GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject));
|
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||||
|
|
||||||
|
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots");
|
||||||
|
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
string coverFilePath = ImgFetch.Result;
|
||||||
|
|
||||||
string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots", screenshotObject.ImageId + ".png");
|
|
||||||
if (System.IO.File.Exists(coverFilePath))
|
if (System.IO.File.Exists(coverFilePath))
|
||||||
{
|
{
|
||||||
string filename = screenshotObject.ImageId + ".png";
|
string filename = screenshotObject.ImageId + ".jpg";
|
||||||
string filepath = coverFilePath;
|
string filepath = coverFilePath;
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||||
string contentType = "image/png";
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
{
|
||||||
|
@@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -37,6 +38,32 @@ namespace gaseous_server.Controllers
|
|||||||
return Ok(PlatformMapping.PlatformMap);
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
@@ -77,7 +77,8 @@ namespace gaseous_server.Controllers
|
|||||||
// Process uploaded files
|
// Process uploaded files
|
||||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
||||||
{
|
{
|
||||||
Classes.ImportGame.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
Classes.ImportGame uploadImport = new ImportGame();
|
||||||
|
uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(workPath))
|
if (Directory.Exists(workPath))
|
||||||
|
@@ -1,13 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NuGet.Common;
|
||||||
using static gaseous_server.Classes.Metadata.Games;
|
using static gaseous_server.Classes.Metadata.Games;
|
||||||
|
|
||||||
|
|
||||||
@@ -37,36 +40,88 @@ namespace gaseous_server.Controllers
|
|||||||
string searchFields = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
|
string searchFields = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
|
||||||
searchBody += "where name ~ *\"" + SearchString + "\"*;";
|
searchBody += "where name ~ *\"" + SearchString + "\"*;";
|
||||||
|
|
||||||
// get Platform metadata
|
List<Platform>? searchCache = Communications.GetSearchCache<List<Platform>>(searchFields, searchBody);
|
||||||
Communications comms = new Communications();
|
|
||||||
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, searchFields, searchBody);
|
|
||||||
|
|
||||||
return results.ToList();
|
if (searchCache == null)
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
// get Platform metadata from data source
|
||||||
|
Communications comms = new Communications();
|
||||||
|
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, searchFields, searchBody);
|
||||||
|
|
||||||
|
Communications.SetSearchCache<List<Platform>>(searchFields, searchBody, results.ToList());
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return searchCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Game")]
|
[Route("Game")]
|
||||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<GaseousGame>), StatusCodes.Status200OK)]
|
||||||
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
|
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
List<Game> RetVal = await _SearchForGame(PlatformId, SearchString);
|
List<GaseousGame> RetVal = await _SearchForGame(PlatformId, SearchString);
|
||||||
return Ok(RetVal);
|
return Ok(RetVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<List<Game>> _SearchForGame(long PlatformId, string SearchString)
|
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
string searchBody = "";
|
string searchBody = "";
|
||||||
string searchFields = "fields cover.*,first_release_date,name,platforms,slug; ";
|
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||||
searchBody += "search \"" + SearchString + "\";";
|
searchBody += "search \"" + SearchString + "\";";
|
||||||
searchBody += "where platforms = (" + PlatformId + ");";
|
searchBody += "where platforms = (" + PlatformId + ");";
|
||||||
|
|
||||||
// get Platform metadata
|
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
||||||
Communications comms = new Communications();
|
|
||||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
|
||||||
|
|
||||||
return results.ToList();
|
if (searchCache == null)
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
// get Game metadata from data source
|
||||||
|
Communications comms = new Communications();
|
||||||
|
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||||
|
|
||||||
|
List<GaseousGame> games = new List<GaseousGame>();
|
||||||
|
foreach (Game game in results.ToList())
|
||||||
|
{
|
||||||
|
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
||||||
|
switch(cacheStatus)
|
||||||
|
{
|
||||||
|
case Storage.CacheStatus.NotPresent:
|
||||||
|
Storage.NewCacheValue(game, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Storage.CacheStatus.Expired:
|
||||||
|
Storage.NewCacheValue(game, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
games.Add(new GaseousGame(game));
|
||||||
|
}
|
||||||
|
|
||||||
|
Communications.SetSearchCache<List<GaseousGame>>(searchFields, searchBody, games);
|
||||||
|
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get full version of results from database
|
||||||
|
// this is a hacky workaround due to the readonly nature of IGDB.Model.Game IdentityOrValue fields
|
||||||
|
List<GaseousGame> gamesToReturn = new List<GaseousGame>();
|
||||||
|
foreach (GaseousGame game in searchCache)
|
||||||
|
{
|
||||||
|
Game tempGame = Games.GetGame((long)game.Id, false, false, false);
|
||||||
|
gamesToReturn.Add(new GaseousGame(tempGame));
|
||||||
|
}
|
||||||
|
|
||||||
|
return gamesToReturn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,82 +37,27 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public List<Models.Signatures_Games> GetSignature(string md5 = "", string sha1 = "")
|
public List<gaseous_server.Models.Signatures_Games> GetSignature(string md5 = "", string sha1 = "")
|
||||||
{
|
{
|
||||||
if (md5.Length > 0)
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
{
|
return signatureManagement.GetSignature(md5, sha1);
|
||||||
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public List<Models.Signatures_Games> GetByTosecName(string TosecName = "")
|
public List<gaseous_server.Models.Signatures_Games> GetByTosecName(string TosecName = "")
|
||||||
{
|
{
|
||||||
if (TosecName.Length > 0)
|
if (TosecName.Length > 0)
|
||||||
{
|
{
|
||||||
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
|
return signatureManagement.GetByTosecName(TosecName);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Models.Signatures_Games> _GetSignature(string sqlWhere, string searchString)
|
|
||||||
{
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
|
||||||
string sql = "SELECT view_Signatures_Games.*, Signatures_Roms.Id AS romid, Signatures_Roms.Name AS romname, Signatures_Roms.Size, Signatures_Roms.CRC, Signatures_Roms.MD5, Signatures_Roms.SHA1, Signatures_Roms.DevelopmentStatus, Signatures_Roms.Attributes, Signatures_Roms.RomType, Signatures_Roms.RomTypeMedia, Signatures_Roms.MediaLabel, Signatures_Roms.MetadataSource FROM Signatures_Roms INNER JOIN view_Signatures_Games ON Signatures_Roms.GameId = view_Signatures_Games.Id WHERE " + sqlWhere;
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
|
||||||
dbDict.Add("searchString", searchString);
|
|
||||||
|
|
||||||
DataTable sigDb = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
|
||||||
List<Models.Signatures_Games> GamesList = new List<Models.Signatures_Games>();
|
|
||||||
|
|
||||||
foreach (DataRow sigDbRow in sigDb.Rows)
|
|
||||||
{
|
|
||||||
Models.Signatures_Games gameItem = new Models.Signatures_Games
|
|
||||||
{
|
|
||||||
Game = new Models.Signatures_Games.GameItem
|
|
||||||
{
|
|
||||||
Id = (Int32)sigDbRow["Id"],
|
|
||||||
Name = (string)sigDbRow["Name"],
|
|
||||||
Description = (string)sigDbRow["Description"],
|
|
||||||
Year = (string)sigDbRow["Year"],
|
|
||||||
Publisher = (string)sigDbRow["Publisher"],
|
|
||||||
Demo = (Models.Signatures_Games.GameItem.DemoTypes)(int)sigDbRow["Demo"],
|
|
||||||
System = (string)sigDbRow["Platform"],
|
|
||||||
SystemVariant = (string)sigDbRow["SystemVariant"],
|
|
||||||
Video = (string)sigDbRow["Video"],
|
|
||||||
Country = (string)sigDbRow["Country"],
|
|
||||||
Language = (string)sigDbRow["Language"],
|
|
||||||
Copyright = (string)sigDbRow["Copyright"]
|
|
||||||
},
|
|
||||||
Rom = new Models.Signatures_Games.RomItem
|
|
||||||
{
|
|
||||||
Id = (Int32)sigDbRow["romid"],
|
|
||||||
Name = (string)sigDbRow["romname"],
|
|
||||||
Size = (Int64)sigDbRow["Size"],
|
|
||||||
Crc = (string)sigDbRow["CRC"],
|
|
||||||
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
|
||||||
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
|
||||||
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
|
|
||||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
|
||||||
RomType = (RomSignatureObject.Game.Rom.RomTypes)(int)sigDbRow["RomType"],
|
|
||||||
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
|
||||||
MediaLabel = (string)sigDbRow["MediaLabel"],
|
|
||||||
SignatureSource = (gaseous_signature_parser.models.RomSignatureObject.RomSignatureObject.Game.Rom.SignatureSourceType)(Int32)sigDbRow["MetadataSource"]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
GamesList.Add(gameItem);
|
|
||||||
}
|
|
||||||
return GamesList;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -103,7 +103,7 @@ namespace gaseous_server.Controllers
|
|||||||
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions{
|
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
}) + ";" + Environment.NewLine +
|
}) + ";" + Environment.NewLine +
|
||||||
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeRatings.AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions{
|
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
}) + ";";
|
}) + ";";
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
||||||
|
@@ -52,15 +52,22 @@ namespace gaseous_server.Controllers
|
|||||||
NormalizedEmail = model.Email.ToUpper(),
|
NormalizedEmail = model.Email.ToUpper(),
|
||||||
SecurityProfile = new SecurityProfileViewModel()
|
SecurityProfile = new SecurityProfileViewModel()
|
||||||
};
|
};
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Creating new account " + model.Email);
|
||||||
var result = await _userManager.CreateAsync(user, model.Password);
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Creation of " + model.Email + " successful.");
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Adding Player role to " + model.Email);
|
||||||
await _userManager.AddToRoleAsync(user, "Player");
|
await _userManager.AddToRoleAsync(user, "Player");
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Adding Gamer role to " + model.Email);
|
||||||
await _userManager.AddToRoleAsync(user, "Gamer");
|
await _userManager.AddToRoleAsync(user, "Gamer");
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Adding Admin role to " + model.Email);
|
||||||
await _userManager.AddToRoleAsync(user, "Admin");
|
await _userManager.AddToRoleAsync(user, "Admin");
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Signing in as " + model.Email);
|
||||||
await _signInManager.SignInAsync(user, isPersistent: true);
|
await _signInManager.SignInAsync(user, isPersistent: true);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Setting first run state to 1");
|
||||||
Config.SetSetting("FirstRunStatus", "1");
|
Config.SetSetting("FirstRunStatus", "1");
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
|
@@ -85,7 +85,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
model.GameAgeRating.IncludeUnrated = false;
|
model.GameAgeRating.IncludeUnrated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(GetGames(model, pageNumber, pageSize));
|
return Ok(GetGames(model, user.Id, pageNumber, pageSize));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -144,6 +144,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
|
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
|
||||||
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
|
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
|
||||||
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
||||||
|
public bool HasSavedGame { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public class GameRatingItem
|
public class GameRatingItem
|
||||||
@@ -181,22 +182,32 @@ 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 whereClause = "";
|
||||||
string havingClause = "";
|
string havingClause = "";
|
||||||
Dictionary<string, object> whereParams = new Dictionary<string, object>();
|
Dictionary<string, object> whereParams = new Dictionary<string, object>();
|
||||||
|
whereParams.Add("userid", userid);
|
||||||
|
|
||||||
List<string> whereClauses = new List<string>();
|
List<string> whereClauses = new List<string>();
|
||||||
List<string> havingClauses = new List<string>();
|
List<string> havingClauses = new List<string>();
|
||||||
|
|
||||||
string tempVal = "";
|
string tempVal = "";
|
||||||
|
|
||||||
|
string nameWhereClause = "";
|
||||||
if (model.Name.Length > 0)
|
if (model.Name.Length > 0)
|
||||||
{
|
{
|
||||||
tempVal = "`Name` LIKE @Name";
|
// tempVal = "`Name` LIKE @Name";
|
||||||
whereParams.Add("@Name", "%" + model.Name + "%");
|
// whereParams.Add("@Name", "%" + model.Name + "%");
|
||||||
havingClauses.Add(tempVal);
|
// havingClauses.Add(tempVal);
|
||||||
|
nameWhereClause = "WHERE (MATCH(Game.`Name`) AGAINST (@Name IN BOOLEAN MODE) OR MATCH(AlternativeName.`Name`) AGAINST (@Name IN BOOLEAN MODE))";
|
||||||
|
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)
|
if (model.GameRating != null)
|
||||||
@@ -263,9 +274,10 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string platformWhereClause = "";
|
||||||
if (model.Platform.Count > 0)
|
if (model.Platform.Count > 0)
|
||||||
{
|
{
|
||||||
tempVal = "Games_Roms.PlatformId IN (";
|
tempVal = " AND Games_Roms.PlatformId IN (";
|
||||||
for (int i = 0; i < model.Platform.Count; i++)
|
for (int i = 0; i < model.Platform.Count; i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
@@ -277,7 +289,8 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
whereParams.Add(platformLabel, model.Platform[i]);
|
whereParams.Add(platformLabel, model.Platform[i]);
|
||||||
}
|
}
|
||||||
tempVal += ")";
|
tempVal += ")";
|
||||||
whereClauses.Add(tempVal);
|
//whereClauses.Add(tempVal);
|
||||||
|
platformWhereClause = tempVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.Genre.Count > 0)
|
if (model.Genre.Count > 0)
|
||||||
@@ -352,7 +365,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
{
|
{
|
||||||
if (model.GameAgeRating.AgeGroupings.Count > 0)
|
if (model.GameAgeRating.AgeGroupings.Count > 0)
|
||||||
{
|
{
|
||||||
tempVal = "(AgeGroupId IN (";
|
tempVal = "(Game.AgeGroupId IN (";
|
||||||
for (int i = 0; i < model.GameAgeRating.AgeGroupings.Count; i++)
|
for (int i = 0; i < model.GameAgeRating.AgeGroupings.Count; i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
@@ -367,7 +380,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
|
|
||||||
if (model.GameAgeRating.IncludeUnrated == true)
|
if (model.GameAgeRating.IncludeUnrated == true)
|
||||||
{
|
{
|
||||||
tempVal += " OR AgeGroupId IS NULL";
|
tempVal += " OR Game.AgeGroupId IS NULL";
|
||||||
}
|
}
|
||||||
tempVal += ")";
|
tempVal += ")";
|
||||||
|
|
||||||
@@ -439,9 +452,71 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT DISTINCT view_Games.* FROM view_Games LEFT JOIN Games_Roms ON view_Games.Id = Games_Roms.GameId 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 = @"
|
||||||
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
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);
|
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||||
|
|
||||||
@@ -457,10 +532,25 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetVal.Add(Classes.Metadata.Games.GetGame(dbResponse.Rows[i]));
|
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
||||||
|
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;
|
return gameReturn;
|
||||||
}
|
}
|
||||||
|
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
@@ -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; } = "";
|
||||||
|
}
|
||||||
|
}
|
52
gaseous-server/Models/GaseousGame.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using gaseous_server.Classes;
|
||||||
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class GaseousGame : IGDB.Models.Game
|
||||||
|
{
|
||||||
|
public GaseousGame()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GaseousGame(IGDB.Models.Game game)
|
||||||
|
{
|
||||||
|
var targetType = this.GetType();
|
||||||
|
var sourceType = game.GetType();
|
||||||
|
foreach(var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public| BindingFlags.SetProperty))
|
||||||
|
{
|
||||||
|
// check whether source object has the the property
|
||||||
|
var sp = sourceType.GetProperty(prop.Name);
|
||||||
|
if (sp != null)
|
||||||
|
{
|
||||||
|
// if yes, copy the value to the matching property
|
||||||
|
var value = sp.GetValue(game, null);
|
||||||
|
prop.SetValue(this, value, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasSavedGame { get; set; } = false;
|
||||||
|
|
||||||
|
public IGDB.Models.Cover? CoverItem
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.Cover != null)
|
||||||
|
{
|
||||||
|
if (this.Cover.Id != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
||||||
|
|
||||||
|
return cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -106,11 +106,19 @@ namespace gaseous_server.Models
|
|||||||
long mapId = (long)row["Id"];
|
long mapId = (long)row["Id"];
|
||||||
if (PlatformMapCache.ContainsKey(mapId.ToString()))
|
if (PlatformMapCache.ContainsKey(mapId.ToString()))
|
||||||
{
|
{
|
||||||
platformMaps.Add(PlatformMapCache[mapId.ToString()]);
|
PlatformMapItem mapItem = PlatformMapCache[mapId.ToString()];
|
||||||
|
if (mapItem != null)
|
||||||
|
{
|
||||||
|
platformMaps.Add(mapItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
platformMaps.Add(BuildPlatformMapItem(row));
|
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||||
|
if (mapItem != null)
|
||||||
|
{
|
||||||
|
platformMaps.Add(mapItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,18 +165,18 @@ namespace gaseous_server.Models
|
|||||||
if (Update == false)
|
if (Update == false)
|
||||||
{
|
{
|
||||||
// insert
|
// insert
|
||||||
sql = "INSERT INTO PlatformMap (Id, RetroPieDirectoryName, WebEmulator_Type, WebEmulator_Core, AvailableWebEmulators) VALUES (@Id, @RetroPieDirectoryName, @WebEmulator_Type, @WebEmulator_Core, @AvailableWebEmulators)";
|
sql = "INSERT INTO PlatformMap (Id, RetroPieDirectoryName, WebEmulator_Type, WebEmulator_Core, AvailableWebEmulators) VALUES (@Id, @RetroPieDirectoryName, @WebEmulator_Type, @WebEmulator_Core, @AvailableWebEmulators);";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// update
|
// update
|
||||||
if (AllowAvailableEmulatorOverwrite == true)
|
if (AllowAvailableEmulatorOverwrite == true)
|
||||||
{
|
{
|
||||||
sql = "UPDATE PlatformMap SET RetroPieDirectoryName=@RetroPieDirectoryName, WebEmulator_Type=@WebEmulator_Type, WebEmulator_Core=@WebEmulator_Core, AvailableWebEmulators=@AvailableWebEmulators WHERE Id = @Id";
|
sql = "UPDATE PlatformMap SET RetroPieDirectoryName=@RetroPieDirectoryName, WebEmulator_Type=@WebEmulator_Type, WebEmulator_Core=@WebEmulator_Core, AvailableWebEmulators=@AvailableWebEmulators WHERE Id = @Id; ";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sql = "UPDATE PlatformMap SET RetroPieDirectoryName=@RetroPieDirectoryName, WebEmulator_Type=@WebEmulator_Type, WebEmulator_Core=@WebEmulator_Core WHERE Id = @Id";
|
sql = "UPDATE PlatformMap SET RetroPieDirectoryName=@RetroPieDirectoryName, WebEmulator_Type=@WebEmulator_Type, WebEmulator_Core=@WebEmulator_Core WHERE Id = @Id;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbDict.Add("Id", item.IGDBId);
|
dbDict.Add("Id", item.IGDBId);
|
||||||
@@ -253,119 +261,129 @@ namespace gaseous_server.Models
|
|||||||
string sql = "";
|
string sql = "";
|
||||||
|
|
||||||
// get platform data
|
// get platform data
|
||||||
IGDB.Models.Platform platform = Platforms.GetPlatform(IGDBId);
|
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId);
|
||||||
|
|
||||||
// get platform alternate names
|
if (platform != null)
|
||||||
sql = "SELECT * FROM PlatformMap_AlternateNames WHERE Id = @Id ORDER BY Name";
|
|
||||||
dbDict.Clear();
|
|
||||||
dbDict.Add("Id", IGDBId);
|
|
||||||
DataTable altTable = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
|
||||||
List<string> alternateNames = new List<string>();
|
|
||||||
foreach (DataRow altRow in altTable.Rows)
|
|
||||||
{
|
{
|
||||||
string altVal = (string)altRow["Name"];
|
// get platform alternate names
|
||||||
if (!alternateNames.Contains(altVal, StringComparer.OrdinalIgnoreCase))
|
sql = "SELECT * FROM PlatformMap_AlternateNames WHERE Id = @Id ORDER BY Name";
|
||||||
|
dbDict.Clear();
|
||||||
|
dbDict.Add("Id", IGDBId);
|
||||||
|
DataTable altTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
List<string> alternateNames = new List<string>();
|
||||||
|
foreach (DataRow altRow in altTable.Rows)
|
||||||
{
|
{
|
||||||
alternateNames.Add(altVal);
|
string altVal = (string)altRow["Name"];
|
||||||
|
if (!alternateNames.Contains(altVal, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
alternateNames.Add(altVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (platform.AlternativeName != null)
|
||||||
if (platform.AlternativeName != null)
|
|
||||||
{
|
|
||||||
if (!alternateNames.Contains(platform.AlternativeName, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
alternateNames.Add(platform.AlternativeName);
|
if (!alternateNames.Contains(platform.AlternativeName, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
alternateNames.Add(platform.AlternativeName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// get platform known extensions
|
// get platform known extensions
|
||||||
sql = "SELECT * FROM PlatformMap_Extensions WHERE Id = @Id ORDER BY Extension";
|
sql = "SELECT * FROM PlatformMap_Extensions WHERE Id = @Id ORDER BY Extension";
|
||||||
dbDict.Clear();
|
dbDict.Clear();
|
||||||
dbDict.Add("Id", IGDBId);
|
dbDict.Add("Id", IGDBId);
|
||||||
DataTable extTable = db.ExecuteCMD(sql, dbDict);
|
DataTable extTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<string> knownExtensions = new List<string>();
|
List<string> knownExtensions = new List<string>();
|
||||||
foreach (DataRow extRow in extTable.Rows)
|
foreach (DataRow extRow in extTable.Rows)
|
||||||
{
|
|
||||||
string extVal = (string)extRow["Extension"];
|
|
||||||
if (!knownExtensions.Contains(extVal, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
knownExtensions.Add(extVal);
|
string extVal = (string)extRow["Extension"];
|
||||||
|
if (!knownExtensions.Contains(extVal, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
knownExtensions.Add(extVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// get platform unique extensions
|
// get platform unique extensions
|
||||||
sql = "SELECT * FROM PlatformMap_UniqueExtensions WHERE Id = @Id ORDER BY Extension";
|
sql = "SELECT * FROM PlatformMap_UniqueExtensions WHERE Id = @Id ORDER BY Extension";
|
||||||
dbDict.Clear();
|
dbDict.Clear();
|
||||||
dbDict.Add("Id", IGDBId);
|
dbDict.Add("Id", IGDBId);
|
||||||
DataTable uextTable = db.ExecuteCMD(sql, dbDict);
|
DataTable uextTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<string> uniqueExtensions = new List<string>();
|
List<string> uniqueExtensions = new List<string>();
|
||||||
foreach (DataRow uextRow in uextTable.Rows)
|
foreach (DataRow uextRow in uextTable.Rows)
|
||||||
{
|
|
||||||
string uextVal = (string)uextRow["Extension"];
|
|
||||||
if (!uniqueExtensions.Contains(uextVal, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
uniqueExtensions.Add(uextVal);
|
string uextVal = (string)uextRow["Extension"];
|
||||||
|
if (!uniqueExtensions.Contains(uextVal, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
uniqueExtensions.Add(uextVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// get platform bios
|
// get platform bios
|
||||||
sql = "SELECT * FROM PlatformMap_Bios WHERE Id = @Id ORDER BY Filename";
|
sql = "SELECT * FROM PlatformMap_Bios WHERE Id = @Id ORDER BY Filename";
|
||||||
dbDict.Clear();
|
dbDict.Clear();
|
||||||
dbDict.Add("Id", IGDBId);
|
dbDict.Add("Id", IGDBId);
|
||||||
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
||||||
foreach (DataRow biosRow in biosTable.Rows)
|
foreach (DataRow biosRow in biosTable.Rows)
|
||||||
{
|
|
||||||
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
|
||||||
{
|
{
|
||||||
filename = (string)Common.ReturnValueIfNull(biosRow["Filename"], ""),
|
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
||||||
description = (string)Common.ReturnValueIfNull(biosRow["Description"], ""),
|
{
|
||||||
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
filename = (string)Common.ReturnValueIfNull(biosRow["Filename"], ""),
|
||||||
|
description = (string)Common.ReturnValueIfNull(biosRow["Description"], ""),
|
||||||
|
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
||||||
|
};
|
||||||
|
bioss.Add(bios);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build item
|
||||||
|
PlatformMapItem mapItem = new PlatformMapItem();
|
||||||
|
mapItem.IGDBId = IGDBId;
|
||||||
|
mapItem.IGDBName = platform.Name;
|
||||||
|
mapItem.IGDBSlug = platform.Slug;
|
||||||
|
mapItem.AlternateNames = alternateNames;
|
||||||
|
mapItem.Extensions = new PlatformMapItem.FileExtensions{
|
||||||
|
SupportedFileExtensions = knownExtensions,
|
||||||
|
UniqueFileExtensions = uniqueExtensions
|
||||||
};
|
};
|
||||||
bioss.Add(bios);
|
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
||||||
|
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem{
|
||||||
|
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
||||||
|
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
||||||
|
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
||||||
|
};
|
||||||
|
mapItem.Bios = bioss;
|
||||||
|
|
||||||
|
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
||||||
|
{
|
||||||
|
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// build item
|
return null;
|
||||||
PlatformMapItem mapItem = new PlatformMapItem();
|
|
||||||
mapItem.IGDBId = IGDBId;
|
|
||||||
mapItem.IGDBName = platform.Name;
|
|
||||||
mapItem.IGDBSlug = platform.Slug;
|
|
||||||
mapItem.AlternateNames = alternateNames;
|
|
||||||
mapItem.Extensions = new PlatformMapItem.FileExtensions{
|
|
||||||
SupportedFileExtensions = knownExtensions,
|
|
||||||
UniqueFileExtensions = uniqueExtensions
|
|
||||||
};
|
|
||||||
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
|
||||||
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem{
|
|
||||||
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
|
||||||
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
|
||||||
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
|
||||||
};
|
|
||||||
mapItem.Bios = bioss;
|
|
||||||
|
|
||||||
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
|
||||||
{
|
|
||||||
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetIGDBPlatformMapping(ref Models.Signatures_Games Signature, FileInfo RomFileInfo, bool SetSystemName)
|
public static void GetIGDBPlatformMapping(ref gaseous_server.Models.Signatures_Games Signature, string ImageExtension, bool SetSystemName)
|
||||||
{
|
{
|
||||||
|
if (Signature.Game != null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Platform Mapping", "Determining platform based on extension " + ImageExtension + " or \"" + Signature.Game.System + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
bool PlatformFound = false;
|
bool PlatformFound = false;
|
||||||
foreach (Models.PlatformMapping.PlatformMapItem PlatformMapping in Models.PlatformMapping.PlatformMap)
|
foreach (Models.PlatformMapping.PlatformMapItem PlatformMapping in Models.PlatformMapping.PlatformMap)
|
||||||
{
|
{
|
||||||
if (PlatformMapping.Extensions != null)
|
if (PlatformMapping.Extensions != null)
|
||||||
{
|
{
|
||||||
if (PlatformMapping.Extensions.UniqueFileExtensions.Contains(RomFileInfo.Extension, StringComparer.OrdinalIgnoreCase))
|
if (PlatformMapping.Extensions.UniqueFileExtensions.Contains(ImageExtension, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (SetSystemName == true)
|
if (SetSystemName == true)
|
||||||
{
|
{
|
||||||
@@ -375,6 +393,8 @@ namespace gaseous_server.Models
|
|||||||
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
||||||
|
|
||||||
PlatformFound = true;
|
PlatformFound = true;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Platform Mapping", "Platform id " + PlatformMapping.IGDBId + " determined from file extension");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,10 +417,17 @@ namespace gaseous_server.Models
|
|||||||
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
||||||
|
|
||||||
PlatformFound = true;
|
PlatformFound = true;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Platform Mapping", "Platform id " + PlatformMapping.IGDBId + " determined from signature system to platform map");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PlatformFound == false)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Platform Mapping", "Unable to determine platform");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PlatformMapItem
|
public class PlatformMapItem
|
||||||
|
@@ -4,197 +4,19 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
|||||||
|
|
||||||
namespace gaseous_server.Models
|
namespace gaseous_server.Models
|
||||||
{
|
{
|
||||||
public class Signatures_Games
|
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
||||||
{
|
{
|
||||||
public Signatures_Games()
|
public Signatures_Games()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameItem? Game { get; set; }
|
|
||||||
public RomItem? Rom { get; set; }
|
|
||||||
|
|
||||||
//[JsonIgnore]
|
|
||||||
public int Score
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
int _score = 0;
|
|
||||||
|
|
||||||
if (Game != null)
|
|
||||||
{
|
|
||||||
_score = _score + Game.Score;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Rom != null)
|
|
||||||
{
|
|
||||||
_score = _score + Rom.Score;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignatureFlags Flags = new SignatureFlags();
|
public SignatureFlags Flags = new SignatureFlags();
|
||||||
|
|
||||||
public class GameItem
|
|
||||||
{
|
|
||||||
public Int32? Id { get; set; }
|
|
||||||
public string? Name { get; set; }
|
|
||||||
public string? Description { get; set; }
|
|
||||||
public string? Year { get; set; }
|
|
||||||
public string? Publisher { get; set; }
|
|
||||||
public DemoTypes Demo { get; set; }
|
|
||||||
public string? System { get; set; }
|
|
||||||
public string? SystemVariant { get; set; }
|
|
||||||
public string? Video { get; set; }
|
|
||||||
public string? Country { get; set; }
|
|
||||||
public string? Language { get; set; }
|
|
||||||
public string? Copyright { get; set; }
|
|
||||||
|
|
||||||
public enum DemoTypes
|
|
||||||
{
|
|
||||||
NotDemo = 0,
|
|
||||||
demo = 1,
|
|
||||||
demo_kiosk = 2,
|
|
||||||
demo_playable = 3,
|
|
||||||
demo_rolling = 4,
|
|
||||||
demo_slideshow = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int Score
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// calculate a score based on the availablility of data
|
|
||||||
int _score = 0;
|
|
||||||
var properties = this.GetType().GetProperties();
|
|
||||||
foreach (var prop in properties)
|
|
||||||
{
|
|
||||||
if (prop.GetGetMethod() != null)
|
|
||||||
{
|
|
||||||
switch (prop.Name.ToLower())
|
|
||||||
{
|
|
||||||
case "id":
|
|
||||||
case "score":
|
|
||||||
break;
|
|
||||||
case "name":
|
|
||||||
case "year":
|
|
||||||
case "publisher":
|
|
||||||
case "system":
|
|
||||||
if (prop.PropertyType == typeof(string))
|
|
||||||
{
|
|
||||||
if (prop.GetValue(this) != null)
|
|
||||||
{
|
|
||||||
string propVal = prop.GetValue(this).ToString();
|
|
||||||
if (propVal.Length > 0)
|
|
||||||
{
|
|
||||||
_score = _score + 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (prop.PropertyType == typeof(string))
|
|
||||||
{
|
|
||||||
if (prop.GetValue(this) != null)
|
|
||||||
{
|
|
||||||
string propVal = prop.GetValue(this).ToString();
|
|
||||||
if (propVal.Length > 0)
|
|
||||||
{
|
|
||||||
_score = _score + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RomItem
|
|
||||||
{
|
|
||||||
public Int32? Id { get; set; }
|
|
||||||
public string? Name { get; set; }
|
|
||||||
public Int64? Size { get; set; }
|
|
||||||
public string? Crc { get; set; }
|
|
||||||
public string? Md5 { get; set; }
|
|
||||||
public string? Sha1 { get; set; }
|
|
||||||
|
|
||||||
public string? DevelopmentStatus { get; set; }
|
|
||||||
|
|
||||||
public List<KeyValuePair<string, object>> Attributes { get; set; } = new List<KeyValuePair<string, object>>();
|
|
||||||
|
|
||||||
public RomSignatureObject.Game.Rom.RomTypes RomType { get; set; }
|
|
||||||
public string? RomTypeMedia { get; set; }
|
|
||||||
public string? MediaLabel { get; set; }
|
|
||||||
|
|
||||||
public RomSignatureObject.Game.Rom.SignatureSourceType SignatureSource { get; set; }
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int Score
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// calculate a score based on the availablility of data
|
|
||||||
int _score = 0;
|
|
||||||
var properties = this.GetType().GetProperties();
|
|
||||||
foreach (var prop in properties)
|
|
||||||
{
|
|
||||||
if (prop.GetGetMethod() != null)
|
|
||||||
{
|
|
||||||
switch (prop.Name.ToLower())
|
|
||||||
{
|
|
||||||
case "name":
|
|
||||||
case "size":
|
|
||||||
case "crc":
|
|
||||||
case "developmentstatus":
|
|
||||||
case "flags":
|
|
||||||
case "attributes":
|
|
||||||
case "romtypemedia":
|
|
||||||
case "medialabel":
|
|
||||||
if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(Int64) || prop.PropertyType == typeof(List<string>))
|
|
||||||
{
|
|
||||||
if (prop.GetValue(this) != null)
|
|
||||||
{
|
|
||||||
string propVal = prop.GetValue(this).ToString();
|
|
||||||
if (propVal.Length > 0)
|
|
||||||
{
|
|
||||||
_score = _score + 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (prop.PropertyType == typeof(string))
|
|
||||||
{
|
|
||||||
if (prop.GetValue(this) != null)
|
|
||||||
{
|
|
||||||
string propVal = prop.GetValue(this).ToString();
|
|
||||||
if (propVal.Length > 0)
|
|
||||||
{
|
|
||||||
_score = _score + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SignatureFlags
|
public class SignatureFlags
|
||||||
{
|
{
|
||||||
public long IGDBPlatformId { get; set; }
|
public long IGDBPlatformId { get; set; }
|
||||||
public string IGDBPlatformName { get; set; }
|
public string IGDBPlatformName { get; set; }
|
||||||
|
public long IGDBGameId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
using System.ComponentModel.Design.Serialization;
|
using System.ComponentModel.Design.Serialization;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
|
using NuGet.Common;
|
||||||
|
using NuGet.Packaging;
|
||||||
|
|
||||||
namespace gaseous_server
|
namespace gaseous_server
|
||||||
{
|
{
|
||||||
@@ -113,6 +115,7 @@ namespace gaseous_server
|
|||||||
_CorrelationId = correlationId.ToString();
|
_CorrelationId = correlationId.ToString();
|
||||||
CallContext.SetData("CorrelationId", correlationId);
|
CallContext.SetData("CorrelationId", correlationId);
|
||||||
CallContext.SetData("CallingProcess", _ItemType.ToString());
|
CallContext.SetData("CallingProcess", _ItemType.ToString());
|
||||||
|
CallContext.SetData("CallingUser", "System");
|
||||||
|
|
||||||
// log the start
|
// log the start
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Executing " + _ItemType + " with correlation id " + _CorrelationId);
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Executing " + _ItemType + " with correlation id " + _CorrelationId);
|
||||||
@@ -143,11 +146,13 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.TitleIngestor:
|
case QueueItemType.TitleIngestor:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Title Ingestor");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Title Ingestor");
|
||||||
Classes.ImportGames importGames = new Classes.ImportGames(Config.LibraryConfiguration.LibraryImportDirectory)
|
Classes.ImportGame import = new ImportGame
|
||||||
{
|
{
|
||||||
CallingQueueItem = this
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
|
import.ProcessDirectory(Config.LibraryConfiguration.LibraryImportDirectory);
|
||||||
|
|
||||||
|
// clean up
|
||||||
Classes.ImportGame.DeleteOrphanedDirectories(Config.LibraryConfiguration.LibraryImportDirectory);
|
Classes.ImportGame.DeleteOrphanedDirectories(Config.LibraryConfiguration.LibraryImportDirectory);
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
@@ -168,24 +173,39 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.OrganiseLibrary:
|
case QueueItemType.OrganiseLibrary:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Organiser");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Organiser");
|
||||||
Classes.ImportGame.OrganiseLibrary();
|
Classes.ImportGame importLibraryOrg = new ImportGame
|
||||||
|
{
|
||||||
|
CallingQueueItem = this
|
||||||
|
};
|
||||||
|
importLibraryOrg.OrganiseLibrary();
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QueueItemType.LibraryScan:
|
case QueueItemType.LibraryScan:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Scanner");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Scanners");
|
||||||
Classes.ImportGame import = new ImportGame
|
Classes.ImportGame libScan = new ImportGame
|
||||||
{
|
{
|
||||||
CallingQueueItem = this
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
import.LibraryScan();
|
libScan.LibraryScan();
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QueueItemType.LibraryScanWorker:
|
||||||
|
GameLibrary.LibraryItem library = (GameLibrary.LibraryItem)Options;
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Scanner worker for library " + library.Name);
|
||||||
|
Classes.ImportGame importLibraryScan = new ImportGame
|
||||||
|
{
|
||||||
|
CallingQueueItem = this
|
||||||
|
};
|
||||||
|
importLibraryScan.LibrarySpecificScan(library);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case QueueItemType.Rematcher:
|
case QueueItemType.Rematcher:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Rematch");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Rematch");
|
||||||
Classes.ImportGame importRematch = new ImportGame
|
Classes.ImportGame importRematch = new ImportGame
|
||||||
@@ -221,6 +241,32 @@ namespace gaseous_server
|
|||||||
maintenance.RunMaintenance();
|
maintenance.RunMaintenance();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QueueItemType.TempCleanup:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
|
||||||
|
{
|
||||||
|
string rootPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, libraryItem.Id.ToString());
|
||||||
|
if (Directory.Exists(rootPath))
|
||||||
|
{
|
||||||
|
foreach (string directory in Directory.GetDirectories(rootPath))
|
||||||
|
{
|
||||||
|
DirectoryInfo info = new DirectoryInfo(directory);
|
||||||
|
if (info.LastWriteTimeUtc.AddMinutes(5) < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Deleting temporary decompress folder: " + directory);
|
||||||
|
Directory.Delete(directory, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception tcEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "An error occurred while cleaning temporary files", tcEx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -348,6 +394,11 @@ namespace gaseous_server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
LibraryScan,
|
LibraryScan,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the work for the LibraryScan task
|
||||||
|
/// </summary>
|
||||||
|
LibraryScanWorker,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks for roms in the library that have an unknown platform or game match
|
/// Looks for roms in the library that have an unknown platform or game match
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -371,7 +422,12 @@ namespace gaseous_server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a clean up of old files, and optimises the database
|
/// Performs a clean up of old files, and optimises the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Maintainer
|
Maintainer,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cleans up marked paths in the temporary directory
|
||||||
|
/// </summary>
|
||||||
|
TempCleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum QueueItemState
|
public enum QueueItemState
|
||||||
|
@@ -50,7 +50,10 @@ Config.InitSettings();
|
|||||||
Config.UpdateConfig();
|
Config.UpdateConfig();
|
||||||
|
|
||||||
// set api metadata source from config
|
// set api metadata source from config
|
||||||
Communications.MetadataSource = Config.MetadataConfiguration.Source;
|
Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource;
|
||||||
|
|
||||||
|
// set up hasheous client
|
||||||
|
HasheousClient.WebApp.HttpHelper.BaseUri = Config.MetadataConfiguration.HasheousHost;
|
||||||
|
|
||||||
// set initial values
|
// set initial values
|
||||||
Guid APIKey = Guid.NewGuid();
|
Guid APIKey = Guid.NewGuid();
|
||||||
@@ -106,6 +109,11 @@ builder.Services.AddControllers().AddJsonOptions(x =>
|
|||||||
builder.Services.AddResponseCaching();
|
builder.Services.AddResponseCaching();
|
||||||
builder.Services.AddControllers(options =>
|
builder.Services.AddControllers(options =>
|
||||||
{
|
{
|
||||||
|
options.CacheProfiles.Add("None",
|
||||||
|
new CacheProfile()
|
||||||
|
{
|
||||||
|
Duration = 1
|
||||||
|
});
|
||||||
options.CacheProfiles.Add("Default30",
|
options.CacheProfiles.Add("Default30",
|
||||||
new CacheProfile()
|
new CacheProfile()
|
||||||
{
|
{
|
||||||
@@ -297,20 +305,6 @@ using (var scope = app.Services.CreateScope())
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.Use(async (context, next) =>
|
|
||||||
{
|
|
||||||
// set the correlation id
|
|
||||||
string correlationId = Guid.NewGuid().ToString();
|
|
||||||
CallContext.SetData("CorrelationId", correlationId);
|
|
||||||
CallContext.SetData("CallingProcess", context.Request.Method + ": " + context.Request.Path);
|
|
||||||
|
|
||||||
context.Response.Headers.Add("x-correlation-id", correlationId.ToString());
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseDefaultFiles();
|
app.UseDefaultFiles();
|
||||||
@@ -322,6 +316,28 @@ app.UseStaticFiles(new StaticFileOptions
|
|||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
// set the correlation id
|
||||||
|
string correlationId = Guid.NewGuid().ToString();
|
||||||
|
CallContext.SetData("CorrelationId", correlationId);
|
||||||
|
CallContext.SetData("CallingProcess", context.Request.Method + ": " + context.Request.Path);
|
||||||
|
|
||||||
|
string userIdentity;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
userIdentity = context.User.Claims.Where(x=>x.Type==System.Security.Claims.ClaimTypes.NameIdentifier).FirstOrDefault().Value;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
userIdentity = "";
|
||||||
|
}
|
||||||
|
CallContext.SetData("CallingUser", userIdentity);
|
||||||
|
|
||||||
|
context.Response.Headers.Add("x-correlation-id", correlationId.ToString());
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
// emergency password recovery if environment variable is set
|
// emergency password recovery if environment variable is set
|
||||||
// process:
|
// process:
|
||||||
// - set the environment variable "recoveraccount" to the email address of the account to be recovered
|
// - set the environment variable "recoveraccount" to the email address of the account to be recovered
|
||||||
@@ -393,7 +409,9 @@ Config.LibraryConfiguration.InitLibrary();
|
|||||||
|
|
||||||
// insert unknown platform and game if not present
|
// insert unknown platform and game if not present
|
||||||
gaseous_server.Classes.Metadata.Games.GetGame(0, false, false, false);
|
gaseous_server.Classes.Metadata.Games.GetGame(0, false, false, false);
|
||||||
|
gaseous_server.Classes.Metadata.Games.AssignAllGamesToPlatformIdZero();
|
||||||
gaseous_server.Classes.Metadata.Platforms.GetPlatform(0);
|
gaseous_server.Classes.Metadata.Platforms.GetPlatform(0);
|
||||||
|
gaseous_server.Classes.Metadata.Platforms.AssignAllPlatformsToGameIdZero();
|
||||||
|
|
||||||
// extract platform map if not present
|
// extract platform map if not present
|
||||||
PlatformMapping.ExtractPlatformMap();
|
PlatformMapping.ExtractPlatformMap();
|
||||||
@@ -458,6 +476,16 @@ ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ProcessQueue.QueueItem tempCleanup = new ProcessQueue.QueueItem(
|
||||||
|
ProcessQueue.QueueItemType.TempCleanup,
|
||||||
|
1,
|
||||||
|
new List<ProcessQueue.QueueItemType>(),
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
tempCleanup.ForceExecute();
|
||||||
|
ProcessQueue.QueueItems.Add(tempCleanup);
|
||||||
|
|
||||||
Logging.WriteToDiskOnly = false;
|
Logging.WriteToDiskOnly = false;
|
||||||
|
|
||||||
// start the app
|
// start the app
|
||||||
|
4
gaseous-server/Support/Database/MySQL/gaseous-1009.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `Games_Roms`
|
||||||
|
ADD INDEX `id_LibraryId` (`LibraryId` ASC) VISIBLE,
|
||||||
|
ADD INDEX `id_MD5` USING BTREE (`MD5`) VISIBLE;
|
||||||
|
|
23
gaseous-server/Support/Database/MySQL/gaseous-1010.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CREATE OR REPLACE VIEW `view_Games` AS
|
||||||
|
SELECT
|
||||||
|
a.*, b.AgeGroupId
|
||||||
|
FROM
|
||||||
|
view_GamesWithRoms a
|
||||||
|
INNER JOIN
|
||||||
|
(SELECT
|
||||||
|
view_GamesWithRoms.Id,
|
||||||
|
MAX((SELECT
|
||||||
|
AgeGroupId
|
||||||
|
FROM
|
||||||
|
ClassificationMap
|
||||||
|
WHERE
|
||||||
|
RatingId = AgeRating.Rating)) AgeGroupId
|
||||||
|
FROM
|
||||||
|
view_GamesWithRoms
|
||||||
|
LEFT JOIN Relation_Game_AgeRatings ON view_GamesWithRoms.Id = Relation_Game_AgeRatings.GameId
|
||||||
|
LEFT JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id
|
||||||
|
GROUP BY Id) b ON a.Id = b.Id
|
||||||
|
ORDER BY NameThe;
|
||||||
|
|
||||||
|
ALTER TABLE `ServerLogs`
|
||||||
|
ADD COLUMN `CallingUser` VARCHAR(255) NULL AFTER `CallingProcess`;
|
29
gaseous-server/Support/Database/MySQL/gaseous-1011.sql
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
CREATE TABLE `AgeGroup` (
|
||||||
|
`Id` BIGINT NOT NULL,
|
||||||
|
`GameId` BIGINT NULL,
|
||||||
|
`AgeGroupId` INT NULL,
|
||||||
|
`dateAdded` DATETIME NULL DEFAULT NULL,
|
||||||
|
`lastUpdated` DATETIME NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`Id`));
|
||||||
|
|
||||||
|
ALTER TABLE `AgeGroup`
|
||||||
|
ADD INDEX `id_GameId` (`GameId` ASC) VISIBLE,
|
||||||
|
ADD INDEX `id_AgeGroupId` (`AgeGroupId` ASC) VISIBLE;
|
||||||
|
|
||||||
|
ALTER TABLE `Game`
|
||||||
|
CHANGE COLUMN `Slug` `Slug` VARCHAR(255) NULL DEFAULT NULL;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW `view_Games` AS
|
||||||
|
SELECT
|
||||||
|
a.*, b.AgeGroupId
|
||||||
|
FROM
|
||||||
|
view_GamesWithRoms a
|
||||||
|
LEFT JOIN AgeGroup b ON b.GameId = a.Id
|
||||||
|
ORDER BY NameThe;
|
||||||
|
|
||||||
|
ALTER TABLE `Game`
|
||||||
|
ADD FULLTEXT INDEX `ft_Name` (`Name`) VISIBLE;
|
||||||
|
|
||||||
|
ALTER TABLE `AlternativeName`
|
||||||
|
ADD FULLTEXT INDEX `ft_Name` (`Name`) VISIBLE,
|
||||||
|
ADD INDEX `id_GameId` (`Game` ASC) VISIBLE;
|
5
gaseous-server/Support/Database/MySQL/gaseous-1012.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE `Games_Roms`
|
||||||
|
ADD INDEX `id_IdAndLibraryId` (`Id` ASC, `LibraryId` ASC) VISIBLE;
|
||||||
|
|
||||||
|
ALTER TABLE `ServerLogs`
|
||||||
|
ADD INDEX `idx_EventDate` (`EventTime` ASC) VISIBLE;
|
9
gaseous-server/Support/Database/MySQL/gaseous-1013.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE `SearchCache` (
|
||||||
|
`SearchFields` varchar(384) NOT NULL,
|
||||||
|
`SearchString` varchar(128) NOT NULL,
|
||||||
|
`Content` longtext DEFAULT NULL,
|
||||||
|
`LastSearch` datetime DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`SearchFields`,`SearchString`),
|
||||||
|
KEY `idx_SearchString` (`SearchFields`,`SearchString`),
|
||||||
|
KEY `idx_LastSearch` (`LastSearch`)
|
||||||
|
);
|
2
gaseous-server/Support/Database/MySQL/gaseous-1014.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `RomCollections`
|
||||||
|
ADD COLUMN `ArchiveType` INT NULL AFTER `IncludeBIOSFiles`;
|
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);
|
@@ -188,6 +188,91 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"igdbId": 114,
|
||||||
|
"igdbName": "Amiga CD32",
|
||||||
|
"igdbSlug": "amiga-cd32",
|
||||||
|
"alternateNames": [
|
||||||
|
"Amiga CD32",
|
||||||
|
"Commodore Amiga CD32"
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"supportedFileExtensions": [
|
||||||
|
".ZIP"
|
||||||
|
],
|
||||||
|
"uniqueFileExtensions": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"retroPieDirectoryName": "amiga",
|
||||||
|
"webEmulator": {
|
||||||
|
"type": "EmulatorJS",
|
||||||
|
"core": "amiga",
|
||||||
|
"availableWebEmulators": [
|
||||||
|
{
|
||||||
|
"emulatorType": "EmulatorJS",
|
||||||
|
"availableWebEmulatorCores": [
|
||||||
|
{
|
||||||
|
"core": "amiga",
|
||||||
|
"alternateCoreName": "puae",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bios": [
|
||||||
|
{
|
||||||
|
"hash": "85ad74194e87c08904327de1a9443b7a",
|
||||||
|
"description": "Kickstart v1.2 rev 33.180",
|
||||||
|
"filename": "kick33180.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "82a21c1890cae844b3df741f2762d48d",
|
||||||
|
"description": "Kickstart v1.3 rev 34.005",
|
||||||
|
"filename": "kick34005.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "89da1838a24460e4b93f4f0c5d92d48d",
|
||||||
|
"description": "CDTV extended ROM v1.00",
|
||||||
|
"filename": "kick34005.CDTV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "dc10d7bdd1b6f450773dfb558477c230",
|
||||||
|
"description": "Kickstart v2.04 rev 37.175",
|
||||||
|
"filename": "kick37175.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "5f8924d013dd57a89cf349f4cdedc6b1",
|
||||||
|
"description": "CD32 Kickstart v3.1 rev 40.060",
|
||||||
|
"filename": "kick40060.CD32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "f2f241bf094168cfb9e7805dc2856433",
|
||||||
|
"description": "CD32 KS + extended v3.1 rev 40.060",
|
||||||
|
"filename": "kick40060.CD32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "bb72565701b1b6faece07d68ea5da639",
|
||||||
|
"description": "CD32 extended ROM rev 40.060",
|
||||||
|
"filename": "kick40060.CD32.ext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "e40a5dfb3d017ba8779faba30cbd1c8e",
|
||||||
|
"description": "Kickstart v3.1 rev 40.063",
|
||||||
|
"filename": "kick40063.A600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "646773759326fbac3b2311fd8c8793ee",
|
||||||
|
"description": "Kickstart v3.1 rev 40.068",
|
||||||
|
"filename": "kick40068.A1200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "9bdedde6a4f33555b4a270c8ca53297d",
|
||||||
|
"description": "Kickstart v3.1 rev 40.068",
|
||||||
|
"filename": "kick40068.A4000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"igdbId": 25,
|
"igdbId": 25,
|
||||||
"igdbName": "Amstrad CPC",
|
"igdbName": "Amstrad CPC",
|
||||||
@@ -543,6 +628,48 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"igdbId": 68,
|
||||||
|
"igdbName": "ColecoVision",
|
||||||
|
"igdbSlug": "colecovision",
|
||||||
|
"alternateNames": [
|
||||||
|
"ColecoVision"
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"supportedFileExtensions": [
|
||||||
|
".BIN",
|
||||||
|
".COL",
|
||||||
|
".ROM",
|
||||||
|
".ZIP"
|
||||||
|
],
|
||||||
|
"uniqueFileExtensions": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"retroPieDirectoryName": "coleco",
|
||||||
|
"webEmulator": {
|
||||||
|
"type": "EmulatorJS",
|
||||||
|
"core": "coleco",
|
||||||
|
"availableWebEmulators": [
|
||||||
|
{
|
||||||
|
"emulatorType": "EmulatorJS",
|
||||||
|
"availableWebEmulatorCores": [
|
||||||
|
{
|
||||||
|
"core": "coleco",
|
||||||
|
"alternateCoreName": "coleco",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bios": [
|
||||||
|
{
|
||||||
|
"hash": "2c66f5911e5b42b8ebe113403548eee7",
|
||||||
|
"description": "ColecoVision BIOS - Mandatory",
|
||||||
|
"filename": "colecovision.rom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"igdbId": 15,
|
"igdbId": 15,
|
||||||
"igdbName": "Commodore C64/128/MAX",
|
"igdbName": "Commodore C64/128/MAX",
|
||||||
@@ -620,6 +747,92 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"igdbId": 158,
|
||||||
|
"igdbName": "Commodore CDTV",
|
||||||
|
"igdbSlug": "commodore-cdtv",
|
||||||
|
"alternateNames": [
|
||||||
|
"Commodore CDTV",
|
||||||
|
"Amiga CDTV",
|
||||||
|
"Commodore Amiga CDTV"
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"supportedFileExtensions": [
|
||||||
|
".ZIP"
|
||||||
|
],
|
||||||
|
"uniqueFileExtensions": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"retroPieDirectoryName": "amiga",
|
||||||
|
"webEmulator": {
|
||||||
|
"type": "EmulatorJS",
|
||||||
|
"core": "amiga",
|
||||||
|
"availableWebEmulators": [
|
||||||
|
{
|
||||||
|
"emulatorType": "EmulatorJS",
|
||||||
|
"availableWebEmulatorCores": [
|
||||||
|
{
|
||||||
|
"core": "amiga",
|
||||||
|
"alternateCoreName": "puae",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bios": [
|
||||||
|
{
|
||||||
|
"hash": "85ad74194e87c08904327de1a9443b7a",
|
||||||
|
"description": "Kickstart v1.2 rev 33.180",
|
||||||
|
"filename": "kick33180.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "82a21c1890cae844b3df741f2762d48d",
|
||||||
|
"description": "Kickstart v1.3 rev 34.005",
|
||||||
|
"filename": "kick34005.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "89da1838a24460e4b93f4f0c5d92d48d",
|
||||||
|
"description": "CDTV extended ROM v1.00",
|
||||||
|
"filename": "kick34005.CDTV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "dc10d7bdd1b6f450773dfb558477c230",
|
||||||
|
"description": "Kickstart v2.04 rev 37.175",
|
||||||
|
"filename": "kick37175.A500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "5f8924d013dd57a89cf349f4cdedc6b1",
|
||||||
|
"description": "CD32 Kickstart v3.1 rev 40.060",
|
||||||
|
"filename": "kick40060.CD32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "f2f241bf094168cfb9e7805dc2856433",
|
||||||
|
"description": "CD32 KS + extended v3.1 rev 40.060",
|
||||||
|
"filename": "kick40060.CD32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "bb72565701b1b6faece07d68ea5da639",
|
||||||
|
"description": "CD32 extended ROM rev 40.060",
|
||||||
|
"filename": "kick40060.CD32.ext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "e40a5dfb3d017ba8779faba30cbd1c8e",
|
||||||
|
"description": "Kickstart v3.1 rev 40.063",
|
||||||
|
"filename": "kick40063.A600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "646773759326fbac3b2311fd8c8793ee",
|
||||||
|
"description": "Kickstart v3.1 rev 40.068",
|
||||||
|
"filename": "kick40068.A1200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "9bdedde6a4f33555b4a270c8ca53297d",
|
||||||
|
"description": "Kickstart v3.1 rev 40.068",
|
||||||
|
"filename": "kick40068.A4000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"igdbId": 33,
|
"igdbId": 33,
|
||||||
"igdbName": "Game Boy",
|
"igdbName": "Game Boy",
|
||||||
|
@@ -20,11 +20,15 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="gaseous-signature-parser" Version="2.0.0" />
|
<PackageReference Include="gaseous-signature-parser" Version="2.0.0" />
|
||||||
<PackageReference Include="gaseous.IGDB" Version="1.0.1" />
|
<PackageReference Include="gaseous.IGDB" Version="1.0.1" />
|
||||||
|
<PackageReference Include="hasheous-client" Version="0.1.0" />
|
||||||
|
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.13" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.13" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.12" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.12" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
|
<PackageReference Include="sharpcompress" Version="0.35.0" />
|
||||||
|
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
|
||||||
<PackageReference Include="MySqlConnector" Version="2.3.1" />
|
<PackageReference Include="MySqlConnector" Version="2.3.1" />
|
||||||
@@ -49,60 +53,14 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1006.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1006.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1007.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1007.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1008.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1008.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1009.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1010.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1011.sql" />
|
||||||
|
<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\" />
|
<None Remove="Classes\Metadata\" />
|
||||||
<None Remove="Assets\" />
|
|
||||||
<None Remove="Assets\Ratings\" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\AO.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\E.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\E10plus.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\M.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\RP.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\RP-LM17-English.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ESRB\T.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_A.png" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_B.png" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_C.png" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_D.png" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_Z.png" />
|
|
||||||
<None Remove="Assets\Ratings\USK\" />
|
|
||||||
<None Remove="Assets\Ratings\USK\USK_0.svg" />
|
|
||||||
<None Remove="Assets\Ratings\USK\USK_12.svg" />
|
|
||||||
<None Remove="Assets\Ratings\USK\USK_16.svg" />
|
|
||||||
<None Remove="Assets\Ratings\USK\USK_18.svg" />
|
|
||||||
<None Remove="Assets\Ratings\USK\USK_6.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_G.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_M.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_MA15.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_PG.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_R18.svg" />
|
|
||||||
<None Remove="Assets\Ratings\ACB\ACB_RC.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_A.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_B.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_C.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_D.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CERO\CERO_Z.svg" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\Eighteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\Seven.svg" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\Sixteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\Three.svg" />
|
|
||||||
<None Remove="Assets\Ratings\PEGI\Twelve.svg" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\GRAC_All.svg" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\GRAC_Eighteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\GRAC_Fifteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\GRAC_Testing.svg" />
|
|
||||||
<None Remove="Assets\Ratings\GRAC\GRAC_Twelve.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_Eighteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_Fourteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_L.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_Sixteen.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_Ten.svg" />
|
|
||||||
<None Remove="Assets\Ratings\CLASS_IND\CLASS_IND_Twelve.svg" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Controllers\" />
|
<Folder Include="Controllers\" />
|
||||||
@@ -111,15 +69,6 @@
|
|||||||
<Folder Include="Classes\SignatureIngestors\" />
|
<Folder Include="Classes\SignatureIngestors\" />
|
||||||
<Folder Include="Support\" />
|
<Folder Include="Support\" />
|
||||||
<Folder Include="Classes\Metadata\" />
|
<Folder Include="Classes\Metadata\" />
|
||||||
<Folder Include="Assets\" />
|
|
||||||
<Folder Include="Assets\Ratings\" />
|
|
||||||
<Folder Include="Assets\Ratings\ESRB\" />
|
|
||||||
<Folder Include="Assets\Ratings\ACB\" />
|
|
||||||
<Folder Include="Assets\Ratings\PEGI\" />
|
|
||||||
<Folder Include="Assets\Ratings\CERO\" />
|
|
||||||
<Folder Include="Assets\Ratings\USK\" />
|
|
||||||
<Folder Include="Assets\Ratings\GRAC\" />
|
|
||||||
<Folder Include="Assets\Ratings\CLASS_IND\" />
|
|
||||||
<Folder Remove="Reference" />
|
<Folder Remove="Reference" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -132,45 +81,6 @@
|
|||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\AO.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\E.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\E10.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\M.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\RP.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\RP-LM17-English.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ESRB\T.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\USK\USK_0.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\USK\USK_12.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\USK\USK_16.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\USK\USK_18.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\USK\USK_6.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_G.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_M.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_MA15.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_PG.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_R18.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\ACB\ACB_RC.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CERO\CERO_A.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CERO\CERO_B.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CERO\CERO_C.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CERO\CERO_D.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CERO\CERO_Z.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\PEGI\Eighteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\PEGI\Seven.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\PEGI\Sixteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\PEGI\Three.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\PEGI\Twelve.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\GRAC\GRAC_All.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\GRAC\GRAC_Eighteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\GRAC\GRAC_Fifteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\GRAC\GRAC_Testing.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\GRAC\GRAC_Twelve.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_Eighteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_Fourteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_L.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_Sixteen.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_Ten.svg" />
|
|
||||||
<EmbeddedResource Include="Assets\Ratings\CLASS_IND\CLASS_IND_Twelve.svg" />
|
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1000.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1000.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1001.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1001.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
||||||
@@ -180,5 +90,12 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1006.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1006.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1007.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1007.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1008.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1008.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1009.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1010.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1011.sql" />
|
||||||
|
<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>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
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>
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |