Compare commits
39 Commits
v1.7.0
...
v1.7.4-pre
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8519d4c745 | ||
![]() |
822a40b61b | ||
![]() |
b463bb6064 | ||
![]() |
3e8696e6e8 | ||
![]() |
d1f157ac08 | ||
![]() |
30be179367 | ||
![]() |
787bb47bd3 | ||
![]() |
ccf9afd561 | ||
![]() |
c7b6233ad6 | ||
![]() |
afb72c3d74 | ||
![]() |
299e24793f | ||
![]() |
de9b9bf706 | ||
![]() |
28bc50a82e | ||
![]() |
f9f65f3ffb | ||
![]() |
87f3a1aa89 | ||
![]() |
b3e7696292 | ||
![]() |
29c685c791 | ||
![]() |
f0020e5b1f | ||
![]() |
3897ed65ef | ||
![]() |
cebab38dd6 | ||
![]() |
69da6ee346 | ||
![]() |
f85109abd2 | ||
![]() |
59173d8ae5 | ||
![]() |
178f70cb98 | ||
![]() |
080a823cda | ||
![]() |
60dbaf85a4 | ||
![]() |
8a80274030 | ||
![]() |
7e8679151b | ||
![]() |
123239cf58 | ||
![]() |
04419383aa | ||
![]() |
0bef298abf | ||
![]() |
a4d581b369 | ||
![]() |
16cb0c89dc | ||
![]() |
95b52c47dd | ||
![]() |
b1056299b8 | ||
![]() |
14c5761959 | ||
![]() |
d7b3711be6 | ||
![]() |
f2a58d23f0 | ||
![]() |
111c501911 |
@@ -9,9 +9,14 @@ on:
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Install dotnet tool
|
||||
@@ -21,18 +26,37 @@ jobs:
|
||||
- name: Sign in to Nuget
|
||||
run: dotnet nuget add source --username michael-j-green --password ${{ secrets.NUGETKEY }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/gaseous-project/index.json"
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
- name: Login to GitHub Package Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}
|
||||
- name: Build and push image with embedded mariadb
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile-EmbeddedDB
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
|
40
.github/workflows/BuildDockerOnTag-Release.yml
vendored
40
.github/workflows/BuildDockerOnTag-Release.yml
vendored
@@ -8,9 +8,14 @@ on:
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Install dotnet tool
|
||||
@@ -20,18 +25,39 @@ jobs:
|
||||
- name: Sign in to Nuget
|
||||
run: dotnet nuget add source --username michael-j-green --password ${{ secrets.NUGETKEY }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/gaseous-project/index.json"
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
- name: Login to GitHub Package Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: gaseousgames/gaseousserver:latest,gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:latest
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||
ghcr.io/gaseous-project/gaseousserver:latest
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}
|
||||
- name: Build and push image with embedded mariadb
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile-EmbeddedDB
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
|
@@ -8,21 +8,34 @@ RUN echo "Target: $TARGETARCH"
|
||||
RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY . ./
|
||||
COPY .. ./
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-server/gaseous-server.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# download and unzip EmulatorJS from CDN
|
||||
RUN apt-get update && apt-get install -y p7zip-full
|
||||
# disabled for 1.7.4 as the next version EmulatorJS is not yet available
|
||||
# # update apt-get
|
||||
# RUN apt-get update
|
||||
|
||||
# # download and unzip EmulatorJS from CDN
|
||||
# RUN apt-get install -y p7zip-full
|
||||
# RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
# RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
# RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
||||
RUN wget --recursive --no-parent https://cdn.emulatorjs.org/latest/
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.11.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.11.7z
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# Build runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
ENV INDOCKER=1
|
||||
WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
|
||||
# start gaseous-server
|
||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
61
build/Dockerfile-EmbeddedDB
Normal file
61
build/Dockerfile-EmbeddedDB
Normal file
@@ -0,0 +1,61 @@
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||
ARG TARGETARCH
|
||||
ARG BUILDPLATFORM
|
||||
WORKDIR /App
|
||||
EXPOSE 80
|
||||
|
||||
RUN echo "Target: $TARGETARCH"
|
||||
RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY .. ./
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-server/gaseous-server.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# disabled for 1.7.4 as the next version EmulatorJS is not yet available
|
||||
# # update apt-get
|
||||
# RUN apt-get update
|
||||
|
||||
# # download and unzip EmulatorJS from CDN
|
||||
# RUN apt-get install -y p7zip-full
|
||||
# RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
# RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
# RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
||||
RUN wget --recursive --no-parent https://cdn.emulatorjs.org/latest/
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
|
||||
# Build runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
ENV INDOCKER=1
|
||||
WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
|
||||
# variables
|
||||
ENV dbhost=localhost
|
||||
ENV dbuser=root
|
||||
ENV dbpass=gaseous
|
||||
ENV MARIADB_ROOT_PASSWORD=$dbpass
|
||||
|
||||
# install mariadb
|
||||
RUN DEBIAN_FRONTEND=noninteractive && \
|
||||
apt-get update && apt-get install -y mariadb-server
|
||||
RUN mkdir -p /run/mysqld
|
||||
COPY ../build/mariadb.sh /usr/sbin/start-mariadb.sh
|
||||
RUN chmod +x /usr/sbin/start-mariadb.sh
|
||||
|
||||
# install supervisord
|
||||
RUN apt-get install -y supervisor
|
||||
COPY ../build/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# volumes
|
||||
VOLUME /root/.gaseous-server /var/lib/mysql
|
||||
|
||||
# start services
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
9
build/mariadb.sh
Normal file
9
build/mariadb.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wait for the service to start
|
||||
while ! mysqladmin ping -h localhost --silent; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Set the root password
|
||||
mariadb -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD';"
|
31
build/supervisord.conf
Normal file
31
build/supervisord.conf
Normal file
@@ -0,0 +1,31 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel = INFO
|
||||
|
||||
[program:mariadb]
|
||||
command=/usr/sbin/mariadbd --user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:mariadb-setup]
|
||||
command=bash -c "/usr/sbin/start-mariadb.sh"
|
||||
autostart=true
|
||||
autorestart=false
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:gaseous-server]
|
||||
command=dotnet /App/gaseous-server.dll
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
@@ -19,7 +19,8 @@ namespace gaseous_server.Classes
|
||||
if (ObjectToCheck == null || ObjectToCheck == System.DBNull.Value)
|
||||
{
|
||||
return IfNullValue;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return ObjectToCheck;
|
||||
}
|
||||
@@ -43,11 +44,13 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
var xmlStream = File.OpenRead(FileName);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Hash File", "Generating MD5 hash for file: " + FileName);
|
||||
var md5 = MD5.Create();
|
||||
byte[] md5HashByte = md5.ComputeHash(xmlStream);
|
||||
string md5Hash = BitConverter.ToString(md5HashByte).Replace("-", "").ToLowerInvariant();
|
||||
_md5hash = md5Hash;
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Hash File", "Generating SHA1 hash for file: " + FileName);
|
||||
var sha1 = SHA1.Create();
|
||||
xmlStream.Position = 0;
|
||||
byte[] sha1HashByte = sha1.ComputeHash(xmlStream);
|
||||
|
@@ -196,6 +196,11 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
string SettingName = (string)dataRow["Setting"];
|
||||
|
||||
if (SettingName.StartsWith("LastRun_"))
|
||||
{
|
||||
Console.WriteLine("Break");
|
||||
}
|
||||
|
||||
if (AppSettings.ContainsKey(SettingName))
|
||||
{
|
||||
AppSettings.Remove(SettingName);
|
||||
@@ -204,6 +209,8 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
|
||||
try
|
||||
{
|
||||
if (Database.schema_version >= 1016)
|
||||
{
|
||||
switch ((int)dataRow["ValueType"])
|
||||
{
|
||||
@@ -219,6 +226,11 @@ namespace gaseous_server.Classes
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.Add(SettingName, dataRow["Value"]);
|
||||
}
|
||||
}
|
||||
catch (InvalidCastException castEx)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Settings", "Exception when reading server setting " + SettingName + ". Resetting to default.", castEx);
|
||||
@@ -249,17 +261,22 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
string sql = "SELECT Value, ValueDate FROM Settings WHERE Setting = @SettingName";
|
||||
string sql;
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "SettingName", SettingName }
|
||||
};
|
||||
DataTable dbResponse;
|
||||
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Reading setting '" + SettingName + "'");
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (Database.schema_version >= 1016)
|
||||
{
|
||||
sql = "SELECT Value, ValueDate FROM Settings WHERE Setting = @SettingName";
|
||||
|
||||
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
Type type = typeof(T);
|
||||
if (dbResponse.Rows.Count == 0)
|
||||
{
|
||||
@@ -271,12 +288,31 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
if (type.ToString() == "System.DateTime")
|
||||
{
|
||||
AppSettings.Add(SettingName, dbResponse.Rows[0]["ValueDate"]);
|
||||
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["ValueDate"]);
|
||||
return (T)dbResponse.Rows[0]["ValueDate"];
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.Add(SettingName, dbResponse.Rows[0]["Value"]);
|
||||
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["Value"]);
|
||||
return (T)dbResponse.Rows[0]["Value"];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "SELECT Value FROM Settings WHERE Setting = @SettingName";
|
||||
|
||||
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
Type type = typeof(T);
|
||||
if (dbResponse.Rows.Count == 0)
|
||||
{
|
||||
// no value with that name stored - respond with the default value
|
||||
SetSetting<T>(SettingName, DefaultValue);
|
||||
return DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["Value"]);
|
||||
return (T)dbResponse.Rows[0]["Value"];
|
||||
}
|
||||
}
|
||||
@@ -317,8 +353,12 @@ namespace gaseous_server.Classes
|
||||
public static void SetSetting<T>(string SettingName, T Value)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "REPLACE INTO Settings (Setting, ValueType, Value, ValueDate) VALUES (@SettingName, @ValueType, @Value, @ValueDate)";
|
||||
string sql;
|
||||
Dictionary<string, object> dbDict;
|
||||
|
||||
if (Database.schema_version >= 1016)
|
||||
{
|
||||
sql = "REPLACE INTO Settings (Setting, ValueType, Value, ValueDate) VALUES (@SettingName, @ValueType, @Value, @ValueDate)";
|
||||
Type type = typeof(T);
|
||||
if (type.ToString() == "System.DateTime")
|
||||
{
|
||||
@@ -340,6 +380,16 @@ namespace gaseous_server.Classes
|
||||
{ "ValueDate", null }
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "REPLACE INTO Settings (Setting, Value) VALUES (@SettingName, @Value)";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "SettingName", SettingName },
|
||||
{ "Value", Value }
|
||||
};
|
||||
}
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Storing setting '" + SettingName + "' to value: '" + Value + "'");
|
||||
try
|
||||
|
@@ -9,6 +9,21 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
public class Database
|
||||
{
|
||||
private static int _schema_version { get; set; } = 0;
|
||||
public static int schema_version
|
||||
{
|
||||
get
|
||||
{
|
||||
//Logging.Log(Logging.LogType.Information, "Database Schema", "Schema version is " + _schema_version);
|
||||
return _schema_version;
|
||||
}
|
||||
set
|
||||
{
|
||||
//Logging.Log(Logging.LogType.Information, "Database Schema", "Setting schema version " + _schema_version);
|
||||
_schema_version = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Database()
|
||||
{
|
||||
|
||||
@@ -78,7 +93,16 @@ namespace gaseous_server.Classes
|
||||
ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
for (int i = 1000; i < 10000; i++)
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||
if (OuterSchemaVer == 0)
|
||||
{
|
||||
OuterSchemaVer = 1000;
|
||||
}
|
||||
|
||||
for (int i = OuterSchemaVer; i < 10000; i++)
|
||||
{
|
||||
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
|
||||
string dbScript = "";
|
||||
@@ -94,7 +118,7 @@ namespace gaseous_server.Classes
|
||||
// apply script
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
if (SchemaVersion.Rows.Count == 0)
|
||||
{
|
||||
// something is broken here... where's the table?
|
||||
@@ -105,6 +129,8 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
int SchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
||||
// update schema version variable
|
||||
Database.schema_version = SchemaVer;
|
||||
if (SchemaVer < i)
|
||||
{
|
||||
try
|
||||
@@ -123,6 +149,9 @@ namespace gaseous_server.Classes
|
||||
|
||||
// run post-upgrade code
|
||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||
|
||||
// update schema version variable
|
||||
Database.schema_version = i;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -264,7 +264,12 @@ namespace gaseous_server.Classes
|
||||
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||
{
|
||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||
SignatureLookupItem? HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel{
|
||||
SignatureLookupItem? HasheousResult = null;
|
||||
|
||||
try
|
||||
{
|
||||
HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel
|
||||
{
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
});
|
||||
@@ -296,6 +301,11 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ namespace gaseous_server.Classes
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
|
||||
// remove any entries from the library that have an invalid id
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing any entries from the library that have an invalid id");
|
||||
string LibraryWhereClause = "";
|
||||
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||
{
|
||||
@@ -33,9 +34,27 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
// delete old logs
|
||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate;";
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing logs older than " + Config.LoggingConfiguration.LogRetention + " days");
|
||||
long deletedCount = 1;
|
||||
long deletedEventCount = 0;
|
||||
long maxLoops = 1000;
|
||||
while (deletedCount > 0)
|
||||
{
|
||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate LIMIT 1000; SELECT ROW_COUNT() AS Count;";
|
||||
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
DataTable deletedCountTable = db.ExecuteCMD(sql, dbDict);
|
||||
deletedCount = (long)deletedCountTable.Rows[0][0];
|
||||
deletedEventCount += deletedCount;
|
||||
|
||||
// check if we've hit the limit
|
||||
maxLoops -= 1;
|
||||
if (maxLoops <= 0)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Maintenance", "Hit the maximum number of loops for deleting logs. Stopping.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Deleted " + deletedEventCount + " log entries");
|
||||
|
||||
// delete files and directories older than 7 days in PathsToClean
|
||||
List<string> PathsToClean = new List<string>();
|
||||
@@ -87,7 +106,7 @@ namespace gaseous_server.Classes
|
||||
SetStatus(StatusCounter, tables.Rows.Count, "Optimising table " + row[0].ToString());
|
||||
|
||||
sql = "OPTIMIZE TABLE " + row[0].ToString();
|
||||
DataTable response = db.ExecuteCMD(sql);
|
||||
DataTable response = db.ExecuteCMD(sql, new Dictionary<string, object>(), 240);
|
||||
foreach (DataRow responseRow in response.Rows)
|
||||
{
|
||||
string retVal = "";
|
||||
|
@@ -125,17 +125,17 @@ namespace gaseous_server.Classes.Metadata
|
||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
{
|
||||
// required metadata
|
||||
if (Game.Cover != null)
|
||||
{
|
||||
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.Cover != null)
|
||||
// {
|
||||
// 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)
|
||||
{
|
||||
@@ -439,7 +439,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
Game game = new Game{
|
||||
Game game = new Game
|
||||
{
|
||||
Id = (long)row["Id"],
|
||||
Name = (string)Common.ReturnValueIfNull(row["Name"], ""),
|
||||
Slug = (string)Common.ReturnValueIfNull(row["Slug"], ""),
|
||||
@@ -561,6 +562,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
|
||||
public long? Id { get; set; }
|
||||
public long Index { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public double? TotalRating { get; set; }
|
||||
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
}
|
||||
|
||||
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform)
|
||||
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform, bool GetImages = false)
|
||||
{
|
||||
if (Id == 0)
|
||||
{
|
||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform);
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform)
|
||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages)
|
||||
{
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform);
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<PlatformVersion> _GetPlatformVersion(SearchUsing searchUsing, object searchValue, Platform ParentPlatform)
|
||||
private static async Task<PlatformVersion> _GetPlatformVersion(SearchUsing searchUsing, object searchValue, Platform ParentPlatform, bool GetImages)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
@@ -67,7 +67,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
if (returnValue != null)
|
||||
{
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(ParentPlatform, returnValue);
|
||||
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||
}
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
@@ -75,7 +75,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(ParentPlatform, returnValue);
|
||||
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -90,7 +90,9 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion)
|
||||
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion, bool GetImages)
|
||||
{
|
||||
if (GetImages == true)
|
||||
{
|
||||
if (platformVersion.PlatformLogo != null)
|
||||
{
|
||||
@@ -104,6 +106,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
|
@@ -15,7 +15,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
}
|
||||
|
||||
public static Platform? GetPlatform(long Id, bool forceRefresh = false)
|
||||
public static Platform? GetPlatform(long Id, bool forceRefresh = false, bool GetImages = false)
|
||||
{
|
||||
if (Id == 0)
|
||||
{
|
||||
@@ -41,7 +41,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
try
|
||||
{
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh);
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -52,13 +52,13 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
public static Platform GetPlatform(string Slug, bool forceRefresh = false)
|
||||
public static Platform GetPlatform(string Slug, bool forceRefresh = false, bool GetImages = false)
|
||||
{
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.slug, Slug, forceRefresh);
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.slug, Slug, forceRefresh, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Platform> _GetPlatform(SearchUsing searchUsing, object searchValue, bool forceRefresh)
|
||||
private static async Task<Platform> _GetPlatform(SearchUsing searchUsing, object searchValue, bool forceRefresh, bool GetImages)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
@@ -96,7 +96,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue);
|
||||
UpdateSubClasses(returnValue, GetImages);
|
||||
AddPlatformMapping(returnValue);
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
@@ -104,7 +104,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(returnValue);
|
||||
UpdateSubClasses(returnValue, GetImages);
|
||||
AddPlatformMapping(returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Platform platform)
|
||||
private static void UpdateSubClasses(Platform platform, bool GetImages)
|
||||
{
|
||||
if (platform.Versions != null)
|
||||
{
|
||||
@@ -130,6 +130,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
if (GetImages == true)
|
||||
{
|
||||
if (platform.PlatformLogo != null)
|
||||
{
|
||||
try
|
||||
@@ -142,6 +144,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddPlatformMapping(Platform platform)
|
||||
{
|
||||
@@ -158,7 +161,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Platform Map", "Importing " + platform.Name + " from predefined data.");
|
||||
// doesn't exist - add it
|
||||
item = new Models.PlatformMapping.PlatformMapItem{
|
||||
item = new Models.PlatformMapping.PlatformMapItem
|
||||
{
|
||||
IGDBId = (long)platform.Id,
|
||||
IGDBName = platform.Name,
|
||||
IGDBSlug = platform.Slug,
|
||||
|
@@ -428,6 +428,30 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateRelationsTables<T>()
|
||||
{
|
||||
string PrimaryTable = typeof(T).Name;
|
||||
foreach (PropertyInfo property in typeof(T).GetProperties())
|
||||
{
|
||||
string SecondaryTable = property.Name;
|
||||
|
||||
if (property.PropertyType.Name == "IdentitiesOrValues`1")
|
||||
{
|
||||
|
||||
string TableName = "Relation_" + PrimaryTable + "_" + SecondaryTable;
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM information_schema.tables WHERE table_schema = '" + Config.DatabaseConfiguration.DatabaseName + "' AND table_name = '" + TableName + "';";
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
// table doesn't exist, create it
|
||||
sql = "CREATE TABLE `" + Config.DatabaseConfiguration.DatabaseName + "`.`" + TableName + "` (`" + PrimaryTable + "Id` BIGINT NOT NULL, `" + SecondaryTable + "Id` BIGINT NOT NULL, PRIMARY KEY (`" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`), INDEX `idx_PrimaryColumn` (`" + PrimaryTable + "Id` ASC) VISIBLE);";
|
||||
db.ExecuteCMD(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MemoryCacheObject
|
||||
{
|
||||
public object Object { get; set; }
|
||||
|
@@ -5,6 +5,9 @@ using Microsoft.VisualBasic;
|
||||
using IGDB.Models;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using System.IO.Compression;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -259,6 +262,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false);
|
||||
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false);
|
||||
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(mediaGroupItem.PlatformId);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name);
|
||||
|
||||
@@ -293,10 +297,124 @@ namespace gaseous_server.Classes
|
||||
foreach (long RomId in mediaGroupItem.RomIds)
|
||||
{
|
||||
Roms.GameRomItem rom = Roms.GetRom(RomId);
|
||||
bool fileNameFound = false;
|
||||
if (File.Exists(rom.Path))
|
||||
{
|
||||
string romExt = Path.GetExtension(rom.Path);
|
||||
if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
|
||||
|
||||
// is compressed
|
||||
switch (romExt)
|
||||
{
|
||||
case ".zip":
|
||||
try
|
||||
{
|
||||
using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(rom.Path))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||
if (fileNameFound == false)
|
||||
{
|
||||
//check if extension is in valid extensions
|
||||
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
// update rom file name
|
||||
rom.Name = entry.Key;
|
||||
fileNameFound = true;
|
||||
}
|
||||
}
|
||||
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception zipEx)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Media Group", "Unzip error", zipEx);
|
||||
throw;
|
||||
}
|
||||
break;
|
||||
|
||||
case ".rar":
|
||||
try
|
||||
{
|
||||
using (var archive = SharpCompress.Archives.Rar.RarArchive.Open(rom.Path))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||
if (fileNameFound == false)
|
||||
{
|
||||
//check if extension is in valid extensions
|
||||
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
// update rom file name
|
||||
rom.Name = entry.Key;
|
||||
fileNameFound = true;
|
||||
}
|
||||
}
|
||||
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception zipEx)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Media Group", "Unrar error", zipEx);
|
||||
throw;
|
||||
}
|
||||
break;
|
||||
|
||||
case ".7z":
|
||||
try
|
||||
{
|
||||
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(rom.Path))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||
if (fileNameFound == false)
|
||||
{
|
||||
//check if extension is in valid extensions
|
||||
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
// update rom file name
|
||||
rom.Name = entry.Key;
|
||||
fileNameFound = true;
|
||||
}
|
||||
}
|
||||
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception zipEx)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Media Group", "7z error", zipEx);
|
||||
throw;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// is uncompressed
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name);
|
||||
File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path)));
|
||||
}
|
||||
|
||||
romItems.Add(rom);
|
||||
}
|
||||
|
@@ -15,6 +15,12 @@ namespace gaseous_server.Classes
|
||||
{ }
|
||||
}
|
||||
|
||||
public class InvalidRomHash : Exception
|
||||
{
|
||||
public InvalidRomHash(String Hash) : base("Unable to find ROM by hash " + Hash)
|
||||
{ }
|
||||
}
|
||||
|
||||
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
||||
{
|
||||
GameRomObject GameRoms = new GameRomObject();
|
||||
@@ -37,13 +43,16 @@ namespace gaseous_server.Classes
|
||||
// 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)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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;";
|
||||
|
||||
@@ -100,6 +109,26 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static GameRomItem GetRom(string MD5)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.MD5 = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", MD5);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
DataRow romDR = romDT.Rows[0];
|
||||
GameRomItem romItem = BuildRom(romDR);
|
||||
return romItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidRomHash(MD5);
|
||||
}
|
||||
}
|
||||
|
||||
public static GameRomItem UpdateRom(long RomId, long PlatformId, long GameId)
|
||||
{
|
||||
// ensure metadata for platformid is present
|
||||
|
@@ -43,7 +43,7 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
public ActionResult Game(
|
||||
public async Task<ActionResult> Game(
|
||||
string name = "",
|
||||
string platform = "",
|
||||
string genre = "",
|
||||
@@ -303,7 +303,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "5Minute")]
|
||||
public ActionResult Game(long GameId)
|
||||
public async Task<ActionResult> Game(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -331,7 +331,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<AlternativeName>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameAlternativeNames(long GameId)
|
||||
public async Task<ActionResult> GameAlternativeNames(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -364,7 +364,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<AgeRatings.GameAgeRating>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameAgeClassification(long GameId)
|
||||
public async Task<ActionResult> GameAgeClassification(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -397,7 +397,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<Artwork>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameArtwork(long GameId)
|
||||
public async Task<ActionResult> GameArtwork(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -428,7 +428,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Artwork), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameArtwork(long GameId, long ArtworkId)
|
||||
public async Task<ActionResult> GameArtwork(long GameId, long ArtworkId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -464,7 +464,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
||||
public async Task<ActionResult> GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -531,7 +531,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Cover), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameCover(long GameId)
|
||||
public async Task<ActionResult> GameCover(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -566,7 +566,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||
public async Task<ActionResult> GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -693,7 +693,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<Genre>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameGenre(long GameId)
|
||||
public async Task<ActionResult> GameGenre(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -731,7 +731,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<Dictionary<string, object>>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameInvolvedCompanies(long GameId)
|
||||
public async Task<ActionResult> GameInvolvedCompanies(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -776,7 +776,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameInvolvedCompanies(long GameId, long CompanyId)
|
||||
public async Task<ActionResult> GameInvolvedCompanies(long GameId, long CompanyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -818,7 +818,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/companies/{CompanyId}/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameCompanyImage(long GameId, long CompanyId)
|
||||
public async Task<ActionResult> GameCompanyImage(long GameId, long CompanyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -863,7 +863,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/platforms")]
|
||||
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GamePlatforms(long GameId)
|
||||
public async Task<ActionResult> GamePlatforms(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -882,7 +882,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<ReleaseDate>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameReleaseDates(long GameId)
|
||||
public async Task<ActionResult> GameReleaseDates(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -943,7 +943,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||
public ActionResult GameRom(long GameId, long RomId)
|
||||
public async Task<ActionResult> GameRom(long GameId, long RomId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -972,7 +972,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/roms/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
|
||||
public async Task<ActionResult> GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1002,7 +1002,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/roms/{RomId}")]
|
||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomDelete(long GameId, long RomId)
|
||||
public async Task<ActionResult> GameRomDelete(long GameId, long RomId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1034,7 +1034,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/roms/{RomId}/file")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomFile(long GameId, long RomId)
|
||||
public async Task<ActionResult> GameRomFile(long GameId, long RomId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1073,7 +1073,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/roms/{RomId}/{FileName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomFile(long GameId, long RomId, string FileName)
|
||||
public async Task<ActionResult> GameRomFile(long GameId, long RomId, string FileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1172,7 +1172,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/romgroup")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
|
||||
public async Task<ActionResult> NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1233,7 +1233,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/romgroup/{RomGroupId}")]
|
||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomGroupDelete(long GameId, long RomGroupId)
|
||||
public async Task<ActionResult> GameRomGroupDelete(long GameId, long RomGroupId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1266,7 +1266,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/romgroup/{RomGroupId}/{filename}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
|
||||
public async Task<ActionResult> GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1311,7 +1311,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("search")]
|
||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameSearch(long RomId = 0, string SearchString = "")
|
||||
public async Task<ActionResult> GameSearch(long RomId = 0, string SearchString = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1352,7 +1352,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<Screenshot>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameScreenshot(long GameId)
|
||||
public async Task<ActionResult> GameScreenshot(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1383,7 +1383,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(Screenshot), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameScreenshot(long GameId, long ScreenshotId)
|
||||
public async Task<ActionResult> GameScreenshot(long GameId, long ScreenshotId)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1417,7 +1417,7 @@ namespace gaseous_server.Controllers
|
||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||
public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1468,7 +1468,7 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(typeof(List<GameVideo>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "7Days")]
|
||||
public ActionResult GameVideo(long GameId)
|
||||
public async Task<ActionResult> GameVideo(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@@ -73,9 +73,11 @@ namespace gaseous_server.Controllers
|
||||
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||
{
|
||||
string searchBody = "";
|
||||
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||
// string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||
string searchFields = "fields *; ";
|
||||
searchBody += "search \"" + SearchString + "\";";
|
||||
searchBody += "where platforms = (" + PlatformId + ");";
|
||||
searchBody += "limit 100;";
|
||||
|
||||
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
||||
|
||||
|
@@ -70,7 +70,8 @@ namespace gaseous_server.Controllers
|
||||
[HttpGet]
|
||||
[Route("Version")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Version GetSystemVersion() {
|
||||
public Version GetSystemVersion()
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||
}
|
||||
|
||||
@@ -80,7 +81,8 @@ namespace gaseous_server.Controllers
|
||||
[Route("VersionFile")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public FileContentResult GetSystemVersionAsFile() {
|
||||
public FileContentResult GetSystemVersionAsFile()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// get age ratings dictionary
|
||||
@@ -98,14 +100,17 @@ namespace gaseous_server.Controllers
|
||||
|
||||
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
||||
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
||||
"var FirstRunStatus = " + Config.ReadSetting<string>("FirstRunStatus", "0") + ";" + Environment.NewLine +
|
||||
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions{
|
||||
"var FirstRunStatus = \"" + Config.ReadSetting<string>("FirstRunStatus", "0") + "\";" + Environment.NewLine +
|
||||
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
}) + ";" + Environment.NewLine +
|
||||
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions{
|
||||
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
}) + ";" + Environment.NewLine +
|
||||
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions{
|
||||
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
}) + ";" + Environment.NewLine +
|
||||
"var emulatorDebugMode = " + Config.ReadSetting<string>("emulatorDebugMode", false.ToString()).ToLower() + ";";
|
||||
@@ -251,7 +256,8 @@ namespace gaseous_server.Controllers
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ActionResult GetSystemSettings()
|
||||
{
|
||||
SystemSettingsModel systemSettingsModel = new SystemSettingsModel{
|
||||
SystemSettingsModel systemSettingsModel = new SystemSettingsModel
|
||||
{
|
||||
AlwaysLogToDisk = Config.LoggingConfiguration.AlwaysLogToDisk,
|
||||
MinimumLogRetentionPeriod = Config.LoggingConfiguration.LogRetention,
|
||||
EmulatorDebugMode = Boolean.Parse(Config.ReadSetting<string>("emulatorDebugMode", false.ToString()))
|
||||
@@ -281,7 +287,8 @@ namespace gaseous_server.Controllers
|
||||
|
||||
private SystemInfo.PathItem GetDisk(string Path)
|
||||
{
|
||||
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
|
||||
SystemInfo.PathItem pathItem = new SystemInfo.PathItem
|
||||
{
|
||||
LibraryPath = Path,
|
||||
SpaceUsed = Common.DirSize(new DirectoryInfo(Path)),
|
||||
SpaceAvailable = new DriveInfo(Path).AvailableFreeSpace,
|
||||
@@ -293,7 +300,8 @@ namespace gaseous_server.Controllers
|
||||
|
||||
public class SystemInfo
|
||||
{
|
||||
public Version ApplicationVersion {
|
||||
public Version ApplicationVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||
@@ -589,7 +597,8 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
private bool _UserManageable;
|
||||
public bool UserManageable => _UserManageable;
|
||||
public int Interval {
|
||||
public int Interval
|
||||
{
|
||||
get
|
||||
{
|
||||
return int.Parse(Config.ReadSetting<string>("Interval_" + Task, DefaultInterval.ToString()));
|
||||
|
@@ -479,6 +479,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string sql = @"
|
||||
SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
|
||||
SELECT DISTINCT
|
||||
Game.Id,
|
||||
Game.`Name`,
|
||||
@@ -569,6 +570,7 @@ FROM
|
||||
|
||||
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
||||
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||
retMinGame.Index = i;
|
||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||
{
|
||||
retMinGame.HasSavedGame = true;
|
||||
@@ -591,25 +593,31 @@ FROM
|
||||
|
||||
// build alpha list
|
||||
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||
int CurrentPage = 0;
|
||||
int NextPageIndex = 0;
|
||||
int CurrentPage = 1;
|
||||
int NextPageIndex = pageSize;
|
||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||
{
|
||||
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
|
||||
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||
{
|
||||
firstChar = "#";
|
||||
if (!AlphaList.ContainsKey("#"))
|
||||
{
|
||||
AlphaList.Add("#", 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AlphaList.ContainsKey(firstChar))
|
||||
{
|
||||
AlphaList.Add(firstChar, CurrentPage);
|
||||
}
|
||||
if (NextPageIndex == i)
|
||||
if (NextPageIndex == i + 1)
|
||||
{
|
||||
NextPageIndex += pageSize;
|
||||
CurrentPage += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameReturnPackage gameReturn = new GameReturnPackage
|
||||
{
|
||||
|
@@ -6,6 +6,7 @@ using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.Data;
|
||||
using Asp.Versioning;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
@@ -233,11 +234,11 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[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)
|
||||
public async Task<ActionResult> GetStateDataAsync(long RomId, long StateId, bool IsMediaGroup = false, bool StateOnly = false)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Zipped, State FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
string sql = "SELECT * FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", StateId },
|
||||
@@ -254,7 +255,9 @@ namespace gaseous_server.Controllers.v1_1
|
||||
}
|
||||
else
|
||||
{
|
||||
string filename = "savestate.state";
|
||||
// get rom data
|
||||
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||
|
||||
byte[] bytes;
|
||||
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||
{
|
||||
@@ -264,7 +267,86 @@ namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
||||
}
|
||||
string contentType = "application/octet-stream";
|
||||
|
||||
string contentType = "";
|
||||
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romItem.Name);
|
||||
|
||||
|
||||
if (StateOnly == true)
|
||||
{
|
||||
contentType = "application/octet-stream";
|
||||
filename = filename + ".state";
|
||||
}
|
||||
else
|
||||
{
|
||||
contentType = "application/zip";
|
||||
filename = filename + ".zip";
|
||||
|
||||
Dictionary<string, object> RomInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", romItem.Name },
|
||||
{ "StateDateTime", data.Rows[0]["StateDateTime"] },
|
||||
{ "StateName", data.Rows[0]["Name"] }
|
||||
};
|
||||
if ((int)data.Rows[0]["IsMediaGroup"] == 0)
|
||||
{
|
||||
RomInfo.Add("MD5", romItem.Md5);
|
||||
RomInfo.Add("SHA1", romItem.Sha1);
|
||||
RomInfo.Add("Type", "ROM");
|
||||
}
|
||||
else
|
||||
{
|
||||
RomInfo.Add("Type", "Media Group");
|
||||
RomInfo.Add("MediaGroupId", (long)data.Rows[0]["RomId"]);
|
||||
}
|
||||
string RomInfoString = Newtonsoft.Json.JsonConvert.SerializeObject(RomInfo, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore });
|
||||
|
||||
// compile zip file
|
||||
using (var compressedFileStream = new MemoryStream())
|
||||
{
|
||||
List<Dictionary<string, object>> Attachments = new List<Dictionary<string, object>>();
|
||||
Attachments.Add(new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", "savestate.state" },
|
||||
{ "Body", bytes }
|
||||
});
|
||||
// check if value is dbnull
|
||||
if (data.Rows[0]["Screenshot"] != DBNull.Value)
|
||||
{
|
||||
Attachments.Add(new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", "screenshot.jpg" },
|
||||
{ "Body", (byte[])data.Rows[0]["Screenshot"] }
|
||||
});
|
||||
}
|
||||
Attachments.Add(new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", "rominfo.json" },
|
||||
{ "Body", System.Text.Encoding.UTF8.GetBytes(RomInfoString) }
|
||||
});
|
||||
|
||||
//Create an archive and store the stream in memory.
|
||||
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, false))
|
||||
{
|
||||
foreach (var Attachment in Attachments)
|
||||
{
|
||||
//Create a zip entry for each attachment
|
||||
var zipEntry = zipArchive.CreateEntry(Attachment["Name"].ToString());
|
||||
|
||||
//Get the stream of the attachment
|
||||
using (var originalFileStream = new MemoryStream((byte[])Attachment["Body"]))
|
||||
using (var zipEntryStream = zipEntry.Open())
|
||||
{
|
||||
//Copy the attachment stream to the zip entry stream
|
||||
originalFileStream.CopyTo(zipEntryStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = filename };
|
||||
bytes = compressedFileStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
@@ -279,6 +361,156 @@ namespace gaseous_server.Controllers.v1_1
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[Consumes("multipart/form-data")]
|
||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||
[Route("Upload")]
|
||||
public async Task<ActionResult> UploadStateDataAsync(IFormFile file, long RomId = 0, bool IsMediaGroup = false)
|
||||
{
|
||||
// get user
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (file.Length > 0)
|
||||
{
|
||||
MemoryStream fileContent = new MemoryStream();
|
||||
file.CopyTo(fileContent);
|
||||
|
||||
// test if file is a zip file
|
||||
try
|
||||
{
|
||||
using (var zipArchive = new ZipArchive(fileContent, ZipArchiveMode.Read, false))
|
||||
{
|
||||
foreach (var entry in zipArchive.Entries)
|
||||
{
|
||||
if (entry.FullName == "rominfo.json")
|
||||
{
|
||||
using (var stream = entry.Open())
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
string RomInfoString = reader.ReadToEnd();
|
||||
Dictionary<string, object> RomInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(RomInfoString);
|
||||
|
||||
// get rom data
|
||||
Roms.GameRomItem romItem;
|
||||
|
||||
try
|
||||
{
|
||||
romItem = Roms.GetRom((string)RomInfo["MD5"]);
|
||||
}
|
||||
catch (Roms.InvalidRomHash)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
// get state data
|
||||
byte[] StateData = null;
|
||||
byte[] ScreenshotData = null;
|
||||
string StateName = RomInfo["StateName"].ToString();
|
||||
DateTime StateDateTime = DateTime.Parse(RomInfo["StateDateTime"].ToString());
|
||||
IsMediaGroup = RomInfo["Type"].ToString() == "Media Group" ? true : false;
|
||||
|
||||
if (zipArchive.GetEntry("savestate.state") != null)
|
||||
{
|
||||
using (var stateStream = zipArchive.GetEntry("savestate.state").Open())
|
||||
using (var stateReader = new MemoryStream())
|
||||
{
|
||||
stateStream.CopyTo(stateReader);
|
||||
StateData = stateReader.ToArray();
|
||||
}
|
||||
}
|
||||
if (zipArchive.GetEntry("screenshot.jpg") != null)
|
||||
{
|
||||
using (var screenshotStream = zipArchive.GetEntry("screenshot.jpg").Open())
|
||||
using (var screenshotReader = new MemoryStream())
|
||||
{
|
||||
screenshotStream.CopyTo(screenshotReader);
|
||||
ScreenshotData = screenshotReader.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
// save state
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State, Zipped) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state, @zipped); SELECT LAST_INSERT_ID();";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", user.Id },
|
||||
{ "romid", romItem.Id },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "statedatetime", StateDateTime },
|
||||
{ "name", StateName },
|
||||
{ "screenshot", ScreenshotData },
|
||||
{ "state", Common.Compress(StateData) },
|
||||
{ "zipped", true }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
RomInfo.Add("RomId", romItem.Id);
|
||||
RomInfo.Add("Management", "Managed");
|
||||
return Ok(RomInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BadRequest("File is not a valid Gaseous state file.");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// not a zip file
|
||||
if (RomId != 0)
|
||||
{
|
||||
// get rom data
|
||||
Roms.GameRomItem romItem;
|
||||
|
||||
try
|
||||
{
|
||||
romItem = Roms.GetRom(RomId);
|
||||
}
|
||||
catch (Roms.InvalidRomHash)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
// save state
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State, Zipped) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state, @zipped); SELECT LAST_INSERT_ID();";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", user.Id },
|
||||
{ "romid", RomId },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "statedatetime", DateTime.UtcNow },
|
||||
{ "name", "" },
|
||||
{ "screenshot", null },
|
||||
{ "state", Common.Compress(fileContent.ToArray()) },
|
||||
{ "zipped", true }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return Ok(new Dictionary<string, object>
|
||||
{
|
||||
{ "RomId", RomId },
|
||||
{ "Management", "Unmanaged" }
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest("No rom id provided.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest("File is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
private Models.GameStateItem BuildGameStateItem(DataRow dr)
|
||||
{
|
||||
bool HasScreenshot = true;
|
||||
|
@@ -39,7 +39,11 @@ namespace gaseous_server.Models
|
||||
{
|
||||
if (this.Cover.Id != null)
|
||||
{
|
||||
IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
||||
// IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
||||
IGDB.Models.Cover cover = new IGDB.Models.Cover()
|
||||
{
|
||||
Id = this.Cover.Id
|
||||
};
|
||||
|
||||
return cover;
|
||||
}
|
||||
|
@@ -27,7 +27,8 @@ namespace gaseous_server.Models
|
||||
{
|
||||
string rawJson = reader.ReadToEnd();
|
||||
List<PlatformMapItem> platforms = new List<PlatformMapItem>();
|
||||
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings{
|
||||
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
MaxDepth = 64
|
||||
};
|
||||
platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson, jsonSerializerSettings);
|
||||
@@ -74,7 +75,7 @@ namespace gaseous_server.Models
|
||||
foreach (PlatformMapItem mapItem in platforms)
|
||||
{
|
||||
// get the IGDB platform data
|
||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId);
|
||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId, false);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -286,7 +287,7 @@ namespace gaseous_server.Models
|
||||
string sql = "";
|
||||
|
||||
// get platform data
|
||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId);
|
||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId, false);
|
||||
|
||||
if (platform != null)
|
||||
{
|
||||
@@ -369,12 +370,14 @@ namespace gaseous_server.Models
|
||||
mapItem.IGDBName = platform.Name;
|
||||
mapItem.IGDBSlug = platform.Slug;
|
||||
mapItem.AlternateNames = alternateNames;
|
||||
mapItem.Extensions = new PlatformMapItem.FileExtensions{
|
||||
mapItem.Extensions = new PlatformMapItem.FileExtensions
|
||||
{
|
||||
SupportedFileExtensions = knownExtensions,
|
||||
UniqueFileExtensions = uniqueExtensions
|
||||
};
|
||||
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
||||
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem{
|
||||
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"], "[]"))
|
||||
|
@@ -36,12 +36,19 @@ db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.Conn
|
||||
|
||||
// set up db
|
||||
db.InitDB();
|
||||
// create relation tables if they don't exist
|
||||
Storage.CreateRelationsTables<IGDB.Models.Game>();
|
||||
Storage.CreateRelationsTables<IGDB.Models.Platform>();
|
||||
|
||||
// populate db with static data for lookups
|
||||
AgeRatings.PopulateAgeMap();
|
||||
|
||||
// load app settings
|
||||
Config.InitSettings();
|
||||
|
||||
// disable hasheous
|
||||
Config.MetadataConfiguration.SignatureSource = HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly;
|
||||
|
||||
// write updated settings back to the config file
|
||||
Config.UpdateConfig();
|
||||
|
||||
|
@@ -1232,6 +1232,9 @@
|
||||
"alternateCoreName": "melonds",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"core": "desmume"
|
||||
},
|
||||
{
|
||||
"core": "desmume2015"
|
||||
}
|
||||
@@ -1590,18 +1593,21 @@
|
||||
"retroPieDirectoryName": "mastersystem",
|
||||
"webEmulator": {
|
||||
"type": "EmulatorJS",
|
||||
"core": "picodrive",
|
||||
"core": "smsplus",
|
||||
"availableWebEmulators": [
|
||||
{
|
||||
"emulatorType": "EmulatorJS",
|
||||
"availableWebEmulatorCores": [
|
||||
{
|
||||
"core": "picodrive",
|
||||
"core": "segaMS",
|
||||
"alternateCoreName": "smsplus",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"core": "segaMS",
|
||||
"alternateCoreName": "genesis_plus_gx"
|
||||
"core": "picodrive"
|
||||
},
|
||||
{
|
||||
"core": "genesis_plus_gx"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.0.0" />
|
||||
<PackageReference Include="gaseous-signature-parser" Version="2.1.0" />
|
||||
<PackageReference Include="gaseous.IGDB" Version="1.0.2" />
|
||||
<PackageReference Include="hasheous-client" Version="0.2.0" />
|
||||
<PackageReference Include="hasheous-client" Version="0.1.0" />
|
||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.36.0" />
|
||||
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
|
||||
|
@@ -40,6 +40,11 @@
|
||||
|
||||
EJS_threads = false;
|
||||
|
||||
EJS_Buttons = {
|
||||
saveSavFiles: false,
|
||||
loadSavFiles: false
|
||||
}
|
||||
|
||||
EJS_onSaveState = function(e) {
|
||||
var returnValue = {
|
||||
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
@@ -44,6 +45,7 @@
|
||||
var userProfile;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Notifications -->
|
||||
<div id="notifications_target"></div>
|
||||
@@ -54,7 +56,9 @@
|
||||
<div id="banner_header">
|
||||
<div id="bannerButtons">
|
||||
<div id="banner_user" onclick="showMenu();" class="banner_button dropdown dropbtn">
|
||||
<img src="/images/user.svg" alt="Account" title="Account" id="banner_user_image" class="banner_button_image" style="position: relative; top: 10px; right: 0px; pointer-events: none;" onclick="showMenu();" />
|
||||
<img src="/images/user.svg" alt="Account" title="Account" id="banner_user_image"
|
||||
class="banner_button_image" style="position: relative; top: 10px; right: 0px; pointer-events: none;"
|
||||
onclick="showMenu();" />
|
||||
<div id="myDropdown" class="dropdown-content">
|
||||
<div id="banner_user_roles"></div>
|
||||
<a href="#" onclick="showDialog('userprofile');">Profile</a>
|
||||
@@ -63,22 +67,27 @@
|
||||
</div>
|
||||
|
||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';" class="banner_button">
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" class="banner_button_image" />
|
||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image"
|
||||
class="banner_button_image" />
|
||||
<span id="banner_system_label">Settings</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_upload" onclick="showDialog('upload');" class="banner_button">
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image" class="banner_button_image" />
|
||||
<img src="/images/upload.svg" alt="Upload" title="Upload" id="banner_upload_image"
|
||||
class="banner_button_image" />
|
||||
<span id="banner_upload_label">Upload</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_collections" onclick="window.location.href = '/index.html?page=collections';" class="banner_button">
|
||||
<img src="/images/collections.svg" alt="Collections" title="Collections" id="banner_collections_image" class="banner_button_image" />
|
||||
<div id="banner_collections" onclick="window.location.href = '/index.html?page=collections';"
|
||||
class="banner_button">
|
||||
<img src="/images/collections.svg" alt="Collections" title="Collections" id="banner_collections_image"
|
||||
class="banner_button_image" />
|
||||
<span id="banner_collections_label">Collections</span>
|
||||
</div>
|
||||
|
||||
<div id="banner_library" onclick="window.location.href = '/index.html';" class="banner_button">
|
||||
<img src="/images/library.svg" alt="Library" title="Library" id="banner_library_image" class="banner_button_image" />
|
||||
<img src="/images/library.svg" alt="Library" title="Library" id="banner_library_image"
|
||||
class="banner_button_image" />
|
||||
<span id="banner_library_label">Library</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,7 +106,9 @@
|
||||
<!-- Modal content -->
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<div><h1 id="modal-heading">Modal heading</h1></div>
|
||||
<div>
|
||||
<h1 id="modal-heading">Modal heading</h1>
|
||||
</div>
|
||||
<div id="modal-content">Some text in the Modal..</div>
|
||||
</div>
|
||||
|
||||
@@ -118,7 +129,7 @@
|
||||
var modalVariables = null;
|
||||
|
||||
// redirect if first run status = 0
|
||||
if (FirstRunStatus == 0) {
|
||||
if (FirstRunStatus == 0 || FirstRunStatus == "0") {
|
||||
window.location.replace("/pages/first.html");
|
||||
}
|
||||
|
||||
@@ -186,4 +197,5 @@
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -1,6 +1,9 @@
|
||||
<div id="saved_states">
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<span>Upload state file: </span><input type="file" id="stateFile" />
|
||||
</div>
|
||||
|
||||
<script text="text/javascript">
|
||||
document.getElementById('modal-heading').innerHTML = "Load saved state";
|
||||
@@ -16,6 +19,7 @@
|
||||
function (result) {
|
||||
var statesBox = document.getElementById('saved_states');
|
||||
statesBox.innerHTML = '';
|
||||
document.getElementById('stateFile').value = '';
|
||||
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var stateBox = document.createElement('div');
|
||||
@@ -156,4 +160,36 @@
|
||||
JSON.stringify(model)
|
||||
);
|
||||
}
|
||||
|
||||
document.getElementById('stateFile').addEventListener('change', function () {
|
||||
let file = document.getElementById('stateFile').files[0];
|
||||
let formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
console.log("Uploading state file");
|
||||
|
||||
fetch('/api/v1.1/StateManager/Upload?RomId=' + modalVariables.romId + '&IsMediaGroup=' + modalVariables.IsMediaGroup, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
UploadAlert(data);
|
||||
LoadStates();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error:", error);
|
||||
UploadAlert(error);
|
||||
LoadStates();
|
||||
});
|
||||
});
|
||||
|
||||
function UploadAlert(data) {
|
||||
if (data.Management == "Managed") {
|
||||
alert("State uploaded successfully.");
|
||||
} else {
|
||||
alert("State uploaded successfully, but it might not function correctly for this platform and ROM.");
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -1,12 +1,7 @@
|
||||
<div style="padding-top: 5px;">
|
||||
<strong>New Library</strong>
|
||||
</div>
|
||||
|
||||
<div style="width: 300px;">
|
||||
<table style="width: 98%; margin-top: 15px; margin-bottom: 15px;">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><input type="text" id="newlibrary_name" style="width: 95%;" /></td>
|
||||
<th style="width: 20%;">Name</th>
|
||||
<td style="width: 80%;"><input type="text" id="newlibrary_name" style="width: 98%;" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Default Platform</th>
|
||||
@@ -14,21 +9,22 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Path</th>
|
||||
<td><input type="text" id="newlibrary_path" style="width: 95%;" /></td>
|
||||
<td><input type="text" id="newlibrary_path" style="width: 98%;" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="width: 100%; text-align: right;">
|
||||
<div style="width: 100%; text-align: right; margin-top: 160px;">
|
||||
<div style="display: inline-block; margin-right: 20px;">
|
||||
<button value="OK" onclick="newLibrary();">OK</button>
|
||||
</div>
|
||||
<div style="display: inline-block;">
|
||||
<button value="Cancel" onclick="closeSubDialog();">Cancel</button>
|
||||
</div>
|
||||
<button value="Cancel" onclick="closeDialog();">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById('modal-heading').innerHTML = "New Library";
|
||||
|
||||
$('#newlibrary_defaultplatform').select2({
|
||||
minimumInputLength: 3,
|
||||
ajax: {
|
||||
|
@@ -78,7 +78,7 @@
|
||||
<td style="width: 75%;"><select id="properties_fixgame" style="width: 100%;"></select></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;"><button id="properties_fixsave" value="Save Match" onclick="SaveFixedGame();">Save Match</button></td>
|
||||
<td colspan="2" style="text-align: right;"><button id="properties_fixclear" value="Clear Match" onclick="ClearFixedGame();">Clear Match</button><button id="properties_fixsave" value="Save Match" onclick="SaveFixedGame();">Save Match</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -252,6 +252,7 @@
|
||||
var fixplatform = $('#properties_fixplatform').select2('data');
|
||||
var fixgame = $('#properties_fixgame').select2('data');
|
||||
|
||||
document.getElementById('properties_fixclear').setAttribute("disabled", "disabled");
|
||||
document.getElementById('properties_fixsave').setAttribute("disabled", "disabled");
|
||||
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
|
||||
@@ -259,6 +260,18 @@
|
||||
});
|
||||
}
|
||||
|
||||
function ClearFixedGame() {
|
||||
var fixplatform = 0;
|
||||
var fixgame = 0;
|
||||
|
||||
document.getElementById('properties_fixclear').setAttribute("disabled", "disabled");
|
||||
document.getElementById('properties_fixsave').setAttribute("disabled", "disabled");
|
||||
|
||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform + '&NewGameId=' + fixgame, 'PATCH', function (result) {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function BuildAttributesTable(attributes, sourceName) {
|
||||
var aTable = document.createElement('table');
|
||||
aTable.style.width = '100%';
|
||||
|
@@ -72,6 +72,11 @@
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Note</strong>: The page will need to be reloaded for changes to take effect.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: right;">
|
||||
<button id="profile_pref_ok" value="OK" onclick="SavePrefs();">OK</button>
|
||||
@@ -220,7 +225,8 @@
|
||||
SetPreference_Batch(model);
|
||||
|
||||
if (getQueryString('page', 'string') == 'home' || getQueryString('page', 'string') == undefined) {
|
||||
executeFilter1_1(1);
|
||||
setCookie('games_library_last_page', 1);
|
||||
//location.reload();
|
||||
}
|
||||
|
||||
closeDialog();
|
||||
|
@@ -13,7 +13,7 @@
|
||||
if (IsMediaGroupInt == 1) { IsMediaGroup = true; }
|
||||
var StateUrl = undefined;
|
||||
if (getQueryString('stateid', 'int')) {
|
||||
StateUrl = '/api/v1.1/StateManager/' + romId + '/' + getQueryString('stateid', 'int') + '/State/savestate.state?IsMediaGroup=' + IsMediaGroup;
|
||||
StateUrl = '/api/v1.1/StateManager/' + romId + '/' + getQueryString('stateid', 'int') + '/State/savestate.state?StateOnly=true&IsMediaGroup=' + IsMediaGroup;
|
||||
}
|
||||
var gameData;
|
||||
var artworks = null;
|
||||
@@ -23,6 +23,8 @@
|
||||
var emuBios = '';
|
||||
var emuBackground = '';
|
||||
|
||||
console.log("Loading rom url: " + decodeURIComponent(getQueryString('rompath', 'string')));
|
||||
|
||||
ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) {
|
||||
gameData = result;
|
||||
|
||||
@@ -51,10 +53,14 @@
|
||||
emuBios = '';
|
||||
} else {
|
||||
emuBios = '/api/v1.1/Bios/zip/' + platformId;
|
||||
console.log("Using BIOS link: " + emuBios);
|
||||
}
|
||||
|
||||
switch (getQueryString('engine', 'string')) {
|
||||
case 'EmulatorJS':
|
||||
console.log("Emulator: " + getQueryString('engine', 'string'));
|
||||
console.log("Core: " + getQueryString('core', 'string'));
|
||||
|
||||
$('#emulator').load('/emulators/EmulatorJS.html?v=' + AppVersion);
|
||||
break;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/api/v1.1/System/VersionFile"></script>
|
||||
@@ -40,8 +41,10 @@
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="bgImage" style="background-image: url('/images/LoginWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
|
||||
<div id="bgImage"
|
||||
style="background-image: url('/images/LoginWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
|
||||
<div id="bgImage_Opacity"></div>
|
||||
</div>
|
||||
|
||||
@@ -52,7 +55,9 @@
|
||||
|
||||
<div id="loginwindow_header_label" style="display: block; text-align: center;">Gaseous Games</div>
|
||||
|
||||
<button type="button" value="Get Started" onclick="document.getElementById('first_welcome').style.display = 'none'; document.getElementById('first_newadmin').style.display = '';" class="bigbutton">Get Started</button>
|
||||
<button type="button" value="Get Started"
|
||||
onclick="document.getElementById('first_welcome').style.display = 'none'; document.getElementById('first_newadmin').style.display = '';"
|
||||
class="bigbutton">Get Started</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loginwindow" id="first_newadmin" style="display: none;">
|
||||
@@ -67,15 +72,18 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td><input type="email" id="login_email" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
<td><input type="email" id="login_email" style="width: 95%;" onkeyup="checkPasswordsMatch();" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>New Password</th>
|
||||
<td><input type="password" id="login_password" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
<td><input type="password" id="login_password" style="width: 95%;"
|
||||
onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Confirm Password</th>
|
||||
<td><input type="password" id="login_confirmpassword" style="width: 95%;" onkeyup="checkPasswordsMatch();" /></td>
|
||||
<td><input type="password" id="login_confirmpassword" style="width: 95%;"
|
||||
onkeyup="checkPasswordsMatch();" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="login_passwordnotice"> </td>
|
||||
@@ -85,7 +93,9 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="padding-top: 20px;">
|
||||
<button id="login_createaccount" type="button" value="Create Account" onclick="registerAccount();" disabled="disabled" class="bigbutton">Create Account</button>
|
||||
<button id="login_createaccount" type="button" value="Create Account"
|
||||
onclick="registerAccount();" disabled="disabled" class="bigbutton">Create
|
||||
Account</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -94,12 +104,14 @@
|
||||
</div>
|
||||
|
||||
<div id="settings_photocredit">
|
||||
Wallpaper by <a href="https://unsplash.com/@spideyjoey" class="romlink">Joey Kwok</a> / <a href="https://unsplash.com/photos/a-room-filled-with-arcade-machines-and-neon-lights-jbIsTd7rdd8" class="romlink">Unsplash</a>
|
||||
Wallpaper by <a href="https://unsplash.com/@spideyjoey" class="romlink">Joey Kwok</a> / <a
|
||||
href="https://unsplash.com/photos/a-room-filled-with-arcade-machines-and-neon-lights-jbIsTd7rdd8"
|
||||
class="romlink">Unsplash</a>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// redirect if first run status != 0 as 0 indicates that first run needs to be run
|
||||
if (FirstRunStatus != 0) {
|
||||
if (FirstRunStatus != 0 && FirstRunStatus != "0") {
|
||||
window.location.replace("/");
|
||||
}
|
||||
|
||||
|
@@ -545,7 +545,7 @@
|
||||
var saveStatesButton = '';
|
||||
if (mediaGroup.emulator) {
|
||||
if (mediaGroup.emulator.type.length > 0) {
|
||||
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip');
|
||||
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '.zip');
|
||||
|
||||
if (mediaGroup.hasSaveStates == true) {
|
||||
var modalVariables = {
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<table id="settings_libraries" class="romtable" style="width: 100%;" cellspacing="0">
|
||||
|
||||
</table>
|
||||
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showSubDialog('librarynew');">New Library</button></div>
|
||||
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showDialog('librarynew');">New Library</button></div>
|
||||
|
||||
<h2>Advanced Settings</h2>
|
||||
<p><strong>Warning</strong> Do not modify the below settings unless you know what you're doing.</p>
|
||||
|
@@ -27,7 +27,7 @@ function formatFilterPanel(containerElement, result) {
|
||||
// Cancel the default action, if needed
|
||||
event.preventDefault();
|
||||
// Trigger the button element with a click
|
||||
executeFilter1_1();
|
||||
applyFilters();
|
||||
}
|
||||
});
|
||||
containerPanelSearch.appendChild(containerPanelSearchField);
|
||||
@@ -99,7 +99,7 @@ function formatFilterPanel(containerElement, result) {
|
||||
// add filter button
|
||||
var searchButton = document.createElement('div');
|
||||
searchButton.id = 'games_library_searchbutton';
|
||||
searchButton.setAttribute('onclick', 'executeFilter1_1();');
|
||||
searchButton.setAttribute('onclick', 'applyFilters();');
|
||||
searchButton.innerHTML = 'Apply';
|
||||
|
||||
buttonsDiv.appendChild(searchButton);
|
||||
@@ -365,6 +365,12 @@ function filter_panel_range_value(name) {
|
||||
}
|
||||
}
|
||||
|
||||
function applyFilters() {
|
||||
document.getElementById('games_library').innerHTML = '';
|
||||
|
||||
executeFilter1_1();
|
||||
}
|
||||
|
||||
function resetFilters() {
|
||||
// clear name
|
||||
document.getElementById('filter_panel_search').value = '';
|
||||
@@ -381,6 +387,7 @@ function resetFilters() {
|
||||
filter_panel_range_enabled_check(rangeCheckboxes[i].getAttribute('data-name'));
|
||||
}
|
||||
|
||||
document.getElementById('games_library').innerHTML = '';
|
||||
executeFilter1_1();
|
||||
}
|
||||
|
||||
@@ -393,8 +400,18 @@ function executeFilter1_1(pageNumber, pageSize) {
|
||||
existingSearchModel = undefined;
|
||||
}
|
||||
|
||||
let pageMode = GetPreference('LibraryPagination', 'paged');
|
||||
|
||||
if (!pageSize) {
|
||||
switch (pageMode) {
|
||||
case "infinite":
|
||||
pageSize = 30;
|
||||
break;
|
||||
case "paged":
|
||||
default:
|
||||
pageSize = 30;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var model;
|
||||
|
@@ -56,30 +56,77 @@ var ClassificationRatings = {
|
||||
};
|
||||
|
||||
var pageReloadInterval;
|
||||
var firstLoad = true;
|
||||
|
||||
function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScrollTop) {
|
||||
console.log("Displaying page: " + pageNumber);
|
||||
console.log("Page size: " + pageSize);
|
||||
|
||||
var pageMode = GetPreference('LibraryPagination', 'paged');
|
||||
|
||||
if (pageNumber == 1 || pageMode == 'paged') {
|
||||
targetElement.innerHTML = '';
|
||||
if (pageNumber == 1) {
|
||||
localStorage.setItem("gaseous-library-scrollpos", 0);
|
||||
}
|
||||
|
||||
if (pageMode == 'paged') {
|
||||
targetElement.innerHTML = '';
|
||||
}
|
||||
|
||||
switch (pageMode) {
|
||||
case 'paged':
|
||||
if (forceScrollTop == true) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
break;
|
||||
case 'infinite':
|
||||
var gamePlaceholders = document.getElementsByName('GamePlaceholder');
|
||||
|
||||
let currentPage = 1;
|
||||
let totalPages = Math.ceil(result.count / pageSize);
|
||||
let startIndex = 0;
|
||||
let endIndex = pageSize;
|
||||
for (let p = currentPage; p < totalPages + 1; p++) {
|
||||
//console.log("Page: " + p + " - StartIndex: " + startIndex + " - EndIndex: " + endIndex);
|
||||
|
||||
let newPageAnchor = document.getElementById('pageAnchor' + p);
|
||||
if (!newPageAnchor) {
|
||||
newPageAnchor = document.createElement('span');
|
||||
newPageAnchor.id = 'pageAnchor' + p;
|
||||
newPageAnchor.setAttribute('name', 'pageAnchor' + p);
|
||||
newPageAnchor.className = 'pageAnchor';
|
||||
newPageAnchor.setAttribute('data-page', p);
|
||||
newPageAnchor.setAttribute('data-loaded', "0");
|
||||
targetElement.appendChild(newPageAnchor);
|
||||
}
|
||||
|
||||
var pagerCheck = document.getElementById('games_library_pagerstore');
|
||||
if (pageNumber == 1) {
|
||||
pagerCheck.innerHTML = "0";
|
||||
if (endIndex > result.count) {
|
||||
endIndex = result.count;
|
||||
}
|
||||
|
||||
if (pageNumber > Number(pagerCheck.innerHTML) || pageMode == 'paged') {
|
||||
pagerCheck.innerHTML = pageNumber;
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
var placeHolderpresent = false;
|
||||
for (var x = 0; x < gamePlaceholders.length; x++) {
|
||||
if (gamePlaceholders[x].getAttribute('data-index') == i) {
|
||||
placeHolderpresent = true;
|
||||
}
|
||||
}
|
||||
if (placeHolderpresent == false) {
|
||||
var gamePlaceholder = document.createElement('div');
|
||||
gamePlaceholder.setAttribute('name', 'GamePlaceholder');
|
||||
gamePlaceholder.id = 'GamePlaceholder' + i;
|
||||
gamePlaceholder.setAttribute('data-index', i);
|
||||
gamePlaceholder.className = 'game_tile';
|
||||
newPageAnchor.appendChild(gamePlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
startIndex = endIndex;
|
||||
endIndex = startIndex + pageSize;
|
||||
|
||||
if (startIndex > result.count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
document.getElementById('games_library_recordcount').innerHTML = result.count + ' games';
|
||||
|
||||
@@ -100,14 +147,24 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
|
||||
for (var i = 0; i < result.games.length; i++) {
|
||||
var game = renderGameIcon(result.games[i], showTitle, showRatings, showClassification, classificationDisplayOrder, false);
|
||||
switch (pageMode) {
|
||||
case "paged":
|
||||
targetElement.appendChild(game);
|
||||
break;
|
||||
|
||||
case "infinite":
|
||||
var placeholderElement = document.getElementById('GamePlaceholder' + result.games[i].index);
|
||||
if (placeholderElement.className != 'game_tile_wrapper') {
|
||||
placeholderElement.className = 'game_tile_wrapper';
|
||||
placeholderElement.innerHTML = '';
|
||||
placeholderElement.appendChild(game);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$('.lazy').Lazy({
|
||||
scrollDirection: 'vertical',
|
||||
effect: 'fadeIn',
|
||||
visibleOnly: true
|
||||
});
|
||||
$(game).fadeIn(500);
|
||||
}
|
||||
|
||||
var pager = document.getElementById('games_pager');
|
||||
pager.style.display = 'none';
|
||||
@@ -117,15 +174,23 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
|
||||
switch(pageMode) {
|
||||
case 'infinite':
|
||||
if (result.games.length == pageSize) {
|
||||
var loadPageButton = document.createElement("div");
|
||||
loadPageButton.id = 'games_library_loadmore';
|
||||
loadPageButton.innerHTML = 'Load More';
|
||||
loadPageButton.setAttribute('onclick', 'executeFilter1_1(' + (pageNumber + 1) + ', ' + pageSize + ');');
|
||||
loadPageButton.setAttribute('data-pagenumber', Number(pageNumber + 1));
|
||||
loadPageButton.setAttribute('data-pagesize', pageSize);
|
||||
targetElement.appendChild(loadPageButton);
|
||||
for (const [key, value] of Object.entries(result.alphaList)) {
|
||||
var letterPager = document.createElement('span');
|
||||
letterPager.className = 'games_library_alpha_pager_letter';
|
||||
letterPager.setAttribute('onclick', 'document.location.hash = "#pageAnchor' + (value) + '"; executeFilter1_1(' + (value) + ');');
|
||||
letterPager.innerHTML = key;
|
||||
alphaPager.appendChild(letterPager);
|
||||
}
|
||||
|
||||
if (firstLoad == true) {
|
||||
if (localStorage.getItem("gaseous-library-scrollpos") != null) {
|
||||
$(window).scrollTop(localStorage.getItem("gaseous-library-scrollpos"));
|
||||
}
|
||||
firstLoad = false;
|
||||
}
|
||||
|
||||
IsInView();
|
||||
|
||||
break;
|
||||
|
||||
case 'paged':
|
||||
@@ -138,11 +203,6 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
}
|
||||
|
||||
if (result.count > pageSize) {
|
||||
// add some padding to the bottom of the games list
|
||||
var loadPageButton = document.createElement("div");
|
||||
loadPageButton.id = 'games_library_padding';
|
||||
targetElement.appendChild(loadPageButton);
|
||||
|
||||
var pageCount = Math.ceil(result.count / pageSize);
|
||||
|
||||
// add first page button
|
||||
@@ -167,7 +227,8 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
|
||||
// add page numbers
|
||||
var pageEitherSide = 4;
|
||||
var currentPage = Number(pagerCheck.innerHTML);
|
||||
// var currentPage = Number(pagerCheck.innerHTML);
|
||||
var currentPage = pageNumber;
|
||||
var pageNumbers = document.createElement('span');
|
||||
for (var i = 1; i <= pageCount; i++) {
|
||||
if (
|
||||
@@ -187,7 +248,7 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
)
|
||||
) {
|
||||
var pageNum = document.createElement('span');
|
||||
if (Number(pagerCheck.innerHTML) == i) {
|
||||
if (pageNumber == i) {
|
||||
pageNum.className = 'games_pager_number_disabled';
|
||||
} else {
|
||||
pageNum.className = 'games_pager_number';
|
||||
@@ -229,19 +290,17 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$('.lazy').Lazy({
|
||||
effect: 'show',
|
||||
effectTime: 500,
|
||||
visibleOnly: true,
|
||||
defaultImage: '/images/unknowngame.png',
|
||||
delay: 250,
|
||||
afterLoad: function(element) {
|
||||
//console.log(element[0].getAttribute('data-id'));
|
||||
}
|
||||
|
||||
// var pageReloadFunction = function() {
|
||||
// formatGamesPanel(targetElement, result, pageNumber, pageSize, false);
|
||||
|
||||
// ajaxCall('/api/v1.1/Filter', 'GET', function (result) {
|
||||
// var scrollerElement = document.getElementById('games_filter_scroller');
|
||||
// formatFilterPanel(scrollerElement, result);
|
||||
// })
|
||||
// };
|
||||
|
||||
// window.clearTimeout(pageReloadInterval);
|
||||
// pageReloadInterval = setTimeout(pageReloadFunction, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
function isScrolledIntoView(elem) {
|
||||
@@ -256,15 +315,49 @@ function isScrolledIntoView(elem) {
|
||||
}
|
||||
}
|
||||
|
||||
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
|
||||
const { top, left, bottom, right } = el.getBoundingClientRect();
|
||||
const { innerHeight, innerWidth } = window;
|
||||
return partiallyVisible
|
||||
? ((top > 0 && top < innerHeight) ||
|
||||
(bottom > 0 && bottom < innerHeight)) &&
|
||||
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
|
||||
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
|
||||
};
|
||||
|
||||
function IsInView() {
|
||||
var pageMode = GetPreference('LibraryPagination', 'paged');
|
||||
switch (pageMode) {
|
||||
case "paged":
|
||||
var loadElement = document.getElementById('games_library_loadmore');
|
||||
if (loadElement) {
|
||||
if (isScrolledIntoView(loadElement)) {
|
||||
//if (isScrolledIntoView(loadElement)) {
|
||||
if (elementIsVisibleInViewport(loadElement, true)) {
|
||||
var pageNumber = Number(document.getElementById('games_library_loadmore').getAttribute('data-pagenumber'));
|
||||
var pageSize = document.getElementById('games_library_loadmore').getAttribute('data-pagesize');
|
||||
executeFilter1_1(pageNumber, pageSize);
|
||||
executeFilter1_1(pageNumber);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "infinite":
|
||||
// store scroll location
|
||||
localStorage.setItem("gaseous-library-scrollpos", $(window).scrollTop());
|
||||
|
||||
// load page
|
||||
let anchors = document.getElementsByClassName('pageAnchor');
|
||||
for (let i = 0; i < anchors.length; i++) {
|
||||
//if (isScrolledIntoView(anchors[i])) {
|
||||
if (elementIsVisibleInViewport(anchors[i], true)) {
|
||||
if (anchors[i].getAttribute('data-loaded') == "0") {
|
||||
console.log("Loading page: " + anchors[i].getAttribute('data-page'));
|
||||
document.getElementById(anchors[i].id).setAttribute('data-loaded', "1");
|
||||
executeFilter1_1(Number(anchors[i].getAttribute('data-page')));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$(window).scroll(IsInView);
|
||||
@@ -279,26 +372,30 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
var gameBox = document.createElement('div');
|
||||
gameBox.id = "game_tile_" + gameObject.id;
|
||||
if (useSmallCover == true) {
|
||||
gameBox.className = classes['game_tile game_tile_small'];
|
||||
gameBox.classList.add(...classes['game_tile game_tile_small']);
|
||||
} else {
|
||||
gameBox.className = classes['game_tile'];
|
||||
gameBox.classList.add(...classes['game_tile']);
|
||||
}
|
||||
gameBox.setAttribute('onclick', 'window.location.href = "/index.html?page=game&id=' + gameObject.id + '";');
|
||||
gameBox.style.display = 'none';
|
||||
|
||||
var gameImageBox = document.createElement('div');
|
||||
gameImageBox.className = classes['game_tile_box'];
|
||||
gameImageBox.classList.add(...classes['game_tile_box']);
|
||||
|
||||
var gameImage = document.createElement('img');
|
||||
gameImage.id = 'game_tile_cover_' + gameObject.id;
|
||||
gameImage.setAttribute('data-id', gameObject.id);
|
||||
if (useSmallCover == true) {
|
||||
gameImage.className = classes['game_tile_image game_tile_image_small lazy'];
|
||||
gameImage.classList.add(...classes['game_tile_image game_tile_image_small lazy']);
|
||||
} else {
|
||||
gameImage.className = classes['game_tile_image lazy'];
|
||||
gameImage.classList.add(...classes['game_tile_image lazy']);
|
||||
}
|
||||
gameImage.src = '/images/unknowngame.png';
|
||||
// gameImage.src = '/images/unknowngame.png';
|
||||
if (gameObject.cover) {
|
||||
gameImage.setAttribute('data-src', '/api/v1.1/Games/' + gameObject.id + '/cover/image/cover_big/' + gameObject.cover.imageId + '.jpg');
|
||||
} else {
|
||||
gameImage.className = classes['game_tile_image unknown'];
|
||||
gameImage.classList.add(...classes['game_tile_image unknown']);
|
||||
gameImage.setAttribute('data-src', '/images/unknowngame.png');
|
||||
}
|
||||
gameImageBox.appendChild(gameImage);
|
||||
|
||||
@@ -312,7 +409,6 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
if (gameObject.ageRatings[c].category == classificationDisplayOrder[b]) {
|
||||
shownClassificationBoard = classificationDisplayOrder[b];
|
||||
displayClassification = true;
|
||||
//classificationPath = '/api/v1.1/Ratings/Images/' + classificationDisplayOrder[b] + '/' + getKeyByValue(AgeRatingStrings, gameObject.ageRatings[c].rating) + '/image.svg';
|
||||
classificationPath = '/images/Ratings/' + classificationDisplayOrder[b] + '/' + gameObject.ageRatings[c].rating + '.svg';
|
||||
}
|
||||
}
|
||||
@@ -326,7 +422,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
if (gameObject.hasSavedGame == true) {
|
||||
var gameSaveIcon = document.createElement('img');
|
||||
gameSaveIcon.src = '/images/SaveStates.png';
|
||||
gameSaveIcon.className = classes['game_tile_box_savedgame savedstateicon'];
|
||||
gameSaveIcon.classList.add(...classes['game_tile_box_savedgame savedstateicon']);
|
||||
gameImageBox.appendChild(gameSaveIcon);
|
||||
}
|
||||
|
||||
@@ -334,13 +430,13 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
if (gameObject.isFavourite == true) {
|
||||
var gameFavIcon = document.createElement('img');
|
||||
gameFavIcon.src = '/images/favourite-filled.svg';
|
||||
gameFavIcon.className = classes['game_tile_box_favouritegame favouriteicon'];
|
||||
gameFavIcon.classList.add(...classes['game_tile_box_favouritegame favouriteicon']);
|
||||
gameImageBox.appendChild(gameFavIcon);
|
||||
}
|
||||
|
||||
if (gameObject.totalRating || displayClassification == true) {
|
||||
var gameImageRatingBanner = document.createElement('div');
|
||||
gameImageRatingBanner.className = classes['game_tile_box_ratingbanner'];
|
||||
gameImageRatingBanner.classList.add(...classes['game_tile_box_ratingbanner']);
|
||||
|
||||
if (showRatings == true || displayClassification == true) {
|
||||
if (showRatings == true) {
|
||||
@@ -361,7 +457,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
if (displayClassification == true) {
|
||||
var gameImageClassificationLogo = document.createElement('img');
|
||||
gameImageClassificationLogo.src = classificationPath;
|
||||
gameImageClassificationLogo.className = classes['rating_image_overlay'];
|
||||
gameImageClassificationLogo.classList.add(...classes['rating_image_overlay']);
|
||||
gameImageBox.appendChild(gameImageClassificationLogo);
|
||||
}
|
||||
}
|
||||
@@ -370,7 +466,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
|
||||
if (showTitle == true) {
|
||||
var gameBoxTitle = document.createElement('div');
|
||||
gameBoxTitle.className = classes['game_tile_label'];
|
||||
gameBoxTitle.classList.add(...classes['game_tile_label']);
|
||||
gameBoxTitle.innerHTML = gameObject.name;
|
||||
gameBox.appendChild(gameBoxTitle);
|
||||
}
|
||||
@@ -381,31 +477,31 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
|
||||
function getViewModeClasses(listView) {
|
||||
if (listView == false) {
|
||||
return {
|
||||
"game_tile game_tile_small": "game_tile game_tile_small",
|
||||
"game_tile": "game_tile",
|
||||
"game_tile_box": "game_tile_box",
|
||||
"game_tile_image game_tile_image_small lazy": "game_tile_image game_tile_image_small lazy",
|
||||
"game_tile_image lazy": "game_tile_image lazy",
|
||||
"game_tile_image unknown": "game_tile_image unknown",
|
||||
"game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame savedstateicon",
|
||||
"game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame favouriteicon",
|
||||
"game_tile_box_ratingbanner": "game_tile_box_ratingbanner",
|
||||
"rating_image_overlay": "rating_image_overlay",
|
||||
"game_tile_label": "game_tile_label"
|
||||
"game_tile game_tile_small": [ "game_tile", "game_tile_small" ],
|
||||
"game_tile": [ "game_tile" ],
|
||||
"game_tile_box": [ "game_tile_box" ],
|
||||
"game_tile_image game_tile_image_small lazy": [ "game_tile_image", "game_tile_image_small", "lazy" ],
|
||||
"game_tile_image lazy": [ "game_tile_image", "lazy" ],
|
||||
"game_tile_image unknown": [ "game_tile_image", "unknown" ],
|
||||
"game_tile_box_savedgame savedstateicon": [ "game_tile_box_savedgame", "savedstateicon" ],
|
||||
"game_tile_box_favouritegame favouriteicon": [ "game_tile_box_favouritegame", "favouriteicon" ],
|
||||
"game_tile_box_ratingbanner": [ "game_tile_box_ratingbanner" ],
|
||||
"rating_image_overlay": [ "rating_image_overlay" ],
|
||||
"game_tile_label": [ "game_tile_label" ]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
"game_tile game_tile_small": "game_tile_row game_tile_small",
|
||||
"game_tile": "game_tile_row",
|
||||
"game_tile_box": "game_tile_box_row",
|
||||
"game_tile_image game_tile_image_small lazy": "game_tile_image_row game_tile_image_small lazy",
|
||||
"game_tile_image lazy": "game_tile_image_row lazy",
|
||||
"game_tile_image unknown": "game_tile_image_row unknown",
|
||||
"game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame_row savedstateicon",
|
||||
"game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame_row favouriteicon",
|
||||
"game_tile_box_ratingbanner": "game_tile_box_ratingbanner_row",
|
||||
"rating_image_overlay": "rating_image_overlay_row",
|
||||
"game_tile_label": "game_tile_label_row"
|
||||
"game_tile game_tile_small": [ "game_tile_row", "game_tile_small" ],
|
||||
"game_tile": [ "game_tile_row" ],
|
||||
"game_tile_box": [ "game_tile_box_row" ],
|
||||
"game_tile_image game_tile_image_small lazy": [ "game_tile_image_row", "game_tile_image_small", "lazy" ],
|
||||
"game_tile_image lazy": [ "game_tile_image_row", "lazy" ],
|
||||
"game_tile_image unknown": [ "game_tile_image_row", "unknown" ],
|
||||
"game_tile_box_savedgame savedstateicon": [ "game_tile_box_savedgame_row", "savedstateicon" ],
|
||||
"game_tile_box_favouritegame favouriteicon": [ "game_tile_box_favouritegame_row", "favouriteicon" ],
|
||||
"game_tile_box_ratingbanner": [ "game_tile_box_ratingbanner_row" ],
|
||||
"rating_image_overlay": [ "rating_image_overlay_row" ],
|
||||
"game_tile_label": [ "game_tile_label_row" ]
|
||||
};
|
||||
}
|
||||
}
|
@@ -258,7 +258,7 @@ function DropDownRenderGameOption(state) {
|
||||
|
||||
if (state.cover) {
|
||||
response = $(
|
||||
'<table class="dropdown-div"><tr><td class="dropdown-cover"><img src="/api/v1.1/Games/' + state.id + '/cover/image/cover_small/' + state.cover.imageId + '.jpg" /></td><td class="dropdown-label"><span class="dropdown-title">' + state.text + '</span><span class="dropdown-releasedate">' + releaseDate + '</span></td></tr></table>'
|
||||
'<table class="dropdown-div"><tr><td class="dropdown-cover"><img src="/api/v1.1/Games/' + state.id + '/cover/image/cover_small/' + state.id + '.jpg" class="game_tile_small_search" /></td><td class="dropdown-label"><span class="dropdown-title">' + state.text + '</span><span class="dropdown-releasedate">' + releaseDate + '</span></td></tr></table>'
|
||||
);
|
||||
} else {
|
||||
response = $(
|
||||
|
@@ -28,16 +28,24 @@ h3 {
|
||||
|
||||
/* The Modal (background) */
|
||||
.modal {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 100; /* Sit on top */
|
||||
display: none;
|
||||
/* Hidden by default */
|
||||
position: fixed;
|
||||
/* Stay in place */
|
||||
z-index: 100;
|
||||
/* Sit on top */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: none; /* Enable scroll if needed */
|
||||
background-color: rgb(0,0,0); /* Fallback color */
|
||||
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||
width: 100%;
|
||||
/* Full width */
|
||||
height: 100%;
|
||||
/* Full height */
|
||||
overflow: none;
|
||||
/* Enable scroll if needed */
|
||||
background-color: rgb(0, 0, 0);
|
||||
/* Fallback color */
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
/* Black w/ opacity */
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
filter: drop-shadow(5px 5px 10px #000);
|
||||
@@ -47,22 +55,28 @@ h3 {
|
||||
/* Modal Content/Box */
|
||||
.modal-content {
|
||||
background-color: #383838;
|
||||
margin: 10% auto; /* 15% from the top and centered */
|
||||
margin: 10% auto;
|
||||
/* 15% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 700px; /* Could be more or less, depending on screen size */
|
||||
width: 700px;
|
||||
/* Could be more or less, depending on screen size */
|
||||
min-height: 358px;
|
||||
}
|
||||
|
||||
.modal-content-sub {
|
||||
background-color: #383838;
|
||||
margin: 20% auto; /* 20% from the top and centered */
|
||||
margin: 20% auto;
|
||||
/* 20% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 300px; /* Could be more or less, depending on screen size */
|
||||
width: 300px;
|
||||
/* Could be more or less, depending on screen size */
|
||||
min-height: 110px;
|
||||
}
|
||||
|
||||
#modal-heading {
|
||||
margin-block: 5px;
|
||||
border-bottom-style: solid;
|
||||
@@ -72,6 +86,7 @@ h3 {
|
||||
|
||||
border-image: linear-gradient(to right, rgba(255, 0, 0, 1) 0%, rgba(251, 255, 0, 1) 16%, rgba(0, 255, 250, 1) 30%, rgba(0, 16, 255, 1) 46%, rgba(250, 0, 255, 1) 62%, rgba(255, 0, 0, 1) 78%, rgba(255, 237, 0, 1) 90%, rgba(20, 255, 0, 1) 100%) 5;
|
||||
}
|
||||
|
||||
#modal-content {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -296,7 +311,11 @@ h3 {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
input[type='text'], input[type='number'], input[type="email"], input[type="password"], input[type="datetime-local"] {
|
||||
input[type='text'],
|
||||
input[type='number'],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="datetime-local"] {
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
padding: 4px;
|
||||
@@ -313,7 +332,11 @@ input[type='text'], input[type='number'], input[type="email"], input[type="passw
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
input[type='text']:hover, input[type='number']:hover, input[type="email"]:hover, input[type="password"]:hover, input[type="datetime-local"]:hover {
|
||||
input[type='text']:hover,
|
||||
input[type='number']:hover,
|
||||
input[type="email"]:hover,
|
||||
input[type="password"]:hover,
|
||||
input[type="datetime-local"]:hover {
|
||||
border-color: #939393;
|
||||
}
|
||||
|
||||
@@ -351,9 +374,7 @@ input[name='filter_panel_range_max'] {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.text_link {
|
||||
|
||||
}
|
||||
.text_link {}
|
||||
|
||||
.text_link:hover {
|
||||
cursor: pointer;
|
||||
@@ -548,11 +569,25 @@ input[name='filter_panel_range_max'] {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.game_tile_wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.game_tile_placeholder {
|
||||
display: inline-block;
|
||||
min-height: 243px;
|
||||
width: 232px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.game_tile {
|
||||
padding: 5px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
display: inline-block;
|
||||
width: 220px;
|
||||
min-height: 200px;
|
||||
min-height: 243px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
@@ -590,6 +625,12 @@ input[name='filter_panel_range_max'] {
|
||||
border: 1px solid #2b2b2b;
|
||||
}
|
||||
|
||||
.game_tile_small_search {
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.game_tile_row {
|
||||
padding: 5px;
|
||||
display: block;
|
||||
@@ -689,6 +730,9 @@ input[name='filter_panel_range_max'] {
|
||||
max-height: 200px;
|
||||
min-height: 200px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.game_tile_image_shadow {
|
||||
box-shadow: 5px 5px 19px 0px rgba(0, 0, 0, 0.44);
|
||||
-webkit-box-shadow: 5px 5px 19px 0px rgba(0, 0, 0, 0.44);
|
||||
-moz-box-shadow: 5px 5px 19px 0px rgba(0, 0, 0, 0.44);
|
||||
@@ -701,16 +745,15 @@ input[name='filter_panel_range_max'] {
|
||||
min-height: 75px;
|
||||
margin-left: 10px;
|
||||
background-color: transparent;
|
||||
box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
-webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
-moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
|
||||
}
|
||||
|
||||
.game_tile_image, .unknown {
|
||||
.game_tile_image,
|
||||
.unknown {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.game_tile_image_row, .unknown {
|
||||
.game_tile_image_row,
|
||||
.unknown {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -889,11 +932,16 @@ iframe {
|
||||
background-color: #383838;
|
||||
color: black;
|
||||
text-align: center;
|
||||
user-select: none; /* standard syntax */
|
||||
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
|
||||
-moz-user-select: none; /* mozilla browsers */
|
||||
-khtml-user-select: none; /* webkit (konqueror) browsers */
|
||||
-ms-user-select: none; /* IE10+ */
|
||||
user-select: none;
|
||||
/* standard syntax */
|
||||
-webkit-user-select: none;
|
||||
/* webkit (safari, chrome) browsers */
|
||||
-moz-user-select: none;
|
||||
/* mozilla browsers */
|
||||
-khtml-user-select: none;
|
||||
/* webkit (konqueror) browsers */
|
||||
-ms-user-select: none;
|
||||
/* IE10+ */
|
||||
}
|
||||
|
||||
.gamescreenshots_arrows:hover {
|
||||
@@ -967,9 +1015,7 @@ iframe {
|
||||
background-color: rgba(56, 56, 56, 0.9);
|
||||
}
|
||||
|
||||
#gamesummarytext_label {
|
||||
|
||||
}
|
||||
#gamesummarytext_label {}
|
||||
|
||||
.line-clamp-4 {
|
||||
overflow: hidden;
|
||||
@@ -1101,14 +1147,18 @@ th {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div[name="properties_toc_item"],div[name="properties_user_toc_item"],div[name="properties_profile_toc_item"] {
|
||||
div[name="properties_toc_item"],
|
||||
div[name="properties_user_toc_item"],
|
||||
div[name="properties_profile_toc_item"] {
|
||||
padding: 10px;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #2b2b2b;
|
||||
}
|
||||
|
||||
div[name="properties_toc_item"]:hover,div[name="properties_user_toc_item"]:hover,div[name="properties_profile_toc_item"]:hover {
|
||||
div[name="properties_toc_item"]:hover,
|
||||
div[name="properties_user_toc_item"]:hover,
|
||||
div[name="properties_profile_toc_item"]:hover {
|
||||
background-color: #2b2b2b;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1136,7 +1186,8 @@ div[name="properties_toc_item"]:hover,div[name="properties_user_toc_item"]:hover
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.select2-container--default:hover, .select2-selection--multiple:hover {
|
||||
.select2-container--default:hover,
|
||||
.select2-selection--multiple:hover {
|
||||
border-color: #939393;
|
||||
}
|
||||
|
||||
@@ -1183,7 +1234,8 @@ div[name="properties_toc_item"]:hover,div[name="properties_user_toc_item"]:hover
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.select2-selection--single:hover, .select2-selection__rendered:hover {
|
||||
.select2-selection--single:hover,
|
||||
.select2-selection__rendered:hover {
|
||||
border-color: #939393;
|
||||
}
|
||||
|
||||
@@ -1288,9 +1340,7 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
#emulator {
|
||||
|
||||
}
|
||||
#emulator {}
|
||||
|
||||
.emulator_partscreen {
|
||||
margin: 0 auto;
|
||||
@@ -1363,15 +1413,14 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.rom_checkbox_box {
|
||||
|
||||
}
|
||||
.rom_checkbox_box {}
|
||||
|
||||
.rom_checkbox_box_hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#rom_edit, #rom_edit_delete {
|
||||
#rom_edit,
|
||||
#rom_edit_delete {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -1454,7 +1503,8 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
}
|
||||
|
||||
.bgalt1 {
|
||||
background-color: transparent;;
|
||||
background-color: transparent;
|
||||
;
|
||||
}
|
||||
|
||||
.logs_table_cell_150px {
|
||||
@@ -1506,13 +1556,33 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
background-color: #383838;
|
||||
}
|
||||
|
||||
.string { color: lightblue; }
|
||||
.number { color: lightblue; }
|
||||
.boolean { color: lightblue; }
|
||||
.null { color: magenta; }
|
||||
.key { color: greenyellow; }
|
||||
.brace { color: #888; }
|
||||
.square { color: #fff000; }
|
||||
.string {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.number {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.boolean {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.null {
|
||||
color: magenta;
|
||||
}
|
||||
|
||||
.key {
|
||||
color: greenyellow;
|
||||
}
|
||||
|
||||
.brace {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.square {
|
||||
color: #fff000;
|
||||
}
|
||||
|
||||
.tagBox {
|
||||
position: absolute;
|
||||
@@ -1543,12 +1613,16 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
}
|
||||
|
||||
.loginwindow {
|
||||
position: fixed; /* Stay in place */
|
||||
position: fixed;
|
||||
/* Stay in place */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
width: 100%;
|
||||
/* Full width */
|
||||
height: 100%;
|
||||
/* Full height */
|
||||
overflow: auto;
|
||||
/* Enable scroll if needed */
|
||||
/*background-color: rgb(0,0,0); /* Fallback color */
|
||||
/*background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||
/*backdrop-filter: blur(8px);
|
||||
@@ -1561,11 +1635,13 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
.loginwindow-content {
|
||||
position: relative;
|
||||
background-color: #383838;
|
||||
margin: 15% auto; /* 15% from the top and centered */
|
||||
margin: 15% auto;
|
||||
/* 15% from the top and centered */
|
||||
padding: 10px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
width: 350px; /* Could be more or less, depending on screen size */
|
||||
width: 350px;
|
||||
/* Could be more or less, depending on screen size */
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
@@ -1601,7 +1677,8 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
}
|
||||
|
||||
/* Links inside the dropdown */
|
||||
.dropdown-content a, .dropdown-content span {
|
||||
.dropdown-content a,
|
||||
.dropdown-content span {
|
||||
color: black;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
@@ -1613,10 +1690,14 @@ button:not(.select2-selection__choice__remove):not(.ejs_menu_button):disabled {
|
||||
}
|
||||
|
||||
/* Change color of dropdown links on hover */
|
||||
.dropdown-content a:hover {background-color: #ddd;}
|
||||
.dropdown-content a:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
|
||||
.show {display:block;}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdownroleitem {
|
||||
text-transform: capitalize;
|
||||
|
Reference in New Issue
Block a user