UI overhaul (#383)
@@ -1,4 +0,0 @@
|
|||||||
DATABASE_HOST=mariadb
|
|
||||||
DATABASE_USER=root
|
|
||||||
DATABASE_PASSWORD=gaseous
|
|
||||||
DATABASE_DB=gaseous
|
|
@@ -2,5 +2,5 @@ FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
|||||||
|
|
||||||
RUN apt-get update && apt-get install -y p7zip-full
|
RUN apt-get update && apt-get install -y p7zip-full
|
||||||
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
||||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.11.7z
|
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||||
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.11.7z
|
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
@@ -36,7 +36,9 @@
|
|||||||
"AndersEAndersen.html-class-suggestions",
|
"AndersEAndersen.html-class-suggestions",
|
||||||
"george-alisson.html-preview-vscode",
|
"george-alisson.html-preview-vscode",
|
||||||
"ms-dotnettools.vscodeintellicode-csharp",
|
"ms-dotnettools.vscodeintellicode-csharp",
|
||||||
"Zignd.html-css-class-completion"
|
"Zignd.html-css-class-completion",
|
||||||
|
"PWABuilder.pwa-studio",
|
||||||
|
"ms-azuretools.vscode-docker"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,11 +11,13 @@ services:
|
|||||||
- dbhost=${DATABASE_HOST}
|
- dbhost=${DATABASE_HOST}
|
||||||
- dbuser=${DATABASE_USER}
|
- dbuser=${DATABASE_USER}
|
||||||
- dbpass=${DATABASE_PASSWORD}
|
- dbpass=${DATABASE_PASSWORD}
|
||||||
- igdbclientid=<clientid>
|
- igdbclientid=${IGDB_CLIENT_ID}
|
||||||
- igdbclientsecret=<clientsecret>
|
- igdbclientsecret=${IGDB_CLIENT_SECRET}
|
||||||
mariadb:
|
mariadb:
|
||||||
hostname: mariadb
|
hostname: mariadb
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
environment:
|
environment:
|
||||||
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
||||||
- MARIADB_DATABASE=${DATABASE_DB}
|
- MARIADB_DATABASE=${DATABASE_DB}
|
||||||
|
@@ -9,9 +9,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
- name: Install dotnet tool
|
- name: Install dotnet tool
|
||||||
@@ -21,18 +26,37 @@ jobs:
|
|||||||
- name: Sign in to Nuget
|
- 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"
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Login to GitHub Package Registry
|
||||||
uses: docker/build-push-action@v4
|
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:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
file: ./build/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
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
@@ -8,9 +8,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
- name: Install dotnet tool
|
- name: Install dotnet tool
|
||||||
@@ -20,18 +25,39 @@ jobs:
|
|||||||
- name: Sign in to Nuget
|
- 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"
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Login to GitHub Package Registry
|
||||||
uses: docker/build-push-action@v4
|
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:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
file: ./build/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
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
|
28
Dockerfile
@@ -1,28 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
# download and unzip EmulatorJS from CDN
|
|
||||||
RUN apt-get update && apt-get install -y p7zip-full
|
|
||||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
|
||||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
|
||||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
|
||||||
|
|
||||||
# Build runtime image
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
|
||||||
ENV INDOCKER=1
|
|
||||||
WORKDIR /App
|
|
||||||
COPY --from=build-env /App/out .
|
|
||||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
|
@@ -16,9 +16,9 @@ Version 1.7.0 and later contain user authentication, and can be exposed to the i
|
|||||||
While we do our best to stay on top of server security, if you expose the server to the internet **you do so at your own risk**.
|
While we do our best to stay on top of server security, if you expose the server to the internet **you do so at your own risk**.
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
41
build/Dockerfile
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
# 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
@@ -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
@@ -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
@@ -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
|
BIN
gaseous-server/.DS_Store
vendored
@@ -12,6 +12,6 @@ namespace Authentication
|
|||||||
{
|
{
|
||||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||||
public Guid Avatar { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -104,7 +104,7 @@ namespace Authentication
|
|||||||
var roleName = GetRoleName(roleId);
|
var roleName = GetRoleName(roleId);
|
||||||
ApplicationRole? role = null;
|
ApplicationRole? role = null;
|
||||||
|
|
||||||
if(roleName != null)
|
if (roleName != null)
|
||||||
{
|
{
|
||||||
role = new ApplicationRole();
|
role = new ApplicationRole();
|
||||||
role.Id = roleId;
|
role.Id = roleId;
|
||||||
@@ -153,7 +153,7 @@ namespace Authentication
|
|||||||
string commandText = "Select Name from Roles";
|
string commandText = "Select Name from Roles";
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText);
|
var rows = _database.ExecuteCMDDict(commandText);
|
||||||
foreach(Dictionary<string, object> row in rows)
|
foreach (Dictionary<string, object> row in rows)
|
||||||
{
|
{
|
||||||
ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
|
ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
|
||||||
role.Id = (string)row["Id"];
|
role.Id = (string)row["Id"];
|
||||||
|
@@ -35,7 +35,7 @@ namespace Authentication
|
|||||||
parameters.Add("@userId", userId);
|
parameters.Add("@userId", userId);
|
||||||
|
|
||||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||||
foreach(DataRow row in rows)
|
foreach (DataRow row in rows)
|
||||||
{
|
{
|
||||||
roles.Add((string)row["Name"]);
|
roles.Add((string)row["Name"]);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ namespace Authentication
|
|||||||
/// Class that represents the Users table in the MySQL Database
|
/// Class that represents the Users table in the MySQL Database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserTable<TUser>
|
public class UserTable<TUser>
|
||||||
where TUser :ApplicationUser
|
where TUser : ApplicationUser
|
||||||
{
|
{
|
||||||
private Database _database;
|
private Database _database;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ namespace Authentication
|
|||||||
public TUser GetUserById(string userId)
|
public TUser GetUserById(string userId)
|
||||||
{
|
{
|
||||||
TUser user = null;
|
TUser user = null;
|
||||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId where Id = @id";
|
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId where Id = @id";
|
||||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||||
@@ -89,7 +89,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||||
@@ -97,10 +97,10 @@ namespace Authentication
|
|||||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||||
user.SecurityProfile = GetSecurityProfile(user);
|
user.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(user);
|
user.UserPreferences = GetPreferences(user);
|
||||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
@@ -114,11 +114,11 @@ namespace Authentication
|
|||||||
public List<TUser> GetUserByName(string normalizedUserName)
|
public List<TUser> GetUserByName(string normalizedUserName)
|
||||||
{
|
{
|
||||||
List<TUser> users = new List<TUser>();
|
List<TUser> users = new List<TUser>();
|
||||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId where NormalizedEmail = @name";
|
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId where NormalizedEmail = @name";
|
||||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||||
foreach(Dictionary<string, object> row in rows)
|
foreach (Dictionary<string, object> row in rows)
|
||||||
{
|
{
|
||||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||||
user.Id = (string)row["Id"];
|
user.Id = (string)row["Id"];
|
||||||
@@ -127,7 +127,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||||
@@ -135,10 +135,10 @@ namespace Authentication
|
|||||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||||
user.SecurityProfile = GetSecurityProfile(user);
|
user.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(user);
|
user.UserPreferences = GetPreferences(user);
|
||||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||||
users.Add(user);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +148,10 @@ namespace Authentication
|
|||||||
public List<TUser> GetUsers()
|
public List<TUser> GetUsers()
|
||||||
{
|
{
|
||||||
List<TUser> users = new List<TUser>();
|
List<TUser> users = new List<TUser>();
|
||||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId order by NormalizedUserName";
|
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId order by NormalizedUserName";
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText);
|
var rows = _database.ExecuteCMDDict(commandText);
|
||||||
foreach(Dictionary<string, object> row in rows)
|
foreach (Dictionary<string, object> row in rows)
|
||||||
{
|
{
|
||||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||||
user.Id = (string)row["Id"];
|
user.Id = (string)row["Id"];
|
||||||
@@ -160,7 +160,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||||
@@ -168,10 +168,10 @@ namespace Authentication
|
|||||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||||
user.SecurityProfile = GetSecurityProfile(user);
|
user.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(user);
|
user.UserPreferences = GetPreferences(user);
|
||||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||||
users.Add(user);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +258,11 @@ namespace Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int Insert(TUser user)
|
public int Insert(TUser user)
|
||||||
{
|
{
|
||||||
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp, ConcurrencyStamp, Email, EmailConfirmed, PhoneNumber, PhoneNumberConfirmed, NormalizedEmail, NormalizedUserName, AccessFailedCount, LockoutEnabled, LockoutEnd, TwoFactorEnabled) values (@name, @id, @pwdHash, @SecStamp, @concurrencystamp, @email ,@emailconfirmed ,@phonenumber, @phonenumberconfirmed, @normalizedemail, @normalizedusername, @accesscount, @lockoutenabled, @lockoutenddate, @twofactorenabled);";
|
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp, ConcurrencyStamp, Email, EmailConfirmed, PhoneNumber, PhoneNumberConfirmed, NormalizedEmail, NormalizedUserName, AccessFailedCount, LockoutEnabled, LockoutEnd, TwoFactorEnabled) values (@name, @id, @pwdHash, @SecStamp, @concurrencystamp, @email ,@emailconfirmed ,@phonenumber, @phonenumberconfirmed, @normalizedemail, @normalizedusername, @accesscount, @lockoutenabled, @lockoutenddate, @twofactorenabled); Insert into UserProfiles (Id, UserId, DisplayName, Quip, UnstructuredData) values (@profileId, @id, @email, '', '{}');";
|
||||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
parameters.Add("@name", user.UserName);
|
parameters.Add("@name", user.UserName);
|
||||||
parameters.Add("@id", user.Id);
|
parameters.Add("@id", user.Id);
|
||||||
|
parameters.Add("@profileId", Guid.NewGuid());
|
||||||
parameters.Add("@pwdHash", user.PasswordHash);
|
parameters.Add("@pwdHash", user.PasswordHash);
|
||||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||||
@@ -292,7 +293,7 @@ namespace Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private int Delete(string userId)
|
private int Delete(string userId)
|
||||||
{
|
{
|
||||||
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from GameState where UserId = @userId;";
|
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from UserProfiles where UserId = @userId; Delete from GameState where UserId = @userId;";
|
||||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
parameters.Add("@userId", userId);
|
parameters.Add("@userId", userId);
|
||||||
|
|
||||||
|
@@ -8,8 +8,9 @@ namespace Authentication
|
|||||||
public List<String> Roles { get; set; }
|
public List<String> Roles { get; set; }
|
||||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||||
public Guid Avatar { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
public string HighestRole {
|
public string HighestRole
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string _highestRole = "";
|
string _highestRole = "";
|
||||||
|
@@ -8,8 +8,9 @@ namespace Authentication
|
|||||||
public DateTimeOffset? LockoutEnd { get; set; }
|
public DateTimeOffset? LockoutEnd { get; set; }
|
||||||
public List<string> Roles { get; set; }
|
public List<string> Roles { get; set; }
|
||||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public Guid Avatar { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
public string HighestRole {
|
public string HighestRole
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string _highestRole = "";
|
string _highestRole = "";
|
||||||
|
@@ -45,11 +45,13 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
var xmlStream = File.OpenRead(FileName);
|
var xmlStream = File.OpenRead(FileName);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Hash File", "Generating MD5 hash for file: " + FileName);
|
||||||
var md5 = MD5.Create();
|
var md5 = MD5.Create();
|
||||||
byte[] md5HashByte = md5.ComputeHash(xmlStream);
|
byte[] md5HashByte = md5.ComputeHash(xmlStream);
|
||||||
string md5Hash = BitConverter.ToString(md5HashByte).Replace("-", "").ToLowerInvariant();
|
string md5Hash = BitConverter.ToString(md5HashByte).Replace("-", "").ToLowerInvariant();
|
||||||
_md5hash = md5Hash;
|
_md5hash = md5Hash;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Hash File", "Generating SHA1 hash for file: " + FileName);
|
||||||
var sha1 = SHA1.Create();
|
var sha1 = SHA1.Create();
|
||||||
xmlStream.Position = 0;
|
xmlStream.Position = 0;
|
||||||
byte[] sha1HashByte = sha1.ComputeHash(xmlStream);
|
byte[] sha1HashByte = sha1.ComputeHash(xmlStream);
|
||||||
|
@@ -197,11 +197,6 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
string SettingName = (string)dataRow["Setting"];
|
string SettingName = (string)dataRow["Setting"];
|
||||||
|
|
||||||
if (SettingName.StartsWith("LastRun_"))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Break");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AppSettings.ContainsKey(SettingName))
|
if (AppSettings.ContainsKey(SettingName))
|
||||||
{
|
{
|
||||||
AppSettings.Remove(SettingName);
|
AppSettings.Remove(SettingName);
|
||||||
|
@@ -70,39 +70,41 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public void InitDB()
|
public void InitDB()
|
||||||
{
|
{
|
||||||
// load resources
|
// load resources
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
switch (_ConnectorType)
|
DatabaseMemoryCacheOptions? CacheOptions = new DatabaseMemoryCacheOptions(false);
|
||||||
|
|
||||||
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
// check if the database exists first - first run must have permissions to create a database
|
// check if the database exists first - first run must have permissions to create a database
|
||||||
string sql = "CREATE DATABASE IF NOT EXISTS `" + Config.DatabaseConfiguration.DatabaseName + "`;";
|
string sql = "CREATE DATABASE IF NOT EXISTS `" + Config.DatabaseConfiguration.DatabaseName + "`;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Creating database if it doesn't exist");
|
Logging.Log(Logging.LogType.Information, "Database", "Creating database if it doesn't exist");
|
||||||
ExecuteCMD(sql, dbDict, 30, "server=" + Config.DatabaseConfiguration.HostName + ";port=" + Config.DatabaseConfiguration.Port + ";userid=" + Config.DatabaseConfiguration.UserName + ";password=" + Config.DatabaseConfiguration.Password);
|
ExecuteCMD(sql, dbDict, CacheOptions, 30, "server=" + Config.DatabaseConfiguration.HostName + ";port=" + Config.DatabaseConfiguration.Port + ";userid=" + Config.DatabaseConfiguration.UserName + ";password=" + Config.DatabaseConfiguration.Password);
|
||||||
|
|
||||||
// check if schema version table is in place - if not, create the schema version table
|
// check if schema version table is in place - if not, create the schema version table
|
||||||
sql = "SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '" + Config.DatabaseConfiguration.DatabaseName + "' AND TABLE_NAME = 'schema_version';";
|
sql = "SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '" + Config.DatabaseConfiguration.DatabaseName + "' AND TABLE_NAME = 'schema_version';";
|
||||||
DataTable SchemaVersionPresent = ExecuteCMD(sql, dbDict);
|
DataTable SchemaVersionPresent = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
if (SchemaVersionPresent.Rows.Count == 0)
|
if (SchemaVersionPresent.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no schema table present - create it
|
// no schema table present - create it
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version table doesn't exist. Creating it.");
|
Logging.Log(Logging.LogType.Information, "Database", "Schema version table doesn't exist. Creating it.");
|
||||||
sql = "CREATE TABLE `schema_version` (`schema_version` INT NOT NULL, PRIMARY KEY (`schema_version`)); INSERT INTO `schema_version` (`schema_version`) VALUES (0);";
|
sql = "CREATE TABLE `schema_version` (`schema_version` INT NOT NULL, PRIMARY KEY (`schema_version`)); INSERT INTO `schema_version` (`schema_version`) VALUES (0);";
|
||||||
ExecuteCMD(sql, dbDict);
|
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = "SELECT schema_version FROM schema_version;";
|
sql = "SELECT schema_version FROM schema_version;";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
DataTable SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||||
if (OuterSchemaVer == 0)
|
if (OuterSchemaVer == 0)
|
||||||
{
|
{
|
||||||
OuterSchemaVer = 1000;
|
OuterSchemaVer = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = OuterSchemaVer; i < 10000; i++)
|
for (int i = OuterSchemaVer; i < 10000; i++)
|
||||||
{
|
{
|
||||||
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
|
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
|
||||||
string dbScript = "";
|
string dbScript = "";
|
||||||
@@ -113,25 +115,25 @@ namespace gaseous_server.Classes
|
|||||||
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
||||||
using (StreamReader reader = new StreamReader(stream))
|
using (StreamReader reader = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
dbScript = reader.ReadToEnd();
|
dbScript = reader.ReadToEnd();
|
||||||
|
|
||||||
// apply script
|
// apply script
|
||||||
sql = "SELECT schema_version FROM schema_version;";
|
sql = "SELECT schema_version FROM schema_version;";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
SchemaVersion = ExecuteCMD(sql, dbDict);
|
SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
if (SchemaVersion.Rows.Count == 0)
|
if (SchemaVersion.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// something is broken here... where's the table?
|
// something is broken here... where's the table?
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Schema table missing! This shouldn't happen!");
|
Logging.Log(Logging.LogType.Critical, "Database", "Schema table missing! This shouldn't happen!");
|
||||||
throw new Exception("schema_version table is missing!");
|
throw new Exception("schema_version table is missing!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int SchemaVer = (int)SchemaVersion.Rows[0][0];
|
int SchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
||||||
// update schema version variable
|
// update schema version variable
|
||||||
Database.schema_version = SchemaVer;
|
Database.schema_version = SchemaVer;
|
||||||
if (SchemaVer < i)
|
if (SchemaVer < i)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -140,12 +142,12 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// apply schema!
|
// apply schema!
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
||||||
ExecuteCMD(dbScript, dbDict, 180);
|
ExecuteCMD(dbScript, dbDict, CacheOptions, 180);
|
||||||
|
|
||||||
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("schemaver", i);
|
dbDict.Add("schemaver", i);
|
||||||
ExecuteCMD(sql, dbDict);
|
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
|
|
||||||
// run post-upgrade code
|
// run post-upgrade code
|
||||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||||
@@ -162,47 +164,91 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Database setup complete");
|
Logging.Log(Logging.LogType.Information, "Database", "Database setup complete");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataTable ExecuteCMD(string Command)
|
public DataTable ExecuteCMD(string Command)
|
||||||
{
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
return _ExecuteCMD(Command, dbDict, 30, "");
|
return _ExecuteCMD(Command, dbDict, CacheOptions, 30, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters)
|
public DataTable ExecuteCMD(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||||
{
|
{
|
||||||
return _ExecuteCMD(Command, Parameters, 30, "");
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
}
|
return _ExecuteCMD(Command, dbDict, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters)
|
||||||
{
|
{
|
||||||
return _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
}
|
|
||||||
|
return _ExecuteCMD(Command, Parameters, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions)
|
||||||
|
{
|
||||||
|
return _ExecuteCMD(Command, Parameters, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||||
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
|
return _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||||
|
{
|
||||||
|
return _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command)
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command)
|
||||||
{
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
return _ExecuteCMDDict(Command, dbDict, 30, "");
|
return _ExecuteCMDDict(Command, dbDict, CacheOptions, 30, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters)
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||||
{
|
|
||||||
return _ExecuteCMDDict(Command, Parameters, 30, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
|
||||||
{
|
|
||||||
return _ExecuteCMDDict(Command, Parameters, Timeout, ConnectionString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Dictionary<string, object>> _ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
|
||||||
{
|
{
|
||||||
DataTable dataTable = _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
return _ExecuteCMDDict(Command, dbDict, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters)
|
||||||
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
|
return _ExecuteCMDDict(Command, Parameters, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions)
|
||||||
|
{
|
||||||
|
return _ExecuteCMDDict(Command, Parameters, CacheOptions, 30, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||||
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
|
return _ExecuteCMDDict(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||||
|
{
|
||||||
|
return _ExecuteCMDDict(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dictionary<string, object>> _ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||||
|
{
|
||||||
|
DataTable dataTable = _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||||
|
|
||||||
// convert datatable to dictionary
|
// convert datatable to dictionary
|
||||||
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
||||||
@@ -228,18 +274,49 @@ namespace gaseous_server.Classes
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||||
{
|
{
|
||||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
string CacheKey = Command + string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||||
switch (_ConnectorType)
|
|
||||||
{
|
if (CacheOptions is object && CacheOptions.CacheEnabled)
|
||||||
case databaseType.MySql:
|
{
|
||||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
object? CachedData = DatabaseMemoryCache.GetCacheObject(CacheKey);
|
||||||
return (DataTable)conn.ExecCMD(Command, Parameters, Timeout);
|
if (CachedData is object)
|
||||||
default:
|
{
|
||||||
return new DataTable();
|
return (DataTable)CachedData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// purge cache if command contains "INSERT", "UPDATE", "DELETE", or "ALTER"
|
||||||
|
if (
|
||||||
|
Command.Contains("INSERT", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
Command.Contains("UPDATE", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
Command.Contains("DELETE", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
Command.Contains("ALTER", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// exclude logging events from purging the cache
|
||||||
|
if (!Command.StartsWith("INSERT INTO SERVERLOGS", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
DatabaseMemoryCache.ClearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||||
|
switch (_ConnectorType)
|
||||||
|
{
|
||||||
|
case databaseType.MySql:
|
||||||
|
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||||
|
DataTable RetTable = conn.ExecCMD(Command, Parameters, Timeout);
|
||||||
|
if (CacheOptions is object && CacheOptions.CacheEnabled)
|
||||||
|
{
|
||||||
|
DatabaseMemoryCache.SetCacheObject(CacheKey, RetTable, CacheOptions.ExpirationSeconds);
|
||||||
|
}
|
||||||
|
return RetTable;
|
||||||
|
default:
|
||||||
|
return new DataTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int ExecuteNonQuery(string Command)
|
public int ExecuteNonQuery(string Command)
|
||||||
{
|
{
|
||||||
@@ -247,52 +324,194 @@ namespace gaseous_server.Classes
|
|||||||
return _ExecuteNonQuery(Command, dbDict, 30, "");
|
return _ExecuteNonQuery(Command, dbDict, 30, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters)
|
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters)
|
||||||
{
|
{
|
||||||
return _ExecuteNonQuery(Command, Parameters, 30, "");
|
return _ExecuteNonQuery(Command, Parameters, 30, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||||
{
|
{
|
||||||
return _ExecuteNonQuery(Command, Parameters, Timeout, ConnectionString);
|
return _ExecuteNonQuery(Command, Parameters, Timeout, ConnectionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
private int _ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||||
{
|
{
|
||||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||||
int retVal = conn.ExecNonQuery(Command, Parameters, Timeout);
|
int retVal = conn.ExecNonQuery(Command, Parameters, Timeout);
|
||||||
return retVal;
|
return retVal;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteTransactionCMD(List<SQLTransactionItem> CommandList, int Timeout = 60)
|
public void ExecuteTransactionCMD(List<SQLTransactionItem> CommandList, int Timeout = 60)
|
||||||
{
|
{
|
||||||
object conn;
|
object conn;
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
{
|
{
|
||||||
var commands = new List<Dictionary<string, object>>();
|
var commands = new List<Dictionary<string, object>>();
|
||||||
foreach (SQLTransactionItem CommandItem in CommandList)
|
foreach (SQLTransactionItem CommandItem in CommandList)
|
||||||
{
|
{
|
||||||
var nCmd = new Dictionary<string, object>();
|
var nCmd = new Dictionary<string, object>();
|
||||||
nCmd.Add("sql", CommandItem.SQLCommand);
|
nCmd.Add("sql", CommandItem.SQLCommand);
|
||||||
nCmd.Add("values", CommandItem.Parameters);
|
nCmd.Add("values", CommandItem.Parameters);
|
||||||
commands.Add(nCmd);
|
commands.Add(nCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = new MySQLServerConnector(_ConnectionString);
|
conn = new MySQLServerConnector(_ConnectionString);
|
||||||
((MySQLServerConnector)conn).TransactionExecCMD(commands, Timeout);
|
((MySQLServerConnector)conn).TransactionExecCMD(commands, Timeout);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DatabaseMemoryCache
|
||||||
|
{
|
||||||
|
private class MemoryCacheItem
|
||||||
|
{
|
||||||
|
public MemoryCacheItem(object CacheObject)
|
||||||
|
{
|
||||||
|
cacheObject = CacheObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoryCacheItem(object CacheObject, int ExpirationSeconds)
|
||||||
|
{
|
||||||
|
cacheObject = CacheObject;
|
||||||
|
expirationSeconds = ExpirationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time the object was added to the cache in ticks
|
||||||
|
/// </summary>
|
||||||
|
public long addedTime { get; } = Environment.TickCount64;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time the object will expire in ticks
|
||||||
|
/// </summary>
|
||||||
|
public long expirationTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return addedTime + _expirationTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of seconds the object will be cached
|
||||||
|
/// </summary>
|
||||||
|
public int expirationSeconds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (int)TimeSpan.FromTicks(_expirationTicks).Seconds;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_expirationTicks = (long)TimeSpan.FromSeconds(value).Ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long _expirationTicks = (long)TimeSpan.FromSeconds(2).Ticks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The object to be cached
|
||||||
|
/// </summary>
|
||||||
|
public object cacheObject { get; set; }
|
||||||
|
}
|
||||||
|
private static Dictionary<string, MemoryCacheItem> MemoryCache = new Dictionary<string, MemoryCacheItem>();
|
||||||
|
private static Timer CacheTimer = new Timer(CacheTimerCallback, null, 0, 1000);
|
||||||
|
|
||||||
|
private static void CacheTimerCallback(object? state)
|
||||||
|
{
|
||||||
|
ClearExpiredCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object? GetCacheObject(string CacheKey)
|
||||||
|
{
|
||||||
|
if (MemoryCache.ContainsKey(CacheKey))
|
||||||
|
{
|
||||||
|
if (MemoryCache[CacheKey].expirationTime < Environment.TickCount)
|
||||||
|
{
|
||||||
|
MemoryCache.Remove(CacheKey);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return MemoryCache[CacheKey].cacheObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void SetCacheObject(string CacheKey, object CacheObject, int ExpirationSeconds = 2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (MemoryCache.ContainsKey(CacheKey))
|
||||||
|
{
|
||||||
|
MemoryCache.Remove(CacheKey);
|
||||||
|
}
|
||||||
|
MemoryCache.Add(CacheKey, new MemoryCacheItem(CacheObject, ExpirationSeconds));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Error while setting cache object", ex);
|
||||||
|
ClearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void RemoveCacheObject(string CacheKey)
|
||||||
|
{
|
||||||
|
if (MemoryCache.ContainsKey(CacheKey))
|
||||||
|
{
|
||||||
|
MemoryCache.Remove(CacheKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void ClearCache()
|
||||||
|
{
|
||||||
|
MemoryCache.Clear();
|
||||||
|
}
|
||||||
|
private static void ClearExpiredCache()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long currTime = Environment.TickCount64;
|
||||||
|
|
||||||
|
Dictionary<string, MemoryCacheItem> ExpiredItems = MemoryCache;
|
||||||
|
foreach (string key in ExpiredItems.Keys)
|
||||||
|
{
|
||||||
|
if (MemoryCache[key].expirationTime < currTime)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\x1b[95mPurging expired cache item " + key + ". Added: " + MemoryCache[key].addedTime + ". Expired: " + MemoryCache[key].expirationTime);
|
||||||
|
MemoryCache.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Database", "Error while clearing expired cache", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DatabaseMemoryCacheOptions
|
||||||
|
{
|
||||||
|
public DatabaseMemoryCacheOptions(bool CacheEnabled = false, int ExpirationSeconds = 1)
|
||||||
|
{
|
||||||
|
this.CacheEnabled = CacheEnabled;
|
||||||
|
this.ExpirationSeconds = ExpirationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CacheEnabled { get; set; }
|
||||||
|
public int ExpirationSeconds { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public int GetDatabaseSchemaVersion()
|
public int GetDatabaseSchemaVersion()
|
||||||
{
|
{
|
||||||
@@ -319,17 +538,17 @@ namespace gaseous_server.Classes
|
|||||||
public bool TestConnection()
|
public bool TestConnection()
|
||||||
{
|
{
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
MySQLServerConnector conn = new MySQLServerConnector(_ConnectionString);
|
MySQLServerConnector conn = new MySQLServerConnector(_ConnectionString);
|
||||||
return conn.TestConnection();
|
return conn.TestConnection();
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SQLTransactionItem
|
public class SQLTransactionItem
|
||||||
{
|
{
|
||||||
public SQLTransactionItem()
|
public SQLTransactionItem()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -341,11 +560,11 @@ namespace gaseous_server.Classes
|
|||||||
this.Parameters = Parameters;
|
this.Parameters = Parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? SQLCommand;
|
public string? SQLCommand;
|
||||||
public Dictionary<string, object>? Parameters = new Dictionary<string, object>();
|
public Dictionary<string, object>? Parameters = new Dictionary<string, object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class MySQLServerConnector
|
private partial class MySQLServerConnector
|
||||||
{
|
{
|
||||||
private string DBConn = "";
|
private string DBConn = "";
|
||||||
|
|
||||||
@@ -358,8 +577,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
DataTable RetTable = new DataTable();
|
DataTable RetTable = new DataTable();
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
{
|
{
|
||||||
conn.Open();
|
conn.Open();
|
||||||
|
|
||||||
@@ -384,7 +603,9 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
}
|
}
|
||||||
RetTable.Load(cmd.ExecuteReader());
|
RetTable.Load(cmd.ExecuteReader());
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
@@ -397,12 +618,12 @@ namespace gaseous_server.Classes
|
|||||||
return RetTable;
|
return RetTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExecNonQuery(string SQL, Dictionary< string, object> Parameters, int Timeout)
|
public int ExecNonQuery(string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
{
|
{
|
||||||
conn.Open();
|
conn.Open();
|
||||||
|
|
||||||
@@ -427,7 +648,9 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
}
|
}
|
||||||
result = cmd.ExecuteNonQuery();
|
result = cmd.ExecuteNonQuery();
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
@@ -440,10 +663,10 @@ namespace gaseous_server.Classes
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
||||||
{
|
{
|
||||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||||
{
|
{
|
||||||
conn.Open();
|
conn.Open();
|
||||||
var command = conn.CreateCommand();
|
var command = conn.CreateCommand();
|
||||||
MySqlTransaction transaction;
|
MySqlTransaction transaction;
|
||||||
@@ -460,28 +683,28 @@ namespace gaseous_server.Classes
|
|||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
conn.Close();
|
conn.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||||
{
|
{
|
||||||
var cmd = new MySqlCommand();
|
var cmd = new MySqlCommand();
|
||||||
cmd.Connection = Conn;
|
cmd.Connection = Conn;
|
||||||
cmd.CommandText = SQL;
|
cmd.CommandText = SQL;
|
||||||
cmd.CommandTimeout = Timeout;
|
cmd.CommandTimeout = Timeout;
|
||||||
{
|
{
|
||||||
var withBlock = cmd.Parameters;
|
var withBlock = cmd.Parameters;
|
||||||
if (Parameters is object)
|
if (Parameters is object)
|
||||||
{
|
{
|
||||||
if (Parameters.Count > 0)
|
if (Parameters.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (string param in Parameters.Keys)
|
foreach (string param in Parameters.Keys)
|
||||||
withBlock.AddWithValue(param, Parameters[param]);
|
withBlock.AddWithValue(param, Parameters[param]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TestConnection()
|
public bool TestConnection()
|
||||||
{
|
{
|
||||||
@@ -499,7 +722,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -153,6 +153,35 @@ namespace gaseous_server.Classes
|
|||||||
// this is a safe background task
|
// this is a safe background task
|
||||||
BackgroundUpgradeTargetSchemaVersions.Add(1022);
|
BackgroundUpgradeTargetSchemaVersions.Add(1022);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1023:
|
||||||
|
// create profiles for all existing users
|
||||||
|
sql = "SELECT * FROM Users;";
|
||||||
|
data = db.ExecuteCMD(sql);
|
||||||
|
foreach (DataRow row in data.Rows)
|
||||||
|
{
|
||||||
|
// get legacy avatar from UserAvatars table
|
||||||
|
sql = "SELECT Avatar FROM UserAvatars WHERE UserId = @userid;";
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", row["Id"] }
|
||||||
|
};
|
||||||
|
DataTable avatarData = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
sql = "INSERT INTO UserProfiles (Id, UserId, DisplayName, Quip, Avatar, AvatarExtension, UnstructuredData) VALUES (@id, @userid, @displayname, @quip, @avatar, @avatarextension, @data);";
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", Guid.NewGuid() },
|
||||||
|
{ "userid", row["Id"] },
|
||||||
|
{ "displayname", row["Email"] },
|
||||||
|
{ "quip", "" },
|
||||||
|
{ "avatar", avatarData.Rows.Count > 0 ? avatarData.Rows[0]["Avatar"] : null },
|
||||||
|
{ "avatarextension", avatarData.Rows.Count > 0 ? ".jpg" : null },
|
||||||
|
{ "data", "{}" }
|
||||||
|
};
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -279,9 +308,10 @@ namespace gaseous_server.Classes
|
|||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM Games_Roms WHERE RomDataVersion = 1;";
|
string sql = "SELECT * FROM Games_Roms WHERE RomDataVersion = 1;";
|
||||||
DataTable data = db.ExecuteCMD(sql);
|
DataTable data = db.ExecuteCMD(sql);
|
||||||
|
long count = 1;
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Database Migration", "Updating ROM table for ROM: " + (string)row["Name"]);
|
Logging.Log(Logging.LogType.Information, "Database Migration", "Updating ROM table for ROM (" + count + " / " + data.Rows.Count + "): " + (string)row["Name"]);
|
||||||
|
|
||||||
GameLibrary.LibraryItem library = GameLibrary.GetLibrary((int)row["LibraryId"]);
|
GameLibrary.LibraryItem library = GameLibrary.GetLibrary((int)row["LibraryId"]);
|
||||||
Common.hashObject hash = new Common.hashObject()
|
Common.hashObject hash = new Common.hashObject()
|
||||||
@@ -300,6 +330,8 @@ namespace gaseous_server.Classes
|
|||||||
Game game = Games.GetGame((long)row["GameId"], false, false, false);
|
Game game = Games.GetGame((long)row["GameId"], false, false, false);
|
||||||
|
|
||||||
ImportGame.StoreROM(library, hash, game, platform, signature, (string)row["Path"], (long)row["Id"]);
|
ImportGame.StoreROM(library, hash, game, platform, signature, (string)row["Path"], (long)row["Id"]);
|
||||||
|
|
||||||
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Net;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using HasheousClient.Models;
|
using HasheousClient.Models;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
@@ -192,37 +193,45 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Checking signature for file: " + GameFileImportPath + "\nMD5 hash: " + hash.md5hash + "\nSHA1 hash: " + hash.sha1hash);
|
Logging.Log(Logging.LogType.Information, "Import Game", "Checking signature for file: " + GameFileImportPath + "\nMD5 hash: " + hash.md5hash + "\nSHA1 hash: " + hash.sha1hash);
|
||||||
|
|
||||||
|
|
||||||
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
gaseous_server.Models.Signatures_Games? discoveredSignature = null;
|
||||||
|
|
||||||
// do database search first
|
// begin signature search
|
||||||
gaseous_server.Models.Signatures_Games? dbSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
switch (Config.MetadataConfiguration.SignatureSource)
|
||||||
|
|
||||||
if (dbSignature != null)
|
|
||||||
{
|
{
|
||||||
// local signature found
|
case HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly:
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous disabled - searching local database only");
|
||||||
discoveredSignature = dbSignature;
|
|
||||||
|
discoveredSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HasheousClient.Models.MetadataModel.SignatureSources.Hasheous:
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous enabled - searching Hashesous and then local database if not found");
|
||||||
|
|
||||||
|
discoveredSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
|
||||||
|
if (discoveredSignature == null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in Hasheous - checking local database");
|
||||||
|
|
||||||
|
discoveredSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + discoveredSignature.Game.Name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (discoveredSignature == null)
|
||||||
{
|
{
|
||||||
// no local signature attempt to pull from Hasheous
|
// construct a signature from file data
|
||||||
dbSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in local database or Hasheous (if enabled) - generating from file data");
|
||||||
|
|
||||||
if (dbSignature != null)
|
discoveredSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||||
{
|
|
||||||
// signature retrieved from Hasheous
|
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
|
||||||
|
|
||||||
discoveredSignature = dbSignature;
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + discoveredSignature.Game.Name);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// construct a signature from file data
|
|
||||||
dbSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
|
||||||
|
|
||||||
discoveredSignature = dbSignature;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
||||||
@@ -290,65 +299,87 @@ namespace gaseous_server.Classes
|
|||||||
MD5 = hash.md5hash,
|
MD5 = hash.md5hash,
|
||||||
SHA1 = hash.sha1hash
|
SHA1 = hash.sha1hash
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (HasheousResult != null)
|
||||||
|
{
|
||||||
|
if (HasheousResult.Signature != null)
|
||||||
|
{
|
||||||
|
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
||||||
|
string gameJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Game);
|
||||||
|
string romJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Rom);
|
||||||
|
signature.Game = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.GameItem>(gameJson);
|
||||||
|
signature.Rom = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.RomItem>(romJson);
|
||||||
|
|
||||||
|
// get platform metadata
|
||||||
|
if (HasheousResult.Platform != null)
|
||||||
|
{
|
||||||
|
if (HasheousResult.Platform.metadata.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Platform.metadata)
|
||||||
|
{
|
||||||
|
if (metadataResult.Id.Length > 0)
|
||||||
|
{
|
||||||
|
switch (metadataResult.Source)
|
||||||
|
{
|
||||||
|
case HasheousClient.Models.MetadataSources.IGDB:
|
||||||
|
signature.Flags.IGDBPlatformId = (long)Platforms.GetPlatform(metadataResult.Id, false).Id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get game metadata
|
||||||
|
if (HasheousResult.Metadata != null)
|
||||||
|
{
|
||||||
|
if (HasheousResult.Metadata.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Metadata)
|
||||||
|
{
|
||||||
|
if (metadataResult.Id.Length > 0)
|
||||||
|
{
|
||||||
|
switch (metadataResult.Source)
|
||||||
|
{
|
||||||
|
case HasheousClient.Models.MetadataSources.IGDB:
|
||||||
|
signature.Flags.IGDBGameId = (long)Games.GetGame(metadataResult.Id, false, false, false).Id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AggregateException aggEx)
|
||||||
|
{
|
||||||
|
foreach (Exception ex in aggEx.InnerExceptions)
|
||||||
|
{
|
||||||
|
// get exception type
|
||||||
|
if (ex is HttpRequestException)
|
||||||
|
{
|
||||||
|
if (ex.Message.Contains("404 (Not Found)"))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "No signature found in Hasheous");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Import Game", "An error occurred while importing " + ImageName, ex);
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasheousResult != null)
|
|
||||||
{
|
|
||||||
if (HasheousResult.Signature != null)
|
|
||||||
{
|
|
||||||
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
|
||||||
string gameJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Game);
|
|
||||||
string romJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Rom);
|
|
||||||
signature.Game = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.GameItem>(gameJson);
|
|
||||||
signature.Rom = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.RomItem>(romJson);
|
|
||||||
|
|
||||||
// get platform metadata
|
|
||||||
if (HasheousResult.Platform != null)
|
|
||||||
{
|
|
||||||
if (HasheousResult.Platform.metadata.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Platform.metadata)
|
|
||||||
{
|
|
||||||
if (metadataResult.Id.Length > 0)
|
|
||||||
{
|
|
||||||
switch (metadataResult.Source)
|
|
||||||
{
|
|
||||||
case HasheousClient.Models.MetadataSources.IGDB:
|
|
||||||
signature.Flags.IGDBPlatformId = (long)Platforms.GetPlatform(metadataResult.Id, false).Id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get game metadata
|
|
||||||
if (HasheousResult.Metadata != null)
|
|
||||||
{
|
|
||||||
if (HasheousResult.Metadata.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Metadata)
|
|
||||||
{
|
|
||||||
if (metadataResult.Id.Length > 0)
|
|
||||||
{
|
|
||||||
switch (metadataResult.Source)
|
|
||||||
{
|
|
||||||
case HasheousClient.Models.MetadataSources.IGDB:
|
|
||||||
signature.Flags.IGDBGameId = (long)Games.GetGame(metadataResult.Id, false, false, false).Id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, Games_Roms.PlatformId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id GROUP BY Platform.`Name`;";
|
string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, Games_Roms.PlatformId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id GROUP BY Platform.`Name`;";
|
||||||
|
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ namespace gaseous_server.Classes
|
|||||||
// age groups
|
// age groups
|
||||||
List<FilterItem> agegroupings = new List<FilterItem>();
|
List<FilterItem> agegroupings = new List<FilterItem>();
|
||||||
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id HAVING RomCount > 0) Game GROUP BY Game.AgeGroupId ORDER BY Game.AgeGroupId DESC";
|
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id HAVING RomCount > 0) Game GROUP BY Game.AgeGroupId ORDER BY Game.AgeGroupId DESC";
|
||||||
dbResponse = db.ExecuteCMD(sql);
|
dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||||
|
|
||||||
foreach (DataRow dr in dbResponse.Rows)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -114,7 +114,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + AgeRestriction + ") GROUP BY Game.Id HAVING RomCount > 0) Game JOIN Relation_Game_<ITEMNAME>s ON Game.Id = Relation_Game_<ITEMNAME>s.GameId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
|
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + AgeRestriction + ") GROUP BY Game.Id HAVING RomCount > 0) Game JOIN Relation_Game_<ITEMNAME>s ON Game.Id = Relation_Game_<ITEMNAME>s.GameId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
|
||||||
sql = sql.Replace("<ITEMNAME>", Name);
|
sql = sql.Replace("<ITEMNAME>", Name);
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||||
|
|
||||||
return dbResponse;
|
return dbResponse;
|
||||||
}
|
}
|
||||||
|
@@ -7,37 +7,37 @@ using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow;
|
|||||||
|
|
||||||
namespace gaseous_server
|
namespace gaseous_server
|
||||||
{
|
{
|
||||||
public static class GameLibrary
|
public static class GameLibrary
|
||||||
{
|
{
|
||||||
// exceptions
|
// exceptions
|
||||||
public class PathExists : Exception
|
public class PathExists : Exception
|
||||||
{
|
{
|
||||||
public PathExists(string path) : base("The library path " + path + " already exists.")
|
public PathExists(string path) : base("The library path " + path + " already exists.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PathNotFound : Exception
|
public class PathNotFound : Exception
|
||||||
{
|
{
|
||||||
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LibraryNotFound : Exception
|
public class LibraryNotFound : Exception
|
||||||
{
|
{
|
||||||
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CannotDeleteDefaultLibrary : Exception
|
public class CannotDeleteDefaultLibrary : Exception
|
||||||
{
|
{
|
||||||
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
||||||
{
|
{
|
||||||
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// code
|
// code
|
||||||
@@ -66,7 +66,7 @@ namespace gaseous_server
|
|||||||
{
|
{
|
||||||
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM GameLibraries";
|
string sql = "SELECT * FROM GameLibraries ORDER BY `Name`;";
|
||||||
DataTable data = db.ExecuteCMD(sql);
|
DataTable data = db.ExecuteCMD(sql);
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
@@ -129,7 +129,7 @@ namespace gaseous_server
|
|||||||
if (library.IsDefaultLibrary == false)
|
if (library.IsDefaultLibrary == false)
|
||||||
{
|
{
|
||||||
// check for active library scans
|
// check for active library scans
|
||||||
foreach(ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
||||||
|
@@ -47,8 +47,11 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
public Dictionary<string, object> ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||||
{
|
{
|
||||||
|
Dictionary<string, object> RetVal = new Dictionary<string, object>();
|
||||||
|
RetVal.Add("path", Path.GetFileName(GameFileImportPath));
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
@@ -67,6 +70,8 @@ namespace gaseous_server.Classes
|
|||||||
if (IsBios == null)
|
if (IsBios == null)
|
||||||
{
|
{
|
||||||
// file is a rom
|
// file is a rom
|
||||||
|
RetVal.Add("type", "rom");
|
||||||
|
|
||||||
// check to make sure we don't already have this file imported
|
// check to make sure we don't already have this file imported
|
||||||
sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
|
sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
|
||||||
dbDict.Add("md5", hash.md5hash);
|
dbDict.Add("md5", hash.md5hash);
|
||||||
@@ -94,6 +99,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RetVal.Add("status", "duplicate");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -122,17 +129,27 @@ namespace gaseous_server.Classes
|
|||||||
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
||||||
|
|
||||||
// add to database
|
// add to database
|
||||||
StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
long RomId = StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
||||||
|
|
||||||
|
// build return value
|
||||||
|
RetVal.Add("romid", RomId);
|
||||||
|
RetVal.Add("platform", determinedPlatform);
|
||||||
|
RetVal.Add("game", determinedGame);
|
||||||
|
RetVal.Add("signature", discoveredSignature);
|
||||||
|
RetVal.Add("status", "imported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// file is a bios
|
// file is a bios
|
||||||
if (IsBios.WebEmulator != null)
|
RetVal.Add("type", "bios");
|
||||||
|
RetVal.Add("status", "notimported");
|
||||||
|
|
||||||
|
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios())
|
||||||
{
|
{
|
||||||
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios())
|
if (biosItem.Available == false)
|
||||||
{
|
{
|
||||||
if (biosItem.Available == false && biosItem.hash == hash.md5hash)
|
if (biosItem.hash == hash.md5hash)
|
||||||
{
|
{
|
||||||
string biosPath = biosItem.biosPath.Replace(biosItem.filename, "");
|
string biosPath = biosItem.biosPath.Replace(biosItem.filename, "");
|
||||||
if (!Directory.Exists(biosPath))
|
if (!Directory.Exists(biosPath))
|
||||||
@@ -142,12 +159,26 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
File.Move(GameFileImportPath, biosItem.biosPath, true);
|
File.Move(GameFileImportPath, biosItem.biosPath, true);
|
||||||
|
|
||||||
break;
|
RetVal.Add("name", biosItem.filename);
|
||||||
|
RetVal.Add("platform", Platforms.GetPlatform(biosItem.platformid, false, false));
|
||||||
|
RetVal["status"] = "imported";
|
||||||
|
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (biosItem.hash == hash.md5hash)
|
||||||
|
{
|
||||||
|
RetVal["status"] = "duplicate";
|
||||||
|
return RetVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return RetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||||
|
@@ -3,10 +3,11 @@ using System.Data;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata.Ecma335;
|
using System.Reflection.Metadata.Ecma335;
|
||||||
|
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class Logging
|
public class Logging
|
||||||
{
|
{
|
||||||
private static DateTime lastDiskRetentionSweep = DateTime.UtcNow;
|
private static DateTime lastDiskRetentionSweep = DateTime.UtcNow;
|
||||||
public static bool WriteToDiskOnly { get; set; } = false;
|
public static bool WriteToDiskOnly { get; set; } = false;
|
||||||
|
|
||||||
@@ -21,8 +22,13 @@ namespace gaseous_server.Classes
|
|||||||
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_ = Task.Run(() => WriteLogAsync(logItem, LogToDiskOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task WriteLogAsync(LogItem logItem, bool LogToDiskOnly)
|
||||||
|
{
|
||||||
bool AllowWrite = false;
|
bool AllowWrite = false;
|
||||||
if (EventType == LogType.Debug)
|
if (logItem.EventType == LogType.Debug)
|
||||||
{
|
{
|
||||||
if (Config.LoggingConfiguration.DebugLogging == true)
|
if (Config.LoggingConfiguration.DebugLogging == true)
|
||||||
{
|
{
|
||||||
@@ -42,26 +48,32 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
||||||
}
|
}
|
||||||
switch(logItem.EventType) {
|
string consoleColour = "";
|
||||||
|
switch (logItem.EventType)
|
||||||
|
{
|
||||||
case LogType.Information:
|
case LogType.Information:
|
||||||
Console.ForegroundColor = ConsoleColor.Blue;
|
// Console.ForegroundColor = ConsoleColor.Blue;
|
||||||
|
consoleColour = "\u001b[1;34m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Warning:
|
case LogType.Warning:
|
||||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
// Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
consoleColour = "\u001b[1;33m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Critical:
|
case LogType.Critical:
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
// Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
consoleColour = "\u001b[1;31m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Debug:
|
case LogType.Debug:
|
||||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
// Console.ForegroundColor = ConsoleColor.Magenta;
|
||||||
|
consoleColour = "\u001b[1;36m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
Console.WriteLine(TraceOutput);
|
Console.WriteLine(consoleColour + TraceOutput);
|
||||||
Console.ResetColor();
|
// Console.ResetColor();
|
||||||
|
|
||||||
if (WriteToDiskOnly == true)
|
if (WriteToDiskOnly == true)
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ using Microsoft.VisualStudio.Web.CodeGeneration;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class Maintenance : QueueItemStatus
|
public class Maintenance : QueueItemStatus
|
||||||
{
|
{
|
||||||
const int MaxFileAge = 30;
|
const int MaxFileAge = 30;
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ namespace gaseous_server.Classes
|
|||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
// remove any entries from the library that have an invalid id
|
// 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 = "";
|
string LibraryWhereClause = "";
|
||||||
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||||
{
|
{
|
||||||
@@ -33,9 +34,29 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete old logs
|
// 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 = 10000;
|
||||||
|
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate LIMIT 1000; SELECT ROW_COUNT() AS Count;";
|
||||||
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||||
db.ExecuteCMD(sql, dbDict);
|
while (deletedCount > 0)
|
||||||
|
{
|
||||||
|
DataTable deletedCountTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
deletedCount = (long)deletedCountTable.Rows[0][0];
|
||||||
|
deletedEventCount += deletedCount;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Deleted " + deletedCount + " log entries");
|
||||||
|
|
||||||
|
// 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
|
// delete files and directories older than 7 days in PathsToClean
|
||||||
List<string> PathsToClean = new List<string>();
|
List<string> PathsToClean = new List<string>();
|
||||||
@@ -87,7 +108,7 @@ namespace gaseous_server.Classes
|
|||||||
SetStatus(StatusCounter, tables.Rows.Count, "Optimising table " + row[0].ToString());
|
SetStatus(StatusCounter, tables.Rows.Count, "Optimising table " + row[0].ToString());
|
||||||
|
|
||||||
sql = "OPTIMIZE 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)
|
foreach (DataRow responseRow in response.Rows)
|
||||||
{
|
{
|
||||||
string retVal = "";
|
string retVal = "";
|
||||||
|
@@ -216,44 +216,48 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Adult_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_Z },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Eighteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Eighteen },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Eighteen },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_18 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Mature_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Sixteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.M },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Fifteen },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Sixteen },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Teen_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_PG },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_B },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.T },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Twelve },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Twelve },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_12 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Child_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_G },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_A },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.EC, AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_All },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Three, AgeRatingTitle.Seven },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_0, AgeRatingTitle.USK_6 }
|
||||||
};
|
};
|
||||||
|
|
||||||
public class AgeGroupItem
|
public class AgeGroupItem
|
||||||
|
@@ -5,7 +5,7 @@ using IGDB.Models;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
{
|
{
|
||||||
public class Artworks
|
public class Artworks
|
||||||
{
|
{
|
||||||
const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
||||||
|
|
||||||
@@ -74,7 +74,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
|
||||||
|
// check if old value is different from the new value - only download if it's different
|
||||||
|
Artwork oldImage = Storage.GetCacheValue<Artwork>(returnValue, "id", (long)searchValue);
|
||||||
|
if (oldImage.ImageId != returnValue.ImageId)
|
||||||
|
{
|
||||||
|
forceImageDownload = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -120,6 +126,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -195,6 +195,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (InRateLimitAvoidanceMode == true)
|
if (InRateLimitAvoidanceMode == true)
|
||||||
{
|
{
|
||||||
// sleep for a moment to help avoid hitting the rate limiter
|
// sleep for a moment to help avoid hitting the rate limiter
|
||||||
|
Logging.Log(Logging.LogType.Information, "API Connection: Endpoint:" + Endpoint, "IGDB rate limit hit. Pausing API communications for " + RateLimitAvoidanceWait + " milliseconds to avoid rate limiter.");
|
||||||
Thread.Sleep(RateLimitAvoidanceWait);
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +246,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, ex);
|
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, ex);
|
||||||
throw;
|
throw;
|
||||||
@@ -393,6 +394,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (InRateLimitAvoidanceMode == true)
|
if (InRateLimitAvoidanceMode == true)
|
||||||
{
|
{
|
||||||
// sleep for a moment to help avoid hitting the rate limiter
|
// sleep for a moment to help avoid hitting the rate limiter
|
||||||
|
Logging.Log(Logging.LogType.Information, "API Connection: Fetch Image", "IGDB rate limit hit. Pausing API communications for " + RateLimitAvoidanceWait + " milliseconds to avoid rate limiter.");
|
||||||
Thread.Sleep(RateLimitAvoidanceWait);
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,7 +76,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
|
||||||
|
// check if old value is different from the new value - only download if it's different
|
||||||
|
CompanyLogo oldImage = Storage.GetCacheValue<CompanyLogo>(returnValue, "id", (long)searchValue);
|
||||||
|
if (oldImage.ImageId != returnValue.ImageId)
|
||||||
|
{
|
||||||
|
forceImageDownload = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Elfie.Model.Strings;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
{
|
{
|
||||||
public class Covers
|
public class Covers
|
||||||
{
|
{
|
||||||
const string fieldList = "fields alpha_channel,animated,checksum,game,game_localization,height,image_id,url,width;";
|
const string fieldList = "fields alpha_channel,animated,checksum,game,game_localization,height,image_id,url,width;";
|
||||||
|
|
||||||
@@ -76,7 +76,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
|
||||||
|
// check if old value is different from the new value - only download if it's different
|
||||||
|
Cover oldCover = Storage.GetCacheValue<Cover>(returnValue, "id", (long)searchValue);
|
||||||
|
if (oldCover.ImageId != returnValue.ImageId)
|
||||||
|
{
|
||||||
|
forceImageDownload = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -135,6 +141,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
public class Games
|
public class Games
|
||||||
{
|
{
|
||||||
const string fieldList = "fields age_ratings,aggregated_rating,aggregated_rating_count,alternative_names,artworks,bundles,category,checksum,collection,collections,cover,created_at,dlcs,expanded_games,expansions,external_games,first_release_date,follows,forks,franchise,franchises,game_engines,game_localizations,game_modes,genres,hypes,involved_companies,keywords,language_supports,multiplayer_modes,name,parent_game,platforms,player_perspectives,ports,rating,rating_count,release_dates,remakes,remasters,screenshots,similar_games,slug,standalone_expansions,status,storyline,summary,tags,themes,total_rating,total_rating_count,updated_at,url,version_parent,version_title,videos,websites;";
|
const string fieldList = "fields age_ratings,aggregated_rating,aggregated_rating_count,alternative_names,artworks,bundles,category,checksum,collections,cover,created_at,dlcs,expanded_games,expansions,external_games,first_release_date,follows,forks,franchise,franchises,game_engines,game_localizations,game_modes,genres,hypes,involved_companies,keywords,language_supports,multiplayer_modes,name,parent_game,platforms,player_perspectives,ports,rating,rating_count,release_dates,remakes,remasters,screenshots,similar_games,slug,standalone_expansions,status,storyline,summary,tags,themes,total_rating,total_rating_count,updated_at,url,version_parent,version_title,videos,websites;";
|
||||||
|
|
||||||
public Games()
|
public Games()
|
||||||
{
|
{
|
||||||
@@ -127,17 +128,17 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||||
{
|
{
|
||||||
// required metadata
|
// required metadata
|
||||||
if (Game.Cover != null)
|
// if (Game.Cover != null)
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
// Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
// Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (Game.Genres != null)
|
if (Game.Genres != null)
|
||||||
{
|
{
|
||||||
@@ -504,24 +505,155 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<KeyValuePair<long, string>> GetAvailablePlatforms(long GameId)
|
public static List<AvailablePlatformItem> GetAvailablePlatforms(string UserId, long GameId)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @gameid ORDER BY Platform.`Name`;";
|
string sql = @"
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
SELECT DISTINCT
|
||||||
dbDict.Add("gameid", GameId);
|
Games_Roms.GameId,
|
||||||
|
Games_Roms.PlatformId,
|
||||||
|
Platform.`Name`,
|
||||||
|
User_RecentPlayedRoms.UserId AS MostRecentUserId,
|
||||||
|
User_RecentPlayedRoms.RomId AS MostRecentRomId,
|
||||||
|
CASE User_RecentPlayedRoms.IsMediaGroup
|
||||||
|
WHEN 0 THEN GMR.`Name`
|
||||||
|
WHEN 1 THEN 'Media Group'
|
||||||
|
ELSE NULL
|
||||||
|
END AS `MostRecentRomName`,
|
||||||
|
User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup,
|
||||||
|
User_GameFavouriteRoms.UserId AS FavouriteUserId,
|
||||||
|
User_GameFavouriteRoms.RomId AS FavouriteRomId,
|
||||||
|
CASE User_GameFavouriteRoms.IsMediaGroup
|
||||||
|
WHEN 0 THEN GFV.`Name`
|
||||||
|
WHEN 1 THEN 'Media Group'
|
||||||
|
ELSE NULL
|
||||||
|
END AS `FavouriteRomName`,
|
||||||
|
User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup
|
||||||
|
FROM
|
||||||
|
Games_Roms
|
||||||
|
LEFT JOIN
|
||||||
|
Platform ON Games_Roms.PlatformId = Platform.Id
|
||||||
|
LEFT JOIN
|
||||||
|
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||||
|
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId
|
||||||
|
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId
|
||||||
|
LEFT JOIN
|
||||||
|
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||||
|
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId
|
||||||
|
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId
|
||||||
|
LEFT JOIN
|
||||||
|
Games_Roms AS GMR ON GMR.Id = User_RecentPlayedRoms.RomId
|
||||||
|
LEFT JOIN
|
||||||
|
Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId
|
||||||
|
WHERE
|
||||||
|
Games_Roms.GameId = @gameid
|
||||||
|
ORDER BY Platform.`Name`;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", UserId }
|
||||||
|
};
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<KeyValuePair<long, string>> platforms = new List<KeyValuePair<long, string>>();
|
PlatformMapping platformMapping = new PlatformMapping();
|
||||||
|
List<AvailablePlatformItem> platforms = new List<AvailablePlatformItem>();
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
KeyValuePair<long, string> valuePair = new KeyValuePair<long, string>((long)row["PlatformId"], (string)row["Name"]);
|
IGDB.Models.Platform platform = Platforms.GetPlatform((long)row["PlatformId"]);
|
||||||
|
PlatformMapping.UserEmulatorConfiguration? emulatorConfiguration = platformMapping.GetUserEmulator(UserId, GameId, (long)platform.Id);
|
||||||
|
|
||||||
|
if (emulatorConfiguration == null)
|
||||||
|
{
|
||||||
|
if (platform.Id != 0)
|
||||||
|
{
|
||||||
|
Models.PlatformMapping.PlatformMapItem platformMap = PlatformMapping.GetPlatformMap((long)platform.Id);
|
||||||
|
emulatorConfiguration = new PlatformMapping.UserEmulatorConfiguration
|
||||||
|
{
|
||||||
|
EmulatorType = platformMap.WebEmulator.Type,
|
||||||
|
Core = platformMap.WebEmulator.Core,
|
||||||
|
EnableBIOSFiles = platformMap.EnabledBIOSHashes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long? LastPlayedRomId = null;
|
||||||
|
bool? LastPlayedIsMediagroup = false;
|
||||||
|
string? LastPlayedRomName = null;
|
||||||
|
if (row["MostRecentRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
LastPlayedRomId = (long?)row["MostRecentRomId"];
|
||||||
|
LastPlayedIsMediagroup = (bool)row["MostRecentRomIsMediaGroup"];
|
||||||
|
LastPlayedRomName = (string)row["MostRecentRomName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
long? FavouriteRomId = null;
|
||||||
|
bool? FavouriteRomIsMediagroup = false;
|
||||||
|
string? FavouriteRomName = null;
|
||||||
|
if (row["FavouriteRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
FavouriteRomId = (long?)row["FavouriteRomId"];
|
||||||
|
FavouriteRomIsMediagroup = (bool)row["FavouriteRomIsMediaGroup"];
|
||||||
|
FavouriteRomName = (string)row["FavouriteRomName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
AvailablePlatformItem valuePair = new AvailablePlatformItem
|
||||||
|
{
|
||||||
|
Id = platform.Id,
|
||||||
|
Name = platform.Name,
|
||||||
|
Category = platform.Category,
|
||||||
|
emulatorConfiguration = emulatorConfiguration,
|
||||||
|
LastPlayedRomId = LastPlayedRomId,
|
||||||
|
LastPlayedRomIsMediagroup = LastPlayedIsMediagroup,
|
||||||
|
LastPlayedRomName = LastPlayedRomName,
|
||||||
|
FavouriteRomId = FavouriteRomId,
|
||||||
|
FavouriteRomIsMediagroup = FavouriteRomIsMediagroup,
|
||||||
|
FavouriteRomName = FavouriteRomName
|
||||||
|
};
|
||||||
platforms.Add(valuePair);
|
platforms.Add(valuePair);
|
||||||
}
|
}
|
||||||
|
|
||||||
return platforms;
|
return platforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void GameSetFavouriteRom(string UserId, long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "DELETE FROM User_GameFavouriteRoms WHERE UserId = @userid AND GameId = @gameid AND PlatformId = @platformid; INSERT INTO User_GameFavouriteRoms (UserId, GameId, PlatformId, RomId, IsMediaGroup) VALUES (@userid, @gameid, @platformid, @romid, @ismediagroup);";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "platformid", PlatformId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GameClearFavouriteRom(string UserId, long GameId, long PlatformId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "DELETE FROM User_GameFavouriteRoms WHERE UserId = @userid AND GameId = @gameid AND PlatformId = @platformid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "platformid", PlatformId }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AvailablePlatformItem : IGDB.Models.Platform
|
||||||
|
{
|
||||||
|
public PlatformMapping.UserEmulatorConfiguration emulatorConfiguration { get; set; }
|
||||||
|
public long? LastPlayedRomId { get; set; }
|
||||||
|
public bool? LastPlayedRomIsMediagroup { get; set; }
|
||||||
|
public string? LastPlayedRomName { get; set; }
|
||||||
|
public long? FavouriteRomId { get; set; }
|
||||||
|
public bool? FavouriteRomIsMediagroup { get; set; }
|
||||||
|
public string? FavouriteRomName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public enum SearchType
|
public enum SearchType
|
||||||
{
|
{
|
||||||
where = 0,
|
where = 0,
|
||||||
@@ -542,6 +674,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
this.Id = gameObject.Id;
|
this.Id = gameObject.Id;
|
||||||
this.Name = gameObject.Name;
|
this.Name = gameObject.Name;
|
||||||
this.Slug = gameObject.Slug;
|
this.Slug = gameObject.Slug;
|
||||||
|
this.Summary = gameObject.Summary;
|
||||||
this.TotalRating = gameObject.TotalRating;
|
this.TotalRating = gameObject.TotalRating;
|
||||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||||
this.Cover = gameObject.Cover;
|
this.Cover = gameObject.Cover;
|
||||||
@@ -567,6 +700,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
public long Index { get; set; }
|
public long Index { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
|
public string Summary { get; set; }
|
||||||
public double? TotalRating { get; set; }
|
public double? TotalRating { get; set; }
|
||||||
public int? TotalRatingCount { get; set; }
|
public int? TotalRatingCount { get; set; }
|
||||||
public bool HasSavedGame { get; set; } = false;
|
public bool HasSavedGame { get; set; } = false;
|
||||||
|
@@ -76,7 +76,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
|
||||||
|
// check if old value is different from the new value - only download if it's different
|
||||||
|
PlatformLogo oldImage = Storage.GetCacheValue<PlatformLogo>(returnValue, "id", (long)searchValue);
|
||||||
|
if (oldImage.ImageId != returnValue.ImageId)
|
||||||
|
{
|
||||||
|
forceImageDownload = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -5,15 +5,15 @@ using IGDB.Models;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
{
|
{
|
||||||
public class PlatformVersions
|
public class PlatformVersions
|
||||||
{
|
{
|
||||||
const string fieldList = "fields checksum,companies,connectivity,cpu,graphics,main_manufacturer,media,memory,name,online,os,output,platform_logo,platform_version_release_dates,resolutions,slug,sound,storage,summary,url;";
|
const string fieldList = "fields checksum,companies,connectivity,cpu,graphics,main_manufacturer,media,memory,name,online,os,output,platform_logo,platform_version_release_dates,resolutions,slug,sound,storage,summary,url;";
|
||||||
|
|
||||||
public PlatformVersions()
|
public PlatformVersions()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform)
|
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform, bool GetImages = false)
|
||||||
{
|
{
|
||||||
if (Id == 0)
|
if (Id == 0)
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform);
|
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform)
|
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages = false)
|
||||||
{
|
{
|
||||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform);
|
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform, GetImages);
|
||||||
return RetVal.Result;
|
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
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -67,7 +67,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (returnValue != null)
|
if (returnValue != null)
|
||||||
{
|
{
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
UpdateSubClasses(ParentPlatform, returnValue);
|
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
@@ -75,7 +75,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
UpdateSubClasses(ParentPlatform, returnValue);
|
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -90,17 +90,20 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion)
|
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion, bool GetImages)
|
||||||
{
|
{
|
||||||
if (platformVersion.PlatformLogo != null)
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
try
|
if (platformVersion.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(ParentPlatform), "Versions", platformVersion.Slug));
|
try
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(ParentPlatform), "Versions", platformVersion.Slug));
|
||||||
{
|
}
|
||||||
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
if (Id == 0)
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh);
|
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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;
|
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
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -99,7 +99,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
UpdateSubClasses(returnValue);
|
UpdateSubClasses(returnValue, GetImages);
|
||||||
AddPlatformMapping(returnValue);
|
AddPlatformMapping(returnValue);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
@@ -107,7 +107,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
UpdateSubClasses(returnValue);
|
UpdateSubClasses(returnValue, GetImages);
|
||||||
AddPlatformMapping(returnValue);
|
AddPlatformMapping(returnValue);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSubClasses(Platform platform)
|
private static void UpdateSubClasses(Platform platform, bool GetImages)
|
||||||
{
|
{
|
||||||
if (platform.Versions != null)
|
if (platform.Versions != null)
|
||||||
{
|
{
|
||||||
@@ -133,15 +133,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (platform.PlatformLogo != null)
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
try
|
if (platform.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platform.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platform));
|
try
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platform.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platform));
|
||||||
{
|
}
|
||||||
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ using IGDB.Models;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
{
|
{
|
||||||
public class Screenshots
|
public class Screenshots
|
||||||
{
|
{
|
||||||
const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
||||||
|
|
||||||
@@ -74,7 +74,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
forceImageDownload = true;
|
|
||||||
|
// check if old value is different from the new value - only download if it's different
|
||||||
|
Screenshot oldImage = Storage.GetCacheValue<Screenshot>(returnValue, "id", (long)searchValue);
|
||||||
|
if (oldImage.ImageId != returnValue.ImageId)
|
||||||
|
{
|
||||||
|
forceImageDownload = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -120,6 +126,6 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,19 +7,19 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes.Metadata
|
namespace gaseous_server.Classes.Metadata
|
||||||
{
|
{
|
||||||
public class Storage
|
public class Storage
|
||||||
{
|
{
|
||||||
public enum CacheStatus
|
public enum CacheStatus
|
||||||
{
|
{
|
||||||
NotPresent,
|
NotPresent,
|
||||||
Current,
|
Current,
|
||||||
Expired
|
Expired
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CacheStatus GetCacheStatus(string Endpoint, string Slug)
|
public static CacheStatus GetCacheStatus(string Endpoint, string Slug)
|
||||||
{
|
{
|
||||||
return _GetCacheStatus(Endpoint, "slug", Slug);
|
return _GetCacheStatus(Endpoint, "slug", Slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CacheStatus GetCacheStatus(string Endpoint, long Id)
|
public static CacheStatus GetCacheStatus(string Endpoint, long Id)
|
||||||
{
|
{
|
||||||
@@ -47,124 +47,124 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static CacheStatus _GetCacheStatus(string Endpoint, string SearchField, object SearchValue)
|
private static CacheStatus _GetCacheStatus(string Endpoint, string SearchField, object SearchValue)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
string sql = "SELECT lastUpdated FROM " + Endpoint + " WHERE " + SearchField + " = @" + SearchField;
|
string sql = "SELECT lastUpdated FROM " + Endpoint + " WHERE " + SearchField + " = @" + SearchField;
|
||||||
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("Endpoint", Endpoint);
|
dbDict.Add("Endpoint", Endpoint);
|
||||||
dbDict.Add(SearchField, SearchValue);
|
dbDict.Add(SearchField, SearchValue);
|
||||||
|
|
||||||
DataTable dt = db.ExecuteCMD(sql, dbDict);
|
DataTable dt = db.ExecuteCMD(sql, dbDict);
|
||||||
if (dt.Rows.Count == 0)
|
if (dt.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no data stored for this item, or lastUpdated
|
// no data stored for this item, or lastUpdated
|
||||||
return CacheStatus.NotPresent;
|
return CacheStatus.NotPresent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DateTime CacheExpiryTime = DateTime.UtcNow.AddHours(-168);
|
DateTime CacheExpiryTime = DateTime.UtcNow.AddHours(-168);
|
||||||
if ((DateTime)dt.Rows[0]["lastUpdated"] < CacheExpiryTime)
|
if ((DateTime)dt.Rows[0]["lastUpdated"] < CacheExpiryTime)
|
||||||
{
|
{
|
||||||
return CacheStatus.Expired;
|
return CacheStatus.Expired;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return CacheStatus.Current;
|
return CacheStatus.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewCacheValue(object ObjectToCache, bool UpdateRecord = false)
|
public static void NewCacheValue(object ObjectToCache, bool UpdateRecord = false)
|
||||||
{
|
{
|
||||||
// get the object type name
|
// get the object type name
|
||||||
string ObjectTypeName = ObjectToCache.GetType().Name;
|
string ObjectTypeName = ObjectToCache.GetType().Name;
|
||||||
|
|
||||||
// build dictionary
|
// build dictionary
|
||||||
string objectJson = Newtonsoft.Json.JsonConvert.SerializeObject(ObjectToCache);
|
string objectJson = Newtonsoft.Json.JsonConvert.SerializeObject(ObjectToCache);
|
||||||
Dictionary<string, object?> objectDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object?>>(objectJson);
|
Dictionary<string, object?> objectDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object?>>(objectJson);
|
||||||
objectDict.Add("dateAdded", DateTime.UtcNow);
|
objectDict.Add("dateAdded", DateTime.UtcNow);
|
||||||
objectDict.Add("lastUpdated", DateTime.UtcNow);
|
objectDict.Add("lastUpdated", DateTime.UtcNow);
|
||||||
|
|
||||||
// generate sql
|
// generate sql
|
||||||
string fieldList = "";
|
string fieldList = "";
|
||||||
string valueList = "";
|
string valueList = "";
|
||||||
string updateFieldValueList = "";
|
string updateFieldValueList = "";
|
||||||
foreach (KeyValuePair<string, object?> key in objectDict)
|
foreach (KeyValuePair<string, object?> key in objectDict)
|
||||||
{
|
{
|
||||||
if (fieldList.Length > 0)
|
if (fieldList.Length > 0)
|
||||||
{
|
{
|
||||||
fieldList = fieldList + ", ";
|
fieldList = fieldList + ", ";
|
||||||
valueList = valueList + ", ";
|
valueList = valueList + ", ";
|
||||||
}
|
}
|
||||||
fieldList = fieldList + key.Key;
|
fieldList = fieldList + key.Key;
|
||||||
valueList = valueList + "@" + key.Key;
|
valueList = valueList + "@" + key.Key;
|
||||||
if ((key.Key != "id") && (key.Key != "dateAdded"))
|
if ((key.Key != "id") && (key.Key != "dateAdded"))
|
||||||
{
|
{
|
||||||
if (updateFieldValueList.Length > 0)
|
if (updateFieldValueList.Length > 0)
|
||||||
{
|
{
|
||||||
updateFieldValueList = updateFieldValueList + ", ";
|
updateFieldValueList = updateFieldValueList + ", ";
|
||||||
}
|
}
|
||||||
updateFieldValueList += key.Key + " = @" + key.Key;
|
updateFieldValueList += key.Key + " = @" + key.Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check property type
|
// check property type
|
||||||
Type objectType = ObjectToCache.GetType();
|
Type objectType = ObjectToCache.GetType();
|
||||||
if (objectType != null)
|
if (objectType != null)
|
||||||
{
|
{
|
||||||
PropertyInfo objectProperty = objectType.GetProperty(key.Key);
|
PropertyInfo objectProperty = objectType.GetProperty(key.Key);
|
||||||
if (objectProperty != null)
|
if (objectProperty != null)
|
||||||
{
|
{
|
||||||
string compareName = objectProperty.PropertyType.Name.ToLower().Split("`")[0];
|
string compareName = objectProperty.PropertyType.Name.ToLower().Split("`")[0];
|
||||||
var objectValue = objectProperty.GetValue(ObjectToCache);
|
var objectValue = objectProperty.GetValue(ObjectToCache);
|
||||||
if (objectValue != null)
|
if (objectValue != null)
|
||||||
{
|
{
|
||||||
string newObjectValue;
|
string newObjectValue;
|
||||||
Dictionary<string, object> newDict;
|
Dictionary<string, object> newDict;
|
||||||
switch (compareName)
|
switch (compareName)
|
||||||
{
|
{
|
||||||
case "identityorvalue":
|
case "identityorvalue":
|
||||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
||||||
newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
||||||
objectDict[key.Key] = newDict["Id"];
|
objectDict[key.Key] = newDict["Id"];
|
||||||
break;
|
break;
|
||||||
case "identitiesorvalues":
|
case "identitiesorvalues":
|
||||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
||||||
newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
||||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(newDict["Ids"]);
|
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(newDict["Ids"]);
|
||||||
objectDict[key.Key] = newObjectValue;
|
objectDict[key.Key] = newObjectValue;
|
||||||
|
|
||||||
StoreRelations(ObjectTypeName, key.Key, (long)objectDict["Id"], newObjectValue);
|
StoreRelations(ObjectTypeName, key.Key, (long)objectDict["Id"], newObjectValue);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "int32[]":
|
case "int32[]":
|
||||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
||||||
objectDict[key.Key] = newObjectValue;
|
objectDict[key.Key] = newObjectValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string sql = "";
|
string sql = "";
|
||||||
if (UpdateRecord == false)
|
if (UpdateRecord == false)
|
||||||
{
|
{
|
||||||
sql = "INSERT INTO " + ObjectTypeName + " (" + fieldList + ") VALUES (" + valueList + ")";
|
sql = "INSERT INTO " + ObjectTypeName + " (" + fieldList + ") VALUES (" + valueList + ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql = "UPDATE " + ObjectTypeName + " SET " + updateFieldValueList + " WHERE Id = @Id";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
sql = "UPDATE " + ObjectTypeName + " SET " + updateFieldValueList + " WHERE Id = @Id";
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute sql
|
// execute sql
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
db.ExecuteCMD(sql, objectDict);
|
db.ExecuteCMD(sql, objectDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T GetCacheValue<T>(T EndpointType, string SearchField, object SearchValue)
|
public static T GetCacheValue<T>(T EndpointType, string SearchField, object SearchValue)
|
||||||
{
|
{
|
||||||
string Endpoint = EndpointType.GetType().Name;
|
string Endpoint = EndpointType.GetType().Name;
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
@@ -175,23 +175,23 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
dbDict.Add("Endpoint", Endpoint);
|
dbDict.Add("Endpoint", Endpoint);
|
||||||
dbDict.Add(SearchField, SearchValue);
|
dbDict.Add(SearchField, SearchValue);
|
||||||
|
|
||||||
DataTable dt = db.ExecuteCMD(sql, dbDict);
|
DataTable dt = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromHours(8).Ticks));
|
||||||
if (dt.Rows.Count == 0)
|
if (dt.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no data stored for this item
|
// no data stored for this item
|
||||||
throw new Exception("No record found that matches endpoint " + Endpoint + " with search value " + SearchValue);
|
throw new Exception("No record found that matches endpoint " + Endpoint + " with search value " + SearchValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DataRow dataRow = dt.Rows[0];
|
DataRow dataRow = dt.Rows[0];
|
||||||
object returnObject = BuildCacheObject<T>(EndpointType, dataRow);
|
object returnObject = BuildCacheObject<T>(EndpointType, dataRow);
|
||||||
|
|
||||||
return (T)returnObject;
|
return (T)returnObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T BuildCacheObject<T>(T EndpointType, DataRow dataRow)
|
public static T BuildCacheObject<T>(T EndpointType, DataRow dataRow)
|
||||||
{
|
{
|
||||||
foreach (PropertyInfo property in EndpointType.GetType().GetProperties())
|
foreach (PropertyInfo property in EndpointType.GetType().GetProperties())
|
||||||
{
|
{
|
||||||
if (dataRow.Table.Columns.Contains(property.Name))
|
if (dataRow.Table.Columns.Contains(property.Name))
|
||||||
@@ -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
|
private class MemoryCacheObject
|
||||||
{
|
{
|
||||||
public object Object { get; set; }
|
public object Object { get; set; }
|
||||||
|
@@ -11,12 +11,12 @@ using gaseous_server.Models;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class RomMediaGroup
|
public class RomMediaGroup
|
||||||
{
|
{
|
||||||
public class InvalidMediaGroupId : Exception
|
public class InvalidMediaGroupId : Exception
|
||||||
{
|
{
|
||||||
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameRomMediaGroupItem CreateMediaGroup(long GameId, long PlatformId, List<long> RomIds)
|
public static GameRomMediaGroupItem CreateMediaGroup(long GameId, long PlatformId, List<long> RomIds)
|
||||||
@@ -81,14 +81,42 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "")
|
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "", long? PlatformId = null)
|
||||||
{
|
{
|
||||||
|
string PlatformWhereClause = "";
|
||||||
|
if (PlatformId != null)
|
||||||
|
{
|
||||||
|
PlatformWhereClause = " AND RomMediaGroup.PlatformId=@platformid";
|
||||||
|
}
|
||||||
|
|
||||||
|
string UserFields = "";
|
||||||
|
string UserJoin = "";
|
||||||
|
if (userid.Length > 0)
|
||||||
|
{
|
||||||
|
UserFields = ", User_RecentPlayedRoms.RomId AS MostRecentRomId, User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup, User_GameFavouriteRoms.RomId AS FavouriteRomId, User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup";
|
||||||
|
UserJoin = @"
|
||||||
|
LEFT JOIN
|
||||||
|
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||||
|
AND User_RecentPlayedRoms.GameId = RomMediaGroup.GameId
|
||||||
|
AND User_RecentPlayedRoms.PlatformId = RomMediaGroup.PlatformId
|
||||||
|
AND User_RecentPlayedRoms.RomId = RomMediaGroup.Id
|
||||||
|
AND User_RecentPlayedRoms.IsMediaGroup = 1
|
||||||
|
LEFT JOIN
|
||||||
|
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||||
|
AND User_GameFavouriteRoms.GameId = RomMediaGroup.GameId
|
||||||
|
AND User_GameFavouriteRoms.PlatformId = RomMediaGroup.PlatformId
|
||||||
|
AND User_GameFavouriteRoms.RomId = RomMediaGroup.Id
|
||||||
|
AND User_GameFavouriteRoms.IsMediaGroup = 1
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid WHERE RomMediaGroup.GameId=@gameid;";
|
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId" + UserFields + " FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid " + UserJoin + " WHERE RomMediaGroup.GameId=@gameid" + PlatformWhereClause + ";";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "gameid", GameId },
|
{ "gameid", GameId },
|
||||||
{ "userid", userid }
|
{ "userid", userid },
|
||||||
|
{ "platformid", PlatformId }
|
||||||
};
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -165,7 +193,7 @@ namespace gaseous_server.Classes
|
|||||||
public static void DeleteMediaGroup(long Id)
|
public static void DeleteMediaGroup(long Id)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState WHERE RomId=@id AND IsMediaGroup=1;";
|
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState WHERE RomId=@id AND IsMediaGroup=1; UPDATE UserTimeTracking SET PlatformId = NULL, IsMediaGroup = NULL, RomId = NULL WHERE RomId=@id AND IsMediaGroup = 1;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", Id);
|
dbDict.Add("id", Id);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -180,22 +208,42 @@ namespace gaseous_server.Classes
|
|||||||
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
||||||
{
|
{
|
||||||
bool hasSaveStates = false;
|
bool hasSaveStates = false;
|
||||||
if (row.Table.Columns.Contains("GameStateRomId"))
|
if (row.Table.Columns.Contains("GameStateRomId"))
|
||||||
{
|
{
|
||||||
if (row["GameStateRomId"] != DBNull.Value)
|
if (row["GameStateRomId"] != DBNull.Value)
|
||||||
{
|
{
|
||||||
hasSaveStates = true;
|
hasSaveStates = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem
|
||||||
mediaGroupItem.Id = (long)row["Id"];
|
{
|
||||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
Id = (long)row["Id"],
|
||||||
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"],
|
||||||
mediaGroupItem.GameId = (long)row["GameId"];
|
PlatformId = (long)row["PlatformId"],
|
||||||
mediaGroupItem.RomIds = new List<long>();
|
GameId = (long)row["GameId"],
|
||||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
RomIds = new List<long>(),
|
||||||
mediaGroupItem.HasSaveStates = hasSaveStates;
|
Roms = new List<Roms.GameRomItem>(),
|
||||||
|
HasSaveStates = hasSaveStates
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaGroupItem.RomUserLastUsed = false;
|
||||||
|
if (row.Table.Columns.Contains("MostRecentRomId"))
|
||||||
|
{
|
||||||
|
if (row["MostRecentRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
mediaGroupItem.RomUserLastUsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaGroupItem.RomUserFavourite = false;
|
||||||
|
if (row.Table.Columns.Contains("FavouriteRomId"))
|
||||||
|
{
|
||||||
|
if (row["FavouriteRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
mediaGroupItem.RomUserFavourite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get members
|
// get members
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
@@ -216,18 +264,6 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for a web emulator and update the romItem
|
|
||||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
|
||||||
{
|
|
||||||
if (platformMapping.IGDBId == mediaGroupItem.PlatformId)
|
|
||||||
{
|
|
||||||
if (platformMapping.WebEmulator != null)
|
|
||||||
{
|
|
||||||
mediaGroupItem.Emulator = platformMapping.WebEmulator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mediaGroupItem;
|
return mediaGroupItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +337,7 @@ namespace gaseous_server.Classes
|
|||||||
if (File.Exists(rom.Path))
|
if (File.Exists(rom.Path))
|
||||||
{
|
{
|
||||||
string romExt = Path.GetExtension(rom.Path);
|
string romExt = Path.GetExtension(rom.Path);
|
||||||
if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt))
|
if (new string[] { ".zip", ".rar", ".7z" }.Contains(romExt))
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
|
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
|
||||||
|
|
||||||
@@ -511,11 +547,12 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class GameRomMediaGroupItem
|
public class GameRomMediaGroupItem
|
||||||
{
|
{
|
||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
public string Platform {
|
public string Platform
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -528,37 +565,40 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
public List<long> RomIds { get; set; }
|
||||||
public List<long> RomIds { get; set; }
|
|
||||||
public List<Roms.GameRomItem> Roms { get; set; }
|
public List<Roms.GameRomItem> Roms { get; set; }
|
||||||
public bool HasSaveStates { get; set; } = false;
|
public bool HasSaveStates { get; set; } = false;
|
||||||
private GroupBuildStatus _Status { get; set; }
|
public bool RomUserLastUsed { get; set; }
|
||||||
public GroupBuildStatus Status {
|
public bool RomUserFavourite { get; set; }
|
||||||
get
|
private GroupBuildStatus _Status { get; set; }
|
||||||
{
|
public GroupBuildStatus Status
|
||||||
if (_Status == GroupBuildStatus.Completed)
|
{
|
||||||
{
|
get
|
||||||
if (File.Exists(MediaGroupZipPath))
|
{
|
||||||
{
|
if (_Status == GroupBuildStatus.Completed)
|
||||||
return GroupBuildStatus.Completed;
|
{
|
||||||
}
|
if (File.Exists(MediaGroupZipPath))
|
||||||
else
|
{
|
||||||
{
|
return GroupBuildStatus.Completed;
|
||||||
return GroupBuildStatus.NoStatus;
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
else
|
return GroupBuildStatus.NoStatus;
|
||||||
{
|
}
|
||||||
return _Status;
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
return _Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_Status = value;
|
_Status = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public long? Size {
|
public long? Size
|
||||||
get
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
if (Status == GroupBuildStatus.Completed)
|
if (Status == GroupBuildStatus.Completed)
|
||||||
{
|
{
|
||||||
@@ -577,15 +617,15 @@ namespace gaseous_server.Classes
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal string MediaGroupZipPath
|
internal string MediaGroupZipPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, Id + ".zip");
|
return Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, Id + ".zip");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public enum GroupBuildStatus
|
public enum GroupBuildStatus
|
||||||
{
|
{
|
||||||
NoStatus = 0,
|
NoStatus = 0,
|
||||||
WaitingForBuild = 1,
|
WaitingForBuild = 1,
|
||||||
@@ -593,6 +633,6 @@ namespace gaseous_server.Classes
|
|||||||
Completed = 3,
|
Completed = 3,
|
||||||
Failed = 4
|
Failed = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -18,6 +18,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 = "")
|
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
||||||
{
|
{
|
||||||
GameRomObject GameRoms = new GameRomObject();
|
GameRomObject GameRoms = new GameRomObject();
|
||||||
@@ -37,13 +43,34 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("namesearch", '%' + NameSearch + '%');
|
dbDict.Add("namesearch", '%' + NameSearch + '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string UserFields = "";
|
||||||
|
string UserJoin = "";
|
||||||
|
if (userid.Length > 0)
|
||||||
|
{
|
||||||
|
UserFields = ", User_RecentPlayedRoms.RomId AS MostRecentRomId, User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup, User_GameFavouriteRoms.RomId AS FavouriteRomId, User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup";
|
||||||
|
UserJoin = @"
|
||||||
|
LEFT JOIN
|
||||||
|
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||||
|
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId
|
||||||
|
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId
|
||||||
|
AND User_RecentPlayedRoms.RomId = Games_Roms.Id
|
||||||
|
AND User_RecentPlayedRoms.IsMediaGroup = 0
|
||||||
|
LEFT JOIN
|
||||||
|
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||||
|
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId
|
||||||
|
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId
|
||||||
|
AND User_GameFavouriteRoms.RomId = Games_Roms.Id
|
||||||
|
AND User_GameFavouriteRoms.IsMediaGroup = 0
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
// platform query
|
// 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`;";
|
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
|
// 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;";
|
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||||
|
|
||||||
// count query
|
// count query
|
||||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
||||||
@@ -51,16 +78,15 @@ namespace gaseous_server.Classes
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// data query
|
// 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;";
|
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||||
|
|
||||||
// count query
|
// count query
|
||||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
||||||
|
|
||||||
dbDict.Add("platformid", PlatformId);
|
dbDict.Add("platformid", PlatformId);
|
||||||
}
|
}
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks));
|
||||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict)[0];
|
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks))[0];
|
||||||
DataTable platformDT = db.ExecuteCMD(sqlPlatform, dbDict);
|
|
||||||
|
|
||||||
if (romDT.Rows.Count > 0)
|
if (romDT.Rows.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -70,10 +96,9 @@ namespace gaseous_server.Classes
|
|||||||
int pageOffset = pageSize * (pageNumber - 1);
|
int pageOffset = pageSize * (pageNumber - 1);
|
||||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||||
{
|
{
|
||||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
|
||||||
|
|
||||||
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
||||||
{
|
{
|
||||||
|
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||||
GameRoms.GameRomItems.Add(gameRomItem);
|
GameRoms.GameRomItems.Add(gameRomItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +114,7 @@ namespace gaseous_server.Classes
|
|||||||
public static GameRomItem GetRom(long RomId)
|
public static GameRomItem GetRom(long RomId)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.Id = @id";
|
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id WHERE Games_Roms.Id = @id";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -106,6 +131,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, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.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)
|
public static GameRomItem UpdateRom(long RomId, long PlatformId, long GameId)
|
||||||
{
|
{
|
||||||
// ensure metadata for platformid is present
|
// ensure metadata for platformid is present
|
||||||
@@ -185,7 +230,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @id;";
|
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @id; UPDATE UserTimeTracking SET PlatformId = NULL, IsMediaGroup = NULL, RomId = NULL WHERE RomId = @id AND IsMediaGroup = 0;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -225,6 +270,7 @@ namespace gaseous_server.Classes
|
|||||||
PlatformId = (long)romDR["platformid"],
|
PlatformId = (long)romDR["platformid"],
|
||||||
Platform = (string)romDR["platformname"],
|
Platform = (string)romDR["platformname"],
|
||||||
GameId = (long)romDR["gameid"],
|
GameId = (long)romDR["gameid"],
|
||||||
|
Game = (string)romDR["gamename"],
|
||||||
Name = (string)romDR["name"],
|
Name = (string)romDR["name"],
|
||||||
Size = (long)romDR["size"],
|
Size = (long)romDR["size"],
|
||||||
Crc = ((string)romDR["crc"]).ToLower(),
|
Crc = ((string)romDR["crc"]).ToLower(),
|
||||||
@@ -242,15 +288,21 @@ namespace gaseous_server.Classes
|
|||||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||||
};
|
};
|
||||||
|
|
||||||
// check for a web emulator and update the romItem
|
romItem.RomUserLastUsed = false;
|
||||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
if (romDR.Table.Columns.Contains("MostRecentRomId"))
|
||||||
{
|
{
|
||||||
if (platformMapping.IGDBId == romItem.PlatformId)
|
if (romDR["MostRecentRomId"] != DBNull.Value)
|
||||||
{
|
{
|
||||||
if (platformMapping.WebEmulator != null)
|
romItem.RomUserLastUsed = true;
|
||||||
{
|
}
|
||||||
romItem.Emulator = platformMapping.WebEmulator;
|
}
|
||||||
}
|
|
||||||
|
romItem.RomUserFavourite = false;
|
||||||
|
if (romDR.Table.Columns.Contains("FavouriteRomId"))
|
||||||
|
{
|
||||||
|
if (romDR["FavouriteRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
romItem.RomUserFavourite = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,12 +319,14 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
public string Platform { get; set; }
|
public string Platform { get; set; }
|
||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
|
public string Game { get; set; }
|
||||||
public string? Path { get; set; }
|
public string? Path { get; set; }
|
||||||
public string? SignatureSourceGameTitle { get; set; }
|
public string? SignatureSourceGameTitle { get; set; }
|
||||||
public bool HasSaveStates { get; set; } = false;
|
public bool HasSaveStates { get; set; } = false;
|
||||||
public GameLibrary.LibraryItem Library { get; set; }
|
public GameLibrary.LibraryItem Library { get; set; }
|
||||||
|
public bool RomUserLastUsed { get; set; }
|
||||||
|
public bool RomUserFavourite { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
using gaseous_signature_parser.models.RomSignatureObject;
|
using gaseous_signature_parser.models.RomSignatureObject;
|
||||||
using static gaseous_server.Classes.Common;
|
using static gaseous_server.Classes.Common;
|
||||||
|
|
||||||
@@ -81,6 +82,47 @@ namespace gaseous_server.Classes
|
|||||||
return GamesList;
|
return GamesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Signatures_Sources> GetSources()
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM Signatures_Sources ORDER BY `SourceType`, `Name`;";
|
||||||
|
DataTable sigDb = db.ExecuteCMD(sql);
|
||||||
|
|
||||||
|
List<Signatures_Sources> SourcesList = new List<Signatures_Sources>();
|
||||||
|
|
||||||
|
foreach (DataRow sigDbRow in sigDb.Rows)
|
||||||
|
{
|
||||||
|
Signatures_Sources sourceItem = new Signatures_Sources
|
||||||
|
{
|
||||||
|
Id = (int)sigDbRow["Id"],
|
||||||
|
Name = (string)sigDbRow["Name"],
|
||||||
|
Description = (string)sigDbRow["Description"],
|
||||||
|
URL = (string)sigDbRow["URL"],
|
||||||
|
Category = (string)sigDbRow["Category"],
|
||||||
|
Version = (string)sigDbRow["Version"],
|
||||||
|
Author = (string)sigDbRow["Author"],
|
||||||
|
Email = (string)sigDbRow["Email"],
|
||||||
|
Homepage = (string)sigDbRow["Homepage"],
|
||||||
|
SourceType = (gaseous_signature_parser.parser.SignatureParser)Enum.Parse(typeof(gaseous_signature_parser.parser.SignatureParser), sigDbRow["SourceType"].ToString()),
|
||||||
|
MD5 = (string)sigDbRow["SourceMD5"],
|
||||||
|
SHA1 = (string)sigDbRow["SourceSHA1"]
|
||||||
|
};
|
||||||
|
SourcesList.Add(sourceItem);
|
||||||
|
}
|
||||||
|
return SourcesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteSource(int sourceId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "DELETE FROM Signatures_Sources WHERE Id = @sourceId;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "sourceId", sourceId }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> GetLookup(LookupTypes LookupType, long GameId)
|
public Dictionary<string, string> GetLookup(LookupTypes LookupType, long GameId)
|
||||||
{
|
{
|
||||||
string tableName = "";
|
string tableName = "";
|
||||||
|
@@ -5,29 +5,45 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
public class Statistics
|
public class Statistics
|
||||||
{
|
{
|
||||||
public StatisticsModel RecordSession(Guid SessionId, long GameId, string UserId)
|
public StatisticsModel RecordSession(Guid SessionId, long GameId, long PlatformId, long RomId, bool IsMediaGroup, string UserId)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql;
|
string sql;
|
||||||
Dictionary<string, object> dbDict;
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "platformid", PlatformId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
|
||||||
|
// update last played rom id
|
||||||
|
sql = "INSERT INTO User_RecentPlayedRoms (UserId, GameId, PlatformId, RomId, IsMediaGroup) VALUES (@userid, @gameid, @platformid, @romid, @ismediagroup) ON DUPLICATE KEY UPDATE RomId = @romid, IsMediaGroup = @ismediagroup;";
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
// update sessions
|
||||||
|
|
||||||
if (SessionId == Guid.Empty)
|
if (SessionId == Guid.Empty)
|
||||||
{
|
{
|
||||||
// new session required
|
// new session required
|
||||||
SessionId = Guid.NewGuid();
|
SessionId = Guid.NewGuid();
|
||||||
|
|
||||||
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength);";
|
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength, PlatformId, IsMediaGroup, RomId) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength, @platformid, @ismediagroup, @romid);";
|
||||||
dbDict = new Dictionary<string, object>{
|
dbDict = new Dictionary<string, object>{
|
||||||
{ "gameid", GameId },
|
{ "gameid", GameId },
|
||||||
{ "userid", UserId },
|
{ "userid", UserId },
|
||||||
{ "sessionid", SessionId },
|
{ "sessionid", SessionId },
|
||||||
{ "sessiontime", DateTime.UtcNow },
|
{ "sessiontime", DateTime.UtcNow },
|
||||||
{ "sessionlength", 1 }
|
{ "sessionlength", 1 },
|
||||||
|
{ "platformid", PlatformId },
|
||||||
|
{ "ismediagroup", IsMediaGroup },
|
||||||
|
{ "romid", RomId }
|
||||||
};
|
};
|
||||||
|
|
||||||
db.ExecuteNonQuery(sql, dbDict);
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = GameId,
|
GameId = GameId,
|
||||||
SessionId = SessionId,
|
SessionId = SessionId,
|
||||||
SessionStart = (DateTime)dbDict["sessiontime"],
|
SessionStart = (DateTime)dbDict["sessiontime"],
|
||||||
@@ -50,7 +66,8 @@ namespace gaseous_server.Classes
|
|||||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = (long)data.Rows[0]["GameId"],
|
GameId = (long)data.Rows[0]["GameId"],
|
||||||
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
||||||
@@ -87,7 +104,8 @@ namespace gaseous_server.Classes
|
|||||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
||||||
data = db.ExecuteCMD(sql, dbDict);
|
data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = GameId,
|
GameId = GameId,
|
||||||
SessionLength = TotalTime,
|
SessionLength = TotalTime,
|
||||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
||||||
|
187
gaseous-server/Classes/UserProfile.cs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes
|
||||||
|
{
|
||||||
|
public class UserProfile
|
||||||
|
{
|
||||||
|
static readonly Dictionary<string, string> supportedImages = new Dictionary<string, string>{
|
||||||
|
{ ".png", "image/png" },
|
||||||
|
{ ".jpg", "image/jpeg" },
|
||||||
|
{ ".jpeg", "image/jpeg" },
|
||||||
|
{ ".gif", "image/gif" },
|
||||||
|
{ ".bmp", "image/bmp" },
|
||||||
|
{ ".svg", "image/svg+xml" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public Models.UserProfile? GetUserProfile(string UserId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT Id, DisplayName, Quip, AvatarExtension, ProfileBackgroundExtension, UnstructuredData FROM UserProfiles WHERE Id = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", UserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Models.UserProfile.ProfileImageItem? Avatar = null;
|
||||||
|
if (data.Rows[0]["AvatarExtension"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
Avatar = new Models.UserProfile.ProfileImageItem
|
||||||
|
{
|
||||||
|
MimeType = supportedImages[data.Rows[0]["AvatarExtension"].ToString()],
|
||||||
|
Extension = data.Rows[0]["AvatarExtension"].ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Models.UserProfile.ProfileImageItem? ProfileBackground = null;
|
||||||
|
if (data.Rows[0]["ProfileBackgroundExtension"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
ProfileBackground = new Models.UserProfile.ProfileImageItem
|
||||||
|
{
|
||||||
|
MimeType = supportedImages[data.Rows[0]["ProfileBackgroundExtension"].ToString()],
|
||||||
|
Extension = data.Rows[0]["ProfileBackgroundExtension"].ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Models.UserProfile
|
||||||
|
{
|
||||||
|
UserId = Guid.Parse(data.Rows[0]["Id"].ToString()),
|
||||||
|
DisplayName = data.Rows[0]["DisplayName"].ToString(),
|
||||||
|
Quip = data.Rows[0]["Quip"].ToString(),
|
||||||
|
Avatar = Avatar,
|
||||||
|
ProfileBackground = ProfileBackground,
|
||||||
|
Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(data.Rows[0]["UnstructuredData"].ToString())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateUserProfile(string InternalUserId, Models.UserProfile profile)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "UPDATE UserProfiles SET DisplayName = @displayname, Quip = @quip, UnstructuredData = @data WHERE UserId = @internalId AND Id = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "displayname", profile.DisplayName },
|
||||||
|
{ "quip", profile.Quip },
|
||||||
|
{ "data", Newtonsoft.Json.JsonConvert.SerializeObject(profile.Data) },
|
||||||
|
{ "userid", profile.UserId },
|
||||||
|
{ "internalId", InternalUserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ImageType
|
||||||
|
{
|
||||||
|
Avatar,
|
||||||
|
Background
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateImage(ImageType imageType, string UserId, string InternalUserId, string Filename, byte[] bytes)
|
||||||
|
{
|
||||||
|
// check if it's a supported file type
|
||||||
|
if (!supportedImages.ContainsKey(Path.GetExtension(Filename).ToLower()))
|
||||||
|
{
|
||||||
|
throw new Exception("File type not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
string ByteFieldName;
|
||||||
|
string ExtensionFieldName;
|
||||||
|
switch (imageType)
|
||||||
|
{
|
||||||
|
case ImageType.Avatar:
|
||||||
|
ByteFieldName = "Avatar";
|
||||||
|
ExtensionFieldName = "AvatarExtension";
|
||||||
|
break;
|
||||||
|
case ImageType.Background:
|
||||||
|
ByteFieldName = "ProfileBackground";
|
||||||
|
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid image type");
|
||||||
|
}
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = String.Format("UPDATE UserProfiles SET {0} = @content, {1} = @extension WHERE Id = @userid AND UserId = @internaluserid;", ByteFieldName, ExtensionFieldName);
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "content", bytes },
|
||||||
|
{ "extension", Path.GetExtension(Filename) },
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "internaluserid", InternalUserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.ImageItem? GetImage(ImageType imageType, string UserId)
|
||||||
|
{
|
||||||
|
string ByteFieldName;
|
||||||
|
string ExtensionFieldName;
|
||||||
|
switch (imageType)
|
||||||
|
{
|
||||||
|
case ImageType.Avatar:
|
||||||
|
ByteFieldName = "Avatar";
|
||||||
|
ExtensionFieldName = "AvatarExtension";
|
||||||
|
break;
|
||||||
|
case ImageType.Background:
|
||||||
|
ByteFieldName = "ProfileBackground";
|
||||||
|
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid image type");
|
||||||
|
}
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = String.Format("SELECT {0}, {1} FROM UserProfiles WHERE Id = @userid;", ByteFieldName, ExtensionFieldName);
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", UserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Models.ImageItem? image = new Models.ImageItem
|
||||||
|
{
|
||||||
|
content = data.Rows[0][ByteFieldName] as byte[],
|
||||||
|
mimeType = supportedImages[data.Rows[0][ExtensionFieldName] as string],
|
||||||
|
extension = data.Rows[0][ExtensionFieldName] as string
|
||||||
|
};
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteImage(ImageType imageType, string UserId)
|
||||||
|
{
|
||||||
|
string ByteFieldName;
|
||||||
|
string ExtensionFieldName;
|
||||||
|
switch (imageType)
|
||||||
|
{
|
||||||
|
case ImageType.Avatar:
|
||||||
|
ByteFieldName = "Avatar";
|
||||||
|
ExtensionFieldName = "AvatarExtension";
|
||||||
|
break;
|
||||||
|
case ImageType.Background:
|
||||||
|
ByteFieldName = "ProfileBackground";
|
||||||
|
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid image type");
|
||||||
|
}
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = String.Format("UPDATE UserProfiles SET {0} = NULL, {1} = NULL WHERE UserId = @userid;", ByteFieldName, ExtensionFieldName);
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", UserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -99,7 +99,7 @@ namespace gaseous_server.Controllers
|
|||||||
profile.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
profile.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
||||||
profile.SecurityProfile = user.SecurityProfile;
|
profile.SecurityProfile = user.SecurityProfile;
|
||||||
profile.UserPreferences = user.UserPreferences;
|
profile.UserPreferences = user.UserPreferences;
|
||||||
profile.Avatar = user.Avatar;
|
profile.ProfileId = user.ProfileId;
|
||||||
profile.Roles.Sort();
|
profile.Roles.Sort();
|
||||||
|
|
||||||
return Ok(profile);
|
return Ok(profile);
|
||||||
@@ -188,7 +188,7 @@ namespace gaseous_server.Controllers
|
|||||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||||
user.LockoutEnd = rawUser.LockoutEnd;
|
user.LockoutEnd = rawUser.LockoutEnd;
|
||||||
user.SecurityProfile = rawUser.SecurityProfile;
|
user.SecurityProfile = rawUser.SecurityProfile;
|
||||||
user.Avatar = rawUser.Avatar;
|
user.ProfileId = rawUser.ProfileId;
|
||||||
|
|
||||||
// get roles
|
// get roles
|
||||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||||
@@ -220,6 +220,10 @@ namespace gaseous_server.Controllers
|
|||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
NormalizedEmail = model.Email.ToUpper()
|
NormalizedEmail = model.Email.ToUpper()
|
||||||
};
|
};
|
||||||
|
if (await _userManager.FindByEmailAsync(model.Email) != null)
|
||||||
|
{
|
||||||
|
return NotFound("User already exists");
|
||||||
|
}
|
||||||
var result = await _userManager.CreateAsync(user, model.Password);
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
@@ -241,6 +245,23 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Users/Test")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public async Task<IActionResult> TestUserExists(string Email)
|
||||||
|
{
|
||||||
|
ApplicationUser? rawUser = await _userManager.FindByEmailAsync(Email);
|
||||||
|
|
||||||
|
if (rawUser != null)
|
||||||
|
{
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Users/{UserId}")]
|
[Route("Users/{UserId}")]
|
||||||
[Authorize(Roles = "Admin")]
|
[Authorize(Roles = "Admin")]
|
||||||
@@ -256,6 +277,7 @@ namespace gaseous_server.Controllers
|
|||||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||||
user.LockoutEnd = rawUser.LockoutEnd;
|
user.LockoutEnd = rawUser.LockoutEnd;
|
||||||
user.SecurityProfile = rawUser.SecurityProfile;
|
user.SecurityProfile = rawUser.SecurityProfile;
|
||||||
|
user.ProfileId = rawUser.ProfileId;
|
||||||
|
|
||||||
// get roles
|
// get roles
|
||||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
||||||
@@ -306,7 +328,7 @@ namespace gaseous_server.Controllers
|
|||||||
// delete all roles
|
// delete all roles
|
||||||
foreach (string role in userRoles)
|
foreach (string role in userRoles)
|
||||||
{
|
{
|
||||||
if ((new string[] { "Admin", "Gamer", "Player" }).Contains(role) )
|
if ((new string[] { "Admin", "Gamer", "Player" }).Contains(role))
|
||||||
{
|
{
|
||||||
await _userManager.RemoveFromRoleAsync(user, role);
|
await _userManager.RemoveFromRoleAsync(user, role);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,9 @@ using gaseous_server.Classes;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using Authentication;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -17,6 +20,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class BiosController : Controller
|
public class BiosController : Controller
|
||||||
{
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public BiosController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -43,29 +55,59 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpHead]
|
[HttpHead]
|
||||||
[Route("zip/{PlatformId}")]
|
[Route("zip/{PlatformId}")]
|
||||||
|
[Route("zip/{PlatformId}/{GameId}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetBiosCompressed(long PlatformId)
|
public async Task<ActionResult> GetBiosCompressedAsync(long PlatformId, long GameId = -1, bool filtered = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
if (GameId == -1 || filtered == false)
|
||||||
|
|
||||||
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platform.Slug);
|
|
||||||
|
|
||||||
string tempFile = Path.GetTempFileName();
|
|
||||||
|
|
||||||
using (FileStream zipFile = System.IO.File.Create(tempFile))
|
|
||||||
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
|
|
||||||
{
|
{
|
||||||
foreach (string file in Directory.GetFiles(biosPath))
|
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
{
|
|
||||||
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = new FileStream(tempFile, FileMode.Open);
|
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platform.Slug);
|
||||||
return File(stream, "application/zip", platform.Slug + ".zip");
|
|
||||||
|
string tempFile = Path.GetTempFileName();
|
||||||
|
|
||||||
|
using (FileStream zipFile = System.IO.File.Create(tempFile))
|
||||||
|
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
|
||||||
|
{
|
||||||
|
foreach (string file in Directory.GetFiles(biosPath))
|
||||||
|
{
|
||||||
|
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var stream = new FileStream(tempFile, FileMode.Open);
|
||||||
|
return File(stream, "application/zip", platform.Slug + ".zip");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get user platform map
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
PlatformMapping platformMapping = new PlatformMapping();
|
||||||
|
PlatformMapping.PlatformMapItem userPlatformMap = platformMapping.GetUserPlatformMap(user.Id, PlatformId, GameId);
|
||||||
|
|
||||||
|
// build zip file
|
||||||
|
string tempFile = Path.GetTempFileName();
|
||||||
|
|
||||||
|
using (FileStream zipFile = System.IO.File.Create(tempFile))
|
||||||
|
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
|
||||||
|
{
|
||||||
|
foreach (Bios.BiosItem bios in GetBios(PlatformId, true))
|
||||||
|
{
|
||||||
|
if (userPlatformMap.EnabledBIOSHashes.Contains(bios.hash))
|
||||||
|
{
|
||||||
|
zipArchive.CreateEntryFromFile(bios.biosPath, bios.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var stream = new FileStream(tempFile, FileMode.Open);
|
||||||
|
return File(stream, "application/zip", userPlatformMap.IGDBSlug + ".zip");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using static gaseous_server.Models.PlatformMapping;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -53,7 +54,7 @@ namespace gaseous_server.Controllers
|
|||||||
int minrating = -1,
|
int minrating = -1,
|
||||||
int maxrating = -1,
|
int maxrating = -1,
|
||||||
bool sortdescending = false)
|
bool sortdescending = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
return Ok(GetGames(name, platform, genre, gamemode, playerperspective, theme, minrating, maxrating, "Adult", true, true, sortdescending));
|
return Ok(GetGames(name, platform, genre, gamemode, playerperspective, theme, minrating, maxrating, "Adult", true, true, sortdescending));
|
||||||
}
|
}
|
||||||
@@ -457,73 +458,6 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
|
||||||
[MapToApiVersion("1.1")]
|
|
||||||
[HttpGet]
|
|
||||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}")]
|
|
||||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ActionResult> GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
|
||||||
|
|
||||||
if (artworkObject != null) {
|
|
||||||
//string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork", size.ToString(), artworkObject.ImageId + ".jpg");
|
|
||||||
|
|
||||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork");
|
|
||||||
|
|
||||||
Communications comms = new Communications();
|
|
||||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, artworkObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
|
||||||
|
|
||||||
string coverFilePath = ImgFetch.Result;
|
|
||||||
|
|
||||||
|
|
||||||
if (System.IO.File.Exists(coverFilePath))
|
|
||||||
{
|
|
||||||
string filename = artworkObject.ImageId + ".jpg";
|
|
||||||
string filepath = coverFilePath;
|
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
|
||||||
string contentType = "image/jpg";
|
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
|
||||||
{
|
|
||||||
FileName = filename,
|
|
||||||
Inline = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
|
||||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
|
||||||
|
|
||||||
return File(filedata, contentType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -562,47 +496,126 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/cover/image/{size}")]
|
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}")]
|
||||||
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}/{imagename}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
public async Task<ActionResult> GameImage(long GameId, MetadataImageType imageType, long ImageId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
if (gameObject.Cover != null)
|
string? imageId = null;
|
||||||
|
string? imageTypePath = null;
|
||||||
|
|
||||||
|
switch (imageType)
|
||||||
{
|
{
|
||||||
if (gameObject.Cover.Id != null)
|
case MetadataImageType.cover:
|
||||||
{
|
if (gameObject.Cover != null)
|
||||||
IGDB.Models.Cover cover = Classes.Metadata.Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
{
|
||||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Covers");
|
if (gameObject.Cover.Id != null)
|
||||||
|
|
||||||
Communications comms = new Communications();
|
|
||||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, cover.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
|
||||||
|
|
||||||
string coverFilePath = ImgFetch.Result;
|
|
||||||
|
|
||||||
if (System.IO.File.Exists(coverFilePath)) {
|
|
||||||
string filename = cover.ImageId + ".jpg";
|
|
||||||
string filepath = coverFilePath;
|
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
|
||||||
string contentType = "image/jpg";
|
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
|
||||||
{
|
{
|
||||||
FileName = filename,
|
IGDB.Models.Cover cover = Classes.Metadata.Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
Inline = true,
|
imageId = cover.ImageId;
|
||||||
};
|
imageTypePath = "Covers";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
case MetadataImageType.screenshots:
|
||||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
if (gameObject.Screenshots != null)
|
||||||
|
{
|
||||||
|
if (gameObject.Screenshots.Ids.Contains(ImageId))
|
||||||
|
{
|
||||||
|
IGDB.Models.Screenshot imageObject = Screenshots.GetScreenshot(ImageId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||||
|
|
||||||
return File(filedata, contentType);
|
imageId = imageObject.ImageId;
|
||||||
|
imageTypePath = "Screenshots";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MetadataImageType.artwork:
|
||||||
|
if (gameObject.Artworks != null)
|
||||||
|
{
|
||||||
|
if (gameObject.Artworks.Ids.Contains(ImageId))
|
||||||
|
{
|
||||||
|
IGDB.Models.Artwork imageObject = Artworks.GetArtwork(ImageId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||||
|
|
||||||
|
imageId = imageObject.ImageId;
|
||||||
|
imageTypePath = "Artwork";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageId == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath);
|
||||||
|
string imagePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath, size.ToString(), imageId + ".jpg");
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath), imageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
imagePath = ImgFetch.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, imageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
imagePath = ImgFetch.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
string filename = imageId + ".jpg";
|
||||||
|
string filepath = imagePath;
|
||||||
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
|
{
|
||||||
|
FileName = filename,
|
||||||
|
Inline = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
|
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||||
|
|
||||||
|
byte[] filedata = null;
|
||||||
|
using (FileStream fs = System.IO.File.OpenRead(filepath))
|
||||||
|
{
|
||||||
|
using (BinaryReader binaryReader = new BinaryReader(fs))
|
||||||
|
{
|
||||||
|
filedata = binaryReader.ReadBytes((int)fs.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return File(filedata, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -611,6 +624,13 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum MetadataImageType
|
||||||
|
{
|
||||||
|
cover,
|
||||||
|
screenshots,
|
||||||
|
artwork
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
@@ -796,7 +816,8 @@ namespace gaseous_server.Controllers
|
|||||||
companyData.Add("company", company);
|
companyData.Add("company", company);
|
||||||
|
|
||||||
return Ok(companyData);
|
return Ok(companyData);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
@@ -857,17 +878,146 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(UserEmulatorConfiguration), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetGameEmulator(long GameId, long PlatformId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
|
if (platformObject != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
PlatformMapping platformMapping = new PlatformMapping();
|
||||||
|
UserEmulatorConfiguration platformMappingObject = platformMapping.GetUserEmulator(user.Id, GameId, PlatformId);
|
||||||
|
|
||||||
|
if (platformMappingObject != null)
|
||||||
|
{
|
||||||
|
return Ok(platformMappingObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> SetGameEmulator(long GameId, long PlatformId, UserEmulatorConfiguration configuration)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
|
if (platformObject != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
PlatformMapping platformMapping = new PlatformMapping();
|
||||||
|
platformMapping.SetUserEmulator(user.Id, GameId, PlatformId, configuration);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> DeleteGameEmulator(long GameId, long PlatformId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
|
if (platformObject != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
PlatformMapping platformMapping = new PlatformMapping();
|
||||||
|
platformMapping.DeleteUserEmulator(user.Id, GameId, PlatformId);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/platforms")]
|
[Route("{GameId}/platforms")]
|
||||||
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Games.AvailablePlatformItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GamePlatforms(long GameId)
|
public async Task<ActionResult> GamePlatforms(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(Games.GetAvailablePlatforms(GameId));
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
return Ok(Games.GetAvailablePlatforms(user.Id, GameId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -1025,6 +1175,67 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("{GameId}/roms/{RomId}/{PlatformId}/favourite")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GameRomFavourite(long GameId, long RomId, long PlatformId, bool IsMediaGroup, bool favourite)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ApplicationUser? user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (IsMediaGroup == false)
|
||||||
|
{
|
||||||
|
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||||
|
if (rom.GameId == GameId)
|
||||||
|
{
|
||||||
|
if (favourite == true)
|
||||||
|
{
|
||||||
|
Classes.Metadata.Games.GameSetFavouriteRom(user.Id, GameId, PlatformId, RomId, IsMediaGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Classes.Metadata.Games.GameClearFavouriteRom(user.Id, GameId, PlatformId);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomId, user.Id);
|
||||||
|
if (rom.GameId == GameId)
|
||||||
|
{
|
||||||
|
if (favourite == true)
|
||||||
|
{
|
||||||
|
Classes.Metadata.Games.GameSetFavouriteRom(user.Id, GameId, PlatformId, RomId, IsMediaGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Classes.Metadata.Games.GameClearFavouriteRom(user.Id, GameId, PlatformId);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -1137,11 +1348,10 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Authorize(Roles = "Admin,Gamer")]
|
|
||||||
[Route("{GameId}/romgroup")]
|
[Route("{GameId}/romgroup")]
|
||||||
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GetGameRomGroupAsync(long GameId)
|
public async Task<ActionResult> GetGameRomGroupAsync(long GameId, long? PlatformId = null)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
@@ -1151,7 +1361,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id));
|
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id, PlatformId));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1388,7 +1598,8 @@ namespace gaseous_server.Controllers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
if (gameObject != null) {
|
if (gameObject != null)
|
||||||
|
{
|
||||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
if (screenshotObject != null)
|
if (screenshotObject != null)
|
||||||
{
|
{
|
||||||
@@ -1410,56 +1621,56 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
// [MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
// [MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
// [HttpGet]
|
||||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
||||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
// [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<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
|
// try
|
||||||
{
|
// {
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
// IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
// IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||||
|
|
||||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots");
|
// string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots");
|
||||||
|
|
||||||
Communications comms = new Communications();
|
// Communications comms = new Communications();
|
||||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
// Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
string coverFilePath = ImgFetch.Result;
|
// string coverFilePath = ImgFetch.Result;
|
||||||
|
|
||||||
if (System.IO.File.Exists(coverFilePath))
|
// if (System.IO.File.Exists(coverFilePath))
|
||||||
{
|
// {
|
||||||
string filename = screenshotObject.ImageId + ".jpg";
|
// string filename = screenshotObject.ImageId + ".jpg";
|
||||||
string filepath = coverFilePath;
|
// string filepath = coverFilePath;
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
// byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||||
string contentType = "image/jpg";
|
// string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
// var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
// {
|
||||||
FileName = filename,
|
// FileName = filename,
|
||||||
Inline = true,
|
// Inline = true,
|
||||||
};
|
// };
|
||||||
|
|
||||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
// Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
// Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||||
|
|
||||||
return File(filedata, contentType);
|
// return File(filedata, contentType);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
return NotFound();
|
// return NotFound();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
return NotFound();
|
// return NotFound();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
|
@@ -149,35 +149,6 @@ namespace gaseous_server.Controllers
|
|||||||
return Ok(new { count = files.Count, size });
|
return Ok(new { count = files.Count, size });
|
||||||
}
|
}
|
||||||
|
|
||||||
// [MapToApiVersion("1.0")]
|
|
||||||
[MapToApiVersion("1.1")]
|
|
||||||
[HttpPost]
|
|
||||||
// [Route("{PlatformId}")]
|
|
||||||
// [ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
|
|
||||||
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
// [ProducesResponseType(StatusCodes.Status409Conflict)]
|
|
||||||
// public ActionResult NewPlatformMap(long PlatformId, PlatformMapping.PlatformMapItem Map)
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
|
|
||||||
|
|
||||||
// if (platformMapItem != null)
|
|
||||||
// {
|
|
||||||
// return Conflict();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// PlatformMapping.WritePlatformMap(Map, false, false);
|
|
||||||
// return Ok(PlatformMapping.GetPlatformMap(PlatformId));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch
|
|
||||||
// {
|
|
||||||
// return NotFound();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpPatch]
|
[HttpPatch]
|
||||||
|
@@ -114,22 +114,64 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{PlatformId}/platformlogo/image")]
|
[Route("{PlatformId}/platformlogo/{size}/logo.png")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult PlatformLogoImage(long PlatformId)
|
public async Task<ActionResult> GameImage(long PlatformId, Communications.IGDBAPI_ImageSize size)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
IGDB.Models.PlatformLogo? logoObject = null;
|
||||||
string logoFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), "Logo_Medium.png");
|
try
|
||||||
if (System.IO.File.Exists(logoFilePath))
|
|
||||||
{
|
{
|
||||||
string filename = "Logo.png";
|
logoObject = PlatformLogos.GetPlatformLogo(platformObject.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||||
string filepath = logoFilePath;
|
}
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
catch
|
||||||
string contentType = "image/png";
|
{
|
||||||
|
// getting the logo failed, so we'll try a platform variant if available
|
||||||
|
if (platformObject.Versions != null)
|
||||||
|
{
|
||||||
|
if (platformObject.Versions.Ids.Length > 0)
|
||||||
|
{
|
||||||
|
IGDB.Models.PlatformVersion platformVersion = Classes.Metadata.PlatformVersions.GetPlatformVersion(platformObject.Versions.Ids[0], platformObject);
|
||||||
|
logoObject = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||||
|
string imagePath = Path.Combine(basePath, size.ToString(), logoObject.ImageId + ".jpg");
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject)), logoObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
imagePath = ImgFetch.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
Communications comms = new Communications();
|
||||||
|
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, logoObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||||
|
|
||||||
|
imagePath = ImgFetch.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
string filename = logoObject.ImageId + ".jpg";
|
||||||
|
string filepath = imagePath;
|
||||||
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
{
|
||||||
@@ -138,13 +180,21 @@ namespace gaseous_server.Controllers
|
|||||||
};
|
};
|
||||||
|
|
||||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
|
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||||
|
|
||||||
|
byte[] filedata = null;
|
||||||
|
using (FileStream fs = System.IO.File.OpenRead(filepath))
|
||||||
|
{
|
||||||
|
using (BinaryReader binaryReader = new BinaryReader(fs))
|
||||||
|
{
|
||||||
|
filedata = binaryReader.ReadBytes((int)fs.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return File(filedata, contentType);
|
return File(filedata, contentType);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return NotFound();
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -31,63 +31,70 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize(Roles = "Admin,Gamer")]
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||||
[RequestSizeLimit(long.MaxValue)]
|
[RequestSizeLimit(long.MaxValue)]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||||
public async Task<IActionResult> UploadRom(List<IFormFile> files, long? OverridePlatformId = null)
|
public async Task<IActionResult> UploadRom(IFormFile file, long? OverridePlatformId = null)
|
||||||
{
|
{
|
||||||
Guid sessionid = Guid.NewGuid();
|
Guid sessionid = Guid.NewGuid();
|
||||||
|
|
||||||
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
||||||
|
|
||||||
long size = files.Sum(f => f.Length);
|
if (file.Length > 0)
|
||||||
|
|
||||||
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
|
|
||||||
|
|
||||||
foreach (IFormFile formFile in files)
|
|
||||||
{
|
{
|
||||||
if (formFile.Length > 0)
|
Guid FileId = Guid.NewGuid();
|
||||||
|
|
||||||
|
string filePath = Path.Combine(workPath, Path.GetFileName(file.FileName));
|
||||||
|
|
||||||
|
if (!Directory.Exists(workPath))
|
||||||
{
|
{
|
||||||
Guid FileId = Guid.NewGuid();
|
Directory.CreateDirectory(workPath);
|
||||||
|
|
||||||
string filePath = Path.Combine(workPath, Path.GetFileName(formFile.FileName));
|
|
||||||
|
|
||||||
if (!Directory.Exists(workPath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(workPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var stream = System.IO.File.Create(filePath))
|
|
||||||
{
|
|
||||||
await formFile.CopyToAsync(stream);
|
|
||||||
|
|
||||||
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
|
||||||
UploadedFile.Add("id", FileId.ToString());
|
|
||||||
UploadedFile.Add("originalname", Path.GetFileName(formFile.FileName));
|
|
||||||
UploadedFile.Add("fullpath", filePath);
|
|
||||||
UploadedFiles.Add(UploadedFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// get override platform if specified
|
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
||||||
IGDB.Models.Platform? OverridePlatform = null;
|
|
||||||
if (OverridePlatformId != null)
|
|
||||||
{
|
|
||||||
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process uploaded files
|
using (var stream = System.IO.File.Create(filePath))
|
||||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
{
|
||||||
{
|
await file.CopyToAsync(stream);
|
||||||
|
|
||||||
|
UploadedFile.Add("id", FileId.ToString());
|
||||||
|
UploadedFile.Add("originalname", Path.GetFileName(file.FileName));
|
||||||
|
UploadedFile.Add("fullpath", filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get override platform if specified
|
||||||
|
IGDB.Models.Platform? OverridePlatform = null;
|
||||||
|
if (OverridePlatformId != null)
|
||||||
|
{
|
||||||
|
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process uploaded file
|
||||||
Classes.ImportGame uploadImport = new ImportGame();
|
Classes.ImportGame uploadImport = new ImportGame();
|
||||||
uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
Dictionary<string, object> RetVal = uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
||||||
|
switch (RetVal["type"])
|
||||||
|
{
|
||||||
|
case "rom":
|
||||||
|
if (RetVal["status"] == "imported")
|
||||||
|
{
|
||||||
|
IGDB.Models.Game? game = (IGDB.Models.Game)RetVal["game"];
|
||||||
|
if (game.Id == null)
|
||||||
|
{
|
||||||
|
RetVal["game"] = Games.GetGame(0, false, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(workPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(workPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(RetVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(workPath))
|
return Ok();
|
||||||
{
|
|
||||||
Directory.Delete(workPath, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(new { count = files.Count, size });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -73,7 +73,7 @@ namespace gaseous_server.Controllers
|
|||||||
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
string searchBody = "";
|
string searchBody = "";
|
||||||
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
string searchFields = "fields *; ";
|
||||||
searchBody += "search \"" + SearchString + "\";";
|
searchBody += "search \"" + SearchString + "\";";
|
||||||
searchBody += "where platforms = (" + PlatformId + ");";
|
searchBody += "where platforms = (" + PlatformId + ");";
|
||||||
searchBody += "limit 100;";
|
searchBody += "limit 100;";
|
||||||
@@ -91,7 +91,7 @@ namespace gaseous_server.Controllers
|
|||||||
foreach (Game game in results.ToList())
|
foreach (Game game in results.ToList())
|
||||||
{
|
{
|
||||||
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
||||||
switch(cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
Storage.NewCacheValue(game, false);
|
Storage.NewCacheValue(game, false);
|
||||||
|
@@ -9,6 +9,7 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||||
|
|
||||||
@@ -54,11 +55,34 @@ namespace gaseous_server.Controllers
|
|||||||
{
|
{
|
||||||
SignatureManagement signatureManagement = new SignatureManagement();
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
return signatureManagement.GetByTosecName(TosecName);
|
return signatureManagement.GetByTosecName(TosecName);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public List<Signatures_Sources> GetSignatureSources()
|
||||||
|
{
|
||||||
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
|
return signatureManagement.GetSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpDelete]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public IActionResult DeleteSignatureSource(int Id)
|
||||||
|
{
|
||||||
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
|
signatureManagement.DeleteSource(Id);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,7 +38,10 @@ namespace gaseous_server.Controllers
|
|||||||
List<SystemInfo.PathItem> Disks = new List<SystemInfo.PathItem>();
|
List<SystemInfo.PathItem> Disks = new List<SystemInfo.PathItem>();
|
||||||
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
|
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
|
||||||
{
|
{
|
||||||
Disks.Add(GetDisk(libraryItem.Path));
|
SystemInfo.PathItem pathItem = GetDisk(libraryItem.Path);
|
||||||
|
pathItem.Name = libraryItem.Name;
|
||||||
|
|
||||||
|
Disks.Add(pathItem);
|
||||||
}
|
}
|
||||||
ReturnValue.Paths = Disks;
|
ReturnValue.Paths = Disks;
|
||||||
|
|
||||||
@@ -100,7 +103,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
||||||
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
||||||
"var FirstRunStatus = " + Config.ReadSetting<string>("FirstRunStatus", "0") + ";" + Environment.NewLine +
|
"var FirstRunStatus = \"" + Config.ReadSetting<string>("FirstRunStatus", "0") + "\";" + Environment.NewLine +
|
||||||
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions
|
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
@@ -324,6 +327,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
public class PathItem
|
public class PathItem
|
||||||
{
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
public string LibraryPath { get; set; }
|
public string LibraryPath { get; set; }
|
||||||
public long SpaceUsed { get; set; }
|
public long SpaceUsed { get; set; }
|
||||||
public long SpaceAvailable { get; set; }
|
public long SpaceAvailable { get; set; }
|
||||||
|
80
gaseous-server/Controllers/V1.1/FileSystemController.cs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using gaseous_server.Classes;
|
||||||
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using IGDB.Models;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
|
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
|
namespace gaseous_server.Controllers.v1_1
|
||||||
|
{
|
||||||
|
[Route("api/v{version:apiVersion}/[controller]")]
|
||||||
|
[ApiVersion("1.1")]
|
||||||
|
[ApiController]
|
||||||
|
public class FileSystemController : ControllerBase
|
||||||
|
{
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public ActionResult GetFileSystem(string path, bool showFiles = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (path.Contains(".."))
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Dictionary<string, List<Dictionary<string, string>>> allFiles = new Dictionary<string, List<Dictionary<string, string>>>();
|
||||||
|
List<Dictionary<string, string>> directories = new List<Dictionary<string, string>>();
|
||||||
|
string[] dirs = Directory.GetDirectories(path);
|
||||||
|
Array.Sort(dirs);
|
||||||
|
foreach (string dir in dirs)
|
||||||
|
{
|
||||||
|
DirectoryInfo directoryInfo = new DirectoryInfo(dir);
|
||||||
|
directories.Add(new Dictionary<string, string> { { "name", directoryInfo.Name }, { "path", directoryInfo.FullName } });
|
||||||
|
}
|
||||||
|
allFiles.Add("directories", directories);
|
||||||
|
|
||||||
|
if (showFiles == true)
|
||||||
|
{
|
||||||
|
List<Dictionary<string, string>> files = new List<Dictionary<string, string>>();
|
||||||
|
string[] filePaths = Directory.GetFiles(path);
|
||||||
|
Array.Sort(filePaths);
|
||||||
|
foreach (string file in filePaths)
|
||||||
|
{
|
||||||
|
FileInfo fileInfo = new FileInfo(file);
|
||||||
|
files.Add(new Dictionary<string, string> { { "name", fileInfo.Name }, { "path", fileInfo.FullName } });
|
||||||
|
}
|
||||||
|
allFiles.Add("files", files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(allFiles);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ApiVersion("1.1")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class GamesController: ControllerBase
|
public class GamesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -106,7 +106,8 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
string IncludeUnrated = "";
|
string IncludeUnrated = "";
|
||||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true) {
|
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true)
|
||||||
|
{
|
||||||
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +447,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
string orderByOrder = "ASC";
|
string orderByOrder = "ASC";
|
||||||
if (model.Sorting != null)
|
if (model.Sorting != null)
|
||||||
{
|
{
|
||||||
switch(model.Sorting.SortBy)
|
switch (model.Sorting.SortBy)
|
||||||
{
|
{
|
||||||
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
||||||
orderByField = "NameThe";
|
orderByField = "NameThe";
|
||||||
@@ -485,6 +486,7 @@ SELECT DISTINCT
|
|||||||
Game.`Name`,
|
Game.`Name`,
|
||||||
Game.NameThe,
|
Game.NameThe,
|
||||||
Game.Slug,
|
Game.Slug,
|
||||||
|
Game.Summary,
|
||||||
Game.PlatformId,
|
Game.PlatformId,
|
||||||
Game.TotalRating,
|
Game.TotalRating,
|
||||||
Game.TotalRatingCount,
|
Game.TotalRatingCount,
|
||||||
@@ -551,7 +553,7 @@ FROM
|
|||||||
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||||
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
||||||
|
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
DataTable dbResponse = db.ExecuteCMD(sql, whereParams, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 60));
|
||||||
|
|
||||||
// get count
|
// get count
|
||||||
int RecordCount = dbResponse.Rows.Count;
|
int RecordCount = dbResponse.Rows.Count;
|
||||||
@@ -568,7 +570,7 @@ FROM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
Game retGame = Storage.BuildCacheObject<Game>(new Game(), dbResponse.Rows[i]);
|
||||||
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||||
retMinGame.Index = i;
|
retMinGame.Index = i;
|
||||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||||
@@ -593,29 +595,44 @@ FROM
|
|||||||
|
|
||||||
// build alpha list
|
// build alpha list
|
||||||
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||||
int CurrentPage = 1;
|
if (orderByField == "NameThe" || orderByField == "Name")
|
||||||
int NextPageIndex = pageSize;
|
|
||||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
|
||||||
{
|
{
|
||||||
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
|
int CurrentPage = 1;
|
||||||
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
int NextPageIndex = pageSize;
|
||||||
|
|
||||||
|
string alphaSearchField;
|
||||||
|
if (orderByField == "NameThe")
|
||||||
{
|
{
|
||||||
if (!AlphaList.ContainsKey("#"))
|
alphaSearchField = "NameThe";
|
||||||
{
|
|
||||||
AlphaList.Add("#", 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!AlphaList.ContainsKey(firstChar))
|
alphaSearchField = "Name";
|
||||||
{
|
}
|
||||||
AlphaList.Add(firstChar, CurrentPage);
|
|
||||||
}
|
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||||
|
{
|
||||||
if (NextPageIndex == i + 1)
|
if (NextPageIndex == i + 1)
|
||||||
{
|
{
|
||||||
NextPageIndex += pageSize;
|
NextPageIndex += pageSize;
|
||||||
CurrentPage += 1;
|
CurrentPage += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string firstChar = dbResponse.Rows[i][alphaSearchField].ToString().Substring(0, 1).ToUpperInvariant();
|
||||||
|
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||||
|
{
|
||||||
|
if (!AlphaList.ContainsKey(firstChar))
|
||||||
|
{
|
||||||
|
AlphaList.Add(firstChar, CurrentPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!AlphaList.ContainsKey("#"))
|
||||||
|
{
|
||||||
|
AlphaList.Add("#", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ using Authentication;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers.v1_1
|
namespace gaseous_server.Controllers.v1_1
|
||||||
{
|
{
|
||||||
@@ -13,7 +14,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ApiVersion("1.0")]
|
[ApiVersion("1.0")]
|
||||||
[ApiVersion("1.1")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class StateManagerController: ControllerBase
|
public class StateManagerController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -233,11 +234,11 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("{RomId}/{StateId}/State/")]
|
[Route("{RomId}/{StateId}/State/")]
|
||||||
[Route("{RomId}/{StateId}/State/savestate.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);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "id", StateId },
|
{ "id", StateId },
|
||||||
@@ -254,7 +255,9 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string filename = "savestate.state";
|
// get rom data
|
||||||
|
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||||
|
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
if ((bool)data.Rows[0]["Zipped"] == false)
|
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||||
{
|
{
|
||||||
@@ -264,7 +267,85 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
{
|
{
|
||||||
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
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
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
{
|
||||||
@@ -279,6 +360,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)
|
private Models.GameStateItem BuildGameStateItem(DataRow dr)
|
||||||
{
|
{
|
||||||
bool HasScreenshot = true;
|
bool HasScreenshot = true;
|
||||||
|
@@ -12,7 +12,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ApiVersion("1.0")]
|
[ApiVersion("1.0")]
|
||||||
[ApiVersion("1.1")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class StatisticsController: ControllerBase
|
public class StatisticsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -32,15 +32,15 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("Games/{GameId}/")]
|
[Route("Games/{GameId}/{PlatformId}/{RomId}")]
|
||||||
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
public async Task<ActionResult> NewRecordStatistics(long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
Statistics statistics = new Statistics();
|
Statistics statistics = new Statistics();
|
||||||
return Ok(statistics.RecordSession(Guid.Empty, GameId, user.Id));
|
return Ok(statistics.RecordSession(Guid.Empty, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -54,15 +54,15 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("Games/{GameId}/{SessionId}")]
|
[Route("Games/{GameId}/{PlatformId}/{RomId}/{SessionId}")]
|
||||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, long PlatformId, long RomId, Guid SessionId, bool IsMediaGroup)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
Statistics statistics = new Statistics();
|
Statistics statistics = new Statistics();
|
||||||
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
return Ok(statistics.RecordSession(SessionId, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
137
gaseous-server/Controllers/V1.1/UserProfileController.cs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
using Asp.Versioning;
|
||||||
|
using Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace gaseous_server.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v{version:apiVersion}/[controller]")]
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[ApiVersion("1.1")]
|
||||||
|
[Authorize]
|
||||||
|
public class UserProfileController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public UserProfileController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{UserId}")]
|
||||||
|
[ProducesResponseType(typeof(Models.UserProfile), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
|
public ActionResult GetUserProfile(string UserId)
|
||||||
|
{
|
||||||
|
Classes.UserProfile profile = new Classes.UserProfile();
|
||||||
|
Models.UserProfile RetVal = profile.GetUserProfile(UserId);
|
||||||
|
return Ok(RetVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPut]
|
||||||
|
[Route("{UserId}")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> UpdateUserProfileAsync(string UserId, Models.UserProfile profile)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user.ProfileId.ToString() != UserId)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||||
|
userProfile.UpdateUserProfile(user.Id, profile);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPut]
|
||||||
|
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||||
|
[RequestSizeLimit(long.MaxValue)]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
|
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||||
|
[Route("{UserId}/{ProfileImageType}")]
|
||||||
|
public async Task<ActionResult> UpdateAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType, IFormFile file)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user.ProfileId.ToString() != UserId)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.Length > 0)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
file.CopyTo(ms);
|
||||||
|
byte[] fileBytes = ms.ToArray();
|
||||||
|
|
||||||
|
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||||
|
userProfile.UpdateImage(ProfileImageType, UserId, user.Id, file.FileName, fileBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{UserId}/{ProfileImageType}")]
|
||||||
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
|
public async Task<ActionResult> GetAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType)
|
||||||
|
{
|
||||||
|
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||||
|
|
||||||
|
Models.ImageItem image = userProfile.GetImage(ProfileImageType, UserId);
|
||||||
|
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return File(image.content, image.mimeType, UserId + image.extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("{UserId}/{ProfileImageType}")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<ActionResult> DeleteAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user.ProfileId.ToString() != UserId)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||||
|
userProfile.DeleteImage(ProfileImageType, user.Id);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,7 +16,7 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
var targetType = this.GetType();
|
var targetType = this.GetType();
|
||||||
var sourceType = game.GetType();
|
var sourceType = game.GetType();
|
||||||
foreach(var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public| BindingFlags.SetProperty))
|
foreach (var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty))
|
||||||
{
|
{
|
||||||
// check whether source object has the the property
|
// check whether source object has the the property
|
||||||
var sp = sourceType.GetProperty(prop.Name);
|
var sp = sourceType.GetProperty(prop.Name);
|
||||||
@@ -39,9 +39,11 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
if (this.Cover.Id != null)
|
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()
|
||||||
return cover;
|
{
|
||||||
|
Id = this.Cover.Id
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
gaseous-server/Models/ImageItem.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class ImageItem
|
||||||
|
{
|
||||||
|
public byte[] content { get; set; }
|
||||||
|
public string mimeType { get; set; }
|
||||||
|
public string extension { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -13,10 +13,8 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace gaseous_server.Models
|
namespace gaseous_server.Models
|
||||||
{
|
{
|
||||||
public class PlatformMapping
|
public class PlatformMapping
|
||||||
{
|
{
|
||||||
private static Dictionary<string, PlatformMapItem> PlatformMapCache = new Dictionary<string, PlatformMapItem>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the platform map from the embedded platform map resource
|
/// Updates the platform map from the embedded platform map resource
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -27,7 +25,8 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
string rawJson = reader.ReadToEnd();
|
string rawJson = reader.ReadToEnd();
|
||||||
List<PlatformMapItem> platforms = new List<PlatformMapItem>();
|
List<PlatformMapItem> platforms = new List<PlatformMapItem>();
|
||||||
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings{
|
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
MaxDepth = 64
|
MaxDepth = 64
|
||||||
};
|
};
|
||||||
platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson, jsonSerializerSettings);
|
platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson, jsonSerializerSettings);
|
||||||
@@ -73,8 +72,8 @@ namespace gaseous_server.Models
|
|||||||
|
|
||||||
foreach (PlatformMapItem mapItem in platforms)
|
foreach (PlatformMapItem mapItem in platforms)
|
||||||
{
|
{
|
||||||
// get the IGDB platform data
|
// insert dummy platform data - it'll be cleaned up on the first metadata refresh
|
||||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId);
|
Platform platform = CreateDummyPlatform(mapItem);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -93,73 +92,82 @@ namespace gaseous_server.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IGDB.Models.Platform CreateDummyPlatform(PlatformMapItem mapItem)
|
||||||
|
{
|
||||||
|
IGDB.Models.Platform platform = new IGDB.Models.Platform
|
||||||
|
{
|
||||||
|
Id = mapItem.IGDBId,
|
||||||
|
Name = mapItem.IGDBName,
|
||||||
|
Slug = mapItem.IGDBSlug,
|
||||||
|
AlternativeName = mapItem.AlternateNames.FirstOrDefault()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Storage.GetCacheStatus("Platform", mapItem.IGDBId) == Storage.CacheStatus.NotPresent)
|
||||||
|
{
|
||||||
|
Storage.NewCacheValue(platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return platform;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<PlatformMapItem> PlatformMap
|
public static List<PlatformMapItem> PlatformMap
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
// if (Database.DatabaseMemoryCache.GetCacheObject("PlatformMap") != null)
|
||||||
|
// {
|
||||||
|
// return (List<PlatformMapItem>)Database.DatabaseMemoryCache.GetCacheObject("PlatformMap");
|
||||||
|
// }
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM PlatformMap";
|
string sql = "SELECT * FROM PlatformMap";
|
||||||
DataTable data = db.ExecuteCMD(sql);
|
DataTable data = db.ExecuteCMD(sql); //, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromSeconds(5).Ticks));
|
||||||
|
|
||||||
List<PlatformMapItem> platformMaps = new List<PlatformMapItem>();
|
List<PlatformMapItem> platformMaps = new List<PlatformMapItem>();
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
long mapId = (long)row["Id"];
|
long mapId = (long)row["Id"];
|
||||||
if (PlatformMapCache.ContainsKey(mapId.ToString()))
|
|
||||||
|
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||||
|
if (mapItem != null)
|
||||||
{
|
{
|
||||||
PlatformMapItem mapItem = PlatformMapCache[mapId.ToString()];
|
platformMaps.Add(mapItem);
|
||||||
if (mapItem != null)
|
|
||||||
{
|
|
||||||
platformMaps.Add(mapItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
|
||||||
if (mapItem != null)
|
|
||||||
{
|
|
||||||
platformMaps.Add(mapItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
||||||
|
|
||||||
|
//Database.DatabaseMemoryCache.SetCacheObject("PlatformMap", platformMaps, 600);
|
||||||
|
|
||||||
return platformMaps;
|
return platformMaps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformMapItem GetPlatformMap(long Id)
|
public static PlatformMapItem GetPlatformMap(long Id)
|
||||||
{
|
{
|
||||||
if (PlatformMapCache.ContainsKey(Id.ToString()))
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM PlatformMap WHERE Id = @Id";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
dbDict.Add("Id", Id);
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count > 0)
|
||||||
{
|
{
|
||||||
return PlatformMapCache[Id.ToString()];
|
PlatformMapItem platformMap = BuildPlatformMapItem(data.Rows[0]);
|
||||||
|
|
||||||
|
return platformMap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Exception exception = new Exception("Platform Map Id " + Id + " does not exist.");
|
||||||
string sql = "SELECT * FROM PlatformMap WHERE Id = @Id";
|
Logging.Log(Logging.LogType.Critical, "Platform Map", "Platform Map Id " + Id + " does not exist.", exception);
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
throw exception;
|
||||||
dbDict.Add("Id", Id);
|
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
|
||||||
if (data.Rows.Count > 0)
|
|
||||||
{
|
|
||||||
PlatformMapItem platformMap = BuildPlatformMapItem(data.Rows[0]);
|
|
||||||
|
|
||||||
return platformMap;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Exception exception = new Exception("Platform Map Id " + Id + " does not exist.");
|
|
||||||
Logging.Log(Logging.LogType.Critical, "Platform Map", "Platform Map Id " + Id + " does not exist.", exception);
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WritePlatformMap(PlatformMapItem item, bool Update, bool AllowAvailableEmulatorOverwrite)
|
public static void WritePlatformMap(PlatformMapItem item, bool Update, bool AllowAvailableEmulatorOverwrite)
|
||||||
{
|
{
|
||||||
|
CreateDummyPlatform(item);
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
@@ -238,23 +246,32 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
foreach (PlatformMapItem.EmulatorBiosItem biosItem in item.Bios)
|
foreach (PlatformMapItem.EmulatorBiosItem biosItem in item.Bios)
|
||||||
{
|
{
|
||||||
sql = "INSERT INTO PlatformMap_Bios (Id, Filename, Description, Hash) VALUES (@Id, @Filename, @Description, @Hash);";
|
bool isEnabled = false;
|
||||||
|
if (item.EnabledBIOSHashes == null)
|
||||||
|
{
|
||||||
|
item.EnabledBIOSHashes = new List<string>();
|
||||||
|
}
|
||||||
|
if (item.EnabledBIOSHashes.Contains(biosItem.hash))
|
||||||
|
{
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = "INSERT INTO PlatformMap_Bios (Id, Filename, Description, Hash, Enabled) VALUES (@Id, @Filename, @Description, @Hash, @Enabled);";
|
||||||
dbDict.Clear();
|
dbDict.Clear();
|
||||||
dbDict.Add("Id", item.IGDBId);
|
dbDict.Add("Id", item.IGDBId);
|
||||||
dbDict.Add("Filename", biosItem.filename);
|
dbDict.Add("Filename", biosItem.filename);
|
||||||
dbDict.Add("Description", biosItem.description);
|
dbDict.Add("Description", biosItem.description);
|
||||||
dbDict.Add("Hash", biosItem.hash);
|
dbDict.Add("Hash", biosItem.hash);
|
||||||
|
dbDict.Add("Enabled", isEnabled);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PlatformMapCache.ContainsKey(item.IGDBId.ToString()))
|
// clear cache
|
||||||
{
|
Database.DatabaseMemoryCache.RemoveCacheObject("PlatformMap");
|
||||||
PlatformMapCache.Remove(item.IGDBId.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteAvailableEmulators (PlatformMapItem item)
|
public static void WriteAvailableEmulators(PlatformMapItem item)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
@@ -286,7 +303,16 @@ namespace gaseous_server.Models
|
|||||||
string sql = "";
|
string sql = "";
|
||||||
|
|
||||||
// get platform data
|
// get platform data
|
||||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId);
|
// IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId, false);
|
||||||
|
IGDB.Models.Platform? platform = null;
|
||||||
|
if (Storage.GetCacheStatus("Platform", IGDBId) == Storage.CacheStatus.NotPresent)
|
||||||
|
{
|
||||||
|
//platform = Platforms.GetPlatform(IGDBId, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
platform = (IGDB.Models.Platform)Storage.GetCacheValue<IGDB.Models.Platform>(new Platform(), "id", IGDBId);
|
||||||
|
}
|
||||||
|
|
||||||
if (platform != null)
|
if (platform != null)
|
||||||
{
|
{
|
||||||
@@ -352,6 +378,7 @@ namespace gaseous_server.Models
|
|||||||
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
||||||
|
List<string> enabledBios = new List<string>();
|
||||||
foreach (DataRow biosRow in biosTable.Rows)
|
foreach (DataRow biosRow in biosTable.Rows)
|
||||||
{
|
{
|
||||||
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
||||||
@@ -361,6 +388,11 @@ namespace gaseous_server.Models
|
|||||||
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
||||||
};
|
};
|
||||||
bioss.Add(bios);
|
bioss.Add(bios);
|
||||||
|
|
||||||
|
if ((bool)Common.ReturnValueIfNull(biosRow["Enabled"], true) == true)
|
||||||
|
{
|
||||||
|
enabledBios.Add(bios.hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build item
|
// build item
|
||||||
@@ -369,26 +401,20 @@ namespace gaseous_server.Models
|
|||||||
mapItem.IGDBName = platform.Name;
|
mapItem.IGDBName = platform.Name;
|
||||||
mapItem.IGDBSlug = platform.Slug;
|
mapItem.IGDBSlug = platform.Slug;
|
||||||
mapItem.AlternateNames = alternateNames;
|
mapItem.AlternateNames = alternateNames;
|
||||||
mapItem.Extensions = new PlatformMapItem.FileExtensions{
|
mapItem.Extensions = new PlatformMapItem.FileExtensions
|
||||||
|
{
|
||||||
SupportedFileExtensions = knownExtensions,
|
SupportedFileExtensions = knownExtensions,
|
||||||
UniqueFileExtensions = uniqueExtensions
|
UniqueFileExtensions = uniqueExtensions
|
||||||
};
|
};
|
||||||
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
||||||
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem{
|
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem
|
||||||
|
{
|
||||||
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
||||||
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
||||||
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
||||||
};
|
};
|
||||||
mapItem.Bios = bioss;
|
mapItem.Bios = bioss;
|
||||||
|
mapItem.EnabledBIOSHashes = enabledBios;
|
||||||
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
|
||||||
{
|
|
||||||
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapItem;
|
return mapItem;
|
||||||
}
|
}
|
||||||
@@ -455,6 +481,74 @@ namespace gaseous_server.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlatformMapItem GetUserPlatformMap(string UserId, long PlatformId, long GameId)
|
||||||
|
{
|
||||||
|
// get the system enabled bios hashes
|
||||||
|
Models.PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
|
||||||
|
|
||||||
|
// get the user enabled bios hashes
|
||||||
|
PlatformMapping.UserEmulatorConfiguration userEmulatorConfiguration = GetUserEmulator(UserId, GameId, PlatformId);
|
||||||
|
if (userEmulatorConfiguration != null)
|
||||||
|
{
|
||||||
|
platformMapItem.WebEmulator.Type = userEmulatorConfiguration.EmulatorType;
|
||||||
|
platformMapItem.WebEmulator.Core = userEmulatorConfiguration.Core;
|
||||||
|
platformMapItem.EnabledBIOSHashes = userEmulatorConfiguration.EnableBIOSFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return platformMapItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserEmulatorConfiguration GetUserEmulator(string UserId, long GameId, long PlatformId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT Mapping FROM User_PlatformMap WHERE id = @UserId AND GameId = @GameId AND PlatformId = @PlatformId;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "UserId", UserId },
|
||||||
|
{ "GameId", GameId },
|
||||||
|
{ "PlatformId", PlatformId }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
UserEmulatorConfiguration emulator = Newtonsoft.Json.JsonConvert.DeserializeObject<UserEmulatorConfiguration>((string)data.Rows[0]["Mapping"]);
|
||||||
|
|
||||||
|
return emulator;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUserEmulator(string UserId, long GameId, long PlatformId, UserEmulatorConfiguration Mapping)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "INSERT INTO User_PlatformMap (id, GameId, PlatformId, Mapping) VALUES (@UserId, @GameId, @PlatformId, @Mapping) ON DUPLICATE KEY UPDATE Mapping = @Mapping;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "UserId", UserId },
|
||||||
|
{ "GameId", GameId },
|
||||||
|
{ "PlatformId", PlatformId },
|
||||||
|
{ "Mapping", Newtonsoft.Json.JsonConvert.SerializeObject(Mapping) }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteUserEmulator(string UserId, long GameId, long PlatformId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "DELETE FROM User_PlatformMap WHERE id = @UserId AND GameId = @GameId AND PlatformId = @PlatformId;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "UserId", UserId },
|
||||||
|
{ "GameId", GameId },
|
||||||
|
{ "PlatformId", PlatformId }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
public class PlatformMapItem
|
public class PlatformMapItem
|
||||||
{
|
{
|
||||||
public long IGDBId { get; set; }
|
public long IGDBId { get; set; }
|
||||||
@@ -502,7 +596,16 @@ namespace gaseous_server.Models
|
|||||||
public string description { get; set; }
|
public string description { get; set; }
|
||||||
public string filename { get; set; }
|
public string filename { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> EnabledBIOSHashes { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public class UserEmulatorConfiguration
|
||||||
|
{
|
||||||
|
public string EmulatorType { get; set; }
|
||||||
|
public string Core { get; set; }
|
||||||
|
public List<string> EnableBIOSFiles { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
gaseous-server/Models/Signatures_Sources.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using NuGet.Protocol.Core.Types;
|
||||||
|
|
||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class Signatures_Sources
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string URL { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public string Version { get; set; }
|
||||||
|
public string Author { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Homepage { get; set; }
|
||||||
|
public gaseous_signature_parser.parser.SignatureParser SourceType { get; set; }
|
||||||
|
public string MD5 { get; set; }
|
||||||
|
public string SHA1 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
17
gaseous-server/Models/UserProfile.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class UserProfile
|
||||||
|
{
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string Quip { get; set; }
|
||||||
|
public ProfileImageItem? Avatar { get; set; }
|
||||||
|
public ProfileImageItem? ProfileBackground { get; set; }
|
||||||
|
public Dictionary<string, object> Data { get; set; }
|
||||||
|
public class ProfileImageItem
|
||||||
|
{
|
||||||
|
public string MimeType { get; set; }
|
||||||
|
public string Extension { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,6 +36,9 @@ db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.Conn
|
|||||||
|
|
||||||
// set up db
|
// set up db
|
||||||
db.InitDB();
|
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
|
// populate db with static data for lookups
|
||||||
AgeRatings.PopulateAgeMap();
|
AgeRatings.PopulateAgeMap();
|
||||||
@@ -71,7 +74,7 @@ ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(
|
|||||||
1,
|
1,
|
||||||
new List<ProcessQueue.QueueItemType>
|
new List<ProcessQueue.QueueItemType>
|
||||||
{
|
{
|
||||||
ProcessQueue.QueueItemType.All
|
ProcessQueue.QueueItemType.SignatureIngestor
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
true
|
true
|
||||||
@@ -398,9 +401,6 @@ gaseous_server.Classes.Metadata.Platforms.AssignAllPlatformsToGameIdZero();
|
|||||||
// extract platform map if not present
|
// extract platform map if not present
|
||||||
PlatformMapping.ExtractPlatformMap();
|
PlatformMapping.ExtractPlatformMap();
|
||||||
|
|
||||||
// force load platform map into cache
|
|
||||||
var platformMap = PlatformMapping.PlatformMap;
|
|
||||||
|
|
||||||
// add background tasks
|
// add background tasks
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.SignatureIngestor)
|
ProcessQueue.QueueItemType.SignatureIngestor)
|
||||||
|
@@ -1,40 +1 @@
|
|||||||
CREATE TABLE `Signatures_RomToSource` (
|
ALTER TABLE `Platform` CHANGE `Name` `Name` varchar(255);
|
||||||
`SourceId` int NOT NULL,
|
|
||||||
`RomId` int NOT NULL,
|
|
||||||
PRIMARY KEY (`SourceId`, `RomId`)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE `Signatures_Games_Countries` (
|
|
||||||
`GameId` INT NOT NULL,
|
|
||||||
`CountryId` INT NOT NULL,
|
|
||||||
PRIMARY KEY (`GameId`, `CountryId`),
|
|
||||||
CONSTRAINT `GameCountry` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE `Signatures_Games_Languages` (
|
|
||||||
`GameId` INT NOT NULL,
|
|
||||||
`LanguageId` INT NOT NULL,
|
|
||||||
PRIMARY KEY (`GameId`, `LanguageId`),
|
|
||||||
CONSTRAINT `GameLanguage` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE `Country` (
|
|
||||||
`Id` INT NOT NULL AUTO_INCREMENT,
|
|
||||||
`Code` VARCHAR(20) NULL,
|
|
||||||
`Value` VARCHAR(255) NULL,
|
|
||||||
PRIMARY KEY (`Id`),
|
|
||||||
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
|
||||||
INDEX `id_Value` (`Value` ASC) VISIBLE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE `Language` (
|
|
||||||
`Id` INT NOT NULL AUTO_INCREMENT,
|
|
||||||
`Code` VARCHAR(20) NULL,
|
|
||||||
`Value` VARCHAR(255) NULL,
|
|
||||||
PRIMARY KEY (`Id`),
|
|
||||||
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
|
||||||
INDEX `id_Value` (`Value` ASC) VISIBLE
|
|
||||||
);
|
|
||||||
|
|
||||||
ALTER TABLE `Games_Roms`
|
|
||||||
ADD COLUMN `RomDataVersion` INT DEFAULT 1;
|
|
97
gaseous-server/Support/Database/MySQL/gaseous-1023.sql
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
CREATE TABLE `Signatures_RomToSource` (
|
||||||
|
`SourceId` int NOT NULL,
|
||||||
|
`RomId` int NOT NULL,
|
||||||
|
PRIMARY KEY (`SourceId`, `RomId`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Signatures_Games_Countries` (
|
||||||
|
`GameId` INT NOT NULL,
|
||||||
|
`CountryId` INT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `CountryId`),
|
||||||
|
CONSTRAINT `GameCountry` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Signatures_Games_Languages` (
|
||||||
|
`GameId` INT NOT NULL,
|
||||||
|
`LanguageId` INT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `LanguageId`),
|
||||||
|
CONSTRAINT `GameLanguage` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Country` (
|
||||||
|
`Id` INT NOT NULL AUTO_INCREMENT,
|
||||||
|
`Code` VARCHAR(20) NULL,
|
||||||
|
`Value` VARCHAR(255) NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
||||||
|
INDEX `id_Value` (`Value` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Language` (
|
||||||
|
`Id` INT NOT NULL AUTO_INCREMENT,
|
||||||
|
`Code` VARCHAR(20) NULL,
|
||||||
|
`Value` VARCHAR(255) NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
||||||
|
INDEX `id_Value` (`Value` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `Games_Roms` ADD COLUMN `RomDataVersion` INT DEFAULT 1;
|
||||||
|
|
||||||
|
CREATE TABLE UserProfiles (
|
||||||
|
`Id` VARCHAR(45) NOT NULL,
|
||||||
|
`UserId` VARCHAR(45) NOT NULL,
|
||||||
|
`DisplayName` VARCHAR(255) NOT NULL,
|
||||||
|
`Quip` VARCHAR(255) NOT NULL,
|
||||||
|
`Avatar` LONGBLOB,
|
||||||
|
`AvatarExtension` CHAR(6),
|
||||||
|
`ProfileBackground` LONGBLOB,
|
||||||
|
`ProfileBackgroundExtension` CHAR(6),
|
||||||
|
`UnstructuredData` LONGTEXT NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`, `UserId`)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `PlatformMap_Bios`
|
||||||
|
ADD COLUMN `Enabled` BOOLEAN DEFAULT TRUE;
|
||||||
|
|
||||||
|
CREATE TABLE `User_PlatformMap` (
|
||||||
|
`id` VARCHAR(128) NOT NULL,
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`PlatformId` BIGINT NOT NULL,
|
||||||
|
`Mapping` LONGTEXT,
|
||||||
|
PRIMARY KEY (`id`, `GameId`, `PlatformId`),
|
||||||
|
CONSTRAINT `User_PlatformMap_UserId` FOREIGN KEY (`id`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `UserTimeTracking`
|
||||||
|
ADD COLUMN `PlatformId` BIGINT,
|
||||||
|
ADD COLUMN `IsMediaGroup` BOOLEAN DEFAULT FALSE,
|
||||||
|
ADD COLUMN `RomId` BIGINT;
|
||||||
|
|
||||||
|
CREATE TABLE `User_RecentPlayedRoms` (
|
||||||
|
`UserId` varchar(128) NOT NULL,
|
||||||
|
`GameId` bigint(20) NOT NULL,
|
||||||
|
`PlatformId` bigint(20) NOT NULL,
|
||||||
|
`RomId` bigint(20) NOT NULL,
|
||||||
|
`IsMediaGroup` tinyint(1) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (
|
||||||
|
`UserId`,
|
||||||
|
`GameId`,
|
||||||
|
`PlatformId`
|
||||||
|
),
|
||||||
|
CONSTRAINT `RecentPlayedRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `User_GameFavouriteRoms` (
|
||||||
|
`UserId` varchar(128) NOT NULL,
|
||||||
|
`GameId` bigint(20) NOT NULL,
|
||||||
|
`PlatformId` bigint(20) NOT NULL,
|
||||||
|
`RomId` bigint(20) NOT NULL,
|
||||||
|
`IsMediaGroup` tinyint(1) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (
|
||||||
|
`UserId`,
|
||||||
|
`GameId`,
|
||||||
|
`PlatformId`
|
||||||
|
),
|
||||||
|
CONSTRAINT `GameFavouriteRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||||
|
);
|
@@ -67,6 +67,7 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1021.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1021.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1022.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1022.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1023.sql" />
|
||||||
<None Remove="Classes\Metadata\" />
|
<None Remove="Classes\Metadata\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -114,5 +115,6 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1021.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1021.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1022.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1022.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1023.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
@@ -22,9 +22,11 @@
|
|||||||
if (StateUrl) {
|
if (StateUrl) {
|
||||||
console.log('Loading saved state from: ' + StateUrl);
|
console.log('Loading saved state from: ' + StateUrl);
|
||||||
EJS_loadStateURL = StateUrl;
|
EJS_loadStateURL = StateUrl;
|
||||||
EJS_startOnLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the emulator automatically when loaded
|
||||||
|
EJS_startOnLoaded = true;
|
||||||
|
|
||||||
// Path to the data directory
|
// Path to the data directory
|
||||||
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
||||||
|
|
||||||
@@ -42,10 +44,11 @@
|
|||||||
|
|
||||||
EJS_Buttons = {
|
EJS_Buttons = {
|
||||||
saveSavFiles: false,
|
saveSavFiles: false,
|
||||||
loadSavFiles: false
|
loadSavFiles: false,
|
||||||
|
exitEmulation: false
|
||||||
}
|
}
|
||||||
|
|
||||||
EJS_onSaveState = function(e) {
|
EJS_onSaveState = function (e) {
|
||||||
var returnValue = {
|
var returnValue = {
|
||||||
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
||||||
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
||||||
@@ -72,8 +75,12 @@
|
|||||||
returnValue = undefined;
|
returnValue = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
EJS_onLoadState = function(e) {
|
EJS_onLoadState = function (e) {
|
||||||
showDialog('emulatorloadstate', { "romId": romId, "IsMediaGroup": IsMediaGroup });
|
let rompath = decodeURIComponent(getQueryString('rompath', 'string'));
|
||||||
|
rompath = rompath.substring(rompath.lastIndexOf('/') + 1);
|
||||||
|
console.log(rompath);
|
||||||
|
let stateManager = new EmulatorStateManager(romId, IsMediaGroup, getQueryString('engine', 'string'), getQueryString('core', 'string'), platformId, gameId, rompath);
|
||||||
|
stateManager.open();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
16
gaseous-server/wwwroot/images/Critical.svg
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<title>stop-warning</title>
|
||||||
|
<g id="Layer_2" data-name="Layer 2">
|
||||||
|
<g id="invisible_box" data-name="invisible box">
|
||||||
|
<rect width="48" height="48" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<g id="icons_Q2" data-name="icons Q2">
|
||||||
|
<g>
|
||||||
|
<path d="M43.4,15.1,32.9,4.6A2,2,0,0,0,31.5,4h-15a2,2,0,0,0-1.4.6L4.6,15.1A2,2,0,0,0,4,16.5v15a2,2,0,0,0,.6,1.4L15.1,43.4a2,2,0,0,0,1.4.6h15a2,2,0,0,0,1.4-.6L43.4,32.9a2,2,0,0,0,.6-1.4v-15A2,2,0,0,0,43.4,15.1ZM40,30.6,30.6,40H17.4L8,30.6V17.4L17.4,8H30.6L40,17.4Z"/>
|
||||||
|
<path d="M26.8,24l5.6-5.6a2,2,0,0,0-2.8-2.8L24,21.2l-5.6-5.6a2,2,0,0,0-2.8,2.8L21.2,24l-5.6,5.6a1.9,1.9,0,0,0,0,2.8,1.9,1.9,0,0,0,2.8,0L24,26.8l5.6,5.6a1.9,1.9,0,0,0,2.8,0,1.9,1.9,0,0,0,0-2.8Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
After Width: | Height: | Size: 969 B |
8
gaseous-server/wwwroot/images/NoIntro-logo.svg
Normal file
After Width: | Height: | Size: 480 KiB |
1
gaseous-server/wwwroot/images/Ratings/ESRB/EC.svg
Normal file
After Width: | Height: | Size: 8.3 KiB |
17
gaseous-server/wwwroot/images/Warning.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<title>warning</title>
|
||||||
|
<g id="Layer_2" data-name="Layer 2">
|
||||||
|
<g id="invisible_box" data-name="invisible box">
|
||||||
|
<rect width="48" height="48" fill="none"/>
|
||||||
|
</g>
|
||||||
|
<g id="icons_Q2" data-name="icons Q2">
|
||||||
|
<g>
|
||||||
|
<path d="M24,9,40.6,39H7.5L24,9M2.3,40A2,2,0,0,0,4,43H44a2,2,0,0,0,1.7-3L25.7,4a2,2,0,0,0-3.4,0Z"/>
|
||||||
|
<path d="M22,19v9a2,2,0,0,0,4,0V19a2,2,0,0,0-4,0Z"/>
|
||||||
|
<circle cx="24" cy="34" r="2"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
After Width: | Height: | Size: 695 B |
12
gaseous-server/wwwroot/images/arrow-down.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512.011 512.011" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M505.755,123.592c-8.341-8.341-21.824-8.341-30.165,0L256.005,343.176L36.421,123.592c-8.341-8.341-21.824-8.341-30.165,0
|
||||||
|
s-8.341,21.824,0,30.165l234.667,234.667c4.16,4.16,9.621,6.251,15.083,6.251c5.462,0,10.923-2.091,15.083-6.251l234.667-234.667
|
||||||
|
C514.096,145.416,514.096,131.933,505.755,123.592z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 684 B |
12
gaseous-server/wwwroot/images/arrow-left.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512.006 512.006" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M388.419,475.59L168.834,256.005L388.418,36.421c8.341-8.341,8.341-21.824,0-30.165s-21.824-8.341-30.165,0
|
||||||
|
L123.586,240.923c-8.341,8.341-8.341,21.824,0,30.165l234.667,234.667c4.16,4.16,9.621,6.251,15.083,6.251
|
||||||
|
c5.461,0,10.923-2.091,15.083-6.251C396.76,497.414,396.76,483.931,388.419,475.59z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 679 B |
12
gaseous-server/wwwroot/images/arrow-right.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512.005 512.005" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M388.418,240.923L153.751,6.256c-8.341-8.341-21.824-8.341-30.165,0s-8.341,21.824,0,30.165L343.17,256.005
|
||||||
|
L123.586,475.589c-8.341,8.341-8.341,21.824,0,30.165c4.16,4.16,9.621,6.251,15.083,6.251c5.461,0,10.923-2.091,15.083-6.251
|
||||||
|
l234.667-234.667C396.759,262.747,396.759,249.264,388.418,240.923z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 682 B |
11
gaseous-server/wwwroot/images/arrow-up.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M505.752,358.248L271.085,123.582c-8.331-8.331-21.839-8.331-30.17,0L6.248,358.248c-8.331,8.331-8.331,21.839,0,30.17
|
||||||
|
s21.839,8.331,30.17,0L256,168.837l219.582,219.582c8.331,8.331,21.839,8.331,30.17,0S514.083,366.58,505.752,358.248z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 609 B |
69
gaseous-server/wwwroot/images/bios.svg
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<rect x="342.232" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="234.442" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="126.653" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="8.084" y="234.442" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
<rect x="8.084" y="342.232" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
<rect x="460.8" y="342.232" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
<rect x="460.8" y="234.442" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
<rect x="460.8" y="126.653" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
<rect x="342.232" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="234.442" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="126.653" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||||
|
<rect x="8.084" y="126.653" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="51.2" y="126.653" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="51.2" y="234.442" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="51.2" y="342.232" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="126.653" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
<rect x="234.442" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
<rect x="342.232" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
<rect x="428.463" y="342.232" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="428.463" y="234.442" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="428.463" y="126.653" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||||
|
<rect x="342.232" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
<rect x="234.442" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
<rect x="126.653" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#595E62;" d="M428.463,385.347v32.337c0,5.928-4.851,10.779-10.779,10.779h-32.337h-43.116h-64.674h-43.116
|
||||||
|
h-64.674h-43.116H94.316c-5.928,0-10.779-4.851-10.779-10.779v-32.337v-43.116v-64.674v-43.116v-64.674v-43.116V94.316
|
||||||
|
c0-5.928,4.851-10.779,10.779-10.779h32.337h43.116h64.674h43.116h64.674h43.116h32.337c5.928,0,10.779,4.851,10.779,10.779v32.337
|
||||||
|
v43.116v64.674v43.116v64.674V385.347z M385.347,385.347V126.653H126.653v258.695H385.347z"/>
|
||||||
|
<rect x="126.653" y="126.653" style="fill:#36C63F;" width="258.695" height="258.695"/>
|
||||||
|
<path style="fill:#00AB4E;" d="M173.785,126.653h-47.132v258.695h258.695v-47.132C284.709,306.659,205.341,227.291,173.785,126.653z
|
||||||
|
"/>
|
||||||
|
<path style="fill:#44494C;" d="M126.653,385.347V126.653H256V83.537h-21.558h-64.674h-43.116H94.316
|
||||||
|
c-5.928,0-10.779,4.851-10.779,10.779v32.337v43.116v64.674v43.116v64.674v43.116v32.337c0,5.928,4.851,10.779,10.779,10.779h32.337
|
||||||
|
h43.116h64.674H256v-43.116H126.653z"/>
|
||||||
|
<g>
|
||||||
|
<rect x="180.547" y="161.684" style="fill:#FFFFFF;" width="150.905" height="16.168"/>
|
||||||
|
<rect x="180.547" y="237.137" style="fill:#FFFFFF;" width="150.905" height="16.168"/>
|
||||||
|
<rect x="180.547" y="199.411" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||||
|
<rect x="180.547" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||||
|
<rect x="223.663" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||||
|
<rect x="299.116" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||||
|
<rect x="239.832" y="199.411" style="fill:#FFFFFF;" width="91.621" height="16.168"/>
|
||||||
|
</g>
|
||||||
|
<path d="M118.568,393.432h274.863V118.568H118.568V393.432z M134.737,134.737h242.526v242.526H134.737V134.737z"/>
|
||||||
|
<path d="M512,177.853v-59.284h-75.453V94.316c0-10.401-8.463-18.863-18.863-18.863h-24.253V5.389h-59.284v70.063h-48.505V5.389
|
||||||
|
h-59.284v70.063h-48.505V5.389h-59.284v70.063H94.316c-10.401,0-18.863,8.463-18.863,18.863v24.253H0v59.284h75.453v48.505H0v59.284
|
||||||
|
h75.453v48.505H0v59.284h75.453v24.253c0,10.401,8.463,18.863,18.863,18.863h24.253v70.063h59.284v-70.063h48.505v70.063h59.284
|
||||||
|
v-70.063h48.505v70.063h59.284v-70.063h24.253c10.401,0,18.863-8.463,18.863-18.863v-24.253H512v-59.284h-75.453v-48.505H512
|
||||||
|
v-59.284h-75.453v-48.505H512z M436.547,134.737h16.168v26.947h-16.168V134.737z M495.832,161.684h-26.947v-26.947h26.947V161.684z
|
||||||
|
M350.316,59.284h26.947v16.168h-26.947V59.284z M377.263,21.558v21.558h-26.947V21.558H377.263z M242.526,59.284h26.947v16.168
|
||||||
|
h-26.947V59.284z M269.474,21.558v21.558h-26.947V21.558H269.474z M134.737,59.284h26.947v16.168h-26.947V59.284z M161.684,21.558
|
||||||
|
v21.558h-26.947V21.558H161.684z M75.453,161.684H59.284v-26.947h16.168V161.684z M16.168,134.737h26.947v26.947H16.168V134.737z
|
||||||
|
M75.453,269.474H59.284v-26.947h16.168V269.474z M16.168,242.526h26.947v26.947H16.168V242.526z M75.453,377.263H59.284v-26.947
|
||||||
|
h16.168V377.263z M16.168,350.316h26.947v26.947H16.168V350.316z M161.684,452.716h-26.947v-16.168h26.947V452.716z
|
||||||
|
M134.737,490.442v-21.558h26.947v21.558H134.737z M269.474,452.716h-26.947v-16.168h26.947V452.716z M242.526,490.442v-21.558
|
||||||
|
h26.947v21.558H242.526z M377.263,452.716h-26.947v-16.168h26.947V452.716z M350.316,490.442v-21.558h26.947v21.558H350.316z
|
||||||
|
M436.547,350.316h16.168v26.947h-16.168V350.316z M495.832,377.263h-26.947v-26.947h26.947V377.263z M436.547,242.526h16.168
|
||||||
|
v26.947h-16.168V242.526z M495.832,269.474h-26.947v-26.947h26.947V269.474z M420.379,417.684c0,1.461-1.234,2.695-2.695,2.695
|
||||||
|
H94.316c-1.461,0-2.695-1.234-2.695-2.695V94.316c0-1.461,1.234-2.695,2.695-2.695h323.368c1.461,0,2.695,1.234,2.695,2.695V417.684
|
||||||
|
z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
17
gaseous-server/wwwroot/images/cross.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
|
||||||
|
<title>cross-circle</title>
|
||||||
|
<desc>Created with Sketch Beta.</desc>
|
||||||
|
<defs>
|
||||||
|
|
||||||
|
</defs>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g id="Icon-Set" sketch:type="MSLayerGroup" transform="translate(-568.000000, -1087.000000)" fill="red">
|
||||||
|
<path d="M584,1117 C576.268,1117 570,1110.73 570,1103 C570,1095.27 576.268,1089 584,1089 C591.732,1089 598,1095.27 598,1103 C598,1110.73 591.732,1117 584,1117 L584,1117 Z M584,1087 C575.163,1087 568,1094.16 568,1103 C568,1111.84 575.163,1119 584,1119 C592.837,1119 600,1111.84 600,1103 C600,1094.16 592.837,1087 584,1087 L584,1087 Z M589.717,1097.28 C589.323,1096.89 588.686,1096.89 588.292,1097.28 L583.994,1101.58 L579.758,1097.34 C579.367,1096.95 578.733,1096.95 578.344,1097.34 C577.953,1097.73 577.953,1098.37 578.344,1098.76 L582.58,1102.99 L578.314,1107.26 C577.921,1107.65 577.921,1108.29 578.314,1108.69 C578.708,1109.08 579.346,1109.08 579.74,1108.69 L584.006,1104.42 L588.242,1108.66 C588.633,1109.05 589.267,1109.05 589.657,1108.66 C590.048,1108.27 590.048,1107.63 589.657,1107.24 L585.42,1103.01 L589.717,1098.71 C590.11,1098.31 590.11,1097.68 589.717,1097.28 L589.717,1097.28 Z" id="cross-circle" sketch:type="MSShapeGroup">
|
||||||
|
|
||||||
|
</path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
4
gaseous-server/wwwroot/images/discord.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18.59 5.88997C17.36 5.31997 16.05 4.89997 14.67 4.65997C14.5 4.95997 14.3 5.36997 14.17 5.69997C12.71 5.47997 11.26 5.47997 9.83001 5.69997C9.69001 5.36997 9.49001 4.95997 9.32001 4.65997C7.94001 4.89997 6.63001 5.31997 5.40001 5.88997C2.92001 9.62997 2.25001 13.28 2.58001 16.87C4.23001 18.1 5.82001 18.84 7.39001 19.33C7.78001 18.8 8.12001 18.23 8.42001 17.64C7.85001 17.43 7.31001 17.16 6.80001 16.85C6.94001 16.75 7.07001 16.64 7.20001 16.54C10.33 18 13.72 18 16.81 16.54C16.94 16.65 17.07 16.75 17.21 16.85C16.7 17.16 16.15 17.42 15.59 17.64C15.89 18.23 16.23 18.8 16.62 19.33C18.19 18.84 19.79 18.1 21.43 16.87C21.82 12.7 20.76 9.08997 18.61 5.88997H18.59ZM8.84001 14.67C7.90001 14.67 7.13001 13.8 7.13001 12.73C7.13001 11.66 7.88001 10.79 8.84001 10.79C9.80001 10.79 10.56 11.66 10.55 12.73C10.55 13.79 9.80001 14.67 8.84001 14.67ZM15.15 14.67C14.21 14.67 13.44 13.8 13.44 12.73C13.44 11.66 14.19 10.79 15.15 10.79C16.11 10.79 16.87 11.66 16.86 12.73C16.86 13.79 16.11 14.67 15.15 14.67Z" fill="#000000"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
gaseous-server/wwwroot/images/github-mark.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
After Width: | Height: | Size: 963 B |
5
gaseous-server/wwwroot/images/hasheous.svg
Normal file
After Width: | Height: | Size: 567 KiB |
4
gaseous-server/wwwroot/images/home.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3103 1.77586C11.6966 1.40805 12.3034 1.40805 12.6897 1.77586L20.6897 9.39491L23.1897 11.7759C23.5896 12.1567 23.605 12.7897 23.2241 13.1897C22.8433 13.5896 22.2103 13.605 21.8103 13.2241L21 12.4524V20C21 21.1046 20.1046 22 19 22H14H10H5C3.89543 22 3 21.1046 3 20V12.4524L2.18966 13.2241C1.78972 13.605 1.15675 13.5896 0.775862 13.1897C0.394976 12.7897 0.410414 12.1567 0.810345 11.7759L3.31034 9.39491L11.3103 1.77586ZM5 10.5476V20H9V15C9 13.3431 10.3431 12 12 12C13.6569 12 15 13.3431 15 15V20H19V10.5476L12 3.88095L5 10.5476ZM13 20V15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V20H13Z" fill="#000000"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 901 B |
9
gaseous-server/wwwroot/images/pending.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
|
<g fill-rule="evenodd">
|
||||||
|
|
||||||
|
<path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/>
|
||||||
|
|
After Width: | Height: | Size: 576 B |
54
gaseous-server/wwwroot/images/processing.svg
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 33.132 33.132" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M33.132,30.941l-6.096-5.439c1.151-1.459,1.843-3.297,1.843-5.297c0-4.453-3.414-8.107-7.761-8.525
|
||||||
|
c-0.061-0.18-0.127-0.355-0.232-0.537l-0.148-0.258c0.339-0.482,0.529-0.996,0.529-1.535V6.289c0-0.416-0.116-0.838-0.347-1.256
|
||||||
|
l-0.07-0.131c0.095-0.221,0.161-0.447,0.161-0.688c0-2.472-5.35-3.81-10.379-3.81c-5.03,0-10.375,1.338-10.375,3.811
|
||||||
|
c0,0.24,0.064,0.467,0.16,0.688L0.345,5.037C0.114,5.451,0,5.873,0,6.289V9.35c0,0.539,0.188,1.053,0.528,1.535l-0.15,0.262
|
||||||
|
C0.126,11.578,0,12.019,0,12.455v3.062c0,0.525,0.179,1.029,0.502,1.502l-0.124,0.213C0.126,17.666,0,18.107,0,18.539v3.066
|
||||||
|
c0,2.721,4.669,4.85,10.632,4.85c1.221,0,2.383-0.092,3.465-0.26c-0.068-0.09-0.123-0.193-0.188-0.291
|
||||||
|
c1.571,1.762,3.846,2.881,6.389,2.881c2.076,0,3.984-0.74,5.47-1.973l5.431,5.916L33.132,30.941z M16.665,16.543
|
||||||
|
c2.088-2.074,5.455-2.061,7.523,0.02c2.073,2.086,2.059,5.459-0.024,7.525c-2.087,2.072-5.454,2.062-7.528-0.023
|
||||||
|
C14.565,21.98,14.583,18.611,16.665,16.543z M10.632,1.545c5.723,0,9.24,1.555,9.24,2.67c0,1.117-3.518,2.672-9.24,2.672
|
||||||
|
c-5.726,0-9.238-1.555-9.238-2.672C1.394,3.099,4.906,1.545,10.632,1.545z M1.14,6.802c1.705,1.445,5.66,2.193,9.492,2.193
|
||||||
|
c3.834,0,7.787-0.748,9.494-2.193v2.547c0,1.756-3.896,3.713-9.494,3.713c-5.594,0-9.492-1.957-9.492-3.713
|
||||||
|
C1.14,9.349,1.14,6.802,1.14,6.802z M1.14,12.636c1.744,1.6,5.336,2.621,9.492,2.621c0.99,0,1.926-0.078,2.829-0.191
|
||||||
|
c-0.695,0.926-1.224,1.986-1.501,3.146c-0.077,0.316-0.136,0.639-0.176,0.969c-0.382,0.018-0.754,0.049-1.152,0.049
|
||||||
|
c-5.594,0-9.492-1.957-9.492-3.713C1.14,15.517,1.14,12.636,1.14,12.636z M10.632,25.318c-5.594,0-9.492-1.957-9.492-3.713v-2.881
|
||||||
|
c1.744,1.6,5.336,2.619,9.492,2.619c0.396,0,0.779-0.025,1.164-0.049c0.133,1.045,0.447,2.029,0.922,2.918
|
||||||
|
c0.173,0.332,0.38,0.641,0.594,0.941C12.474,25.258,11.579,25.318,10.632,25.318z"/>
|
||||||
|
<path d="M24.4,19.961l0.379-1.129c-2.979-4.801-7.113-2.014-7.113-2.014C22.841,15.881,24.4,19.961,24.4,19.961z"/>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
70
gaseous-server/wwwroot/images/recent.svg
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="30"
|
||||||
|
height="30"
|
||||||
|
viewBox="0 0 30 30"
|
||||||
|
version="1.1"
|
||||||
|
id="svg822"
|
||||||
|
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"
|
||||||
|
sodipodi:docname="recent.svg">
|
||||||
|
<defs
|
||||||
|
id="defs816" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="17.833333"
|
||||||
|
inkscape:cx="15"
|
||||||
|
inkscape:cy="15"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="713"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid816" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata819">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>
|
||||||
|
|
||||||
|
</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-289.0625)">
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 15 3 C 8.3844276 3 3 8.38443 3 15 C 3 21.61557 8.3844276 27 15 27 C 21.615572 27 27 21.61557 27 15 C 27 8.38443 21.615572 3 15 3 z M 15 5 C 20.534692 5 25 9.46531 25 15 C 25 20.53469 20.534692 25 15 25 C 9.4653079 25 5 20.53469 5 15 C 5 9.46531 9.4653079 5 15 5 z M 15 7 C 14.446 7 14 7.446 14 8 L 14 15 C 14 15.554 14.446 16 15 16 L 22 16 C 22.554 16 23 15.554 23 15 C 23 14.446 22.554 14 22 14 L 16 14 L 16 8 C 16 7.446 15.554 7 15 7 z "
|
||||||
|
transform="translate(0,289.0625)"
|
||||||
|
id="path1099" />
|
||||||
|
</g>
|
After Width: | Height: | Size: 3.5 KiB |
15
gaseous-server/wwwroot/images/start-task.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
width="800px" height="800px" viewBox="0 0 46 46" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M20.913,34.756c-0.625,0.627-1.565,0.816-2.383,0.479c-0.818-0.336-1.352-1.135-1.352-2.02V12.784
|
||||||
|
c0-0.885,0.534-1.683,1.352-2.021c0.818-0.338,1.759-0.149,2.383,0.479l9.657,9.706c1.129,1.134,1.129,2.967,0,4.102
|
||||||
|
L20.913,34.756z"/>
|
||||||
|
<path d="M23,6c9.374,0,17,7.626,17,17s-7.626,17-17,17S6,32.374,6,23S13.626,6,23,6 M23,0C10.298,0,0,10.297,0,23s10.298,23,23,23
|
||||||
|
s23-10.297,23-23S35.702,0,23,0L23,0z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 878 B |
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" version="1.1" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="m14.25 8.75c-.5 2.5-2.3849 4.85363-5.03069 5.37991-2.64578.5263-5.33066-.7044-6.65903-3.0523-1.32837-2.34784-1.00043-5.28307.81336-7.27989 1.81379-1.99683 4.87636-2.54771 7.37636-1.54771"/>
|
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="green" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<polyline points="5.75 7.75,8.25 10.25,14.25 3.75"/>
|
<path d="M7.75 12L10.58 14.83L16.25 9.17004" stroke="green" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 579 B After Width: | Height: | Size: 538 B |
12
gaseous-server/wwwroot/images/viewicon.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C1.89543 1 1 1.89543 1 3V5C1 6.10457 1.89543 7 3 7H5C6.10457 7 7 6.10457 7 5V3C7 1.89543 6.10457 1 5 1H3ZM5 3H3L3 5H5V3Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 9C1.89543 9 1 9.89543 1 11V13C1 14.1046 1.89543 15 3 15H5C6.10457 15 7 14.1046 7 13V11C7 9.89543 6.10457 9 5 9H3ZM5 11H3L3 13H5V11Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 19C1 17.8954 1.89543 17 3 17H5C6.10457 17 7 17.8954 7 19V21C7 22.1046 6.10457 23 5 23H3C1.89543 23 1 22.1046 1 21V19ZM3 19H5V21H3L3 19Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 1C9.89543 1 9 1.89543 9 3V5C9 6.10457 9.89543 7 11 7H13C14.1046 7 15 6.10457 15 5V3C15 1.89543 14.1046 1 13 1H11ZM13 3H11V5H13V3Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 11C9 9.89543 9.89543 9 11 9H13C14.1046 9 15 9.89543 15 11V13C15 14.1046 14.1046 15 13 15H11C9.89543 15 9 14.1046 9 13V11ZM11 11H13V13H11V11Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 17C9.89543 17 9 17.8954 9 19V21C9 22.1046 9.89543 23 11 23H13C14.1046 23 15 22.1046 15 21V19C15 17.8954 14.1046 17 13 17H11ZM13 19H11V21H13V19Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 3C17 1.89543 17.8954 1 19 1H21C22.1046 1 23 1.89543 23 3V5C23 6.10457 22.1046 7 21 7H19C17.8954 7 17 6.10457 17 5V3ZM19 3H21V5H19V3Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 9C17.8954 9 17 9.89543 17 11V13C17 14.1046 17.8954 15 19 15H21C22.1046 15 23 14.1046 23 13V11C23 9.89543 22.1046 9 21 9H19ZM21 11H19V13H21V11Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 19C17 17.8954 17.8954 17 19 17H21C22.1046 17 23 17.8954 23 19V21C23 22.1046 22.1046 23 21 23H19C17.8954 23 17 22.1046 17 21V19ZM19 19H21V21H19V19Z" fill="#0F0F0F"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
8
gaseous-server/wwwroot/images/viewinfinite.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="#2e3436">
|
||||||
|
<path d="m 5.5 0 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 5 c 0.277344 0 0.5 -0.222656 0.5 -0.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 5 c 0.277344 0 0.5 -0.222656 0.5 -0.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 8 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 5 c 0.277344 0 0.5 -0.222656 0.5 -0.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 5 c 0.277344 0 0.5 -0.222656 0.5 -0.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 0" fill-opacity="0.34902"/>
|
||||||
|
<path d="m 15 7 h -14 v 2 h 14 z m 0 0"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1023 B |
7
gaseous-server/wwwroot/images/viewlist.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 6C9 4.34315 7.65685 3 6 3H4C2.34315 3 1 4.34315 1 6V8C1 9.65685 2.34315 11 4 11H6C7.65685 11 9 9.65685 9 8V6ZM7 6C7 5.44772 6.55228 5 6 5H4C3.44772 5 3 5.44772 3 6V8C3 8.55228 3.44772 9 4 9H6C6.55228 9 7 8.55228 7 8V6Z" fill="#0F0F0F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 16C9 14.3431 7.65685 13 6 13H4C2.34315 13 1 14.3431 1 16V18C1 19.6569 2.34315 21 4 21H6C7.65685 21 9 19.6569 9 18V16ZM7 16C7 15.4477 6.55228 15 6 15H4C3.44772 15 3 15.4477 3 16V18C3 18.5523 3.44772 19 4 19H6C6.55228 19 7 18.5523 7 18V16Z" fill="#0F0F0F"/>
|
||||||
|
<path d="M11 7C11 6.44772 11.4477 6 12 6H22C22.5523 6 23 6.44772 23 7C23 7.55228 22.5523 8 22 8H12C11.4477 8 11 7.55228 11 7Z" fill="#0F0F0F"/>
|
||||||
|
<path d="M11 17C11 16.4477 11.4477 16 12 16H22C22.5523 16 23 16.4477 23 17C23 17.5523 22.5523 18 22 18H12C11.4477 18 11 17.5523 11 17Z" fill="#0F0F0F"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
9
gaseous-server/wwwroot/images/viewpaged.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="#2e3436">
|
||||||
|
<path d="m 9 5.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 h -3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 3 c 0.277344 0 0.5 -0.222656 0.5 -0.5 z m 0 0" fill-opacity="0.34902"/>
|
||||||
|
<path d="m 4 0 c -1.644531 0 -3 1.355469 -3 3 v 7 c 0 1.644531 1.355469 3 3 3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -7 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 6 c 0.570312 0 1 0.429688 1 1 v 7 c 0 0.570312 -0.429688 1 -1 1 h -6 c -0.570312 0 -1 -0.429688 -1 -1 v -7 c 0 -0.570312 0.429688 -1 1 -1 z m 11 2 c -0.550781 0 -1 0.449219 -1 1 v 8 c 0 0.550781 -0.449219 1 -1 1 h -7 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 7 c 1.65625 0 3 -1.34375 3 -3 v -8 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0"/>
|
||||||
|
<path d="m 9 8.5 v -1 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 h -3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 1 c 0 0.277344 0.222656 0.5 0.5 0.5 h 3 c 0.277344 0 0.5 -0.222656 0.5 -0.5 z m 0 0" fill-opacity="0.34902"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,23 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<script src="/api/v1.1/System/VersionFile"></script>
|
<script src="/api/v1.1/System/VersionFile"></script>
|
||||||
<link type="text/css" rel="stylesheet" href="/styles/style.css" dat-href="/styles/style.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/styles/notifications.css" dat-href="/styles/notifications.css" />
|
|
||||||
<script src="/scripts/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="/scripts/moment-with-locales.min.js"></script>
|
|
||||||
<link href="/styles/select2.min.css" rel="stylesheet" />
|
|
||||||
<link href="/styles/dropzone.min.css" rel="stylesheet" type="text/css" />
|
|
||||||
<script src="/scripts/jquery.lazy.min.js"></script>
|
|
||||||
<script src="/scripts/jquery.lazy.plugins.min.js"></script>
|
|
||||||
<script src="/scripts/select2.min.js"></script>
|
|
||||||
<script src="/scripts/dropzone.min.js"></script>
|
|
||||||
<script src="/scripts/simpleUpload.min.js"></script>
|
|
||||||
<script src="/scripts/main.js" type="text/javascript"></script>
|
|
||||||
<script src="/scripts/notifications.js" type="text/javascript"></script>
|
|
||||||
<script src="/scripts/filterformating.js" type="text/javascript"></script>
|
|
||||||
<script src="/scripts/gamesformating.js" type="text/javascript"></script>
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||||
@@ -25,165 +11,138 @@
|
|||||||
<title>Gaseous Games</title>
|
<title>Gaseous Games</title>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var head = document.getElementsByTagName('head')[0];
|
// update src links to ensure the latest versions are always loaded.
|
||||||
|
|
||||||
// update links
|
let styleSheets = [
|
||||||
var headLinks = document.getElementsByTagName('link');
|
"/styles/select2.min.css",
|
||||||
for (var i = 0; i < headLinks.length; i++) {
|
"/styles/stylevars.css",
|
||||||
if (headLinks[i].getAttribute('dat-href') && headLinks[i].rel == "stylesheet") {
|
"/styles/style.css",
|
||||||
var newLink = document.createElement('link');
|
"/styles/notifications.css"
|
||||||
newLink.rel = "stylesheet";
|
];
|
||||||
newLink.href = headLinks[i].getAttribute('dat-href') + '?v=' + AppVersion;
|
|
||||||
newLink.type = "text/css";
|
|
||||||
|
|
||||||
headLinks[i].parentElement.removeChild(headLinks[i]);
|
let scriptLinks = [
|
||||||
head.appendChild(newLink);
|
"/scripts/jquery-3.6.0.min.js",
|
||||||
}
|
"/scripts/jquery.lazy.min.js",
|
||||||
|
"/scripts/jquery.lazy.plugins.min.js",
|
||||||
|
"/scripts/moment-with-locales.min.js",
|
||||||
|
"/scripts/select2.min.js",
|
||||||
|
"/scripts/modals.js",
|
||||||
|
"/scripts/preferences.js",
|
||||||
|
"/scripts/account.js",
|
||||||
|
"/scripts/libraries.js",
|
||||||
|
"/scripts/notifications.js",
|
||||||
|
"/scripts/rominfo.js",
|
||||||
|
"/scripts/uploadrom.js",
|
||||||
|
"/scripts/filterformating.js",
|
||||||
|
"/scripts/gamesformating.js",
|
||||||
|
"/scripts/main.js"
|
||||||
|
];
|
||||||
|
|
||||||
|
let head = document.getElementsByTagName('head')[0];
|
||||||
|
|
||||||
|
// placeholder for global userProfile variable
|
||||||
|
var userProfile;
|
||||||
|
|
||||||
|
// update script links
|
||||||
|
for (let i = 0; i < scriptLinks.length; i++) {
|
||||||
|
let newScript = document.createElement('script');
|
||||||
|
newScript.src = scriptLinks[i] + '?v=' + AppVersion;
|
||||||
|
newScript.type = "text/javascript";
|
||||||
|
newScript.async = false;
|
||||||
|
|
||||||
|
head.appendChild(newScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userProfile;
|
// update stylesheet links
|
||||||
|
for (let i = 0; i < styleSheets.length; i++) {
|
||||||
|
let newLink = document.createElement('link');
|
||||||
|
newLink.rel = "stylesheet";
|
||||||
|
newLink.href = styleSheets[i] + '?v=' + AppVersion;
|
||||||
|
newLink.type = "text/css";
|
||||||
|
|
||||||
|
head.appendChild(newLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function LoadPageContent(page, targetDiv) {
|
||||||
|
if (targetDiv == undefined || targetDiv == null || targetDiv == '') {
|
||||||
|
targetDiv = 'content';
|
||||||
|
}
|
||||||
|
|
||||||
|
// load page content
|
||||||
|
let pageContentResponse = await fetch('/pages/' + page + '.html' + '?v=' + AppVersion);
|
||||||
|
let pageContentContent = await pageContentResponse.text();
|
||||||
|
document.getElementById(targetDiv).innerHTML = pageContentContent;
|
||||||
|
|
||||||
|
// load page script
|
||||||
|
let pageScriptLink = '/pages/' + page + '.js';
|
||||||
|
let script = document.createElement('script');
|
||||||
|
script.type = 'text/javascript';
|
||||||
|
script.src = pageScriptLink + '?v=' + AppVersion;
|
||||||
|
script.async = false;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
backgroundImageHandler = new BackgroundImageRotator();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Background Images -->
|
||||||
|
<div id="bgImages"></div>
|
||||||
|
<div id="bgImage_Opacity"></div>
|
||||||
|
|
||||||
<!-- Notifications -->
|
<!-- Notifications -->
|
||||||
<div id="notifications_target"></div>
|
<div id="notifications_target"></div>
|
||||||
|
|
||||||
<div id="banner_icon" onclick="window.location.href = '/index.html';">
|
<!-- Page Banner -->
|
||||||
<img src="/images/logo.png" alt="Gaseous" id="banner_icon_image" />
|
<div id="banner_target"></div>
|
||||||
</div>
|
|
||||||
<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();" />
|
|
||||||
<div id="myDropdown" class="dropdown-content">
|
|
||||||
<div id="banner_user_roles"></div>
|
|
||||||
<a href="#" onclick="showDialog('userprofile');">Profile</a>
|
|
||||||
<a href="#" onclick="userLogoff();">Sign Out</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="banner_cog" onclick="window.location.href = '/index.html?page=settings';" class="banner_button">
|
<!-- Page Content -->
|
||||||
<img src="/images/settings.svg" alt="Settings" title="Settings" id="banner_system_image" class="banner_button_image" />
|
<div id="content"></div>
|
||||||
<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" />
|
|
||||||
<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" />
|
|
||||||
<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" />
|
|
||||||
<span id="banner_library_label">Library</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous Games</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="content">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- The Modal -->
|
|
||||||
<div id="myModal" class="modal">
|
|
||||||
|
|
||||||
<!-- Modal content -->
|
|
||||||
<div class="modal-content">
|
|
||||||
<span class="close">×</span>
|
|
||||||
<div><h1 id="modal-heading">Modal heading</h1></div>
|
|
||||||
<div id="modal-content">Some text in the Modal..</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- The Modal -->
|
|
||||||
<div id="myModalSub" class="modal">
|
|
||||||
|
|
||||||
<!-- Modal content -->
|
|
||||||
<div class="modal-content-sub">
|
|
||||||
<span id="modal-close-sub" class="close">×</span>
|
|
||||||
<div id="modal-content-sub">Some text in the Modal..</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var modalVariables = null;
|
// start the application
|
||||||
|
let backgroundImageHandler = undefined;
|
||||||
|
console.log("Starting Gaseous Games");
|
||||||
|
console.log("App Version: " + AppVersion);
|
||||||
|
console.log("First Run Status: " + FirstRunStatus);
|
||||||
|
switch (FirstRunStatus) {
|
||||||
|
case 0:
|
||||||
|
case "0":
|
||||||
|
// first run - load first run wizard
|
||||||
|
LoadPageContent('first', 'content');
|
||||||
|
break;
|
||||||
|
|
||||||
// redirect if first run status = 0
|
default:
|
||||||
if (FirstRunStatus == 0) {
|
// first run - load login page or redirect if user already logged in
|
||||||
window.location.replace("/pages/first.html");
|
|
||||||
}
|
|
||||||
|
|
||||||
// redirect if not logged in
|
fetch('/api/v1.1/Account/Profile/Basic')
|
||||||
ajaxCall(
|
.then(async response => {
|
||||||
'/api/v1.1/Account/Profile/Basic',
|
if (response.ok) {
|
||||||
'GET',
|
// user is signed in - start setting up the application
|
||||||
function(result) {
|
console.log("User is logged in");
|
||||||
console.log("User is logged in");
|
userProfile = await response.json();
|
||||||
userProfile = result;
|
|
||||||
|
|
||||||
loadAvatar(userProfile.avatar);
|
// load page banner
|
||||||
|
LoadPageContent('banner', 'banner_target');
|
||||||
|
|
||||||
// hide the upload button if it's not permitted
|
// load page content
|
||||||
var uploadButton = document.getElementById('banner_upload');
|
let pageSelection = getQueryString('page', 'string');
|
||||||
if (!userProfile.roles.includes("Admin") && !userProfile.roles.includes("Gamer")) {
|
|
||||||
uploadButton.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// populate page
|
if (!pageSelection) {
|
||||||
var myParam = getQueryString('page', 'string');
|
pageSelection = GetPreference("DefaultHomePage", 'home');
|
||||||
|
}
|
||||||
if (!myParam) {
|
LoadPageContent(pageSelection, 'content');
|
||||||
myParam = 'home';
|
} else {
|
||||||
}
|
// user is not signed in - load login page
|
||||||
|
LoadPageContent('login');
|
||||||
$('#content').load('/pages/' + myParam + '.html?v=' + AppVersion);
|
}
|
||||||
},
|
})
|
||||||
function(error) {
|
.catch((error) => {
|
||||||
window.location.replace("/pages/login.html");
|
console.log(error);
|
||||||
}
|
LoadPageContent('login');
|
||||||
);
|
});
|
||||||
|
break;
|
||||||
/* When the user clicks on the button,
|
|
||||||
toggle between hiding and showing the dropdown content */
|
|
||||||
function showMenu() {
|
|
||||||
document.getElementById("myDropdown").classList.toggle("show");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the dropdown menu if the user clicks outside of it
|
|
||||||
window.onclick = function(event) {
|
|
||||||
if (!event.target.matches('.dropbtn')) {
|
|
||||||
var dropdowns = document.getElementsByClassName("dropdown-content");
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < dropdowns.length; i++) {
|
|
||||||
var openDropdown = dropdowns[i];
|
|
||||||
if (openDropdown.classList.contains('show')) {
|
|
||||||
openDropdown.classList.remove('show');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function userLogoff() {
|
|
||||||
ajaxCall(
|
|
||||||
'/api/v1.1/Account/LogOff',
|
|
||||||
'POST',
|
|
||||||
function (result) {
|
|
||||||
location.replace("/index.html");
|
|
||||||
},
|
|
||||||
function (error) {
|
|
||||||
location.replace("/index.html");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
53
gaseous-server/wwwroot/pages/banner.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<div id="banner_icon" onclick="window.location.href = '/index.html';">
|
||||||
|
<img src="/images/logo.png" alt="Gaseous" id="banner_icon_image" />
|
||||||
|
</div>
|
||||||
|
<div id="banner_header">
|
||||||
|
<div id="bannerButtons">
|
||||||
|
<div id="banner_user" class="banner_button dropdown dropbtn">
|
||||||
|
<div id="banner_user_image_box"></div>
|
||||||
|
<div id="myDropdown" class="dropdown-content">
|
||||||
|
<div id="banner_user_profilecard"></div>
|
||||||
|
<a href="#" id="dropdown-menu-account">Profile and Account</a>
|
||||||
|
<a href="#" id="dropdown-menu-preferences">Preferences</a>
|
||||||
|
<div class="dropdown-menu-separator"></div>
|
||||||
|
<a id="banner_user_logoff" href="#">Sign Out</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="banner_cog" class="banner_button">
|
||||||
|
<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" class="banner_button">
|
||||||
|
<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" 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" class="banner_button">
|
||||||
|
<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 id="banner_home" class="banner_button">
|
||||||
|
<img src="/images/home.svg" alt="Home" title="Home" id="banner_home_image" class="banner_button_image" />
|
||||||
|
<span id="banner_home_label">Home</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous Games</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- page code -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
setupBanner();
|
||||||
|
</script>
|
103
gaseous-server/wwwroot/pages/banner.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
function setupBanner() {
|
||||||
|
// attach event listeners to the banner elements
|
||||||
|
let userMenu = document.getElementById("banner_user");
|
||||||
|
if (userMenu) {
|
||||||
|
userMenu.addEventListener('click', () => {
|
||||||
|
document.getElementById("myDropdown").classList.toggle("show");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let userMenuLogoff = document.getElementById("banner_user_logoff");
|
||||||
|
if (userMenuLogoff) {
|
||||||
|
userMenuLogoff.addEventListener('click', () => {
|
||||||
|
ajaxCall(
|
||||||
|
'/api/v1.1/Account/LogOff',
|
||||||
|
'POST',
|
||||||
|
function (result) {
|
||||||
|
location.replace("/index.html");
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
location.replace("/index.html");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bannerCog = document.getElementById("banner_cog");
|
||||||
|
if (bannerCog) {
|
||||||
|
bannerCog.addEventListener('click', () => {
|
||||||
|
window.location.href = '/index.html?page=settings';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bannerUpload = document.getElementById("banner_upload");
|
||||||
|
if (bannerUpload) {
|
||||||
|
bannerUpload.addEventListener('click', () => {
|
||||||
|
const uploadDialog = new UploadRom();
|
||||||
|
uploadDialog.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bannerCollection = document.getElementById("banner_collections");
|
||||||
|
if (bannerCollection) {
|
||||||
|
bannerCollection.addEventListener('click', () => {
|
||||||
|
window.location.href = '/index.html?page=collections';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bannerLibrary = document.getElementById("banner_library");
|
||||||
|
if (bannerLibrary) {
|
||||||
|
bannerLibrary.addEventListener('click', () => {
|
||||||
|
window.location.href = '/index.html?page=library';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bannerHome = document.getElementById("banner_home");
|
||||||
|
if (bannerHome) {
|
||||||
|
bannerHome.addEventListener('click', () => {
|
||||||
|
window.location.href = '/index.html?page=home';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// set avatar
|
||||||
|
let avatarBox = document.getElementById('banner_user_image_box');
|
||||||
|
let avatar = new Avatar(userProfile.profileId, 30, 30);
|
||||||
|
avatarBox.style = 'pointer-events: none;';
|
||||||
|
avatar.setAttribute('style', 'margin-top: 5px; pointer-events: none; width: 30px; height: 30px;');
|
||||||
|
avatarBox.appendChild(avatar);
|
||||||
|
|
||||||
|
// set profile card in drop down
|
||||||
|
let profileCard = document.getElementById('banner_user_profilecard');
|
||||||
|
let profileCardContent = new ProfileCard(userProfile.profileId, true);
|
||||||
|
profileCard.appendChild(profileCardContent);
|
||||||
|
|
||||||
|
// hide the upload button if it's not permitted
|
||||||
|
let uploadButton = document.getElementById('banner_upload');
|
||||||
|
if (!userProfile.roles.includes("Admin") && !userProfile.roles.includes("Gamer")) {
|
||||||
|
uploadButton.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the dropdown menu if the user clicks outside of it
|
||||||
|
window.onclick = function (event) {
|
||||||
|
if (!event.target.matches('.dropbtn')) {
|
||||||
|
let dropdowns = document.getElementsByClassName("dropdown-content");
|
||||||
|
for (let i = 0; i < dropdowns.length; i++) {
|
||||||
|
let openDropdown = dropdowns[i];
|
||||||
|
if (openDropdown.classList.contains('show')) {
|
||||||
|
openDropdown.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// event for preferences drop down item
|
||||||
|
document.getElementById('dropdown-menu-preferences').addEventListener('click', function () {
|
||||||
|
const prefsDialog = new PreferencesWindow();
|
||||||
|
prefsDialog.open();
|
||||||
|
});
|
||||||
|
// event for account drop down item
|
||||||
|
document.getElementById('dropdown-menu-account').addEventListener('click', function () {
|
||||||
|
const accountDialog = new AccountWindow(); accountDialog.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setupBanner();
|
@@ -1,4 +1,5 @@
|
|||||||
<div id="bgImage" style="background-image: url('/images/CollectionsWallpaper.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/CollectionsWallpaper.jpg'); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);">
|
||||||
<div id="bgImage_Opacity"></div>
|
<div id="bgImage_Opacity"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -12,88 +13,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="settings_photocredit">
|
<!-- <div id="settings_photocredit">
|
||||||
Wallpaper by <a href="https://wallpapercave.com/u/andrea16" class="romlink">andrea16</a> / <a href="https://wallpapercave.com/w/wp5206111" class="romlink">Wallpaper Cave</a>
|
Wallpaper by <a href="https://wallpapercave.com/u/andrea16" class="romlink">andrea16</a> / <a
|
||||||
</div>
|
href="https://wallpapercave.com/w/wp5206111" class="romlink">Wallpaper Cave</a>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var newCollectionButton = document.getElementById('collection_new');
|
// set up the page
|
||||||
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
SetupPage();
|
||||||
newCollectionButton.style.display = '';
|
|
||||||
} else {
|
|
||||||
newCollectionButton.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
GetCollections();
|
|
||||||
|
|
||||||
function GetCollections() {
|
|
||||||
ajaxCall('/api/v1.1/Collections', 'GET', function (result) {
|
|
||||||
if (result) {
|
|
||||||
var targetDiv = document.getElementById('collection_table_location');
|
|
||||||
targetDiv.innerHTML = '';
|
|
||||||
|
|
||||||
var newTable = document.createElement('table');
|
|
||||||
newTable.id = 'romtable';
|
|
||||||
newTable.className = 'romtable';
|
|
||||||
newTable.setAttribute('cellspacing', 0);
|
|
||||||
newTable.appendChild(createTableRow(true, [ 'Name', 'Description', 'Download Status', 'Size', '' ]));
|
|
||||||
|
|
||||||
for (var i = 0; i < result.length; i++) {
|
|
||||||
var statusText = result[i].buildStatus;
|
|
||||||
var downloadLink = '';
|
|
||||||
var packageSize = '-';
|
|
||||||
var inProgress = false;
|
|
||||||
switch (result[i].buildStatus) {
|
|
||||||
case 'NoStatus':
|
|
||||||
statusText = '-';
|
|
||||||
break;
|
|
||||||
case "WaitingForBuild":
|
|
||||||
statusText = 'Build pending';
|
|
||||||
inProgress = true;
|
|
||||||
break;
|
|
||||||
case "Building":
|
|
||||||
statusText = 'Building';
|
|
||||||
inProgress = true;
|
|
||||||
break;
|
|
||||||
case "Completed":
|
|
||||||
statusText = 'Available';
|
|
||||||
downloadLink = '<a href="/api/v1.1/Collections/' + result[i].id + '/Roms/Zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
|
||||||
packageSize = formatBytes(result[i].collectionBuiltSizeBytes);
|
|
||||||
break;
|
|
||||||
case "Failed":
|
|
||||||
statusText = 'Build error';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
statusText = result[i].buildStatus;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inProgress == true) {
|
|
||||||
setTimeout(GetCollections, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
var editButton = '';
|
|
||||||
var deleteButton = '';
|
|
||||||
|
|
||||||
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
|
||||||
editButton = '<a href="#" onclick="showDialog(\'collectionedit\', ' + result[i].id + ');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
|
||||||
|
|
||||||
deleteButton = '<a href="#" onclick="showSubDialog(\'collectiondelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var newRow = [
|
|
||||||
result[i].name,
|
|
||||||
result[i].description,
|
|
||||||
statusText,
|
|
||||||
packageSize,
|
|
||||||
'<div style="text-align: right;">' + downloadLink + editButton + deleteButton + '</div>'
|
|
||||||
];
|
|
||||||
|
|
||||||
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
|
|
||||||
}
|
|
||||||
|
|
||||||
targetDiv.appendChild(newTable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
85
gaseous-server/wwwroot/pages/collections.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
function SetupPage() {
|
||||||
|
backgroundImageHandler = new BackgroundImageRotator(['/images/CollectionsWallpaper.jpg']);
|
||||||
|
|
||||||
|
var newCollectionButton = document.getElementById('collection_new');
|
||||||
|
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
||||||
|
newCollectionButton.style.display = '';
|
||||||
|
} else {
|
||||||
|
newCollectionButton.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetCollections() {
|
||||||
|
ajaxCall('/api/v1.1/Collections', 'GET', function (result) {
|
||||||
|
if (result) {
|
||||||
|
var targetDiv = document.getElementById('collection_table_location');
|
||||||
|
targetDiv.innerHTML = '';
|
||||||
|
|
||||||
|
var newTable = document.createElement('table');
|
||||||
|
newTable.id = 'romtable';
|
||||||
|
newTable.className = 'romtable';
|
||||||
|
newTable.setAttribute('cellspacing', 0);
|
||||||
|
newTable.appendChild(createTableRow(true, ['Name', 'Description', 'Download Status', 'Size', '']));
|
||||||
|
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
var statusText = result[i].buildStatus;
|
||||||
|
var downloadLink = '';
|
||||||
|
var packageSize = '-';
|
||||||
|
var inProgress = false;
|
||||||
|
switch (result[i].buildStatus) {
|
||||||
|
case 'NoStatus':
|
||||||
|
statusText = '-';
|
||||||
|
break;
|
||||||
|
case "WaitingForBuild":
|
||||||
|
statusText = 'Build pending';
|
||||||
|
inProgress = true;
|
||||||
|
break;
|
||||||
|
case "Building":
|
||||||
|
statusText = 'Building';
|
||||||
|
inProgress = true;
|
||||||
|
break;
|
||||||
|
case "Completed":
|
||||||
|
statusText = 'Available';
|
||||||
|
downloadLink = '<a href="/api/v1.1/Collections/' + result[i].id + '/Roms/Zip" class="romlink"><img src="/images/download.svg" class="banner_button_image" alt="Download" title="Download" /></a>';
|
||||||
|
packageSize = formatBytes(result[i].collectionBuiltSizeBytes);
|
||||||
|
break;
|
||||||
|
case "Failed":
|
||||||
|
statusText = 'Build error';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
statusText = result[i].buildStatus;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inProgress == true) {
|
||||||
|
setTimeout(GetCollections, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
var editButton = '';
|
||||||
|
var deleteButton = '';
|
||||||
|
|
||||||
|
if (userProfile.roles.includes("Admin") || userProfile.roles.includes("Gamer")) {
|
||||||
|
editButton = '<a href="#" onclick="showDialog(\'collectionedit\', ' + result[i].id + ');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
|
||||||
|
|
||||||
|
deleteButton = '<a href="#" onclick="showSubDialog(\'collectiondelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var newRow = [
|
||||||
|
result[i].name,
|
||||||
|
result[i].description,
|
||||||
|
statusText,
|
||||||
|
packageSize,
|
||||||
|
'<div style="text-align: right;">' + downloadLink + editButton + deleteButton + '</div>'
|
||||||
|
];
|
||||||
|
|
||||||
|
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
|
||||||
|
}
|
||||||
|
|
||||||
|
targetDiv.appendChild(newTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupPage();
|
@@ -10,7 +10,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div id="collection_filter_box" style="position: absolute; top: 40px; left: 0px; bottom: 5px; width: 40%; max-width: 40%; overflow-x: scroll;">
|
<div id="collection_filter_box"
|
||||||
|
style="position: absolute; top: 40px; left: 0px; bottom: 5px; width: 40%; max-width: 40%; overflow-x: scroll;">
|
||||||
<table style="width: 100%;">
|
<table style="width: 100%;">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 25%;">Platforms</th>
|
<th style="width: 25%;">Platforms</th>
|
||||||
@@ -26,7 +27,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Player Perspectives</th>
|
<th>Player Perspectives</th>
|
||||||
<td><select id="collection_playerperspectives" style="width: 100%;" multiple="multiple"></select></td>
|
<td><select id="collection_playerperspectives" style="width: 100%;" multiple="multiple"></select>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Themes</th>
|
<th>Themes</th>
|
||||||
@@ -50,17 +52,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Maximum size per platform (bytes)</th>
|
<th>Maximum size per platform (bytes)</th>
|
||||||
<td><input id="collection_maxplatformsize" type="number" placeholder="0" step="1048576" oninput="DisplayFormattedBytes('collection_maxplatformsize', 'maxplatformsize_label');"><span id="maxplatformsize_label" style="margin-left: 10px;"></span></td>
|
<td><input id="collection_maxplatformsize" type="number" placeholder="0" step="1048576"
|
||||||
|
oninput="DisplayFormattedBytes('collection_maxplatformsize', 'maxplatformsize_label');"><span
|
||||||
|
id="maxplatformsize_label" style="margin-left: 10px;"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Maximum collection size (bytes)</th>
|
<th>Maximum collection size (bytes)</th>
|
||||||
<td><input id="collection_maxcollectionsize" type="number" placeholder="0" step="1048576" oninput="DisplayFormattedBytes('collection_maxcollectionsize', 'maxcollectionsize_label');"><span id="maxcollectionsize_label" style="margin-left: 10px;"></span></td></td>
|
<td><input id="collection_maxcollectionsize" type="number" placeholder="0" step="1048576"
|
||||||
|
oninput="DisplayFormattedBytes('collection_maxcollectionsize', 'maxcollectionsize_label');"><span
|
||||||
|
id="maxcollectionsize_label" style="margin-left: 10px;"></span></td>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Directory Layout</th>
|
<th>Directory Layout</th>
|
||||||
<td>
|
<td>
|
||||||
<select id="collection_directorylayout" style="width: 100%;" data-minimum-results-for-search="Infinity" onchange="DisplayDirectoryLabel();">
|
<select id="collection_directorylayout" style="width: 100%;"
|
||||||
<option id="collection_directorylayout_gaseous" selected="selected" value="Gaseous">Standard</option>
|
data-minimum-results-for-search="Infinity" onchange="DisplayDirectoryLabel();">
|
||||||
|
<option id="collection_directorylayout_gaseous" selected="selected" value="Gaseous">Standard
|
||||||
|
</option>
|
||||||
<option id="collection_directorylayout_retropie" value="RetroPie">RetroPie</option>
|
<option id="collection_directorylayout_retropie" value="RetroPie">RetroPie</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
@@ -74,7 +83,8 @@
|
|||||||
<p>Standard layout: /<IGDB Platform Slug>/<IGDB Game Slug>/Game ROMs</p>
|
<p>Standard layout: /<IGDB Platform Slug>/<IGDB Game Slug>/Game ROMs</p>
|
||||||
<p>Example: /genesis-slash-megadrive/sonic-the-hedgehog/Sonic the Hedgehog.smd</p>
|
<p>Example: /genesis-slash-megadrive/sonic-the-hedgehog/Sonic the Hedgehog.smd</p>
|
||||||
</span>
|
</span>
|
||||||
<span id="collection_directorylayout_retropie_label" style="display: none;" name="collection_directorylayout_label">
|
<span id="collection_directorylayout_retropie_label" style="display: none;"
|
||||||
|
name="collection_directorylayout_label">
|
||||||
<p>RetroPie layout: /roms/<RetroPie Platform Label>/Game ROMs</p>
|
<p>RetroPie layout: /roms/<RetroPie Platform Label>/Game ROMs</p>
|
||||||
<p>Example: /roms/megadrive/Sonic the Hedgehog.smd</p>
|
<p>Example: /roms/megadrive/Sonic the Hedgehog.smd</p>
|
||||||
</span>
|
</span>
|
||||||
@@ -85,7 +95,8 @@
|
|||||||
Include BIOS files (if available)
|
Include BIOS files (if available)
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<select id="collection_includebios" style="width: 100%;" data-minimum-results-for-search="Infinity">
|
<select id="collection_includebios" style="width: 100%;"
|
||||||
|
data-minimum-results-for-search="Infinity">
|
||||||
<option id="collection_includebios_yes" selected="selected" value="true">Yes</option>
|
<option id="collection_includebios_yes" selected="selected" value="true">Yes</option>
|
||||||
<option id="collection_includebios_no" value="false">No</option>
|
<option id="collection_includebios_no" value="false">No</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -118,15 +129,18 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div id="collectionedit_previewbox" style="position: absolute; top: 40px; right: 0px; bottom: 60px; width: 60%; overflow-x: scroll;">
|
<div id="collectionedit_previewbox"
|
||||||
|
style="position: absolute; top: 40px; right: 0px; bottom: 60px; width: 60%; overflow-x: scroll;">
|
||||||
<div id="collectionedit_previewbox_content" style="margin: 5px;">
|
<div id="collectionedit_previewbox_content" style="margin: 5px;">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="collectionedit_previewbox_size" style="position: absolute; right: 10px; bottom: 30px; width: 60%; height: 20px; text-align: right;">
|
<div id="collectionedit_previewbox_size"
|
||||||
|
style="position: absolute; right: 10px; bottom: 30px; width: 60%; height: 20px; text-align: right;">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="collectionedit_previewbox_controls" style="position: absolute; right: 10px; bottom: 0px; width: 60%; height: 25px; text-align: right;">
|
<div id="collectionedit_previewbox_controls"
|
||||||
|
style="position: absolute; right: 10px; bottom: 0px; width: 60%; height: 25px; text-align: right;">
|
||||||
<button id="collectionedit_preview" onclick="GetPreview();">Preview</button>
|
<button id="collectionedit_preview" onclick="GetPreview();">Preview</button>
|
||||||
<button id="collectionedit_cancel" onclick="closeDialog();">Cancel</button>
|
<button id="collectionedit_cancel" onclick="closeDialog();">Cancel</button>
|
||||||
<button id="collectionedit_ok" onclick="SaveCollection();">Ok</button>
|
<button id="collectionedit_ok" onclick="SaveCollection();">Ok</button>
|
||||||
@@ -272,7 +286,7 @@
|
|||||||
ajaxCall(
|
ajaxCall(
|
||||||
'/api/v1.1/Collections/' + modalVariables,
|
'/api/v1.1/Collections/' + modalVariables,
|
||||||
'GET',
|
'GET',
|
||||||
function(result) {
|
function (result) {
|
||||||
if (result.name) { document.getElementById('collection_name').value = result.name; }
|
if (result.name) { document.getElementById('collection_name').value = result.name; }
|
||||||
if (result.description) { document.getElementById('collection_description').value = result.description; }
|
if (result.description) { document.getElementById('collection_description').value = result.description; }
|
||||||
if (result.minimumRating != -1) { document.getElementById('collection_userrating_min').value = result.minimumRating; }
|
if (result.minimumRating != -1) { document.getElementById('collection_userrating_min').value = result.minimumRating; }
|
||||||
@@ -358,10 +372,10 @@
|
|||||||
ajaxCall(
|
ajaxCall(
|
||||||
'/api/v1.1/Collections/' + modalVariables,
|
'/api/v1.1/Collections/' + modalVariables,
|
||||||
'PATCH',
|
'PATCH',
|
||||||
function(result) {
|
function (result) {
|
||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
function(error) {
|
function (error) {
|
||||||
alert(error);
|
alert(error);
|
||||||
},
|
},
|
||||||
JSON.stringify(item)
|
JSON.stringify(item)
|
||||||
@@ -371,10 +385,10 @@
|
|||||||
ajaxCall(
|
ajaxCall(
|
||||||
'/api/v1.1/Collections',
|
'/api/v1.1/Collections',
|
||||||
'POST',
|
'POST',
|
||||||
function(result) {
|
function (result) {
|
||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
function(error) {
|
function (error) {
|
||||||
alert(error);
|
alert(error);
|
||||||
},
|
},
|
||||||
JSON.stringify(item)
|
JSON.stringify(item)
|
||||||
@@ -440,10 +454,10 @@
|
|||||||
ajaxCall(
|
ajaxCall(
|
||||||
'/api/v1.1/Collections/Preview',
|
'/api/v1.1/Collections/Preview',
|
||||||
'POST',
|
'POST',
|
||||||
function(result) {
|
function (result) {
|
||||||
DisplayPreview(result, 'collectionedit_previewbox_content');
|
DisplayPreview(result, 'collectionedit_previewbox_content');
|
||||||
},
|
},
|
||||||
function(error) {
|
function (error) {
|
||||||
console.log(JSON.stringify(error));
|
console.log(JSON.stringify(error));
|
||||||
},
|
},
|
||||||
JSON.stringify(item)
|
JSON.stringify(item)
|
||||||
@@ -592,7 +606,7 @@
|
|||||||
gameImage.className = 'game_tile_image game_tile_image_small lazy';
|
gameImage.className = 'game_tile_image game_tile_image_small lazy';
|
||||||
gameImage.src = '/images/unknowngame.png';
|
gameImage.src = '/images/unknowngame.png';
|
||||||
if (gameItem.cover) {
|
if (gameItem.cover) {
|
||||||
gameImage.setAttribute('data-src', '/api/v1.1/Games/' + gameItem.id + '/cover/image/cover_small/' + gameItem.coverItem.imageId + '.jpg');
|
gameImage.setAttribute('data-src', '/api/v1.1/Games/' + gameItem.id + '/cover/' + gameItem.cover.id + '/image/cover_small/' + gameItem.coverItem.imageId + '.jpg');
|
||||||
} else {
|
} else {
|
||||||
gameImage.className = 'game_tile_image game_tile_image_small unknown';
|
gameImage.className = 'game_tile_image game_tile_image_small unknown';
|
||||||
}
|
}
|
||||||
@@ -658,7 +672,7 @@
|
|||||||
|
|
||||||
var labelToDisplay = '';
|
var labelToDisplay = '';
|
||||||
if (directoryLayoutMode) {
|
if (directoryLayoutMode) {
|
||||||
switch(directoryLayoutMode) {
|
switch (directoryLayoutMode) {
|
||||||
case "Gaseous":
|
case "Gaseous":
|
||||||
// standard mode
|
// standard mode
|
||||||
labelToDisplay = 'collection_directorylayout_gaseous_label';
|
labelToDisplay = 'collection_directorylayout_gaseous_label';
|
||||||
|