Compare commits
60 Commits
v1.7.5
...
michael-j-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68bd3d8408 | ||
|
|
25ce6979ad | ||
|
|
9145688d35 | ||
|
|
d07300ecb5 | ||
|
|
86c207e389 | ||
|
|
a0a8495597 | ||
|
|
aa90b4ebc3 | ||
|
|
9e93ed1041 | ||
|
|
f8b9ca3b66 | ||
|
|
6863f65640 | ||
|
|
7c327eeb3e | ||
|
|
202c2c0b62 | ||
|
|
da98b1cd74 | ||
|
|
fc0d164a96 | ||
|
|
8153c42fe1 | ||
|
|
97645af336 | ||
|
|
42370a9699 | ||
|
|
1727a62150 | ||
|
|
c170d98a68 | ||
|
|
ae41fae54f | ||
|
|
ffd4dcbb33 | ||
|
|
c724d927bb | ||
|
|
a859d873e6 | ||
|
|
7a9827923f | ||
|
|
142f3ed561 | ||
|
|
2303ab5ffc | ||
|
|
173e49286b | ||
|
|
ca2dbfb4cd | ||
|
|
74171b50af | ||
|
|
b1fcfec14f | ||
|
|
e8ca8ca5ca | ||
|
|
6f5b52058c | ||
|
|
8b9d7c66ab | ||
|
|
f19214ba6b | ||
|
|
2d63a1c416 | ||
|
|
f99eec2eec | ||
|
|
b3ca94b217 | ||
|
|
53c79287a9 | ||
|
|
48e4f17090 | ||
|
|
478044a5a1 | ||
|
|
f25b3d0eaa | ||
|
|
574d3bc39e | ||
|
|
bca4dd178e | ||
|
|
4a76436223 | ||
|
|
32f6a86dc9 | ||
|
|
4075976ad8 | ||
|
|
146597dd4b | ||
|
|
f4ba84a54f | ||
|
|
64fb76484b | ||
|
|
bfade006bd | ||
|
|
c8140d7178 | ||
|
|
070589f718 | ||
|
|
bb86cb52f6 | ||
|
|
7dfb0b54eb | ||
|
|
f0783fcae8 | ||
|
|
68be24d514 | ||
|
|
a5da1a9033 | ||
|
|
fc09681cdd | ||
|
|
6185912151 | ||
|
|
deef919d5b |
@@ -1,4 +0,0 @@
|
||||
DATABASE_HOST=mariadb
|
||||
DATABASE_USER=root
|
||||
DATABASE_PASSWORD=gaseous
|
||||
DATABASE_DB=gaseous
|
||||
@@ -1,6 +1,10 @@
|
||||
FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
||||
|
||||
RUN apt-get update && apt-get install -y p7zip-full
|
||||
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.11.7z
|
||||
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.11.7z
|
||||
# update apt-get
|
||||
RUN apt-get update
|
||||
|
||||
# download and unzip EmulatorJS from CDN
|
||||
RUN apt-get install -y p7zip-full default-jdk nodejs wget
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.1.1.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.7z
|
||||
@@ -1,27 +1,25 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
|
||||
{
|
||||
"name": "C# (.NET)",
|
||||
"name": "Gaseous C# (.NET)",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
//"image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "development",
|
||||
"workspaceFolder": "/workspace",
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [5198],
|
||||
"forwardPorts": [
|
||||
5198
|
||||
],
|
||||
"portsAttributes": {
|
||||
"5198": {
|
||||
"protocol": "http"
|
||||
}
|
||||
"5198": {
|
||||
"protocol": "http"
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "dotnet restore",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
@@ -36,11 +34,14 @@
|
||||
"AndersEAndersen.html-class-suggestions",
|
||||
"george-alisson.html-preview-vscode",
|
||||
"ms-dotnettools.vscodeintellicode-csharp",
|
||||
"Zignd.html-css-class-completion"
|
||||
"Zignd.html-css-class-completion",
|
||||
"PWABuilder.pwa-studio",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"SonarSource.sonarlint-vscode",
|
||||
"oderwat.indent-rainbow"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
development:
|
||||
build:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
@@ -11,13 +11,15 @@ services:
|
||||
- dbhost=${DATABASE_HOST}
|
||||
- dbuser=${DATABASE_USER}
|
||||
- dbpass=${DATABASE_PASSWORD}
|
||||
- igdbclientid=<clientid>
|
||||
- igdbclientsecret=<clientsecret>
|
||||
- igdbclientid=${IGDB_CLIENT_ID}
|
||||
- igdbclientsecret=${IGDB_CLIENT_SECRET}
|
||||
mariadb:
|
||||
hostname: mariadb
|
||||
image: mariadb:latest
|
||||
ports:
|
||||
- 3306:3306
|
||||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
||||
- MARIADB_DATABASE=${DATABASE_DB}
|
||||
- MARIADB_USER=${DATABASE_USER}
|
||||
- MARIADB_PASSWORD=${DATABASE_PASSWORD}
|
||||
- MARIADB_PASSWORD=${DATABASE_PASSWORD}
|
||||
|
||||
@@ -59,4 +59,4 @@ jobs:
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
@@ -59,7 +59,5 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:latest-embeddeddb
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:latest-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
61
.github/workflows/BuildNightly.yml
vendored
Normal file
61
.github/workflows/BuildNightly.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Build Nightly Docker Image
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '15 4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Install dotnet tool
|
||||
run: dotnet tool install -g dotnetCampus.TagToVersion
|
||||
- name: Set tag to version
|
||||
run: dotnet TagToVersion -t 0.0.0-nightly
|
||||
- name: Sign in to Nuget
|
||||
run: dotnet nuget add source --username michael-j-green --password ${{ secrets.NUGETKEY }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/gaseous-project/index.json"
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to GitHub Package Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:nightly
|
||||
ghcr.io/gaseous-project/gaseousserver:nightly
|
||||
- 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:nightly-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:nightly-embeddeddb
|
||||
13
.github/workflows/BuildOnTestBranch.yml
vendored
13
.github/workflows/BuildOnTestBranch.yml
vendored
@@ -27,19 +27,10 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: gaseousgames/test:latest
|
||||
- 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/test:latest-embeddeddb
|
||||
85
.github/workflows/codeql.yml
vendored
85
.github/workflows/codeql.yml
vendored
@@ -1,85 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "branch-v*.*.*" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '21 11 * * 2'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners
|
||||
# Consider using larger runners for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp', 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- 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"
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -404,4 +404,7 @@ ASALocalRun/
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
gaseous-server/.DS_Store
|
||||
gaseous-server/wwwroot/.DS_Store
|
||||
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
.devcontainer/.env
|
||||
.mono/
|
||||
|
||||
@@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "screenshots", "screenshots"
|
||||
screenshots\Game.png = screenshots\Game.png
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gaseous-cli", "gaseous-cli\gaseous-cli.csproj", "{419CC4E4-8932-4E4A-B027-5521AA0CBA85}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -31,6 +33,10 @@ Global
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
39
README.MD
39
README.MD
@@ -1,34 +1,30 @@
|
||||
[](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/codeql.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml)
|
||||
# Gaseous Server
|
||||
[](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildNightly.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml)
|
||||
# <img src="./logo.png" height="28" style="float: right;" /> Gaseous Server
|
||||
|
||||
This is the server for the Gaseous system. It offers ROM and title management, as well as some basic in browser emulation of those ROMs.
|
||||
|
||||
## Warning
|
||||
|
||||
Versions 1.6.1 and earlier are not suitable for being exposed to the internet, as:
|
||||
1. there is no authentication support, meaning anyone could trash your library
|
||||
2. the server has not been hardened for exposure to the internet - so there maybe unknown vulnerabilities
|
||||
|
||||
If you expose one of these earlier versions of the server to the internet, **you do so at your own risk**.
|
||||
|
||||
Version 1.7.0 and later contain user authentication, and can be exposed to the internet. However, it is recommended to no expose the server to the internet if you're not actively using it remotely, or if you have alternative means to access it remotely like a VPN.
|
||||
Version 1.7.0 and later contain user authentication, and can be exposed to the internet. However, it is recommended to not expose the server to the internet if you're not actively using it remotely, or if you have alternative means to access it remotely like a VPN.
|
||||
|
||||
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
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Requirements
|
||||
* MariaDB 11.1.2 (preferred) or MySQL Server 8+
|
||||
* MariaDB 11.1.2+ (preferred) or MySQL Server 8+
|
||||
* These are the database versions Gaseous has been tested and developed against. Your mileage may vary with earlier versions.
|
||||
* MariaDB is the preferred database server, while MySQL will continue to be supported for existing users (they should be interchangable).
|
||||
* Note that due to the earlier database schema using MySQL specific features, moving to MariaDB from MySQL will require rebuilding your database from scratch. The "Library Scan" background task can be used to re-import all titles.
|
||||
* Internet Game Database API Key. See: https://api-docs.igdb.com/#account-creation
|
||||
|
||||
If using the provided docker-compose.yml, MariaDB will be installed for you.
|
||||
# Installation
|
||||
See https://github.com/gaseous-project/gaseous-server/wiki/Installation for installation instructions.
|
||||
|
||||
# Adding Content
|
||||
1. Import signatures: see https://github.com/gaseous-project/gaseous-server/wiki/Signatures
|
||||
2. Add ROMs: see https://github.com/gaseous-project/gaseous-server/wiki/Adding-ROMs
|
||||
|
||||
## Friends of Gaseous
|
||||
* [EmulatorJS](https://github.com/EmulatorJS/EmulatorJS): A fantastic (and fast) Javascript based implementation of RetroArch, supporting a wide variety of platforms. Discord: https://discord.gg/6akryGkETU
|
||||
@@ -43,11 +39,4 @@ The following projects are used by Gaseous
|
||||
* [EmulatorJS](https://github.com/EmulatorJS/EmulatorJS)
|
||||
|
||||
## Discord Server
|
||||
[](https://discord.gg/Nhu7wpT3k4)
|
||||
|
||||
# Installation
|
||||
See https://github.com/gaseous-project/gaseous-server/wiki/Installation for installation instructions.
|
||||
|
||||
# Adding Content
|
||||
1. Import signatures: see https://github.com/gaseous-project/gaseous-server/wiki/Signatures
|
||||
2. Add ROMs: see https://github.com/gaseous-project/gaseous-server/wiki/Adding-ROMs
|
||||
Join our Discord server: https://discord.gg/Nhu7wpT3k4
|
||||
|
||||
@@ -9,24 +9,21 @@ RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY .. ./
|
||||
|
||||
# Build Gaseous Web Server
|
||||
# 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
|
||||
# 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/
|
||||
# download and unzip EmulatorJS from CDN
|
||||
RUN apt-get install -y p7zip-full
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.1.1.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.7z
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
@@ -37,5 +34,34 @@ ENV INDOCKER=1
|
||||
WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
|
||||
# start gaseous-server
|
||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
||||
# variables
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
ARG dbhost=localhost
|
||||
ARG dbuser=root
|
||||
ARG dbpass=gaseous
|
||||
|
||||
ENV PUID=${PUID}
|
||||
ENV PGID=${PGID}
|
||||
ENV dbhost=${dbhost}
|
||||
ENV dbuser=${dbuser}
|
||||
ENV dbpass=${dbpass}
|
||||
|
||||
# install supervisord
|
||||
RUN apt-get update && apt-get install -y supervisor
|
||||
COPY ../build/standard/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
RUN mkdir -p /var/run/supervisord
|
||||
RUN mkdir -p /var/log/supervisord
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# copy entrypoint
|
||||
COPY ../build/standard/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||
|
||||
# volumes
|
||||
VOLUME /home/gaseous/.gaseous-server
|
||||
|
||||
# start services
|
||||
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
||||
@@ -9,25 +9,21 @@ RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY .. ./
|
||||
|
||||
# Build Gaseous Web Server
|
||||
# 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
|
||||
# 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/
|
||||
# download and unzip EmulatorJS from CDN
|
||||
RUN apt-get install -y p7zip-full
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.1.1.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.7z
|
||||
|
||||
# Build runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
@@ -54,12 +50,12 @@ ENV MARIADB_ROOT_PASSWORD=${dbpass}
|
||||
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
|
||||
COPY ../build/embeddeddb/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
|
||||
COPY ../build/embeddeddb/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
RUN mkdir -p /var/run/supervisord
|
||||
RUN mkdir -p /var/log/supervisord
|
||||
|
||||
@@ -67,11 +63,11 @@ RUN mkdir -p /var/log/supervisord
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# copy entrypoint
|
||||
COPY ../build/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
COPY ../build/embeddeddb/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||
|
||||
# volumes
|
||||
VOLUME /home/gaseous/.gaseous-server /var/lib/mysql
|
||||
|
||||
# start services
|
||||
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
||||
21
build/embeddeddb/entrypoint.sh
Normal file
21
build/embeddeddb/entrypoint.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
# create the user
|
||||
echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
|
||||
groupadd -g ${PGID} gaseous
|
||||
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
|
||||
usermod -p "*" gaseous
|
||||
mkdir -p /home/gaseous/.aspnet
|
||||
chown -R ${PUID} /App /home/gaseous/.aspnet
|
||||
chgrp -R ${PGID} /App /home/gaseous/.aspnet
|
||||
mkdir -p /home/gaseous/.gaseous-server
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server
|
||||
|
||||
# Set MariaDB permissions
|
||||
mkdir -p /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chown -R ${PUID} /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chgrp -R ${PGID} /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
@@ -1,20 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
# install the database
|
||||
echo "Installing MariaDB"
|
||||
/usr/bin/mariadb-install-db --datadir=/var/lib/mysql --user=gaseous
|
||||
|
||||
# start the database server without network or grant tables
|
||||
echo "Starting MariaDB"
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql --skip-grant-tables --skip-networking &
|
||||
|
||||
# wait for the server to start
|
||||
sleep 5
|
||||
|
||||
# change the root password
|
||||
echo "Setting MariaDB root password"
|
||||
mariadb -u root -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; ALTER USER 'gaseous'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; FLUSH PRIVILEGES; SHUTDOWN;"
|
||||
|
||||
# stop the server
|
||||
sleep 5
|
||||
echo "Stopping MariaDB"
|
||||
killall mariadbd
|
||||
|
||||
# start the server normally
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql
|
||||
echo "Starting MariaDB"
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql --user=gaseous
|
||||
@@ -34,4 +34,4 @@ autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stdout_logfile_maxbytes=0
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# create the user
|
||||
echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
|
||||
groupadd -g ${PGID} gaseous
|
||||
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
|
||||
usermod -p "*" gaseous
|
||||
mkdir -p /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
16
build/standard/entrypoint.sh
Normal file
16
build/standard/entrypoint.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
# create the user
|
||||
echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
|
||||
groupadd -g ${PGID} gaseous
|
||||
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
|
||||
usermod -p "*" gaseous
|
||||
mkdir -p /home/gaseous/.aspnet
|
||||
chown -R ${PUID} /App /home/gaseous/.aspnet
|
||||
chgrp -R ${PGID} /App /home/gaseous/.aspnet
|
||||
mkdir -p /home/gaseous/.gaseous-server
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
28
build/standard/supervisord.conf
Normal file
28
build/standard/supervisord.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
logfile=/var/log/supervisord/supervisord.log
|
||||
logfile_maxbytes=50
|
||||
logfile_backups=5
|
||||
pidfile=/var/run/supervisord/supervisord.pid
|
||||
loglevel = info
|
||||
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisord/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///var/run/supervisord/supervisor.sock
|
||||
|
||||
[program:gaseous-server]
|
||||
user=gaseous
|
||||
command=dotnet /App/gaseous-server.dll
|
||||
environment=HOME="/home/gaseous",USER="gaseous"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
@@ -4,6 +4,7 @@ services:
|
||||
container_name: gaseous-server
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./build/Dockerfile
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- gaseous
|
||||
@@ -12,7 +13,7 @@ services:
|
||||
ports:
|
||||
- 5198:80
|
||||
volumes:
|
||||
- gs:/root/.gaseous-server
|
||||
- gs:/home/gaseous/.gaseous-server
|
||||
environment:
|
||||
- TZ=Australia/Sydney
|
||||
- dbhost=gsdb
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
version: '2'
|
||||
services:
|
||||
gaseous-server:
|
||||
container_name: gaseous-server
|
||||
image: gaseousgames/gaseousserver:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- gaseous
|
||||
depends_on:
|
||||
- gsdb
|
||||
ports:
|
||||
- 5198:80
|
||||
volumes:
|
||||
- gs:/root/.gaseous-server
|
||||
environment:
|
||||
- TZ=Australia/Sydney
|
||||
- dbhost=gsdb
|
||||
- dbuser=root
|
||||
- dbpass=gaseous
|
||||
- igdbclientid=<clientid>
|
||||
- igdbclientsecret=<clientsecret>
|
||||
gsdb:
|
||||
container_name: gsdb
|
||||
image: mariadb
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- gaseous
|
||||
volumes:
|
||||
- gsdb:/var/lib/mysql
|
||||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=gaseous
|
||||
- MARIADB_USER=gaseous
|
||||
- MARIADB_PASSWORD=gaseous
|
||||
networks:
|
||||
gaseous:
|
||||
driver: bridge
|
||||
volumes:
|
||||
gs:
|
||||
gsdb:
|
||||
354
gaseous-cli/Program.cs
Normal file
354
gaseous-cli/Program.cs
Normal file
@@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
/* ------------------------------------------------- */
|
||||
/* This tool is a CLI tool that is used to manage */
|
||||
/* the Gaseous Server. */
|
||||
/* Functions such as user management, and backups */
|
||||
/* are available. */
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
// load app settings
|
||||
Config.InitSettings();
|
||||
|
||||
// set up database connection
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// set up identity
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequiredLength = 10;
|
||||
options.User.AllowedUserNameCharacters = null;
|
||||
options.User.RequireUniqueEmail = true;
|
||||
options.SignIn.RequireConfirmedPhoneNumber = false;
|
||||
options.SignIn.RequireConfirmedEmail = false;
|
||||
options.SignIn.RequireConfirmedAccount = false;
|
||||
})
|
||||
.AddUserStore<UserStore>()
|
||||
.AddRoleStore<RoleStore>()
|
||||
;
|
||||
services.AddScoped<UserStore>();
|
||||
services.AddScoped<RoleStore>();
|
||||
|
||||
services.AddTransient<IUserStore<ApplicationUser>, UserStore>();
|
||||
services.AddTransient<IRoleStore<ApplicationRole>, RoleStore>();
|
||||
var userManager = services.BuildServiceProvider().GetService<UserManager<ApplicationUser>>();
|
||||
|
||||
// load the command line arguments
|
||||
string[] cmdArgs = Environment.GetCommandLineArgs();
|
||||
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 1)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("Gaseous CLI - A tool for managing the Gaseous Server");
|
||||
Console.WriteLine("Usage: gaseous-cli [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" user [command] [options] - Manage users");
|
||||
Console.WriteLine(" role [command] [options] - Manage roles");
|
||||
// Console.WriteLine(" backup [command] [options] - Manage backups");
|
||||
// Console.WriteLine(" restore [command] [options] - Restore backups");
|
||||
Console.WriteLine(" help - Display this help message");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the help command
|
||||
if (cmdArgs[1] == "help")
|
||||
{
|
||||
// display the help message
|
||||
Console.WriteLine("Gaseous CLI - A tool for managing the Gaseous Server");
|
||||
Console.WriteLine("Usage: gaseous-cli [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" user [command] [options] - Manage users");
|
||||
Console.WriteLine(" role [command] [options] - Manage roles");
|
||||
// Console.WriteLine(" backup [command] [options] - Manage backups");
|
||||
// Console.WriteLine(" restore [command] [options] - Restore backups");
|
||||
Console.WriteLine(" help - Display this help message");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the user command
|
||||
if (cmdArgs[1] == "user")
|
||||
{
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 2)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("User Management");
|
||||
Console.WriteLine("Usage: gaseous-cli user [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" add [username] [password] - Add a new user");
|
||||
Console.WriteLine(" delete [username] - Delete a user");
|
||||
Console.WriteLine(" resetpassword [username] [password] - Reset a user's password");
|
||||
Console.WriteLine(" list - List all users");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the add command
|
||||
if (cmdArgs[2] == "add")
|
||||
{
|
||||
// check if the user has entered the username and password
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and password were not entered
|
||||
Console.WriteLine("Error: Please enter a username and password");
|
||||
return;
|
||||
}
|
||||
|
||||
// add a new user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
if (userTable.GetUserByEmail(cmdArgs[3]) != null)
|
||||
{
|
||||
Console.WriteLine("Error: User already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
// create the user object
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Email = cmdArgs[3],
|
||||
NormalizedEmail = cmdArgs[3].ToUpper(),
|
||||
EmailConfirmed = true,
|
||||
UserName = cmdArgs[3],
|
||||
NormalizedUserName = cmdArgs[3].ToUpper()
|
||||
};
|
||||
|
||||
// create the password
|
||||
PasswordHasher<ApplicationUser> passwordHasher = new PasswordHasher<ApplicationUser>();
|
||||
user.PasswordHash = passwordHasher.HashPassword(user, cmdArgs[4]);
|
||||
|
||||
await userManager.CreateAsync(user);
|
||||
await userManager.AddToRoleAsync(user, "Player");
|
||||
|
||||
Console.WriteLine("User created successfully with default role: Player");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the delete command
|
||||
if (cmdArgs[2] == "delete")
|
||||
{
|
||||
// check if the user has entered the username
|
||||
if (cmdArgs.Length < 4)
|
||||
{
|
||||
// the username was not entered
|
||||
Console.WriteLine("Error: Please enter a username");
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
await userManager.DeleteAsync(user);
|
||||
|
||||
Console.WriteLine("User deleted successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the resetpassword command
|
||||
if (cmdArgs[2] == "resetpassword")
|
||||
{
|
||||
// check if the user has entered the username and password
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and password were not entered
|
||||
Console.WriteLine("Error: Please enter a username and password");
|
||||
return;
|
||||
}
|
||||
|
||||
// reset the user's password
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// create the password
|
||||
PasswordHasher<ApplicationUser> passwordHasher = new PasswordHasher<ApplicationUser>();
|
||||
user.PasswordHash = passwordHasher.HashPassword(user, cmdArgs[4]);
|
||||
|
||||
await userManager.UpdateAsync(user);
|
||||
|
||||
Console.WriteLine("Password reset successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the list command
|
||||
if (cmdArgs[2] == "list")
|
||||
{
|
||||
// list all users
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
var userList = userTable.GetUsers();
|
||||
foreach (var user in userList)
|
||||
{
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
Console.WriteLine(user.Email + " - " + string.Join(", ", roles));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the user has entered the role command
|
||||
if (cmdArgs[1] == "role")
|
||||
{
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 2)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("Role Management");
|
||||
Console.WriteLine("Usage: gaseous-cli role [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" set [username] [role] - Set the role of a user");
|
||||
Console.WriteLine(" list - List all roles");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the role command
|
||||
if (cmdArgs[2] == "set")
|
||||
{
|
||||
// check if the user has entered the username and role
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and role were not entered
|
||||
Console.WriteLine("Error: Please enter a username and role");
|
||||
return;
|
||||
}
|
||||
|
||||
// set the role of the user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all existing roles from user
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
await userManager.RemoveFromRolesAsync(user, roles.ToArray());
|
||||
|
||||
// add the new role to the user
|
||||
await userManager.AddToRoleAsync(user, cmdArgs[4]);
|
||||
|
||||
Console.WriteLine("Role set successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the list command
|
||||
if (cmdArgs[2] == "list")
|
||||
{
|
||||
// list all roles
|
||||
string[] roles = { "Player", "Gamer", "Admin" };
|
||||
foreach (var role in roles)
|
||||
{
|
||||
Console.WriteLine(role);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// // check if the user has entered the backup command
|
||||
// if (cmdArgs[1] == "backup")
|
||||
// {
|
||||
// // check if the user has entered any arguments
|
||||
// if (cmdArgs.Length == 2)
|
||||
// {
|
||||
// // no arguments were entered
|
||||
// Console.WriteLine("Backup Management");
|
||||
// Console.WriteLine("Usage: gaseous-cli backup [command] [options]");
|
||||
// Console.WriteLine("Commands:");
|
||||
// Console.WriteLine(" create - Create a backup");
|
||||
// Console.WriteLine(" list - List all backups");
|
||||
// Console.WriteLine(" remove [backup_id] - Remove a backup");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the create command
|
||||
// if (cmdArgs[2] == "create")
|
||||
// {
|
||||
// // create a backup
|
||||
// Backup.CreateBackup();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the list command
|
||||
// if (cmdArgs[2] == "list")
|
||||
// {
|
||||
// // list all backups
|
||||
// Backup.ListBackups();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the remove command
|
||||
// if (cmdArgs[2] == "remove")
|
||||
// {
|
||||
// // check if the user has entered the backup id
|
||||
// if (cmdArgs.Length < 4)
|
||||
// {
|
||||
// // the backup id was not entered
|
||||
// Console.WriteLine("Error: Please enter a backup id");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // remove the backup
|
||||
// Backup.RemoveBackup(cmdArgs[3]);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // check if the user has entered the restore command
|
||||
// if (cmdArgs[1] == "restore")
|
||||
// {
|
||||
// // check if the user has entered any arguments
|
||||
// if (cmdArgs.Length == 2)
|
||||
// {
|
||||
// // no arguments were entered
|
||||
// Console.WriteLine("Restore Management");
|
||||
// Console.WriteLine("Usage: gaseous-cli restore [command] [options]");
|
||||
// Console.WriteLine("Commands:");
|
||||
// Console.WriteLine(" restore [backup_id] - Restore a backup");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the restore command
|
||||
// if (cmdArgs[2] == "restore")
|
||||
// {
|
||||
// // check if the user has entered the backup id
|
||||
// if (cmdArgs.Length < 4)
|
||||
// {
|
||||
// // the backup id was not entered
|
||||
// Console.WriteLine("Error: Please enter a backup id");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // restore the backup
|
||||
// Restore.RestoreBackup(cmdArgs[3]);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// the user entered an invalid command
|
||||
Console.WriteLine("Error: Invalid command");
|
||||
28
gaseous-cli/gaseous-cli.csproj
Normal file
28
gaseous-cli/gaseous-cli.csproj
Normal file
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>gaseous_cli</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\net8.0\gaseous-cli.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\net8.0\gaseous-cli.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\gaseous-server\gaseous-server.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/.DS_Store
vendored
Binary file not shown.
@@ -12,6 +12,6 @@ namespace Authentication
|
||||
{
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Authentication
|
||||
/// <summary>
|
||||
/// Class that represents the Role table in the MySQL Database
|
||||
/// </summary>
|
||||
public class RoleTable
|
||||
public class RoleTable
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Authentication
|
||||
parameters.Add("@id", roleId);
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
@@ -104,7 +104,7 @@ namespace Authentication
|
||||
var roleName = GetRoleName(roleId);
|
||||
ApplicationRole? role = null;
|
||||
|
||||
if(roleName != null)
|
||||
if (roleName != null)
|
||||
{
|
||||
role = new ApplicationRole();
|
||||
role.Id = roleId;
|
||||
@@ -153,7 +153,7 @@ namespace Authentication
|
||||
string commandText = "Select Name from Roles";
|
||||
|
||||
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));
|
||||
role.Id = (string)row["Id"];
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Authentication
|
||||
parameters.Add("providerKey", userLogin.ProviderKey);
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Authentication
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||
foreach(DataRow row in rows)
|
||||
foreach (DataRow row in rows)
|
||||
{
|
||||
roles.Add((string)row["Name"]);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Authentication
|
||||
/// Class that represents the Users table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserTable<TUser>
|
||||
where TUser :ApplicationUser
|
||||
where TUser : ApplicationUser
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Authentication
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||
|
||||
DataTable table = _database.ExecuteCMD(commandText, parameters);
|
||||
|
||||
|
||||
if (table.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
@@ -75,7 +75,7 @@ namespace Authentication
|
||||
public TUser GetUserById(string userId)
|
||||
{
|
||||
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 } };
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||
@@ -89,7 +89,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
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.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
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.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.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(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;
|
||||
@@ -114,11 +114,11 @@ namespace Authentication
|
||||
public List<TUser> GetUserByName(string normalizedUserName)
|
||||
{
|
||||
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 } };
|
||||
|
||||
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));
|
||||
user.Id = (string)row["Id"];
|
||||
@@ -127,7 +127,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
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.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
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.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.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(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);
|
||||
}
|
||||
|
||||
@@ -148,10 +148,10 @@ namespace Authentication
|
||||
public List<TUser> GetUsers()
|
||||
{
|
||||
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);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
foreach (Dictionary<string, object> row in rows)
|
||||
{
|
||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
@@ -160,7 +160,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
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.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
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.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.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(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);
|
||||
}
|
||||
|
||||
@@ -258,10 +258,11 @@ namespace Authentication
|
||||
/// <returns></returns>
|
||||
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>();
|
||||
parameters.Add("@name", user.UserName);
|
||||
parameters.Add("@id", user.Id);
|
||||
parameters.Add("@profileId", Guid.NewGuid());
|
||||
parameters.Add("@pwdHash", user.PasswordHash);
|
||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||
@@ -292,7 +293,7 @@ namespace Authentication
|
||||
/// <returns></returns>
|
||||
private int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; 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>();
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
@@ -376,7 +377,7 @@ namespace Authentication
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("Id", user.Id);
|
||||
parameters.Add("SecurityProfile", Newtonsoft.Json.JsonConvert.SerializeObject(securityProfile));
|
||||
|
||||
|
||||
return _database.ExecuteCMD(commandText, parameters).Rows.Count;
|
||||
}
|
||||
|
||||
@@ -408,7 +409,7 @@ namespace Authentication
|
||||
List<UserPreferenceViewModel> userPreferences = GetPreferences(user);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
|
||||
foreach (UserPreferenceViewModel modelItem in model)
|
||||
{
|
||||
bool prefItemFound = false;
|
||||
@@ -449,7 +450,7 @@ namespace Authentication
|
||||
{
|
||||
{ "userid", user.Id }
|
||||
};
|
||||
|
||||
|
||||
if (bytes.Length == 0)
|
||||
{
|
||||
sql = "DELETE FROM UserAvatars WHERE UserId = @userid";
|
||||
|
||||
@@ -8,8 +8,9 @@ namespace Authentication
|
||||
public List<String> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public string HighestRole {
|
||||
public Guid ProfileId { get; set; }
|
||||
public string HighestRole
|
||||
{
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
|
||||
@@ -8,38 +8,46 @@ namespace Authentication
|
||||
public DateTimeOffset? LockoutEnd { get; set; }
|
||||
public List<string> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public string HighestRole {
|
||||
public Guid ProfileId { get; set; }
|
||||
public string HighestRole
|
||||
{
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
foreach (string role in Roles)
|
||||
if (Roles != null)
|
||||
{
|
||||
switch (role)
|
||||
foreach (string role in Roles)
|
||||
{
|
||||
case "Admin":
|
||||
// there is no higher
|
||||
_highestRole = role;
|
||||
break;
|
||||
case "Gamer":
|
||||
// only one high is Admin, so check for that
|
||||
if (_highestRole != "Admin")
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case "Admin":
|
||||
// there is no higher
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
case "Player":
|
||||
// make sure _highestRole isn't already set to Gamer or Admin
|
||||
if (_highestRole != "Admin" && _highestRole != "Gamer")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_highestRole = "Player";
|
||||
break;
|
||||
break;
|
||||
case "Gamer":
|
||||
// only one high is Admin, so check for that
|
||||
if (_highestRole != "Admin")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
case "Player":
|
||||
// make sure _highestRole isn't already set to Gamer or Admin
|
||||
if (_highestRole != "Admin" && _highestRole != "Gamer")
|
||||
{
|
||||
_highestRole = role;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_highestRole = "Player";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_highestRole = "Player";
|
||||
}
|
||||
|
||||
return _highestRole;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,75 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Bios
|
||||
{
|
||||
public Bios()
|
||||
{
|
||||
|
||||
}
|
||||
public class Bios
|
||||
{
|
||||
public Bios()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static void ImportBiosFile(string FilePath, Common.hashObject Hash, ref Dictionary<string, object> BiosFileInfo)
|
||||
{
|
||||
BiosFileInfo.Add("type", "bios");
|
||||
BiosFileInfo.Add("status", "notimported");
|
||||
|
||||
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios())
|
||||
{
|
||||
if (biosItem.Available == false)
|
||||
{
|
||||
if (biosItem.hash == Hash.md5hash)
|
||||
{
|
||||
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, biosItem.hash + ".bios");
|
||||
Logging.Log(Logging.LogType.Information, "Import BIOS File", " " + FilePath + " is a BIOS file - moving to " + biosPath);
|
||||
|
||||
File.Move(FilePath, biosItem.biosPath, true);
|
||||
|
||||
BiosFileInfo.Add("name", biosItem.filename);
|
||||
BiosFileInfo.Add("platform", Platforms.GetPlatform(biosItem.platformid));
|
||||
BiosFileInfo["status"] = "imported";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (biosItem.hash == Hash.md5hash)
|
||||
{
|
||||
BiosFileInfo["status"] = "duplicate";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MigrateToNewFolderStructure()
|
||||
{
|
||||
// migrate from old BIOS file structure which had each bios file inside a folder named for the platform to the new structure which has each file in a subdirectory named after the MD5 hash
|
||||
if (Directory.Exists(Config.LibraryConfiguration.LibraryBIOSDirectory))
|
||||
{
|
||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
||||
{
|
||||
if (platformMapping.Bios != null)
|
||||
{
|
||||
foreach (Models.PlatformMapping.PlatformMapItem.EmulatorBiosItem emulatorBiosItem in platformMapping.Bios)
|
||||
{
|
||||
string oldBiosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platformMapping.IGDBSlug.ToString(), emulatorBiosItem.filename);
|
||||
string newBiosPath = Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, emulatorBiosItem.hash + ".bios");
|
||||
|
||||
if (File.Exists(oldBiosPath))
|
||||
{
|
||||
File.Copy(oldBiosPath, newBiosPath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove old BIOS folder structure
|
||||
Directory.Delete(Config.LibraryConfiguration.LibraryBIOSDirectory, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static Models.PlatformMapping.PlatformMapItem? BiosHashSignatureLookup(string MD5)
|
||||
{
|
||||
@@ -67,7 +127,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
if (platformMapping.Bios != null)
|
||||
{
|
||||
IGDB.Models.Platform platform = Metadata.Platforms.GetPlatform(platformMapping.IGDBId);
|
||||
Platform platform = Metadata.Platforms.GetPlatform(platformMapping.IGDBId);
|
||||
|
||||
foreach (Models.PlatformMapping.PlatformMapItem.EmulatorBiosItem emulatorBios in platformMapping.Bios)
|
||||
{
|
||||
@@ -96,10 +156,11 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platformslug, base.filename);
|
||||
return Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, hash + ".bios");
|
||||
}
|
||||
}
|
||||
public bool Available {
|
||||
public bool Available
|
||||
{
|
||||
get
|
||||
{
|
||||
bool fileExists = File.Exists(biosPath);
|
||||
|
||||
@@ -9,7 +9,7 @@ using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Controllers;
|
||||
using gaseous_server.Controllers.v1_1;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Newtonsoft.Json;
|
||||
@@ -18,9 +18,10 @@ using static gaseous_server.Classes.Metadata.Games;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Collections
|
||||
{
|
||||
public static List<CollectionItem> GetCollections(string userid) {
|
||||
public class Collections
|
||||
{
|
||||
public static List<CollectionItem> GetCollections(string userid)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM RomCollections WHERE OwnedBy=@ownedby ORDER BY `Name`";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
@@ -30,16 +31,18 @@ namespace gaseous_server.Classes
|
||||
|
||||
List<CollectionItem> collectionItems = new List<CollectionItem>();
|
||||
|
||||
foreach(DataRow row in data.Rows) {
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
collectionItems.Add(BuildCollectionItem(row));
|
||||
}
|
||||
|
||||
return collectionItems;
|
||||
}
|
||||
|
||||
public static CollectionItem GetCollection(long Id, string userid) {
|
||||
public static CollectionItem GetCollection(long Id, string userid)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql;
|
||||
string sql;
|
||||
if (userid == "")
|
||||
{
|
||||
// reserved for internal operations
|
||||
@@ -50,24 +53,24 @@ namespace gaseous_server.Classes
|
||||
// instigated by a user
|
||||
sql = "SELECT * FROM RomCollections WHERE Id = @id AND OwnedBy = @ownedby ORDER BY `Name`";
|
||||
}
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", Id },
|
||||
{ "ownedby", userid }
|
||||
};
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
DataRow row = romDT.Rows[0];
|
||||
CollectionItem collectionItem = BuildCollectionItem(row);
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
DataRow row = romDT.Rows[0];
|
||||
CollectionItem collectionItem = BuildCollectionItem(row);
|
||||
|
||||
return collectionItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unknown Collection Id");
|
||||
}
|
||||
return collectionItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unknown Collection Id");
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionItem NewCollection(CollectionItem item, string userid)
|
||||
@@ -130,9 +133,9 @@ namespace gaseous_server.Classes
|
||||
{ "archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip) },
|
||||
{ "ownedby", userid }
|
||||
};
|
||||
|
||||
|
||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + item.ArchiveExtension);
|
||||
if (ForceRebuild == true)
|
||||
if (ForceRebuild == true)
|
||||
{
|
||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
||||
if (File.Exists(CollectionZipFile))
|
||||
@@ -153,7 +156,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
|
||||
CollectionItem collectionItem = GetCollection(Id, userid);
|
||||
|
||||
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
||||
@@ -208,7 +211,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionContents GetCollectionContent(CollectionItem collectionItem, string userid) {
|
||||
public static CollectionContents GetCollectionContent(CollectionItem collectionItem, string userid)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// get age ratings for specified user
|
||||
@@ -245,30 +249,35 @@ namespace gaseous_server.Classes
|
||||
List<Platform> platforms = new List<Platform>();
|
||||
|
||||
// add platforms with an inclusion status
|
||||
foreach (CollectionItem.AlwaysIncludeItem alwaysIncludeItem in collectionItem.AlwaysInclude)
|
||||
foreach (CollectionItem.AlwaysIncludeItem alwaysIncludeItem in collectionItem.AlwaysInclude)
|
||||
{
|
||||
if (
|
||||
alwaysIncludeItem.InclusionState == CollectionItem.AlwaysIncludeStatus.AlwaysInclude ||
|
||||
alwaysIncludeItem.InclusionState == CollectionItem.AlwaysIncludeStatus.AlwaysExclude
|
||||
)
|
||||
{
|
||||
if (!platformids.Contains(alwaysIncludeItem.PlatformId))
|
||||
{
|
||||
if (!platformids.Contains(alwaysIncludeItem.PlatformId))
|
||||
{
|
||||
platformids.Add(alwaysIncludeItem.PlatformId);
|
||||
}
|
||||
platformids.Add(alwaysIncludeItem.PlatformId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add dynamic platforms
|
||||
if (DynamicPlatforms.Count > 0) {
|
||||
foreach (long PlatformId in platformids) {
|
||||
if (DynamicPlatforms.Count > 0)
|
||||
{
|
||||
foreach (long PlatformId in platformids)
|
||||
{
|
||||
platforms.Add(Platforms.GetPlatform(PlatformId));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// get all platforms to pull from
|
||||
Dictionary<string, List<Filters.FilterItem>> FilterDict = Filters.Filter(AgeGroups.AgeRestrictionGroupings.Adult, true);
|
||||
List<Classes.Filters.FilterItem> filteredPlatforms = (List<Classes.Filters.FilterItem>)FilterDict["platforms"];
|
||||
foreach (Filters.FilterItem filterItem in filteredPlatforms) {
|
||||
foreach (Filters.FilterItem filterItem in filteredPlatforms)
|
||||
{
|
||||
platforms.Add(Platforms.GetPlatform(filterItem.Id));
|
||||
}
|
||||
}
|
||||
@@ -280,7 +289,8 @@ namespace gaseous_server.Classes
|
||||
// build collection
|
||||
List<CollectionContents.CollectionPlatformItem> platformItems = new List<CollectionContents.CollectionPlatformItem>();
|
||||
|
||||
foreach (Platform platform in platforms) {
|
||||
foreach (Platform platform in platforms)
|
||||
{
|
||||
long TotalRomSize = 0;
|
||||
long TotalGameCount = 0;
|
||||
|
||||
@@ -297,7 +307,8 @@ namespace gaseous_server.Classes
|
||||
Controllers.v1_1.GamesController.GameReturnPackage games = new Controllers.v1_1.GamesController.GameReturnPackage();
|
||||
if (isDynamic == true)
|
||||
{
|
||||
Controllers.v1_1.GamesController.GameSearchModel searchModel = new Controllers.v1_1.GamesController.GameSearchModel{
|
||||
Controllers.v1_1.GamesController.GameSearchModel searchModel = new Controllers.v1_1.GamesController.GameSearchModel
|
||||
{
|
||||
Name = "",
|
||||
Platform = new List<string>{
|
||||
platform.Id.ToString()
|
||||
@@ -306,49 +317,52 @@ namespace gaseous_server.Classes
|
||||
GameMode = collectionItem.Players.ConvertAll(s => s.ToString()),
|
||||
PlayerPerspective = collectionItem.PlayerPerspectives.ConvertAll(s => s.ToString()),
|
||||
Theme = collectionItem.Themes.ConvertAll(s => s.ToString()),
|
||||
GameRating = new Controllers.v1_1.GamesController.GameSearchModel.GameRatingItem{
|
||||
GameRating = new Controllers.v1_1.GamesController.GameSearchModel.GameRatingItem
|
||||
{
|
||||
MinimumRating = collectionItem.MinimumRating,
|
||||
MaximumRating = collectionItem.MaximumRating
|
||||
},
|
||||
GameAgeRating = new Controllers.v1_1.GamesController.GameSearchModel.GameAgeRatingItem{
|
||||
GameAgeRating = new Controllers.v1_1.GamesController.GameSearchModel.GameAgeRatingItem
|
||||
{
|
||||
AgeGroupings = UserAgeGroupings,
|
||||
IncludeUnrated = UserAgeGroupIncludeUnrated
|
||||
}
|
||||
};
|
||||
games = Controllers.v1_1.GamesController.GetGames(searchModel, userid);
|
||||
|
||||
|
||||
}
|
||||
|
||||
CollectionContents.CollectionPlatformItem collectionPlatformItem = new CollectionContents.CollectionPlatformItem(platform);
|
||||
collectionPlatformItem.Games = new List<CollectionContents.CollectionPlatformItem.CollectionGameItem>();
|
||||
|
||||
// add titles with an inclusion status
|
||||
foreach (CollectionItem.AlwaysIncludeItem alwaysIncludeItem in collectionItem.AlwaysInclude)
|
||||
foreach (CollectionItem.AlwaysIncludeItem alwaysIncludeItem in collectionItem.AlwaysInclude)
|
||||
{
|
||||
if (
|
||||
(
|
||||
alwaysIncludeItem.InclusionState == CollectionItem.AlwaysIncludeStatus.AlwaysInclude ||
|
||||
alwaysIncludeItem.InclusionState == CollectionItem.AlwaysIncludeStatus.AlwaysExclude
|
||||
) && alwaysIncludeItem.PlatformId == platform.Id
|
||||
)
|
||||
{
|
||||
MinimalGameItem AlwaysIncludeGame = new MinimalGameItem(Games.GetGame(alwaysIncludeItem.GameId, false, false, false));
|
||||
CollectionContents.CollectionPlatformItem.CollectionGameItem gameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(AlwaysIncludeGame);
|
||||
gameItem.InclusionStatus = new CollectionItem.AlwaysIncludeItem();
|
||||
gameItem.InclusionStatus.PlatformId = alwaysIncludeItem.PlatformId;
|
||||
gameItem.InclusionStatus.GameId = alwaysIncludeItem.GameId;
|
||||
gameItem.InclusionStatus.InclusionState = alwaysIncludeItem.InclusionState;
|
||||
gameItem.Roms = Roms.GetRoms((long)gameItem.Id, (long)platform.Id).GameRomItems;
|
||||
)
|
||||
{
|
||||
MinimalGameItem AlwaysIncludeGame = new MinimalGameItem(Games.GetGame(HasheousClient.Models.MetadataSources.IGDB, alwaysIncludeItem.GameId));
|
||||
CollectionContents.CollectionPlatformItem.CollectionGameItem gameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(AlwaysIncludeGame);
|
||||
gameItem.InclusionStatus = new CollectionItem.AlwaysIncludeItem();
|
||||
gameItem.InclusionStatus.PlatformId = alwaysIncludeItem.PlatformId;
|
||||
gameItem.InclusionStatus.GameId = alwaysIncludeItem.GameId;
|
||||
gameItem.InclusionStatus.InclusionState = alwaysIncludeItem.InclusionState;
|
||||
gameItem.Roms = Roms.GetRoms((long)gameItem.Id, (long)platform.Id).GameRomItems;
|
||||
|
||||
collectionPlatformItem.Games.Add(gameItem);
|
||||
collectionPlatformItem.Games.Add(gameItem);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MinimalGameItem game in games.Games) {
|
||||
foreach (MinimalGameItem game in games.Games)
|
||||
{
|
||||
bool gameAlreadyInList = false;
|
||||
foreach (CollectionContents.CollectionPlatformItem.CollectionGameItem existingGame in collectionPlatformItem.Games)
|
||||
foreach (CollectionContents.CollectionPlatformItem.CollectionGameItem existingGame in collectionPlatformItem.Games)
|
||||
{
|
||||
if (existingGame.Id == game.Id)
|
||||
if (existingGame.Id == game.Id)
|
||||
{
|
||||
gameAlreadyInList = true;
|
||||
}
|
||||
@@ -359,31 +373,37 @@ namespace gaseous_server.Classes
|
||||
CollectionContents.CollectionPlatformItem.CollectionGameItem collectionGameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(game);
|
||||
|
||||
List<Roms.GameRomItem> gameRoms = Roms.GetRoms((long)game.Id, (long)platform.Id).GameRomItems;
|
||||
|
||||
|
||||
bool AddGame = false;
|
||||
|
||||
// calculate total rom size for the game
|
||||
long GameRomSize = 0;
|
||||
foreach (Roms.GameRomItem gameRom in gameRoms) {
|
||||
foreach (Roms.GameRomItem gameRom in gameRoms)
|
||||
{
|
||||
GameRomSize += (long)gameRom.Size;
|
||||
}
|
||||
if (collectionItem.MaximumBytesPerPlatform > 0) {
|
||||
if ((TotalRomSize + GameRomSize) < collectionItem.MaximumBytesPerPlatform) {
|
||||
if (collectionItem.MaximumBytesPerPlatform > 0)
|
||||
{
|
||||
if ((TotalRomSize + GameRomSize) < collectionItem.MaximumBytesPerPlatform)
|
||||
{
|
||||
AddGame = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
AddGame = true;
|
||||
}
|
||||
|
||||
if (AddGame == true) {
|
||||
if (AddGame == true)
|
||||
{
|
||||
TotalRomSize += GameRomSize;
|
||||
|
||||
bool AddRoms = false;
|
||||
|
||||
if (collectionItem.MaximumRomsPerPlatform > 0) {
|
||||
if (TotalGameCount < collectionItem.MaximumRomsPerPlatform) {
|
||||
if (collectionItem.MaximumRomsPerPlatform > 0)
|
||||
{
|
||||
if (TotalGameCount < collectionItem.MaximumRomsPerPlatform)
|
||||
{
|
||||
AddRoms = true;
|
||||
}
|
||||
}
|
||||
@@ -392,7 +412,8 @@ namespace gaseous_server.Classes
|
||||
AddRoms = true;
|
||||
}
|
||||
|
||||
if (AddRoms == true) {
|
||||
if (AddRoms == true)
|
||||
{
|
||||
TotalGameCount += 1;
|
||||
collectionGameItem.Roms = gameRoms;
|
||||
collectionPlatformItem.Games.Add(collectionGameItem);
|
||||
@@ -401,7 +422,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
// handle age grouping
|
||||
AgeGroups.AgeRestrictionGroupings CurrentAgeGroup = AgeGroups.GetAgeGroupFromAgeRatings(game.AgeRatings);
|
||||
List<AgeRating> gameAgeRatings = game.AgeRatings.Select(s => (AgeRating)s).ToList();
|
||||
AgeGroups.AgeRestrictionGroupings CurrentAgeGroup = AgeGroups.GetAgeGroupFromAgeRatings(gameAgeRatings);
|
||||
if (CurrentAgeGroup > AgeGrouping)
|
||||
{
|
||||
AgeGrouping = CurrentAgeGroup;
|
||||
@@ -469,14 +491,14 @@ namespace gaseous_server.Classes
|
||||
{ "agu", collectionContents.ContainsUnclassifiedAgeGroup }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
|
||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = collectionContents.Collection;
|
||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + collectionItem.ArchiveExtension);
|
||||
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// clean up if needed
|
||||
if (File.Exists(ZipFilePath))
|
||||
{
|
||||
@@ -500,11 +522,12 @@ namespace gaseous_server.Classes
|
||||
if (collectionItem.IncludeBIOSFiles == true)
|
||||
{
|
||||
List<Bios.BiosItem> bios = Bios.GetBios(collectionPlatformItem.Id, true);
|
||||
if (!Directory.Exists(ZipBiosPath)) {
|
||||
if (!Directory.Exists(ZipBiosPath))
|
||||
{
|
||||
Directory.CreateDirectory(ZipBiosPath);
|
||||
}
|
||||
|
||||
foreach (Bios.BiosItem biosItem in bios)
|
||||
foreach (Bios.BiosItem biosItem in bios)
|
||||
{
|
||||
if (File.Exists(biosItem.biosPath))
|
||||
{
|
||||
@@ -573,8 +596,8 @@ namespace gaseous_server.Classes
|
||||
case CollectionItem.FolderStructures.RetroPie:
|
||||
ZipGamePath = ZipPlatformPath;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// copy in roms
|
||||
foreach (Roms.GameRomItem gameRomItem in collectionGameItem.Roms)
|
||||
{
|
||||
@@ -590,7 +613,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
// compress to zip
|
||||
Logging.Log(Logging.LogType.Information, "Collections", "Compressing collection");
|
||||
switch(collectionItem.ArchiveType)
|
||||
switch (collectionItem.ArchiveType)
|
||||
{
|
||||
case CollectionItem.ArchiveTypes.Zip:
|
||||
ZipFile.CreateFromDirectory(ZipFileTempPath, ZipFilePath, CompressionLevel.SmallestSize, false);
|
||||
@@ -601,10 +624,10 @@ namespace gaseous_server.Classes
|
||||
break;
|
||||
|
||||
case CollectionItem.ArchiveTypes.SevenZip:
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// clean up
|
||||
if (Directory.Exists(ZipFileTempPath))
|
||||
@@ -639,7 +662,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
private static CollectionItem BuildCollectionItem(DataRow row) {
|
||||
private static CollectionItem BuildCollectionItem(DataRow row)
|
||||
{
|
||||
string strPlatforms = (string)Common.ReturnValueIfNull(row["Platforms"], "[ ]");
|
||||
string strGenres = (string)Common.ReturnValueIfNull(row["Genres"], "[ ]");
|
||||
string strPlayers = (string)Common.ReturnValueIfNull(row["Players"], "[ ]");
|
||||
@@ -704,7 +728,7 @@ namespace gaseous_server.Classes
|
||||
case ArchiveTypes.Zip:
|
||||
default:
|
||||
return ".zip";
|
||||
|
||||
|
||||
case ArchiveTypes.RAR:
|
||||
return ".rar";
|
||||
|
||||
@@ -810,7 +834,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectionContents {
|
||||
public class CollectionContents
|
||||
{
|
||||
[JsonIgnore]
|
||||
public List<CollectionPlatformItem> Collection { get; set; }
|
||||
|
||||
@@ -840,13 +865,16 @@ namespace gaseous_server.Classes
|
||||
public AgeGroups.AgeRestrictionGroupings AgeGroup { get; set; }
|
||||
public bool ContainsUnclassifiedAgeGroup { get; set; }
|
||||
|
||||
public class CollectionPlatformItem {
|
||||
public CollectionPlatformItem(IGDB.Models.Platform platform) {
|
||||
public class CollectionPlatformItem
|
||||
{
|
||||
public CollectionPlatformItem(Platform platform)
|
||||
{
|
||||
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug" };
|
||||
|
||||
PropertyInfo[] srcProperties = typeof(IGDB.Models.Platform).GetProperties();
|
||||
PropertyInfo[] srcProperties = typeof(Platform).GetProperties();
|
||||
PropertyInfo[] dstProperties = typeof(CollectionPlatformItem).GetProperties();
|
||||
foreach (PropertyInfo srcProperty in srcProperties) {
|
||||
foreach (PropertyInfo srcProperty in srcProperties)
|
||||
{
|
||||
if (PropertyWhitelist.Contains<string>(srcProperty.Name))
|
||||
{
|
||||
foreach (PropertyInfo dstProperty in dstProperties)
|
||||
@@ -866,10 +894,13 @@ namespace gaseous_server.Classes
|
||||
|
||||
public List<CollectionGameItem> Games { get; set; }
|
||||
|
||||
public int RomCount {
|
||||
get {
|
||||
public int RomCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int Counter = 0;
|
||||
foreach (CollectionGameItem Game in Games) {
|
||||
foreach (CollectionGameItem Game in Games)
|
||||
{
|
||||
Counter += 1;
|
||||
}
|
||||
|
||||
@@ -877,11 +908,15 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public long RomSize {
|
||||
get {
|
||||
public long RomSize
|
||||
{
|
||||
get
|
||||
{
|
||||
long Size = 0;
|
||||
foreach (CollectionGameItem Game in Games) {
|
||||
foreach (Roms.GameRomItem Rom in Game.Roms) {
|
||||
foreach (CollectionGameItem Game in Games)
|
||||
{
|
||||
foreach (Roms.GameRomItem Rom in Game.Roms)
|
||||
{
|
||||
Size += (long)Rom.Size;
|
||||
}
|
||||
}
|
||||
@@ -904,29 +939,13 @@ namespace gaseous_server.Classes
|
||||
this.FirstReleaseDate = gameObject.FirstReleaseDate;
|
||||
this.AgeRatings = gameObject.AgeRatings;
|
||||
}
|
||||
|
||||
public IGDB.Models.Cover? CoverItem
|
||||
|
||||
public AgeGroups.AgeRestrictionGroupings AgeGrouping
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Cover != null)
|
||||
{
|
||||
IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory, "Games", Slug), false);
|
||||
|
||||
return cover;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AgeGroups.AgeRestrictionGroupings AgeGrouping
|
||||
{
|
||||
get
|
||||
{
|
||||
return AgeGroups.GetAgeGroupFromAgeRatings(this.AgeRatings);
|
||||
List<AgeRating> gameAgeRatings = this.AgeRatings.Select(s => (AgeRating)s).ToList();
|
||||
return AgeGroups.GetAgeGroupFromAgeRatings(gameAgeRatings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,17 +953,20 @@ namespace gaseous_server.Classes
|
||||
|
||||
public List<Roms.GameRomItem> Roms { get; set; }
|
||||
|
||||
public long RomSize {
|
||||
get {
|
||||
long Size = 0;
|
||||
foreach (Roms.GameRomItem Rom in Roms) {
|
||||
Size += (long)Rom.Size;
|
||||
public long RomSize
|
||||
{
|
||||
get
|
||||
{
|
||||
long Size = 0;
|
||||
foreach (Roms.GameRomItem Rom in Roms)
|
||||
{
|
||||
Size += (long)Rom.Size;
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using static gaseous_server.Classes.Metadata.Communications;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -126,6 +128,27 @@ namespace gaseous_server.Classes
|
||||
typeof(DescriptionAttribute)))?.Description ?? value.ToString();
|
||||
}
|
||||
|
||||
public static Point GetResolution(this Enum value)
|
||||
{
|
||||
string width = ((ResolutionAttribute)Attribute.GetCustomAttribute(
|
||||
value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||
.Single(x => x.GetValue(null).Equals(value)),
|
||||
typeof(ResolutionAttribute)))?.width.ToString() ?? value.ToString();
|
||||
|
||||
string height = ((ResolutionAttribute)Attribute.GetCustomAttribute(
|
||||
value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||
.Single(x => x.GetValue(null).Equals(value)),
|
||||
typeof(ResolutionAttribute)))?.height.ToString() ?? value.ToString();
|
||||
|
||||
return new Point(int.Parse(width), int.Parse(height));
|
||||
}
|
||||
|
||||
public static bool IsNullableEnum(this Type t)
|
||||
{
|
||||
Type u = Nullable.GetUnderlyingType(t);
|
||||
return u != null && u.IsEnum;
|
||||
}
|
||||
|
||||
// compression
|
||||
public static byte[] Compress(byte[] data)
|
||||
{
|
||||
@@ -159,6 +182,50 @@ namespace gaseous_server.Classes
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLookupByCode(LookupTypes LookupType, string Code)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id FROM " + LookupType.ToString() + " WHERE Code = @code";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "code", Code }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)data.Rows[0]["Id"];
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLookupByValue(LookupTypes LookupType, string Value)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id FROM " + LookupType.ToString() + " WHERE Value = @value";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "value", Value }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)data.Rows[0]["Id"];
|
||||
}
|
||||
}
|
||||
|
||||
public enum LookupTypes
|
||||
{
|
||||
Country,
|
||||
Language
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using Newtonsoft.Json;
|
||||
using IGDB.Models;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using NuGet.Common;
|
||||
|
||||
@@ -115,7 +114,12 @@ namespace gaseous_server.Classes
|
||||
if (File.Exists(ConfigurationFilePath))
|
||||
{
|
||||
string configRaw = File.ReadAllText(ConfigurationFilePath);
|
||||
ConfigFile? _tempConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<ConfigFile>(configRaw);
|
||||
Newtonsoft.Json.JsonSerializerSettings serializerSettings = new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
|
||||
MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore
|
||||
};
|
||||
ConfigFile? _tempConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<ConfigFile>(configRaw, serializerSettings);
|
||||
if (_tempConfig != null)
|
||||
{
|
||||
_config = _tempConfig;
|
||||
@@ -131,9 +135,9 @@ namespace gaseous_server.Classes
|
||||
_config.DatabaseConfiguration.Password = (string)Common.GetEnvVar("dbpass", _config.DatabaseConfiguration.Password);
|
||||
_config.DatabaseConfiguration.DatabaseName = (string)Common.GetEnvVar("dbname", _config.DatabaseConfiguration.DatabaseName);
|
||||
_config.DatabaseConfiguration.Port = int.Parse((string)Common.GetEnvVar("dbport", _config.DatabaseConfiguration.Port.ToString()));
|
||||
_config.MetadataConfiguration.MetadataSource = (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.MetadataSource.ToString()));
|
||||
_config.MetadataConfiguration.DefaultMetadataSource = (HasheousClient.Models.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.DefaultMetadataSource.ToString()));
|
||||
_config.IGDBConfiguration.UseHasheousProxy = bool.Parse((string)Common.GetEnvVar("metadatausehasheousproxy", _config.IGDBConfiguration.UseHasheousProxy.ToString()));
|
||||
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString())); ;
|
||||
_config.MetadataConfiguration.MaxLibraryScanWorkers = int.Parse((string)Common.GetEnvVar("maxlibraryscanworkers", _config.MetadataConfiguration.MaxLibraryScanWorkers.ToString()));
|
||||
_config.MetadataConfiguration.HasheousHost = (string)Common.GetEnvVar("hasheoushost", _config.MetadataConfiguration.HasheousHost);
|
||||
_config.IGDBConfiguration.ClientId = (string)Common.GetEnvVar("igdbclientid", _config.IGDBConfiguration.ClientId);
|
||||
_config.IGDBConfiguration.Secret = (string)Common.GetEnvVar("igdbclientsecret", _config.IGDBConfiguration.Secret);
|
||||
@@ -154,8 +158,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Using configuration:");
|
||||
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
||||
// Console.WriteLine("Using configuration:");
|
||||
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
||||
}
|
||||
|
||||
public static void UpdateConfig()
|
||||
@@ -197,17 +201,12 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
string SettingName = (string)dataRow["Setting"];
|
||||
|
||||
if (SettingName.StartsWith("LastRun_"))
|
||||
{
|
||||
Console.WriteLine("Break");
|
||||
}
|
||||
|
||||
if (AppSettings.ContainsKey(SettingName))
|
||||
{
|
||||
AppSettings.Remove(SettingName);
|
||||
}
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
// Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -536,11 +535,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ReadSetting<string>("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data"));
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSetting<string>("LibraryRootDirectory", value);
|
||||
return Path.Combine(Config.ConfigurationPath, "Data");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,6 +579,14 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryFirmwareDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryRootDirectory, "Firmware");
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryUploadDirectory
|
||||
{
|
||||
get
|
||||
@@ -624,28 +627,35 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public string LibraryMetadataDirectory_Platform(Platform platform)
|
||||
public string LibraryMetadataDirectory_Platform(HasheousClient.Models.Metadata.IGDB.Platform platform)
|
||||
{
|
||||
string MetadataPath = Path.Combine(LibraryMetadataDirectory, "Platforms", platform.Slug);
|
||||
if (!Directory.Exists(MetadataPath)) { Directory.CreateDirectory(MetadataPath); }
|
||||
return MetadataPath;
|
||||
}
|
||||
|
||||
public string LibraryMetadataDirectory_Game(Game game)
|
||||
public string LibraryMetadataDirectory_Game(gaseous_server.Models.Game game)
|
||||
{
|
||||
string MetadataPath = Path.Combine(LibraryMetadataDirectory, "Games", game.Slug);
|
||||
if (!Directory.Exists(MetadataPath)) { Directory.CreateDirectory(MetadataPath); }
|
||||
return MetadataPath;
|
||||
}
|
||||
|
||||
public string LibraryMetadataDirectory_Company(Company company)
|
||||
public string LibraryMetadataDirectory_Company(HasheousClient.Models.Metadata.IGDB.Company company)
|
||||
{
|
||||
string MetadataPath = Path.Combine(LibraryMetadataDirectory, "Companies", company.Slug);
|
||||
if (!Directory.Exists(MetadataPath)) { Directory.CreateDirectory(MetadataPath); }
|
||||
return MetadataPath;
|
||||
}
|
||||
|
||||
public string LibrarySignatureImportDirectory
|
||||
public string LibraryMetadataDirectory_Hasheous()
|
||||
{
|
||||
string MetadataPath = Path.Combine(LibraryMetadataDirectory, "Hasheous");
|
||||
if (!Directory.Exists(MetadataPath)) { Directory.CreateDirectory(MetadataPath); }
|
||||
return MetadataPath;
|
||||
}
|
||||
|
||||
public string LibrarySignaturesDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -653,32 +663,64 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public string LibrarySignaturesProcessedDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryRootDirectory, "Signatures - Processed");
|
||||
}
|
||||
}
|
||||
|
||||
public void InitLibrary()
|
||||
{
|
||||
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
|
||||
if (!Directory.Exists(LibraryImportDirectory)) { Directory.CreateDirectory(LibraryImportDirectory); }
|
||||
if (!Directory.Exists(LibraryBIOSDirectory)) { Directory.CreateDirectory(LibraryBIOSDirectory); }
|
||||
if (!Directory.Exists(LibraryFirmwareDirectory)) { Directory.CreateDirectory(LibraryFirmwareDirectory); }
|
||||
if (!Directory.Exists(LibraryUploadDirectory)) { Directory.CreateDirectory(LibraryUploadDirectory); }
|
||||
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
|
||||
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }
|
||||
if (!Directory.Exists(LibraryCollectionsDirectory)) { Directory.CreateDirectory(LibraryCollectionsDirectory); }
|
||||
if (!Directory.Exists(LibrarySignatureImportDirectory)) { Directory.CreateDirectory(LibrarySignatureImportDirectory); }
|
||||
if (!Directory.Exists(LibrarySignaturesDirectory)) { Directory.CreateDirectory(LibrarySignaturesDirectory); }
|
||||
if (!Directory.Exists(LibrarySignaturesProcessedDirectory)) { Directory.CreateDirectory(LibrarySignaturesProcessedDirectory); }
|
||||
}
|
||||
}
|
||||
|
||||
public class MetadataAPI
|
||||
{
|
||||
private static HasheousClient.Models.MetadataModel.MetadataSources _MetadataSource
|
||||
public static string _HasheousClientAPIKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Pna5SRcbJ6R8aasytab_6vZD0aBKDGNZKRz4WY4xArpfZ-3mdZq0hXIGyy0AD43b";
|
||||
}
|
||||
}
|
||||
|
||||
private static HasheousClient.Models.MetadataSources _MetadataSource
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("metadatasource")))
|
||||
{
|
||||
return (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), Environment.GetEnvironmentVariable("metadatasource"));
|
||||
return (HasheousClient.Models.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataSources), Environment.GetEnvironmentVariable("metadatasource"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return HasheousClient.Models.MetadataModel.MetadataSources.IGDB;
|
||||
return HasheousClient.Models.MetadataSources.IGDB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool _MetadataUseHasheousProxy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("metadatausehasheousproxy")))
|
||||
{
|
||||
return bool.Parse(Environment.GetEnvironmentVariable("metadatausehasheousproxy"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,20 +740,9 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
private static int _MaxLibraryScanWorkers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("maxlibraryscanworkers")))
|
||||
{
|
||||
return int.Parse(Environment.GetEnvironmentVariable("maxlibraryscanworkers"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static bool _HasheousSubmitFixes { get; set; } = false;
|
||||
|
||||
private static string _HasheousAPIKey { get; set; } = "";
|
||||
|
||||
private static string _HasheousHost
|
||||
{
|
||||
@@ -728,11 +759,16 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public HasheousClient.Models.MetadataModel.MetadataSources MetadataSource = _MetadataSource;
|
||||
public HasheousClient.Models.MetadataSources DefaultMetadataSource = _MetadataSource;
|
||||
|
||||
public HasheousClient.Models.MetadataModel.SignatureSources SignatureSource = _SignatureSource;
|
||||
|
||||
public int MaxLibraryScanWorkers = _MaxLibraryScanWorkers;
|
||||
public bool HasheousSubmitFixes = _HasheousSubmitFixes;
|
||||
|
||||
public string HasheousAPIKey = _HasheousAPIKey;
|
||||
|
||||
[JsonIgnore]
|
||||
public string HasheousClientAPIKey = _HasheousClientAPIKey;
|
||||
|
||||
public string HasheousHost = _HasheousHost;
|
||||
}
|
||||
@@ -769,8 +805,24 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
private static bool _MetadataUseHasheousProxy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("igdbusehasheousproxy")))
|
||||
{
|
||||
return bool.Parse(Environment.GetEnvironmentVariable("igdbusehasheousproxy"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ClientId = _DefaultIGDBClientId;
|
||||
public string Secret = _DefaultIGDBSecret;
|
||||
public bool UseHasheousProxy = _MetadataUseHasheousProxy;
|
||||
}
|
||||
|
||||
public class Logging
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace gaseous_server.Classes
|
||||
_schema_version = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Database()
|
||||
{
|
||||
|
||||
@@ -70,39 +70,41 @@ namespace gaseous_server.Classes
|
||||
|
||||
public void InitDB()
|
||||
{
|
||||
// load resources
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
// load resources
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
switch (_ConnectorType)
|
||||
DatabaseMemoryCacheOptions? CacheOptions = new DatabaseMemoryCacheOptions(false);
|
||||
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
// 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 + "`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
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
|
||||
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)
|
||||
{
|
||||
// no schema table present - create 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);";
|
||||
ExecuteCMD(sql, dbDict);
|
||||
// no schema table present - create 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);";
|
||||
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
}
|
||||
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||
if (OuterSchemaVer == 0)
|
||||
{
|
||||
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 dbScript = "";
|
||||
@@ -113,39 +115,39 @@ namespace gaseous_server.Classes
|
||||
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
dbScript = reader.ReadToEnd();
|
||||
dbScript = reader.ReadToEnd();
|
||||
|
||||
// apply script
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
if (SchemaVersion.Rows.Count == 0)
|
||||
{
|
||||
// something is broken here... where's the table?
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Schema table missing! This shouldn't happen!");
|
||||
throw new Exception("schema_version table is missing!");
|
||||
// something is broken here... where's the table?
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Schema table missing! This shouldn't happen!");
|
||||
throw new Exception("schema_version table is missing!");
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
Database.schema_version = SchemaVer;
|
||||
if (SchemaVer < i)
|
||||
if (SchemaVer < i)
|
||||
{
|
||||
try
|
||||
{
|
||||
// run pre-upgrade code
|
||||
DatabaseMigration.PreUpgradeScript(i, _ConnectorType);
|
||||
|
||||
|
||||
// apply schema!
|
||||
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";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("schemaver", i);
|
||||
ExecuteCMD(sql, dbDict);
|
||||
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
|
||||
// run post-upgrade code
|
||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||
@@ -162,47 +164,91 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Database setup complete");
|
||||
break;
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Database setup complete");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command)
|
||||
public DataTable ExecuteCMD(string Command)
|
||||
{
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
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)
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, 30, "");
|
||||
}
|
||||
public DataTable ExecuteCMD(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
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 = "")
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
||||
}
|
||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
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)
|
||||
{
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
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)
|
||||
{
|
||||
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 = "")
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
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
|
||||
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
||||
@@ -228,18 +274,49 @@ namespace gaseous_server.Classes
|
||||
return rows;
|
||||
}
|
||||
|
||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||
return (DataTable)conn.ExecCMD(Command, Parameters, Timeout);
|
||||
default:
|
||||
return new DataTable();
|
||||
}
|
||||
}
|
||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
string CacheKey = Command + string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||
|
||||
if (CacheOptions is object && CacheOptions.CacheEnabled)
|
||||
{
|
||||
object? CachedData = DatabaseMemoryCache.GetCacheObject(CacheKey);
|
||||
if (CachedData is object)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -247,52 +324,194 @@ namespace gaseous_server.Classes
|
||||
return _ExecuteNonQuery(Command, dbDict, 30, "");
|
||||
}
|
||||
|
||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
return _ExecuteNonQuery(Command, Parameters, 30, "");
|
||||
}
|
||||
public int ExecuteNonQuery(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private int _ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||
int retVal = conn.ExecNonQuery(Command, Parameters, Timeout);
|
||||
return retVal;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
private int _ExecuteNonQuery(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||
int retVal = conn.ExecNonQuery(Command, Parameters, Timeout);
|
||||
return retVal;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteTransactionCMD(List<SQLTransactionItem> CommandList, int Timeout = 60)
|
||||
{
|
||||
object conn;
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
{
|
||||
var commands = new List<Dictionary<string, object>>();
|
||||
foreach (SQLTransactionItem CommandItem in CommandList)
|
||||
{
|
||||
var nCmd = new Dictionary<string, object>();
|
||||
nCmd.Add("sql", CommandItem.SQLCommand);
|
||||
nCmd.Add("values", CommandItem.Parameters);
|
||||
commands.Add(nCmd);
|
||||
}
|
||||
public void ExecuteTransactionCMD(List<SQLTransactionItem> CommandList, int Timeout = 60)
|
||||
{
|
||||
object conn;
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
{
|
||||
var commands = new List<Dictionary<string, object>>();
|
||||
foreach (SQLTransactionItem CommandItem in CommandList)
|
||||
{
|
||||
var nCmd = new Dictionary<string, object>();
|
||||
nCmd.Add("sql", CommandItem.SQLCommand);
|
||||
nCmd.Add("values", CommandItem.Parameters);
|
||||
commands.Add(nCmd);
|
||||
}
|
||||
|
||||
conn = new MySQLServerConnector(_ConnectionString);
|
||||
((MySQLServerConnector)conn).TransactionExecCMD(commands, Timeout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
conn = new MySQLServerConnector(_ConnectionString);
|
||||
((MySQLServerConnector)conn).TransactionExecCMD(commands, Timeout);
|
||||
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()
|
||||
{
|
||||
@@ -309,7 +528,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
return (int)SchemaVersion.Rows[0][0];
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
return 0;
|
||||
|
||||
@@ -319,17 +538,17 @@ namespace gaseous_server.Classes
|
||||
public bool TestConnection()
|
||||
{
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(_ConnectionString);
|
||||
return conn.TestConnection();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(_ConnectionString);
|
||||
return conn.TestConnection();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class SQLTransactionItem
|
||||
{
|
||||
public class SQLTransactionItem
|
||||
{
|
||||
public SQLTransactionItem()
|
||||
{
|
||||
|
||||
@@ -341,11 +560,11 @@ namespace gaseous_server.Classes
|
||||
this.Parameters = Parameters;
|
||||
}
|
||||
|
||||
public string? SQLCommand;
|
||||
public Dictionary<string, object>? Parameters = new Dictionary<string, object>();
|
||||
}
|
||||
public string? SQLCommand;
|
||||
public Dictionary<string, object>? Parameters = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private partial class MySQLServerConnector
|
||||
private partial class MySQLServerConnector
|
||||
{
|
||||
private string DBConn = "";
|
||||
|
||||
@@ -358,8 +577,8 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
DataTable RetTable = new DataTable();
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
@@ -384,7 +603,9 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||
}
|
||||
RetTable.Load(cmd.ExecuteReader());
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||
Trace.WriteLine("Error executing " + SQL);
|
||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||
@@ -397,12 +618,12 @@ namespace gaseous_server.Classes
|
||||
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;
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Connecting to database", null, true);
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
@@ -427,7 +648,9 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||
}
|
||||
result = cmd.ExecuteNonQuery();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||
Trace.WriteLine("Error executing " + SQL);
|
||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||
@@ -440,10 +663,10 @@ namespace gaseous_server.Classes
|
||||
return result;
|
||||
}
|
||||
|
||||
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
||||
{
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
{
|
||||
public void TransactionExecCMD(List<Dictionary<string, object>> Parameters, int Timeout)
|
||||
{
|
||||
using (MySqlConnection conn = new MySqlConnection(DBConn))
|
||||
{
|
||||
conn.Open();
|
||||
var command = conn.CreateCommand();
|
||||
MySqlTransaction transaction;
|
||||
@@ -460,28 +683,28 @@ namespace gaseous_server.Classes
|
||||
transaction.Commit();
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||
{
|
||||
var cmd = new MySqlCommand();
|
||||
cmd.Connection = Conn;
|
||||
cmd.CommandText = SQL;
|
||||
cmd.CommandTimeout = Timeout;
|
||||
{
|
||||
var withBlock = cmd.Parameters;
|
||||
if (Parameters is object)
|
||||
{
|
||||
if (Parameters.Count > 0)
|
||||
{
|
||||
foreach (string param in Parameters.Keys)
|
||||
withBlock.AddWithValue(param, Parameters[param]);
|
||||
}
|
||||
}
|
||||
}
|
||||
private MySqlCommand buildcommand(MySqlConnection Conn, string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||
{
|
||||
var cmd = new MySqlCommand();
|
||||
cmd.Connection = Conn;
|
||||
cmd.CommandText = SQL;
|
||||
cmd.CommandTimeout = Timeout;
|
||||
{
|
||||
var withBlock = cmd.Parameters;
|
||||
if (Parameters is object)
|
||||
{
|
||||
if (Parameters.Count > 0)
|
||||
{
|
||||
foreach (string param in Parameters.Keys)
|
||||
withBlock.AddWithValue(param, Parameters[param]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public bool TestConnection()
|
||||
{
|
||||
@@ -499,7 +722,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -64,6 +66,8 @@ namespace gaseous_server.Classes
|
||||
|
||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -103,6 +107,161 @@ namespace gaseous_server.Classes
|
||||
sql = "DELETE FROM Settings WHERE Setting LIKE 'LastRun_%';";
|
||||
db.ExecuteNonQuery(sql);
|
||||
break;
|
||||
|
||||
case 1023:
|
||||
// load country list
|
||||
Logging.Log(Logging.LogType.Information, "Database Upgrade", "Adding country look up table contents");
|
||||
|
||||
string countryResourceName = "gaseous_server.Support.Country.txt";
|
||||
using (Stream stream = assembly.GetManifestResourceStream(countryResourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
do
|
||||
{
|
||||
string[] line = reader.ReadLine().Split("|");
|
||||
|
||||
sql = "INSERT INTO Country (Code, Value) VALUES (@code, @value);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "code", line[0] },
|
||||
{ "value", line[1] }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
} while (reader.EndOfStream == false);
|
||||
}
|
||||
|
||||
// load language list
|
||||
Logging.Log(Logging.LogType.Information, "Database Upgrade", "Adding language look up table contents");
|
||||
|
||||
string languageResourceName = "gaseous_server.Support.Language.txt";
|
||||
using (Stream stream = assembly.GetManifestResourceStream(languageResourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
do
|
||||
{
|
||||
string[] line = reader.ReadLine().Split("|");
|
||||
|
||||
sql = "INSERT INTO Language (Code, Value) VALUES (@code, @value);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "code", line[0] },
|
||||
{ "value", line[1] }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
} while (reader.EndOfStream == false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
// 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);
|
||||
}
|
||||
|
||||
// update all rom paths to use the new format
|
||||
sql = "SELECT * FROM GameLibraries;";
|
||||
data = db.ExecuteCMD(sql);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
sql = "SELECT * FROM Games_Roms WHERE LibraryId = @libraryid;";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "libraryid", row["Id"] }
|
||||
};
|
||||
DataTable romData = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
string libraryRootPath = (string)row["Path"];
|
||||
if (libraryRootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false)
|
||||
{
|
||||
libraryRootPath += Path.DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
bool GetLastThreeElements = false;
|
||||
if ((int)row["DefaultLibrary"] == 1)
|
||||
{
|
||||
GetLastThreeElements = true;
|
||||
}
|
||||
|
||||
foreach (DataRow romRow in romData.Rows)
|
||||
{
|
||||
string existingPath = (string)romRow["RelativePath"];
|
||||
string newPath = "";
|
||||
|
||||
if (GetLastThreeElements == true)
|
||||
{
|
||||
// strip all but the last 3 elements from existingPath separated by directory separator
|
||||
// this mode only works for the default library
|
||||
string[] pathParts = existingPath.Split(Path.DirectorySeparatorChar);
|
||||
if (pathParts.Length > 3)
|
||||
{
|
||||
newPath = Path.Combine(pathParts[pathParts.Length - 3], pathParts[pathParts.Length - 2], pathParts[pathParts.Length - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPath = existingPath;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// strip the library root path from the existing path
|
||||
if (existingPath.StartsWith(libraryRootPath))
|
||||
{
|
||||
newPath = existingPath.Substring(libraryRootPath.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPath = existingPath;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Database Upgrade", "Updating ROM path from " + existingPath + " to " + newPath);
|
||||
|
||||
sql = "UPDATE Games_Roms SET RelativePath = @newpath WHERE Id = @id;";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "newpath", newPath },
|
||||
{ "id", romRow["Id"] }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
}
|
||||
}
|
||||
|
||||
// get all tables that have the prefix "Relation_" and drop them
|
||||
sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = @dbname AND table_name LIKE 'Relation_%';";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "dbname", Config.DatabaseConfiguration.DatabaseName }
|
||||
};
|
||||
data = db.ExecuteCMD(sql, dbDict);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
sql = "DROP TABLE " + (string)row["table_name"] + ";";
|
||||
db.ExecuteNonQuery(sql);
|
||||
}
|
||||
|
||||
// migrating metadata is a safe background task
|
||||
BackgroundUpgradeTargetSchemaVersions.Add(1024);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -117,6 +276,10 @@ namespace gaseous_server.Classes
|
||||
case 1002:
|
||||
MySql_1002_MigrateMetadataVersion();
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
MySql_1024_MigrateMetadataVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,5 +380,38 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MySql_1024_MigrateMetadataVersion()
|
||||
{
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM view_Games_Roms WHERE RomDataVersion = 1;";
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
long count = 1;
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
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"]);
|
||||
Common.hashObject hash = new Common.hashObject()
|
||||
{
|
||||
md5hash = (string)row["MD5"],
|
||||
sha1hash = (string)row["SHA1"]
|
||||
};
|
||||
Signatures_Games signature = fileSignature.GetFileSignature(
|
||||
library,
|
||||
hash,
|
||||
new FileInfo((string)row["Path"]),
|
||||
(string)row["Path"]
|
||||
);
|
||||
|
||||
HasheousClient.Models.Metadata.IGDB.Platform platform = Platforms.GetPlatform((long)row["PlatformId"]);
|
||||
|
||||
ImportGame.StoreGame(library, hash, signature, platform, (string)row["Path"], (long)row["Id"]);
|
||||
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Configuration;
|
||||
using System.IO.Compression;
|
||||
using HasheousClient.Models;
|
||||
using System.Net;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using NuGet.Common;
|
||||
using SevenZip;
|
||||
using SharpCompress.Archives;
|
||||
@@ -110,8 +115,10 @@ namespace gaseous_server.Classes
|
||||
// loop through contents until we find the first signature match
|
||||
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||
bool signatureFound = false;
|
||||
bool signatureSelectorAlreadyApplied = false;
|
||||
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
bool signatureSelector = false;
|
||||
if (File.Exists(file))
|
||||
{
|
||||
FileInfo zfi = new FileInfo(file);
|
||||
@@ -121,16 +128,6 @@ namespace gaseous_server.Classes
|
||||
|
||||
if (zfi != null)
|
||||
{
|
||||
ArchiveData archiveData = new ArchiveData
|
||||
{
|
||||
FileName = Path.GetFileName(file),
|
||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||
Size = zfi.Length,
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
};
|
||||
archiveFiles.Add(archiveData);
|
||||
|
||||
if (signatureFound == false)
|
||||
{
|
||||
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi.Name, zfi.Extension, zfi.Length, file, true);
|
||||
@@ -152,15 +149,37 @@ namespace gaseous_server.Classes
|
||||
discoveredSignature = zDiscoveredSignature;
|
||||
|
||||
signatureFound = true;
|
||||
|
||||
if (signatureSelectorAlreadyApplied == false)
|
||||
{
|
||||
signatureSelector = true;
|
||||
signatureSelectorAlreadyApplied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveData archiveData = new ArchiveData
|
||||
{
|
||||
FileName = Path.GetFileName(file),
|
||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||
Size = zfi.Length,
|
||||
MD5 = zhash.md5hash,
|
||||
SHA1 = zhash.sha1hash,
|
||||
isSignatureSelector = signatureSelector
|
||||
};
|
||||
archiveFiles.Add(archiveData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
discoveredSignature.Rom.Attributes.Add(new KeyValuePair<string, object>(
|
||||
if (discoveredSignature.Rom.Attributes == null)
|
||||
{
|
||||
discoveredSignature.Rom.Attributes = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
discoveredSignature.Rom.Attributes.Add(
|
||||
"ZipContents", Newtonsoft.Json.JsonConvert.SerializeObject(archiveFiles)
|
||||
));
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -168,6 +187,22 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
// get discovered platform
|
||||
Platform? determinedPlatform = null;
|
||||
if (library.DefaultPlatformId == null || library.DefaultPlatformId == 0)
|
||||
{
|
||||
determinedPlatform = Metadata.Platforms.GetPlatform((long)discoveredSignature.Flags.PlatformId);
|
||||
if (determinedPlatform == null)
|
||||
{
|
||||
determinedPlatform = new Platform();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
determinedPlatform = Metadata.Platforms.GetPlatform((long)library.DefaultPlatformId);
|
||||
discoveredSignature.MetadataSources.AddPlatform((long)determinedPlatform.Id, determinedPlatform.Name, HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
|
||||
return discoveredSignature;
|
||||
}
|
||||
|
||||
@@ -176,43 +211,51 @@ namespace gaseous_server.Classes
|
||||
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
|
||||
gaseous_server.Models.Signatures_Games? dbSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
if (dbSignature != null)
|
||||
// begin signature search
|
||||
switch (Config.MetadataConfiguration.SignatureSource)
|
||||
{
|
||||
// local signature found
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
||||
discoveredSignature = dbSignature;
|
||||
case HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly:
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous disabled - searching local database only");
|
||||
|
||||
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
|
||||
dbSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
// construct a signature from file data
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in local database or Hasheous (if enabled) - generating from file data");
|
||||
|
||||
if (dbSignature != null)
|
||||
{
|
||||
// signature retrieved from Hasheous
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
||||
discoveredSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
}
|
||||
else
|
||||
{
|
||||
// construct a signature from file data
|
||||
dbSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + discoveredSignature.Game.Name);
|
||||
}
|
||||
|
||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " Determined import file as: " + discoveredSignature.Game.Name + " (" + discoveredSignature.Game.Year + ") " + discoveredSignature.Game.System);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " Platform determined to be: " + discoveredSignature.Flags.IGDBPlatformName + " (" + discoveredSignature.Flags.IGDBPlatformId + ")");
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " Platform determined to be: " + discoveredSignature.Flags.PlatformName + " (" + discoveredSignature.Flags.PlatformId + ")");
|
||||
|
||||
return discoveredSignature;
|
||||
}
|
||||
@@ -265,34 +308,153 @@ namespace gaseous_server.Classes
|
||||
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||
{
|
||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||
SignatureLookupItem? HasheousResult = null;
|
||||
|
||||
Console.WriteLine(HasheousClient.WebApp.HttpHelper.BaseUri);
|
||||
HasheousClient.Models.LookupItemModel? HasheousResult = null;
|
||||
try
|
||||
{
|
||||
HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel
|
||||
// check the cache first
|
||||
if (!Directory.Exists(Config.LibraryConfiguration.LibraryMetadataDirectory_Hasheous()))
|
||||
{
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
});
|
||||
Directory.CreateDirectory(Config.LibraryConfiguration.LibraryMetadataDirectory_Hasheous());
|
||||
}
|
||||
// create file name from hash object
|
||||
string cacheFileName = hash.md5hash + "_" + hash.sha1hash + ".json";
|
||||
string cacheFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Hasheous(), cacheFileName);
|
||||
// use cache file if it exists and is less than 30 days old, otherwise fetch from hasheous. if the fetch from hasheous is successful, save it to the cache, if it fails, use the cache if it exists even if it's old
|
||||
if (File.Exists(cacheFilePath))
|
||||
{
|
||||
FileInfo cacheFile = new FileInfo(cacheFilePath);
|
||||
if (cacheFile.LastWriteTimeUtc > DateTime.UtcNow.AddDays(-30))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Using cached signature from Hasheous");
|
||||
HasheousResult = Newtonsoft.Json.JsonConvert.DeserializeObject<HasheousClient.Models.LookupItemModel>(File.ReadAllText(cacheFilePath));
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (HasheousResult == null)
|
||||
{
|
||||
// fetch from hasheous
|
||||
HasheousResult = hasheous.RetrieveFromHasheous(new HasheousClient.Models.HashLookupModel
|
||||
{
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
});
|
||||
|
||||
if (HasheousResult != null)
|
||||
{
|
||||
// save to cache
|
||||
File.WriteAllText(cacheFilePath, Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (File.Exists(cacheFilePath))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous - using cached signature", ex);
|
||||
HasheousResult = Newtonsoft.Json.JsonConvert.DeserializeObject<HasheousClient.Models.LookupItemModel>(File.ReadAllText(cacheFilePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasheousResult != null)
|
||||
{
|
||||
if (HasheousResult.Signature != null)
|
||||
{
|
||||
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
||||
signature.Game = HasheousResult.Signature.Game;
|
||||
signature.Rom = HasheousResult.Signature.Rom;
|
||||
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);
|
||||
|
||||
if (HasheousResult.MetadataResults != null)
|
||||
// get platform metadata
|
||||
if (HasheousResult.Platform != null)
|
||||
{
|
||||
if (HasheousResult.MetadataResults.Count > 0)
|
||||
if (HasheousResult.Platform.metadata.Count > 0)
|
||||
{
|
||||
foreach (SignatureLookupItem.MetadataResult metadataResult in HasheousResult.MetadataResults)
|
||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Platform.metadata)
|
||||
{
|
||||
if (metadataResult.Source == MetadataModel.MetadataSources.IGDB)
|
||||
// only IGDB metadata is supported
|
||||
if (metadataResult.Source == HasheousClient.Models.MetadataSources.IGDB)
|
||||
{
|
||||
signature.Flags.IGDBPlatformId = (long)metadataResult.PlatformId;
|
||||
signature.Flags.IGDBGameId = (long)metadataResult.GameId;
|
||||
if (metadataResult.ImmutableId.Length > 0)
|
||||
{
|
||||
// use immutable id
|
||||
Platform hasheousPlatform = Platforms.GetPlatform(long.Parse(metadataResult.ImmutableId));
|
||||
signature.MetadataSources.AddPlatform((long)hasheousPlatform.Id, hasheousPlatform.Name, metadataResult.Source);
|
||||
}
|
||||
else if (metadataResult.Id.Length > 0)
|
||||
{
|
||||
// fall back to id
|
||||
Platform hasheousPlatform = Platforms.GetPlatform(metadataResult.Id);
|
||||
signature.MetadataSources.AddPlatform((long)hasheousPlatform.Id, hasheousPlatform.Name, metadataResult.Source);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no id or immutable id - use unknown platform
|
||||
signature.MetadataSources.AddPlatform(0, "Unknown Platform", HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get game metadata
|
||||
if (HasheousResult.Metadata != null)
|
||||
{
|
||||
if (HasheousResult.Metadata.Count > 0)
|
||||
{
|
||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Metadata)
|
||||
{
|
||||
if (metadataResult.ImmutableId.Length > 0)
|
||||
{
|
||||
signature.MetadataSources.AddGame(long.Parse(metadataResult.ImmutableId), HasheousResult.Name, metadataResult.Source);
|
||||
}
|
||||
else if (metadataResult.Id.Length > 0)
|
||||
{
|
||||
switch (metadataResult.Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
gaseous_server.Models.Game hasheousGame = Games.GetGame(HasheousClient.Models.MetadataSources.IGDB, metadataResult.Id);
|
||||
signature.MetadataSources.AddGame((long)hasheousGame.Id, hasheousGame.Name, metadataResult.Source);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (long.TryParse(metadataResult.Id, out long id) == true)
|
||||
{
|
||||
signature.MetadataSources.AddGame(id, HasheousResult.Name, metadataResult.Source);
|
||||
}
|
||||
else
|
||||
{
|
||||
signature.MetadataSources.AddGame(0, "Unknown Game", HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no id or immutable id - use unknown game
|
||||
signature.MetadataSources.AddGame(0, "Unknown Game", HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check attributes for a user manual link
|
||||
if (HasheousResult.Attributes != null)
|
||||
{
|
||||
if (HasheousResult.Attributes.Count > 0)
|
||||
{
|
||||
foreach (HasheousClient.Models.AttributeItem attribute in HasheousResult.Attributes)
|
||||
{
|
||||
if (attribute.attributeName == HasheousClient.Models.AttributeItem.AttributeName.VIMMManualId)
|
||||
{
|
||||
signature.Game.UserManual = attribute.GetType().GetProperty("Link").GetValue(attribute).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,9 +464,34 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +566,7 @@ namespace gaseous_server.Classes
|
||||
public long Size { get; set; }
|
||||
public string MD5 { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
public bool isSignatureSelector { get; set; } = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
// platforms
|
||||
List<FilterItem> platforms = new List<FilterItem>();
|
||||
|
||||
|
||||
string ageRestriction_Platform = "AgeGroup.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
||||
string ageRestriction_Generic = "view_Games.AgeGroupId <= " + (int)MaximumAgeRestriction;
|
||||
if (IncludeUnrated == true)
|
||||
@@ -24,9 +24,9 @@ namespace gaseous_server.Classes
|
||||
ageRestriction_Generic += " OR view_Games.AgeGroupId IS NULL";
|
||||
}
|
||||
|
||||
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);
|
||||
string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, view_Games_Roms.PlatformId, COUNT(view_Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN view_Games_Roms ON Game.Id = view_Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , view_Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id AND Platform.SourceId = 0 GROUP BY Platform.`Name`;";
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
@@ -82,8 +82,8 @@ namespace gaseous_server.Classes
|
||||
|
||||
// age groups
|
||||
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";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(view_Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN view_Games_Roms ON Game.Id = view_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, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
@@ -112,9 +112,9 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
//string sql = "SELECT DISTINCT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(view_Games.Id) AS GameCount FROM <ITEMNAME> LEFT JOIN Relation_Game_<ITEMNAME>s ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id LEFT JOIN view_Games ON view_Games.Id = Relation_Game_<ITEMNAME>s.GameId WHERE (" + AgeRestriction_Generic + ") GROUP BY <ITEMNAME>.Id HAVING GameCount > 0 ORDER BY <ITEMNAME>.`Name`;";
|
||||
|
||||
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + AgeRestriction + ") GROUP BY Game.Id HAVING RomCount > 0) Game JOIN Relation_Game_<ITEMNAME>s ON Game.Id = Relation_Game_<ITEMNAME>s.GameId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
|
||||
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT view_Games_Roms.GameIdType, Game.Id, AgeGroup.AgeGroupId, COUNT(view_Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN view_Games_Roms ON Game.Id = view_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 AND Game.GameIdType = Relation_Game_<ITEMNAME>s.GameSourceId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <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;
|
||||
}
|
||||
|
||||
@@ -2,42 +2,41 @@ using System;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow;
|
||||
|
||||
namespace gaseous_server
|
||||
{
|
||||
public static class GameLibrary
|
||||
{
|
||||
public static class GameLibrary
|
||||
{
|
||||
// exceptions
|
||||
public class PathExists : Exception
|
||||
{
|
||||
{
|
||||
public PathExists(string path) : base("The library path " + path + " already exists.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PathNotFound : Exception
|
||||
{
|
||||
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class LibraryNotFound : Exception
|
||||
{
|
||||
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class CannotDeleteDefaultLibrary : Exception
|
||||
{
|
||||
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
||||
{
|
||||
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
// code
|
||||
@@ -60,13 +59,25 @@ namespace gaseous_server
|
||||
}
|
||||
}
|
||||
|
||||
// update default library path
|
||||
public static void UpdateDefaultLibraryPath()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE GameLibraries SET Path=@path WHERE DefaultLibrary=1;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "path", Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "Library") }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public static List<LibraryItem> GetLibraries
|
||||
{
|
||||
get
|
||||
{
|
||||
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
||||
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);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
@@ -113,7 +124,7 @@ namespace gaseous_server
|
||||
dbDict.Add("path", PathName);
|
||||
dbDict.Add("defaultplatform", DefaultPlatformId);
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
|
||||
int newLibraryId = (int)(long)data.Rows[0][0];
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Library Management", "Created library " + Name + " at directory " + PathName);
|
||||
@@ -129,10 +140,10 @@ namespace gaseous_server
|
||||
if (library.IsDefaultLibrary == false)
|
||||
{
|
||||
// check for active library scans
|
||||
foreach(ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (
|
||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker && item.ItemState == ProcessQueue.QueueItemState.Running)
|
||||
)
|
||||
{
|
||||
@@ -174,7 +185,25 @@ namespace gaseous_server
|
||||
throw new LibraryNotFound(LibraryId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static LibraryItem ScanLibrary(int LibraryId)
|
||||
{
|
||||
// add the library to scan to the queue
|
||||
LibraryItem library = GetLibrary(LibraryId);
|
||||
ImportGame.LibrariesToScan.Add(library);
|
||||
|
||||
// start the library scan if it's not already running
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState != ProcessQueue.QueueItemState.Running)
|
||||
{
|
||||
item.ForceExecute();
|
||||
}
|
||||
}
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
public class LibraryItem
|
||||
{
|
||||
public LibraryItem(int Id, string Name, string Path, long DefaultPlatformId, bool IsDefaultLibrary)
|
||||
@@ -207,7 +236,7 @@ namespace gaseous_server
|
||||
{
|
||||
if (_DefaultPlatformId != 0)
|
||||
{
|
||||
Platform platform = Platforms.GetPlatform(_DefaultPlatformId);
|
||||
HasheousClient.Models.Metadata.IGDB.Platform platform = Platforms.GetPlatform(_DefaultPlatformId);
|
||||
return platform.Name;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,17 +7,26 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
using NuGet.Common;
|
||||
using NuGet.LibraryModel;
|
||||
using static gaseous_server.Classes.Metadata.Games;
|
||||
using static gaseous_server.Classes.FileSignature;
|
||||
using HasheousClient.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class ImportGame : QueueItemStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Scan the import directory for games and process them
|
||||
/// </summary>
|
||||
/// <param name="ImportPath">
|
||||
/// The path to the directory to scan
|
||||
/// </param>
|
||||
/// <exception cref="DirectoryNotFoundException">
|
||||
/// Thrown when the import directory does not exist
|
||||
/// </exception>
|
||||
public void ProcessDirectory(string ImportPath)
|
||||
{
|
||||
if (Directory.Exists(ImportPath))
|
||||
@@ -47,11 +56,22 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||
/// <summary>
|
||||
/// Import a single game file
|
||||
/// </summary>
|
||||
/// <param name="GameFileImportPath">
|
||||
/// The path to the game file to import
|
||||
/// </param>
|
||||
/// <param name="OverridePlatform">
|
||||
/// The platform to use for the game file
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A dictionary containing the results of the import
|
||||
/// </returns>
|
||||
public Dictionary<string, object> ImportGameFile(string GameFileImportPath, Platform? OverridePlatform)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
Dictionary<string, object> RetVal = new Dictionary<string, object>();
|
||||
RetVal.Add("path", Path.GetFileName(GameFileImportPath));
|
||||
|
||||
if (Common.SkippableFiles.Contains<string>(Path.GetFileName(GameFileImportPath), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -59,7 +79,6 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
else
|
||||
{
|
||||
FileInfo fi = new FileInfo(GameFileImportPath);
|
||||
Common.hashObject hash = new Common.hashObject(GameFileImportPath);
|
||||
|
||||
Models.PlatformMapping.PlatformMapItem? IsBios = Classes.Bios.BiosHashSignatureLookup(hash.md5hash);
|
||||
@@ -67,99 +86,251 @@ namespace gaseous_server.Classes
|
||||
if (IsBios == null)
|
||||
{
|
||||
// file is a rom
|
||||
// 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";
|
||||
dbDict.Add("md5", hash.md5hash);
|
||||
dbDict.Add("sha1", hash.sha1hash);
|
||||
DataTable importDB = db.ExecuteCMD(sql, dbDict);
|
||||
if ((Int64)importDB.Rows[0]["count"] > 0)
|
||||
{
|
||||
// import source was the import directory
|
||||
if (GameFileImportPath.StartsWith(Config.LibraryConfiguration.LibraryImportDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - moving to " + Config.LibraryConfiguration.LibraryImportDuplicatesDirectory);
|
||||
|
||||
string targetPathWithFileName = GameFileImportPath.Replace(Config.LibraryConfiguration.LibraryImportDirectory, Config.LibraryConfiguration.LibraryImportDuplicatesDirectory);
|
||||
string targetPath = Path.GetDirectoryName(targetPathWithFileName);
|
||||
|
||||
if (!Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.CreateDirectory(targetPath);
|
||||
}
|
||||
File.Move(GameFileImportPath, targetPathWithFileName, true);
|
||||
}
|
||||
|
||||
// import source was the upload directory
|
||||
if (GameFileImportPath.StartsWith(Config.LibraryConfiguration.LibraryUploadDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " not in database - processing");
|
||||
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
gaseous_server.Models.Signatures_Games discoveredSignature = fileSignature.GetFileSignature(GameLibrary.GetDefaultLibrary, hash, fi, GameFileImportPath);
|
||||
|
||||
// get discovered platform
|
||||
IGDB.Models.Platform? determinedPlatform = null;
|
||||
if (OverridePlatform == null)
|
||||
{
|
||||
determinedPlatform = Metadata.Platforms.GetPlatform(discoveredSignature.Flags.IGDBPlatformId);
|
||||
if (determinedPlatform == null)
|
||||
{
|
||||
determinedPlatform = new IGDB.Models.Platform();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
determinedPlatform = OverridePlatform;
|
||||
discoveredSignature.Flags.IGDBPlatformId = (long)determinedPlatform.Id;
|
||||
discoveredSignature.Flags.IGDBPlatformName = determinedPlatform.Name;
|
||||
}
|
||||
|
||||
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
||||
|
||||
// add to database
|
||||
StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
||||
}
|
||||
_ImportGameFile(GameFileImportPath, hash, ref RetVal, OverridePlatform);
|
||||
}
|
||||
else
|
||||
{
|
||||
// file is a bios
|
||||
if (IsBios.WebEmulator != null)
|
||||
{
|
||||
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios())
|
||||
{
|
||||
if (biosItem.Available == false && biosItem.hash == hash.md5hash)
|
||||
{
|
||||
string biosPath = biosItem.biosPath.Replace(biosItem.filename, "");
|
||||
if (!Directory.Exists(biosPath))
|
||||
{
|
||||
Directory.CreateDirectory(biosPath);
|
||||
}
|
||||
|
||||
File.Move(GameFileImportPath, biosItem.biosPath, true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Bios.ImportBiosFile(GameFileImportPath, hash, ref RetVal);
|
||||
}
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import a single game file
|
||||
/// </summary>
|
||||
/// <param name="FilePath">
|
||||
/// The path to the game file to import
|
||||
/// </param>
|
||||
/// <param name="Hash">
|
||||
/// The hash of the game file
|
||||
/// </param>
|
||||
/// <param name="GameFileInfo">
|
||||
/// A dictionary to store the results of the import
|
||||
/// </param>
|
||||
/// <param name="OverridePlatform">
|
||||
/// The platform to use for the game file
|
||||
/// </param>
|
||||
private static void _ImportGameFile(string FilePath, Common.hashObject Hash, ref Dictionary<string, object> GameFileInfo, Platform? OverridePlatform)
|
||||
{
|
||||
GameFileInfo.Add("type", "rom");
|
||||
|
||||
// check to make sure we don't already have this file imported
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
|
||||
sql = "SELECT COUNT(Id) AS count FROM view_Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
|
||||
dbDict.Add("md5", Hash.md5hash);
|
||||
dbDict.Add("sha1", Hash.sha1hash);
|
||||
DataTable importDB = db.ExecuteCMD(sql, dbDict);
|
||||
if ((Int64)importDB.Rows[0]["count"] > 0)
|
||||
{
|
||||
// import source was the import directory
|
||||
if (FilePath.StartsWith(Config.LibraryConfiguration.LibraryImportDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + FilePath + " already in database - moving to " + Config.LibraryConfiguration.LibraryImportDuplicatesDirectory);
|
||||
|
||||
string targetPathWithFileName = FilePath.Replace(Config.LibraryConfiguration.LibraryImportDirectory, Config.LibraryConfiguration.LibraryImportDuplicatesDirectory);
|
||||
string targetPath = Path.GetDirectoryName(targetPathWithFileName);
|
||||
|
||||
if (!Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.CreateDirectory(targetPath);
|
||||
}
|
||||
File.Move(FilePath, targetPathWithFileName, true);
|
||||
}
|
||||
|
||||
// import source was the upload directory
|
||||
if (FilePath.StartsWith(Config.LibraryConfiguration.LibraryUploadDirectory))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + FilePath + " already in database - skipping import");
|
||||
}
|
||||
|
||||
GameFileInfo.Add("status", "duplicate");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + FilePath + " not in database - processing");
|
||||
|
||||
FileInfo fi = new FileInfo(FilePath);
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
gaseous_server.Models.Signatures_Games discoveredSignature = fileSignature.GetFileSignature(GameLibrary.GetDefaultLibrary, Hash, fi, FilePath);
|
||||
|
||||
// add to database
|
||||
Platform? determinedPlatform = Metadata.Platforms.GetPlatform((long)discoveredSignature.Flags.PlatformId);
|
||||
Models.Game? determinedGame = Metadata.Games.GetGame(discoveredSignature.Flags.GameMetadataSource, discoveredSignature.Flags.GameId);
|
||||
long RomId = StoreGame(GameLibrary.GetDefaultLibrary, Hash, discoveredSignature, determinedPlatform, FilePath, 0, true);
|
||||
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||
|
||||
// build return value
|
||||
GameFileInfo.Add("romid", RomId);
|
||||
GameFileInfo.Add("platform", determinedPlatform);
|
||||
GameFileInfo.Add("game", determinedGame);
|
||||
GameFileInfo.Add("signature", discoveredSignature);
|
||||
GameFileInfo.Add("rom", romItem);
|
||||
GameFileInfo.Add("status", "imported");
|
||||
}
|
||||
}
|
||||
|
||||
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||
/// <summary>
|
||||
/// Store a game in the database and move the file to the library (if required)
|
||||
/// </summary>
|
||||
/// <param name="library">
|
||||
/// The library to store the game in
|
||||
/// </param>
|
||||
/// <param name="hash">
|
||||
/// The hash of the game file
|
||||
/// </param>
|
||||
/// <param name="signature">
|
||||
/// The signature of the game file
|
||||
/// </param>
|
||||
/// <param name="filePath">
|
||||
/// The path to the game file
|
||||
/// </param>
|
||||
/// <param name="romId">
|
||||
/// The ID of the ROM in the database (if it already exists, 0 if it doesn't)
|
||||
/// </param>
|
||||
/// <param name="SourceIsExternal">
|
||||
/// Whether the source of the file is external to the library
|
||||
/// </param>
|
||||
public static long StoreGame(GameLibrary.LibraryItem library, Common.hashObject hash, Signatures_Games signature, Platform platform, string filePath, long romId = 0, bool SourceIsExternal = false)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string sql = "";
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
|
||||
// add/get the metadata map
|
||||
MetadataMap? map = MetadataManagement.NewMetadataMap((long)platform.Id, signature.Game.Name);
|
||||
|
||||
// add any metadata attributes that may be supplied as part of the signature
|
||||
if (signature.Game.UserManual != null)
|
||||
{
|
||||
if (signature.Game.UserManual.Length > 0)
|
||||
{
|
||||
MetadataManagement.SetMetadataSupportData((long)map.Id, MetadataManagement.MetadataMapSupportDataTypes.UserManualLink, signature.Game.UserManual);
|
||||
}
|
||||
}
|
||||
|
||||
// populate map with the sources from the signature if they don't already exist
|
||||
foreach (MetadataSources source in Enum.GetValues(typeof(MetadataSources)))
|
||||
{
|
||||
bool sourceExists = false;
|
||||
|
||||
if (source != MetadataSources.None)
|
||||
{
|
||||
// get the signature that matches this source
|
||||
Signatures_Games.SourceValues.SourceValueItem? signatureSource = signature.MetadataSources.Games.Find(x => x.Source == source);
|
||||
if (signatureSource == null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " No source found for " + source.ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the metadata map for this source
|
||||
MetadataMap.MetadataMapItem? mapSource = map.MetadataMapItems.Find(x => x.SourceType == source);
|
||||
if (mapSource == null)
|
||||
{
|
||||
// add the source to the map
|
||||
bool preferred = false;
|
||||
if (source == Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
{
|
||||
preferred = true;
|
||||
}
|
||||
MetadataManagement.AddMetadataMapItem((long)map.Id, source, signatureSource.Id, preferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update the source in the map - do not modify the preferred status
|
||||
MetadataManagement.UpdateMetadataMapItem((long)map.Id, source, signatureSource.Id, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reload the map
|
||||
map = MetadataManagement.GetMetadataMap((long)map.Id);
|
||||
|
||||
// add or update the rom
|
||||
dbDict = new Dictionary<string, object>();
|
||||
if (romId == 0)
|
||||
{
|
||||
sql = "INSERT INTO Games_Roms (PlatformId, GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, RelativePath, MetadataSource, MetadataGameName, MetadataVersion, LibraryId, RomDataVersion, MetadataMapId) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid, @romdataversion, @metadatamapid); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid, Name=@name, Size=@size, DevelopmentStatus=@developmentstatus, Attributes=@Attributes, RomType=@romtype, RomTypeMedia=@romtypemedia, MediaLabel=@medialabel, MetadataSource=@metadatasource, MetadataGameName=@metadatagamename, MetadataVersion=@metadataversion, RomDataVersion=@romdataversion, MetadataMapId=@metadatamapid WHERE Id=@id;";
|
||||
dbDict.Add("id", romId);
|
||||
}
|
||||
dbDict.Add("platformid", Common.ReturnValueIfNull(platform.Id, 0));
|
||||
dbDict.Add("gameid", 0); // set to 0 - no longer required as game is mapped using the MetadataMapBridge table
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(signature.Rom.Name, 0));
|
||||
dbDict.Add("size", Common.ReturnValueIfNull(signature.Rom.Size, 0));
|
||||
dbDict.Add("md5", hash.md5hash);
|
||||
dbDict.Add("sha1", hash.sha1hash);
|
||||
dbDict.Add("crc", Common.ReturnValueIfNull(signature.Rom.Crc, ""));
|
||||
dbDict.Add("developmentstatus", Common.ReturnValueIfNull(signature.Rom.DevelopmentStatus, ""));
|
||||
dbDict.Add("metadatasource", signature.Rom.SignatureSource);
|
||||
dbDict.Add("metadatagamename", signature.Game.Name);
|
||||
dbDict.Add("metadataversion", 2);
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
dbDict.Add("romdataversion", 2);
|
||||
dbDict.Add("metadatamapid", map.Id);
|
||||
|
||||
if (signature.Rom.Attributes != null)
|
||||
{
|
||||
if (signature.Rom.Attributes.Count > 0)
|
||||
{
|
||||
dbDict.Add("attributes", Newtonsoft.Json.JsonConvert.SerializeObject(signature.Rom.Attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
}
|
||||
dbDict.Add("romtype", (int)signature.Rom.RomType);
|
||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(signature.Rom.RomTypeMedia, ""));
|
||||
dbDict.Add("medialabel", Common.ReturnValueIfNull(signature.Rom.MediaLabel, ""));
|
||||
|
||||
string libraryRootPath = library.Path;
|
||||
if (libraryRootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false)
|
||||
{
|
||||
libraryRootPath += Path.DirectorySeparatorChar;
|
||||
}
|
||||
dbDict.Add("path", filePath.Replace(libraryRootPath, ""));
|
||||
|
||||
DataTable romInsert = db.ExecuteCMD(sql, dbDict);
|
||||
if (romId == 0)
|
||||
{
|
||||
romId = (long)romInsert.Rows[0][0];
|
||||
}
|
||||
|
||||
// move to destination
|
||||
if (library.IsDefaultLibrary == true)
|
||||
{
|
||||
MoveGameFile(romId, SourceIsExternal);
|
||||
}
|
||||
|
||||
return romId;
|
||||
}
|
||||
|
||||
public static gaseous_server.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||
{
|
||||
if (Signature.Flags != null)
|
||||
{
|
||||
if (Signature.Flags.IGDBGameId != null && Signature.Flags.IGDBGameId != 0)
|
||||
if (Signature.Flags.GameId != null && Signature.Flags.GameId != 0)
|
||||
{
|
||||
// game was determined elsewhere - probably a Hasheous server
|
||||
try
|
||||
{
|
||||
return Games.GetGame(Signature.Flags.IGDBGameId, false, false, FullDownload);
|
||||
return Games.GetGame(MetadataSources.IGDB, Signature.Flags.GameId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -169,7 +340,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
// search discovered game - case insensitive exact match first
|
||||
IGDB.Models.Game determinedGame = new IGDB.Models.Game();
|
||||
gaseous_server.Models.Game determinedGame = new gaseous_server.Models.Game();
|
||||
|
||||
string GameName = Signature.Game.Name;
|
||||
|
||||
@@ -184,31 +355,38 @@ namespace gaseous_server.Classes
|
||||
foreach (Metadata.Games.SearchType searchType in Enum.GetValues(typeof(Metadata.Games.SearchType)))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " Search type: " + searchType.ToString());
|
||||
IGDB.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
||||
if (games.Length == 1)
|
||||
gaseous_server.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
||||
if (games != null)
|
||||
{
|
||||
// exact match!
|
||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " IGDB game: " + determinedGame.Name);
|
||||
GameFound = true;
|
||||
break;
|
||||
}
|
||||
else if (games.Length > 0)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + games.Length + " search results found");
|
||||
|
||||
// quite likely we've found sequels and alternate types
|
||||
foreach (Game game in games)
|
||||
if (games.Length == 1)
|
||||
{
|
||||
if (game.Name == SearchCandidate)
|
||||
// exact match!
|
||||
determinedGame = Metadata.Games.GetGame(MetadataSources.IGDB, (long)games[0].Id);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " IGDB game: " + determinedGame.Name);
|
||||
GameFound = true;
|
||||
break;
|
||||
}
|
||||
else if (games.Length > 0)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + games.Length + " search results found");
|
||||
|
||||
// quite likely we've found sequels and alternate types
|
||||
foreach (gaseous_server.Models.Game game in games)
|
||||
{
|
||||
// found game title matches the search candidate
|
||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Found exact match!");
|
||||
GameFound = true;
|
||||
break;
|
||||
if (game.Name == SearchCandidate)
|
||||
{
|
||||
// found game title matches the search candidate
|
||||
determinedGame = Metadata.Games.GetGame(MetadataSources.IGDB, (long)games[0].Id);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Found exact match!");
|
||||
GameFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " No search results found");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -219,7 +397,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
if (determinedGame == null)
|
||||
{
|
||||
determinedGame = new IGDB.Models.Game();
|
||||
determinedGame = new gaseous_server.Models.Game();
|
||||
}
|
||||
|
||||
string destSlug = "";
|
||||
@@ -231,9 +409,9 @@ namespace gaseous_server.Classes
|
||||
return determinedGame;
|
||||
}
|
||||
|
||||
public static List<IGDB.Models.Game> SearchForGame_GetAll(string GameName, long PlatformId)
|
||||
public static List<gaseous_server.Models.Game> SearchForGame_GetAll(string GameName, long PlatformId)
|
||||
{
|
||||
List<IGDB.Models.Game> searchResults = new List<IGDB.Models.Game>();
|
||||
List<gaseous_server.Models.Game> searchResults = new List<gaseous_server.Models.Game>();
|
||||
|
||||
List<string> SearchCandidates = GetSearchCandidates(GameName);
|
||||
|
||||
@@ -243,11 +421,11 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
if ((PlatformId == 0 && searchType == SearchType.searchNoPlatform) || (PlatformId != 0 && searchType != SearchType.searchNoPlatform))
|
||||
{
|
||||
IGDB.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
||||
foreach (IGDB.Models.Game foundGame in games)
|
||||
gaseous_server.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
||||
foreach (gaseous_server.Models.Game foundGame in games)
|
||||
{
|
||||
bool gameInResults = false;
|
||||
foreach (IGDB.Models.Game searchResult in searchResults)
|
||||
foreach (gaseous_server.Models.Game searchResult in searchResults)
|
||||
{
|
||||
if (searchResult.Id == foundGame.Id)
|
||||
{
|
||||
@@ -298,83 +476,14 @@ namespace gaseous_server.Classes
|
||||
return SearchCandidates;
|
||||
}
|
||||
|
||||
public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, gaseous_server.Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string sql = "";
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
|
||||
if (UpdateId == 0)
|
||||
{
|
||||
sql = "INSERT INTO Games_Roms (PlatformId, GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, Path, MetadataSource, MetadataGameName, MetadataVersion, LibraryId) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid, Name=@name, Size=@size, DevelopmentStatus=@developmentstatus, Attributes=@Attributes, RomType=@romtype, RomTypeMedia=@romtypemedia, MediaLabel=@medialabel, MetadataSource=@metadatasource, MetadataGameName=@metadatagamename, MetadataVersion=@metadataversion WHERE Id=@id;";
|
||||
dbDict.Add("id", UpdateId);
|
||||
}
|
||||
dbDict.Add("platformid", Common.ReturnValueIfNull(determinedPlatform.Id, 0));
|
||||
dbDict.Add("gameid", Common.ReturnValueIfNull(determinedGame.Id, 0));
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(discoveredSignature.Rom.Name, 0));
|
||||
dbDict.Add("size", Common.ReturnValueIfNull(discoveredSignature.Rom.Size, 0));
|
||||
dbDict.Add("md5", hash.md5hash);
|
||||
dbDict.Add("sha1", hash.sha1hash);
|
||||
dbDict.Add("crc", Common.ReturnValueIfNull(discoveredSignature.Rom.Crc, ""));
|
||||
dbDict.Add("developmentstatus", Common.ReturnValueIfNull(discoveredSignature.Rom.DevelopmentStatus, ""));
|
||||
dbDict.Add("metadatasource", discoveredSignature.Rom.SignatureSource);
|
||||
dbDict.Add("metadatagamename", discoveredSignature.Game.Name);
|
||||
dbDict.Add("metadataversion", 2);
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
|
||||
if (discoveredSignature.Rom.Attributes != null)
|
||||
{
|
||||
if (discoveredSignature.Rom.Attributes.Count > 0)
|
||||
{
|
||||
dbDict.Add("attributes", Newtonsoft.Json.JsonConvert.SerializeObject(discoveredSignature.Rom.Attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
}
|
||||
dbDict.Add("romtype", (int)discoveredSignature.Rom.RomType);
|
||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(discoveredSignature.Rom.RomTypeMedia, ""));
|
||||
dbDict.Add("medialabel", Common.ReturnValueIfNull(discoveredSignature.Rom.MediaLabel, ""));
|
||||
dbDict.Add("path", GameFileImportPath);
|
||||
|
||||
DataTable romInsert = db.ExecuteCMD(sql, dbDict);
|
||||
long romId = 0;
|
||||
if (UpdateId == 0)
|
||||
{
|
||||
romId = (long)romInsert.Rows[0][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
romId = UpdateId;
|
||||
}
|
||||
|
||||
// move to destination
|
||||
if (library.IsDefaultLibrary == true)
|
||||
{
|
||||
MoveGameFile(romId);
|
||||
}
|
||||
|
||||
return romId;
|
||||
}
|
||||
|
||||
public static string ComputeROMPath(long RomId)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
|
||||
// get metadata
|
||||
IGDB.Models.Platform platform = gaseous_server.Classes.Metadata.Platforms.GetPlatform(rom.PlatformId);
|
||||
IGDB.Models.Game game = gaseous_server.Classes.Metadata.Games.GetGame(rom.GameId, false, false, false);
|
||||
MetadataMap.MetadataMapItem metadataMap = Classes.MetadataManagement.GetMetadataMap(rom.MetadataMapId).PreferredMetadataMapItem;
|
||||
Platform? platform = gaseous_server.Classes.Metadata.Platforms.GetPlatform(rom.PlatformId);
|
||||
gaseous_server.Models.Game? game = Classes.Metadata.Games.GetGame(metadataMap.SourceType, metadataMap.SourceId);
|
||||
|
||||
// build path
|
||||
string platformSlug = "Unknown Platform";
|
||||
@@ -387,7 +496,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
gameSlug = game.Slug;
|
||||
}
|
||||
string DestinationPath = Path.Combine(GameLibrary.GetDefaultLibrary.Path, gameSlug, platformSlug);
|
||||
string DestinationPath = Path.Combine(GameLibrary.GetDefaultLibrary.Path, platformSlug);
|
||||
if (!Directory.Exists(DestinationPath))
|
||||
{
|
||||
Directory.CreateDirectory(DestinationPath);
|
||||
@@ -398,10 +507,14 @@ namespace gaseous_server.Classes
|
||||
return DestinationPathName;
|
||||
}
|
||||
|
||||
public static bool MoveGameFile(long RomId)
|
||||
public static bool MoveGameFile(long RomId, bool SourceIsExternal)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
string romPath = rom.Path;
|
||||
if (SourceIsExternal == true)
|
||||
{
|
||||
romPath = rom.RelativePath;
|
||||
}
|
||||
|
||||
if (File.Exists(romPath))
|
||||
{
|
||||
@@ -426,10 +539,16 @@ namespace gaseous_server.Classes
|
||||
|
||||
// update the db
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE Games_Roms SET Path=@path WHERE Id=@id";
|
||||
string sql = "UPDATE Games_Roms SET RelativePath=@path WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
dbDict.Add("path", DestinationPath);
|
||||
|
||||
string libraryRootPath = rom.Library.Path;
|
||||
if (libraryRootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false)
|
||||
{
|
||||
libraryRootPath += Path.DirectorySeparatorChar;
|
||||
}
|
||||
dbDict.Add("path", DestinationPath.Replace(libraryRootPath, ""));
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return true;
|
||||
@@ -451,7 +570,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
// move rom files to their new location
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Games_Roms WHERE LibraryId = @libraryid";
|
||||
string sql = "SELECT * FROM view_Games_Roms WHERE LibraryId = @libraryid";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -463,7 +582,7 @@ namespace gaseous_server.Classes
|
||||
SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]);
|
||||
Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
|
||||
long RomId = (long)romDT.Rows[i]["id"];
|
||||
MoveGameFile(RomId);
|
||||
MoveGameFile(RomId, false);
|
||||
}
|
||||
}
|
||||
ClearStatus();
|
||||
@@ -491,61 +610,81 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public void LibraryScan(GameLibrary.LibraryItem? singleLibrary = null)
|
||||
public static List<GameLibrary.LibraryItem> LibrariesToScan = new List<GameLibrary.LibraryItem>();
|
||||
public void LibraryScan()
|
||||
{
|
||||
int maxWorkers = Config.MetadataConfiguration.MaxLibraryScanWorkers;
|
||||
int maxWorkers = 4;
|
||||
|
||||
List<GameLibrary.LibraryItem> libraries = new List<GameLibrary.LibraryItem>();
|
||||
if (singleLibrary == null)
|
||||
if (LibrariesToScan.Count == 0)
|
||||
{
|
||||
libraries.AddRange(GameLibrary.GetLibraries);
|
||||
}
|
||||
else
|
||||
{
|
||||
libraries.Add(singleLibrary);
|
||||
LibrariesToScan.AddRange(GameLibrary.GetLibraries);
|
||||
}
|
||||
|
||||
// setup background tasks for each library
|
||||
foreach (GameLibrary.LibraryItem library in libraries)
|
||||
do
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name);
|
||||
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
||||
ProcessQueue.QueueItemType.LibraryScanWorker,
|
||||
1,
|
||||
new List<ProcessQueue.QueueItemType>
|
||||
{
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||
ProcessQueue.QueueItemType.Rematcher
|
||||
},
|
||||
false,
|
||||
true);
|
||||
queue.Options = library;
|
||||
queue.ForceExecute();
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan queue size: " + LibrariesToScan.Count);
|
||||
|
||||
ProcessQueue.QueueItems.Add(queue);
|
||||
GameLibrary.LibraryItem library = LibrariesToScan[0];
|
||||
LibrariesToScan.RemoveAt(0);
|
||||
|
||||
// check number of running tasks is less than maxWorkers
|
||||
bool allowContinue;
|
||||
do
|
||||
// check if library is already being scanned
|
||||
bool libraryAlreadyScanning = false;
|
||||
List<ProcessQueue.QueueItem> ProcessQueueItems = new List<ProcessQueue.QueueItem>();
|
||||
ProcessQueueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueueItems)
|
||||
{
|
||||
allowContinue = true;
|
||||
int currentWorkerCount = 0;
|
||||
List<ProcessQueue.QueueItem> queueItems = new List<ProcessQueue.QueueItem>();
|
||||
queueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in queueItems)
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||
if (((GameLibrary.LibraryItem)item.Options).Id == library.Id)
|
||||
{
|
||||
currentWorkerCount += 1;
|
||||
libraryAlreadyScanning = true;
|
||||
}
|
||||
}
|
||||
if (currentWorkerCount >= maxWorkers)
|
||||
}
|
||||
|
||||
if (libraryAlreadyScanning == false)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name);
|
||||
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
||||
ProcessQueue.QueueItemType.LibraryScanWorker,
|
||||
1,
|
||||
new List<ProcessQueue.QueueItemType>
|
||||
{
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary
|
||||
},
|
||||
false,
|
||||
true)
|
||||
{
|
||||
allowContinue = false;
|
||||
Thread.Sleep(60000);
|
||||
}
|
||||
} while (allowContinue == false);
|
||||
}
|
||||
Options = library
|
||||
};
|
||||
queue.ForceExecute();
|
||||
|
||||
ProcessQueue.QueueItems.Add(queue);
|
||||
|
||||
// check number of running tasks is less than maxWorkers
|
||||
bool allowContinue;
|
||||
do
|
||||
{
|
||||
allowContinue = true;
|
||||
int currentWorkerCount = 0;
|
||||
List<ProcessQueue.QueueItem> LibraryScan_QueueItems = new List<ProcessQueue.QueueItem>();
|
||||
LibraryScan_QueueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in LibraryScan_QueueItems)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||
{
|
||||
currentWorkerCount += 1;
|
||||
}
|
||||
}
|
||||
if (currentWorkerCount >= maxWorkers)
|
||||
{
|
||||
allowContinue = false;
|
||||
Thread.Sleep(60000);
|
||||
}
|
||||
} while (allowContinue == false);
|
||||
}
|
||||
} while (LibrariesToScan.Count > 0);
|
||||
|
||||
bool WorkersStillWorking;
|
||||
do
|
||||
@@ -565,6 +704,12 @@ namespace gaseous_server.Classes
|
||||
} while (WorkersStillWorking == true);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan complete. All workers stopped");
|
||||
|
||||
if (LibrariesToScan.Count > 0)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "There are still libraries to scan. Restarting scan process");
|
||||
LibraryScan();
|
||||
}
|
||||
}
|
||||
|
||||
public void LibrarySpecificScan(GameLibrary.LibraryItem library)
|
||||
@@ -580,7 +725,7 @@ namespace gaseous_server.Classes
|
||||
dupDict.Add("libraryid", library.Id);
|
||||
db.ExecuteCMD(duplicateSql, dupDict);
|
||||
|
||||
string sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
string sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
DataTable dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -605,7 +750,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
// search for files in the library that aren't in the database
|
||||
@@ -649,9 +794,9 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
// get discovered platform
|
||||
long PlatformId;
|
||||
IGDB.Models.Platform determinedPlatform;
|
||||
Platform determinedPlatform;
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||
if (sig.Flags.PlatformId == null || sig.Flags.PlatformId == 0)
|
||||
{
|
||||
// no platform discovered in the signature
|
||||
PlatformId = library.DefaultPlatformId;
|
||||
@@ -659,13 +804,13 @@ namespace gaseous_server.Classes
|
||||
else
|
||||
{
|
||||
// use the platform discovered in the signature
|
||||
PlatformId = sig.Flags.IGDBPlatformId;
|
||||
PlatformId = (long)sig.Flags.PlatformId;
|
||||
}
|
||||
determinedPlatform = Platforms.GetPlatform(PlatformId);
|
||||
|
||||
IGDB.Models.Game determinedGame = SearchForGame(sig, PlatformId, true);
|
||||
gaseous_server.Models.Game determinedGame = SearchForGame(sig, PlatformId, true);
|
||||
|
||||
StoreROM(library, hash, determinedGame, determinedPlatform, sig, LibraryFile);
|
||||
StoreGame(library, hash, sig, determinedPlatform, LibraryFile, 0, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -677,7 +822,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
ClearStatus();
|
||||
|
||||
sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`";
|
||||
dtRoms = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
// check all roms to see if their local file still exists
|
||||
@@ -701,7 +846,7 @@ namespace gaseous_server.Classes
|
||||
if (romPath != ComputeROMPath(romId))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found, but needs to be moved");
|
||||
MoveGameFile(romId);
|
||||
MoveGameFile(romId, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -727,86 +872,6 @@ namespace gaseous_server.Classes
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan completed");
|
||||
}
|
||||
|
||||
public void Rematcher(bool ForceExecute = false)
|
||||
{
|
||||
// rescan all titles with an unknown platform or title and see if we can get a match
|
||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan starting");
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch on library " + library.Name);
|
||||
|
||||
string sql = "";
|
||||
if (ForceExecute == false)
|
||||
{
|
||||
sql = "SELECT * FROM Games_Roms WHERE (PlatformId = 0 AND GameId <> 0) OR (((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) OR (PlatformId = 0 AND GameId = 0)) AND (LastMatchAttemptDate IS NULL OR LastMatchAttemptDate < @lastmatchattemptdate) AND LibraryId = @libraryid LIMIT 100;";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "SELECT * FROM Games_Roms WHERE (PlatformId = 0 AND GameId <> 0) OR (((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) OR (PlatformId = 0 AND GameId = 0)) AND LibraryId = @libraryid;";
|
||||
}
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7));
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
int StatusCount = -0;
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
SetStatus(StatusCount, data.Rows.Count, "Running rematcher");
|
||||
|
||||
// get rom info
|
||||
long romId = (long)row["Id"];
|
||||
string romPath = (string)row["Path"];
|
||||
Common.hashObject hash = new Common.hashObject
|
||||
{
|
||||
md5hash = (string)row["MD5"],
|
||||
sha1hash = (string)row["SHA1"]
|
||||
};
|
||||
FileInfo fi = new FileInfo(romPath);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Running rematch against " + romPath);
|
||||
|
||||
// determine rom signature
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
gaseous_server.Models.Signatures_Games sig = fileSignature.GetFileSignature(library, hash, fi, romPath);
|
||||
|
||||
// get discovered platform
|
||||
long PlatformId;
|
||||
IGDB.Models.Platform determinedPlatform;
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||
{
|
||||
// no platform discovered in the signature
|
||||
PlatformId = library.DefaultPlatformId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the platform discovered in the signature
|
||||
PlatformId = sig.Flags.IGDBPlatformId;
|
||||
}
|
||||
determinedPlatform = Platforms.GetPlatform(PlatformId);
|
||||
|
||||
IGDB.Models.Game determinedGame = SearchForGame(sig, PlatformId, true);
|
||||
|
||||
StoreROM(library, hash, determinedGame, determinedPlatform, sig, romPath, romId);
|
||||
|
||||
string attemptSql = "UPDATE Games_Roms SET LastMatchAttemptDate=@lastmatchattemptdate WHERE Id=@id;";
|
||||
Dictionary<string, object> dbLastAttemptDict = new Dictionary<string, object>();
|
||||
dbLastAttemptDict.Add("id", romId);
|
||||
dbLastAttemptDict.Add("lastmatchattemptdate", DateTime.UtcNow);
|
||||
db.ExecuteCMD(attemptSql, dbLastAttemptDict);
|
||||
|
||||
StatusCount += 1;
|
||||
}
|
||||
ClearStatus();
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Rematch Scan", "Rematch scan completed");
|
||||
ClearStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@ using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Logging
|
||||
{
|
||||
public class Logging
|
||||
{
|
||||
private static DateTime lastDiskRetentionSweep = DateTime.UtcNow;
|
||||
public static bool WriteToDiskOnly { get; set; } = false;
|
||||
|
||||
@@ -21,8 +22,13 @@ namespace gaseous_server.Classes
|
||||
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
||||
};
|
||||
|
||||
_ = Task.Run(() => WriteLogAsync(logItem, LogToDiskOnly));
|
||||
}
|
||||
|
||||
static async Task WriteLogAsync(LogItem logItem, bool LogToDiskOnly)
|
||||
{
|
||||
bool AllowWrite = false;
|
||||
if (EventType == LogType.Debug)
|
||||
if (logItem.EventType == LogType.Debug)
|
||||
{
|
||||
if (Config.LoggingConfiguration.DebugLogging == true)
|
||||
{
|
||||
@@ -42,26 +48,32 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
||||
}
|
||||
switch(logItem.EventType) {
|
||||
string consoleColour = "";
|
||||
switch (logItem.EventType)
|
||||
{
|
||||
case LogType.Information:
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
// Console.ForegroundColor = ConsoleColor.Blue;
|
||||
consoleColour = "\u001b[1;34m]";
|
||||
break;
|
||||
|
||||
case LogType.Warning:
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
// Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
consoleColour = "\u001b[1;33m]";
|
||||
break;
|
||||
|
||||
case LogType.Critical:
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
// Console.ForegroundColor = ConsoleColor.Red;
|
||||
consoleColour = "\u001b[1;31m]";
|
||||
break;
|
||||
|
||||
case LogType.Debug:
|
||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
// Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
consoleColour = "\u001b[1;36m]";
|
||||
break;
|
||||
|
||||
}
|
||||
Console.WriteLine(TraceOutput);
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(consoleColour + TraceOutput);
|
||||
// Console.ResetColor();
|
||||
|
||||
if (WriteToDiskOnly == true)
|
||||
{
|
||||
@@ -143,7 +155,7 @@ namespace gaseous_server.Classes
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
{
|
||||
LogToDisk(logItem, TraceOutput, ex);
|
||||
}
|
||||
}
|
||||
@@ -162,9 +174,9 @@ namespace gaseous_server.Classes
|
||||
foreach (string file in files)
|
||||
{
|
||||
FileInfo fi = new FileInfo(file);
|
||||
if (fi.LastAccessTime < DateTime.Now.AddDays(Config.LoggingConfiguration.LogRetention * -1))
|
||||
{
|
||||
fi.Delete();
|
||||
if (fi.LastAccessTime < DateTime.Now.AddDays(Config.LoggingConfiguration.LogRetention * -1))
|
||||
{
|
||||
fi.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +188,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
// dump the error
|
||||
File.AppendAllText(Config.LogFilePath, logItem.EventTime.ToString("yyyyMMdd HHmmss") + ": " + logItem.EventType.ToString() + ": " + logItem.Process + ": " + logItem.Message + Environment.NewLine + exception.ToString());
|
||||
|
||||
|
||||
|
||||
// something went wrong writing to the db
|
||||
File.AppendAllText(Config.LogFilePath, logItem.EventTime.ToString("yyyyMMdd HHmmss") + ": The following event was unable to be written to the log database:");
|
||||
@@ -185,7 +197,7 @@ namespace gaseous_server.Classes
|
||||
File.AppendAllText(Config.LogFilePath, TraceOutput);
|
||||
}
|
||||
|
||||
static public List<LogItem> GetLogs(LogsViewModel model)
|
||||
static public List<LogItem> GetLogs(LogsViewModel model)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -278,7 +290,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
whereClause = "WHERE " + whereClause;
|
||||
}
|
||||
|
||||
|
||||
sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
||||
}
|
||||
else
|
||||
@@ -287,7 +299,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
whereClause = "AND " + whereClause;
|
||||
}
|
||||
|
||||
|
||||
sql = "SELECT ServerLogs.Id, ServerLogs.EventTime, ServerLogs.EventType, ServerLogs.`Process`, ServerLogs.Message, ServerLogs.Exception, ServerLogs.CorrelationId, ServerLogs.CallingProcess, Users.Email FROM ServerLogs LEFT JOIN Users ON ServerLogs.CallingUser = Users.Id WHERE ServerLogs.Id < @StartIndex " + whereClause + " ORDER BY ServerLogs.Id DESC LIMIT @PageSize OFFSET @PageNumber;";
|
||||
}
|
||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing logs older than " + Config.LoggingConfiguration.LogRetention + " days");
|
||||
long deletedCount = 1;
|
||||
long deletedEventCount = 0;
|
||||
long maxLoops = 1000;
|
||||
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));
|
||||
while (deletedCount > 0)
|
||||
@@ -46,6 +46,8 @@ namespace gaseous_server.Classes
|
||||
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)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using gaseous_server.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Microsoft.CodeAnalysis.Classification;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
@@ -14,7 +14,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
}
|
||||
|
||||
public static AgeGroup? GetAgeGroup(Game? game)
|
||||
public static AgeGroup? GetAgeGroup(Models.Game? game)
|
||||
{
|
||||
if (game == null)
|
||||
{
|
||||
@@ -23,7 +23,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
else
|
||||
{
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
cacheStatus = Storage.GetCacheStatus("AgeGroup", (long)game.Id);
|
||||
cacheStatus = Storage.GetCacheStatus(HasheousClient.Models.MetadataSources.IGDB, "AgeGroup", (long)game.Id);
|
||||
|
||||
AgeGroup? RetVal = new AgeGroup();
|
||||
|
||||
@@ -31,40 +31,40 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
RetVal = _GetAgeGroup(game);
|
||||
Storage.NewCacheValue(RetVal, false);
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.IGDB, RetVal, false);
|
||||
break;
|
||||
|
||||
case Storage.CacheStatus.Expired:
|
||||
RetVal = _GetAgeGroup(game);
|
||||
Storage.NewCacheValue(RetVal, true);
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.IGDB, RetVal, true);
|
||||
break;
|
||||
|
||||
case Storage.CacheStatus.Current:
|
||||
RetVal = Storage.GetCacheValue<AgeGroup>(RetVal, "Id", game.Id);
|
||||
RetVal = Storage.GetCacheValue<AgeGroup>(HasheousClient.Models.MetadataSources.IGDB, RetVal, "Id", game.Id);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static AgeGroup? _GetAgeGroup(Game game)
|
||||
public static AgeGroup? _GetAgeGroup(Models.Game game)
|
||||
{
|
||||
// compile the maximum age group for the given game
|
||||
if (game != null)
|
||||
{
|
||||
if (game.AgeRatings != null)
|
||||
{
|
||||
if (game.AgeRatings.Ids != null)
|
||||
if (game.AgeRatings != null)
|
||||
{
|
||||
// collect ratings values from metadata
|
||||
List<AgeRating> ageRatings = new List<AgeRating>();
|
||||
foreach (long ratingId in game.AgeRatings.Ids)
|
||||
foreach (long ratingId in game.AgeRatings)
|
||||
{
|
||||
AgeRating? rating = AgeRatings.GetAgeRatings(ratingId);
|
||||
AgeRating? rating = AgeRatings.GetAgeRating(game.MetadataSource, ratingId);
|
||||
if (rating != null)
|
||||
{
|
||||
ageRatings.Add(rating);
|
||||
@@ -73,7 +73,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
// compile the ratings values into the ratings groups
|
||||
AgeRestrictionGroupings highestAgeGroup = GetAgeGroupFromAgeRatings(ageRatings);
|
||||
|
||||
|
||||
// return the compiled ratings group
|
||||
AgeGroup ageGroup = new AgeGroup();
|
||||
ageGroup.Id = game.Id;
|
||||
@@ -86,7 +86,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
ageGroup.AgeGroupId = highestAgeGroup;
|
||||
}
|
||||
|
||||
|
||||
return ageGroup;
|
||||
}
|
||||
else
|
||||
@@ -95,7 +95,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
ageGroup.Id = game.Id;
|
||||
ageGroup.GameId = game.Id;
|
||||
ageGroup.AgeGroupId = null;
|
||||
|
||||
|
||||
return ageGroup;
|
||||
}
|
||||
}
|
||||
@@ -105,11 +105,11 @@ namespace gaseous_server.Classes.Metadata
|
||||
ageGroup.Id = game.Id;
|
||||
ageGroup.GameId = game.Id;
|
||||
ageGroup.AgeGroupId = null;
|
||||
|
||||
|
||||
return ageGroup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
foreach (KeyValuePair<AgeRestrictionGroupings, AgeGroupItem> ageGroupItem in AgeGroupingsFlat)
|
||||
{
|
||||
|
||||
|
||||
PropertyInfo[] groupProps = typeof(AgeGroupItem).GetProperties();
|
||||
foreach (PropertyInfo property in groupProps)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return highestAgeGroup;
|
||||
}
|
||||
|
||||
@@ -158,8 +158,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
get
|
||||
{
|
||||
return new Dictionary<AgeRestrictionGroupings, List<AgeGroupItem>>{
|
||||
{
|
||||
AgeRestrictionGroupings.Adult, new List<AgeGroupItem>{ Adult_Item, Mature_Item, Teen_Item, Child_Item }
|
||||
{
|
||||
AgeRestrictionGroupings.Adult, new List<AgeGroupItem>{ Adult_Item, Mature_Item, Teen_Item, Child_Item }
|
||||
},
|
||||
{
|
||||
AgeRestrictionGroupings.Mature, new List<AgeGroupItem>{ Mature_Item, Teen_Item, Child_Item }
|
||||
@@ -167,7 +167,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
AgeRestrictionGroupings.Teen, new List<AgeGroupItem>{ Teen_Item, Child_Item }
|
||||
},
|
||||
{
|
||||
{
|
||||
AgeRestrictionGroupings.Child, new List<AgeGroupItem>{ Child_Item }
|
||||
}
|
||||
};
|
||||
@@ -216,55 +216,59 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_Z },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Eighteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Eighteen },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Eighteen },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_18 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Sixteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.M },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Fifteen },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Sixteen },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_16 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_PG },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_B },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.T },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Twelve },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Twelve },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_12 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_G },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_A },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.EC, AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_All },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Three, AgeRatingTitle.Seven },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_0, AgeRatingTitle.USK_6 }
|
||||
};
|
||||
|
||||
public class AgeGroupItem
|
||||
{
|
||||
public List<IGDB.Models.AgeRatingTitle> ACB { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> CERO { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> CLASS_IND { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> ESRB { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> GRAC { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> PEGI { get; set; }
|
||||
public List<IGDB.Models.AgeRatingTitle> USK { get; set; }
|
||||
public List<AgeRatingTitle> ACB { get; set; }
|
||||
public List<AgeRatingTitle> CERO { get; set; }
|
||||
public List<AgeRatingTitle> CLASS_IND { get; set; }
|
||||
public List<AgeRatingTitle> ESRB { get; set; }
|
||||
public List<AgeRatingTitle> GRAC { get; set; }
|
||||
public List<AgeRatingTitle> PEGI { get; set; }
|
||||
public List<AgeRatingTitle> USK { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Microsoft.CodeAnalysis.Classification;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class AgeRatings
|
||||
public class AgeRatings
|
||||
{
|
||||
const string fieldList = "fields category,checksum,content_descriptions,rating,rating_cover_url,synopsis;";
|
||||
public const string fieldList = "fields category,checksum,content_descriptions,rating,rating_cover_url,synopsis;";
|
||||
|
||||
public AgeRatings()
|
||||
{
|
||||
}
|
||||
|
||||
public static AgeRating? GetAgeRatings(long? Id)
|
||||
public static AgeRating? GetAgeRating(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -23,106 +23,16 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<AgeRating> RetVal = _GetAgeRatings(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
AgeRating? RetVal = Metadata.GetMetadata<AgeRating>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static AgeRating GetAgeRatings(string Slug)
|
||||
{
|
||||
Task<AgeRating> RetVal = _GetAgeRatings(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<AgeRating> _GetAgeRatings(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AgeRating", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AgeRating", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
AgeRating returnValue = new AgeRating();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<AgeRating>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<AgeRating>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(AgeRating ageRating)
|
||||
{
|
||||
if (ageRating.ContentDescriptions != null)
|
||||
{
|
||||
foreach (long AgeRatingContentDescriptionId in ageRating.ContentDescriptions.Ids)
|
||||
{
|
||||
AgeRatingContentDescription ageRatingContentDescription = AgeRatingContentDescriptions.GetAgeRatingContentDescriptions(AgeRatingContentDescriptionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<AgeRating> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get AgeRatings metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<AgeRating>(IGDBClient.Endpoints.AgeRating, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static GameAgeRating GetConsolidatedAgeRating(long RatingId)
|
||||
public static GameAgeRating GetConsolidatedAgeRating(HasheousClient.Models.MetadataSources SourceType, long RatingId)
|
||||
{
|
||||
GameAgeRating gameAgeRating = new GameAgeRating();
|
||||
|
||||
AgeRating ageRating = GetAgeRatings(RatingId);
|
||||
AgeRating ageRating = GetAgeRating(SourceType, RatingId);
|
||||
gameAgeRating.Id = (long)ageRating.Id;
|
||||
gameAgeRating.RatingBoard = (AgeRatingCategory)ageRating.Category;
|
||||
gameAgeRating.RatingTitle = (AgeRatingTitle)ageRating.Rating;
|
||||
@@ -130,9 +40,9 @@ namespace gaseous_server.Classes.Metadata
|
||||
List<string> descriptions = new List<string>();
|
||||
if (ageRating.ContentDescriptions != null)
|
||||
{
|
||||
foreach (long ContentId in ageRating.ContentDescriptions.Ids)
|
||||
foreach (long ContentId in ageRating.ContentDescriptions)
|
||||
{
|
||||
AgeRatingContentDescription ageRatingContentDescription = AgeRatingContentDescriptions.GetAgeRatingContentDescriptions(ContentId);
|
||||
AgeRatingContentDescription ageRatingContentDescription = AgeRatingContentDescriptions.GetAgeRatingContentDescriptions(SourceType, ContentId);
|
||||
descriptions.Add(ageRatingContentDescription.Description);
|
||||
}
|
||||
}
|
||||
@@ -157,7 +67,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
db.ExecuteNonQuery(sql);
|
||||
|
||||
// loop all age groups
|
||||
foreach(KeyValuePair<AgeGroups.AgeRestrictionGroupings, AgeGroups.AgeGroupItem> ageGrouping in AgeGroups.AgeGroupingsFlat)
|
||||
foreach (KeyValuePair<AgeGroups.AgeRestrictionGroupings, AgeGroups.AgeGroupItem> ageGrouping in AgeGroups.AgeGroupingsFlat)
|
||||
{
|
||||
AgeGroups.AgeGroupItem ageGroupItem = ageGrouping.Value;
|
||||
var properties = ageGroupItem.GetType().GetProperties();
|
||||
@@ -170,7 +80,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
AgeRatingCategory ageRatingCategory = (AgeRatingCategory)Enum.Parse(typeof(AgeRatingCategory), prop.Name);
|
||||
List<AgeRatingTitle> ageRatingTitles = (List<AgeRatingTitle>)prop.GetValue(ageGroupItem);
|
||||
|
||||
|
||||
foreach (AgeRatingTitle ageRatingTitle in ageRatingTitles)
|
||||
{
|
||||
dbDict.Clear();
|
||||
@@ -186,6 +96,6 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class AgeRatingContentDescriptions
|
||||
public class AgeRatingContentDescriptions
|
||||
{
|
||||
const string fieldList = "fields category,checksum,description;";
|
||||
public const string fieldList = "fields category,checksum,description;";
|
||||
|
||||
public AgeRatingContentDescriptions()
|
||||
{
|
||||
}
|
||||
|
||||
public static AgeRatingContentDescription? GetAgeRatingContentDescriptions(long? Id)
|
||||
public static AgeRatingContentDescription? GetAgeRatingContentDescriptions(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<AgeRatingContentDescription> RetVal = _GetAgeRatingContentDescriptions(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
AgeRatingContentDescription? RetVal = Metadata.GetMetadata<AgeRatingContentDescription>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static AgeRatingContentDescription GetAgeRatingContentDescriptions(string Slug)
|
||||
{
|
||||
Task<AgeRatingContentDescription> RetVal = _GetAgeRatingContentDescriptions(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<AgeRatingContentDescription> _GetAgeRatingContentDescriptions(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AgeRatingContentDescription", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AgeRatingContentDescription", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
AgeRatingContentDescription returnValue = new AgeRatingContentDescription();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<AgeRatingContentDescription>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<AgeRatingContentDescription>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<AgeRatingContentDescription> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get AgeRatingContentDescriptionContentDescriptions metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<AgeRatingContentDescription>(IGDBClient.Endpoints.AgeRatingContentDescriptions, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class AlternativeNames
|
||||
public class AlternativeNames
|
||||
{
|
||||
const string fieldList = "fields checksum,comment,game,name;";
|
||||
public const string fieldList = "fields checksum,comment,game,name;";
|
||||
|
||||
public AlternativeNames()
|
||||
{
|
||||
}
|
||||
|
||||
public static AlternativeName? GetAlternativeNames(long? Id)
|
||||
public static AlternativeName? GetAlternativeNames(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<AlternativeName> RetVal = _GetAlternativeNames(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
AlternativeName? RetVal = Metadata.GetMetadata<AlternativeName>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static AlternativeName GetAlternativeNames(string Slug)
|
||||
{
|
||||
Task<AlternativeName> RetVal = _GetAlternativeNames(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<AlternativeName> _GetAlternativeNames(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AlternativeName", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("AlternativeName", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
AlternativeName returnValue = new AlternativeName();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<AlternativeName>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<AlternativeName>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<AlternativeName> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get AlternativeNames metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<AlternativeName>(IGDBClient.Endpoints.AlternativeNames, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
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;";
|
||||
public const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
||||
|
||||
public Artworks()
|
||||
{
|
||||
}
|
||||
|
||||
public static Artwork? GetArtwork(long? Id, string ImagePath, bool GetImages)
|
||||
public static Artwork? GetArtwork(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,105 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Artwork> RetVal = _GetArtwork(SearchUsing.id, Id, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
Artwork? RetVal = Metadata.GetMetadata<Artwork>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Artwork GetArtwork(string Slug, string ImagePath, bool GetImages)
|
||||
{
|
||||
Task<Artwork> RetVal = _GetArtwork(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Artwork> _GetArtwork(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Artwork", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Artwork", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Artwork returnValue = new Artwork();
|
||||
bool forceImageDownload = false;
|
||||
ImagePath = Path.Combine(ImagePath, "Artwork");
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Artwork>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Artwork>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
// check for presence of "original" quality file - download if absent or force download is true
|
||||
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||
if (GetImages == true)
|
||||
{
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Artwork download forced.");
|
||||
|
||||
Communications comms = new Communications();
|
||||
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Artwork> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||
{
|
||||
// get Artwork metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Artwork>(IGDBClient.Endpoints.Artworks, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Collections
|
||||
public class Collections
|
||||
{
|
||||
const string fieldList = "fields as_child_relations,as_parent_relations,checksum,created_at,games,name,slug,type,updated_at,url;";
|
||||
public const string fieldList = "fields as_child_relations,as_parent_relations,checksum,created_at,games,name,slug,type,updated_at,url;";
|
||||
|
||||
public Collections()
|
||||
{
|
||||
}
|
||||
|
||||
public static Collection? GetCollections(long? Id)
|
||||
public static Collection? GetCollections(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Collection> RetVal = _GetCollections(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
Collection? RetVal = Metadata.GetMetadata<Collection>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection GetCollections(string Slug)
|
||||
{
|
||||
Task<Collection> RetVal = _GetCollections(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Collection> _GetCollections(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Collection", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Collection", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Collection returnValue = new Collection();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Collection>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Collection>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Collection> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Collections metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Collection>(IGDBClient.Endpoints.Collections, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,17 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Companies
|
||||
{
|
||||
const string fieldList = "fields change_date,change_date_category,changed_company_id,checksum,country,created_at,description,developed,logo,name,parent,published,slug,start_date,start_date_category,updated_at,url,websites;";
|
||||
public class Companies
|
||||
{
|
||||
public const string fieldList = "fields change_date,change_date_category,changed_company_id,checksum,country,created_at,description,developed,logo,name,parent,published,slug,start_date,start_date_category,updated_at,url,websites;";
|
||||
|
||||
public Companies()
|
||||
{
|
||||
}
|
||||
|
||||
public static Company? GetCompanies(long? Id)
|
||||
public static Company? GetCompanies(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -20,105 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Company> RetVal = _GetCompanies(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
Company? RetVal = Metadata.GetMetadata<Company>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Company GetCompanies(string Slug)
|
||||
{
|
||||
Task<Company> RetVal = _GetCompanies(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Company> _GetCompanies(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Company", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Company", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Company returnValue = new Company();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
if (returnValue != null) { Storage.NewCacheValue(returnValue); }
|
||||
UpdateSubClasses(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Company>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Company>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Company company)
|
||||
{
|
||||
if (company.Logo != null)
|
||||
{
|
||||
CompanyLogo companyLogo = CompanyLogos.GetCompanyLogo(company.Logo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Company(company));
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Company> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Companies metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Company>(IGDBClient.Endpoints.Companies, fieldList, WhereClause);
|
||||
if (results.Length > 0)
|
||||
{
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class CompanyLogos
|
||||
{
|
||||
const string fieldList = "fields alpha_channel,animated,checksum,height,image_id,url,width;";
|
||||
public const string fieldList = "fields alpha_channel,animated,checksum,height,image_id,url,width;";
|
||||
|
||||
public CompanyLogos()
|
||||
{
|
||||
@@ -21,104 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.id, Id, ImagePath);
|
||||
return RetVal.Result;
|
||||
CompanyLogo? RetVal = Metadata.GetMetadata<CompanyLogo>((long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static CompanyLogo GetCompanyLogo(string Slug, string ImagePath)
|
||||
{
|
||||
Task<CompanyLogo> RetVal = _GetCompanyLogo(SearchUsing.slug, Slug, ImagePath);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<CompanyLogo> _GetCompanyLogo(SearchUsing searchUsing, object searchValue, string ImagePath)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("CompanyLogo", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("CompanyLogo", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
CompanyLogo returnValue = new CompanyLogo();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
if (returnValue != null)
|
||||
{
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<CompanyLogo>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<CompanyLogo>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
// check for presence of "original" quality file - download if absent or force download is true
|
||||
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Company logo download forced.");
|
||||
|
||||
Communications comms = new Communications();
|
||||
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<CompanyLogo> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||
{
|
||||
// get Artwork metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<CompanyLogo>(IGDBClient.Endpoints.CompanyLogos, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using Microsoft.CodeAnalysis.Elfie.Model.Strings;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Covers
|
||||
{
|
||||
const string fieldList = "fields alpha_channel,animated,checksum,game,game_localization,height,image_id,url,width;";
|
||||
public const string fieldList = "fields alpha_channel,animated,checksum,game,game_localization,height,image_id,url,width;";
|
||||
|
||||
public Covers()
|
||||
{
|
||||
}
|
||||
|
||||
public static Cover? GetCover(long? Id, string ImagePath, bool GetImages)
|
||||
public static Cover? GetCover(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -23,118 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Cover> RetVal = _GetCover(SearchUsing.id, Id, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
Cover? RetVal = Metadata.GetMetadata<Cover>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Cover GetCover(string Slug, string ImagePath, bool GetImages)
|
||||
{
|
||||
Task<Cover> RetVal = _GetCover(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Cover> _GetCover(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Cover", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Cover", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Cover returnValue = new Cover();
|
||||
bool forceImageDownload = false;
|
||||
ImagePath = Path.Combine(ImagePath, "Covers");
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Cover>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Cover>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||
if (GetImages == true)
|
||||
{
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Cover download forced.");
|
||||
|
||||
// check for presence of image file - download if absent or force download is true
|
||||
List<Communications.IGDBAPI_ImageSize> imageSizes = new List<Communications.IGDBAPI_ImageSize>{
|
||||
Communications.IGDBAPI_ImageSize.cover_big,
|
||||
Communications.IGDBAPI_ImageSize.cover_small,
|
||||
Communications.IGDBAPI_ImageSize.original
|
||||
};
|
||||
|
||||
Communications comms = new Communications();
|
||||
foreach (Communications.IGDBAPI_ImageSize size in imageSizes)
|
||||
{
|
||||
localFile = Path.Combine(ImagePath, size.ToString(), returnValue.ImageId + ".jpg");
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, size, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Cover> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||
{
|
||||
// get Cover metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Cover>(IGDBClient.Endpoints.Covers, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class ExternalGames
|
||||
public class ExternalGames
|
||||
{
|
||||
const string fieldList = "fields category,checksum,countries,created_at,game,media,name,platform,uid,updated_at,url,year;";
|
||||
public const string fieldList = "fields category,checksum,countries,created_at,game,media,name,platform,uid,updated_at,url,year;";
|
||||
|
||||
public ExternalGames()
|
||||
{
|
||||
}
|
||||
|
||||
public static ExternalGame? GetExternalGames(long? Id)
|
||||
public static ExternalGame? GetExternalGames(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,98 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<ExternalGame> RetVal = _GetExternalGames(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
ExternalGame? RetVal = Metadata.GetMetadata<ExternalGame>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static ExternalGame GetExternalGames(string Slug)
|
||||
{
|
||||
Task<ExternalGame> RetVal = _GetExternalGames(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<ExternalGame> _GetExternalGames(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("ExternalGame", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("ExternalGame", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
ExternalGame returnValue = new ExternalGame();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
if (returnValue != null)
|
||||
{
|
||||
Storage.NewCacheValue(returnValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<ExternalGame>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<ExternalGame>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<ExternalGame?> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get ExternalGames metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<ExternalGame>(IGDBClient.Endpoints.ExternalGames, fieldList, WhereClause);
|
||||
if (results.Length > 0)
|
||||
{
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Franchises
|
||||
public class Franchises
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,games,name,slug,updated_at,url;";
|
||||
public const string fieldList = "fields checksum,created_at,games,name,slug,updated_at,url;";
|
||||
|
||||
public Franchises()
|
||||
{
|
||||
}
|
||||
|
||||
public static Franchise? GetFranchises(long? Id)
|
||||
public static Franchise? GetFranchises(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +19,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Franchise> RetVal = _GetFranchises(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
Franchise? RetVal = Metadata.GetMetadata<Franchise>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Franchise GetFranchises(string Slug)
|
||||
{
|
||||
Task<Franchise> RetVal = _GetFranchises(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Franchise> _GetFranchises(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Franchise", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Franchise", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Franchise returnValue = new Franchise();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Franchise>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Franchise>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Franchise> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get FranchiseContentDescriptions metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Franchise>(IGDBClient.Endpoints.Franchies, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class GameModes
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
public const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public GameModes()
|
||||
{
|
||||
}
|
||||
|
||||
public static GameMode? GetGame_Modes(long? Id)
|
||||
public static GameMode? GetGame_Modes(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<GameMode> RetVal = _GetGame_Modes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
GameMode? RetVal = Metadata.GetMetadata<GameMode>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameMode GetGame_Modes(string Slug)
|
||||
{
|
||||
Task<GameMode> RetVal = _GetGame_Modes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<GameMode> _GetGame_Modes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameMode", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameMode", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
GameMode returnValue = new GameMode();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<GameMode>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<GameMode>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<GameMode> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_Modes metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<GameMode>(IGDBClient.Endpoints.GameModes, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class GamesVideos
|
||||
public class GamesVideos
|
||||
{
|
||||
const string fieldList = "fields checksum,game,name,video_id;";
|
||||
public const string fieldList = "fields checksum,game,name,video_id;";
|
||||
|
||||
public GamesVideos()
|
||||
{
|
||||
}
|
||||
|
||||
public static GameVideo? GetGame_Videos(long? Id)
|
||||
public static GameVideo? GetGame_Videos(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<GameVideo> RetVal = _GetGame_Videos(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
GameVideo? RetVal = Metadata.GetMetadata<GameVideo>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameVideo GetGame_Videos(string Slug)
|
||||
{
|
||||
Task<GameVideo> RetVal = _GetGame_Videos(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<GameVideo> _GetGame_Videos(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameVideo", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("GameVideo", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
GameVideo returnValue = new GameVideo();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<GameVideo>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<GameVideo>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<GameVideo> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_Videos metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<GameVideo>(IGDBClient.Endpoints.GameVideos, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
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;";
|
||||
public 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()
|
||||
{
|
||||
@@ -20,39 +20,32 @@ namespace gaseous_server.Classes.Metadata
|
||||
{ }
|
||||
}
|
||||
|
||||
public static Game? GetGame(long Id, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
public static Game? GetGame(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if (Id == 0)
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
Game returnValue = new Game();
|
||||
if (Storage.GetCacheStatus("Game", 0) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
returnValue = new Game
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Unknown Title",
|
||||
Slug = "Unknown"
|
||||
};
|
||||
Storage.NewCacheValue(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Storage.GetCacheValue<Game>(returnValue, "id", 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.id, Id, getAllMetadata, followSubGames, forceRefresh);
|
||||
return RetVal.Result;
|
||||
Game? RetVal = Metadata.GetMetadata<Game>(SourceType, (long)Id, false);
|
||||
RetVal.MetadataSource = SourceType;
|
||||
long? metadataMap = MetadataManagement.GetMetadataMapIdFromSourceId(SourceType, (long)Id);
|
||||
if (metadataMap != null)
|
||||
{
|
||||
RetVal.MetadataMapId = (long)metadataMap;
|
||||
}
|
||||
RetVal = MassageResult(RetVal);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Game GetGame(string Slug, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
public static Game? GetGame(HasheousClient.Models.MetadataSources SourceType, string? Slug)
|
||||
{
|
||||
Task<Game> RetVal = _GetGame(SearchUsing.slug, Slug, getAllMetadata, followSubGames, forceRefresh);
|
||||
return RetVal.Result;
|
||||
Game? RetVal = Metadata.GetMetadata<Game>(SourceType, Slug, false);
|
||||
RetVal.MetadataSource = SourceType;
|
||||
RetVal = MassageResult(RetVal);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
public static Game GetGame(DataRow dataRow)
|
||||
@@ -60,325 +53,41 @@ namespace gaseous_server.Classes.Metadata
|
||||
return Storage.BuildCacheObject<Game>(new Game(), dataRow);
|
||||
}
|
||||
|
||||
private static async Task<Game> _GetGame(SearchUsing searchUsing, object searchValue, bool getAllMetadata = true, bool followSubGames = false, bool forceRefresh = false)
|
||||
private static Game MassageResult(Game result)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Game", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Game", (string)searchValue);
|
||||
}
|
||||
|
||||
if (forceRefresh == true)
|
||||
{
|
||||
if (cacheStatus == Storage.CacheStatus.Current) { cacheStatus = Storage.CacheStatus.Expired; }
|
||||
}
|
||||
|
||||
string WhereClause = "";
|
||||
string searchField = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
searchField = "id";
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||
searchField = "slug";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Game returnValue = new Game();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames, forceRefresh);
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(returnValue, getAllMetadata, followSubGames, forceRefresh);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||
}
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||
UpdateSubClasses(returnValue, false, false, false);
|
||||
return returnValue;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||
{
|
||||
// required metadata
|
||||
// if (Game.Cover != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (Game.Genres != null)
|
||||
{
|
||||
foreach (long GenreId in Game.Genres.Ids)
|
||||
{
|
||||
Genre GameGenre = Genres.GetGenres(GenreId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.GameModes != null)
|
||||
{
|
||||
foreach (long gameModeId in Game.GameModes.Ids)
|
||||
{
|
||||
GameMode gameMode = GameModes.GetGame_Modes(gameModeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.MultiplayerModes != null)
|
||||
{
|
||||
foreach (long multiplayerModeId in Game.MultiplayerModes.Ids)
|
||||
{
|
||||
MultiplayerMode multiplayerMode = MultiplayerModes.GetGame_MultiplayerModes(multiplayerModeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.PlayerPerspectives != null)
|
||||
{
|
||||
foreach (long PerspectiveId in Game.PlayerPerspectives.Ids)
|
||||
{
|
||||
PlayerPerspective GamePlayPerspective = PlayerPerspectives.GetGame_PlayerPerspectives(PerspectiveId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Themes != null)
|
||||
{
|
||||
foreach (long ThemeId in Game.Themes.Ids)
|
||||
{
|
||||
Theme GameTheme = Themes.GetGame_Themes(ThemeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.AgeRatings != null)
|
||||
{
|
||||
foreach (long AgeRatingId in Game.AgeRatings.Ids)
|
||||
{
|
||||
AgeRating GameAgeRating = AgeRatings.GetAgeRatings(AgeRatingId);
|
||||
}
|
||||
}
|
||||
AgeGroups.GetAgeGroup(Game);
|
||||
|
||||
if (Game.ReleaseDates != null)
|
||||
{
|
||||
foreach (long ReleaseDateId in Game.ReleaseDates.Ids)
|
||||
{
|
||||
ReleaseDate GameReleaseDate = ReleaseDates.GetReleaseDates(ReleaseDateId);
|
||||
}
|
||||
}
|
||||
|
||||
// optional metadata - usually downloaded as needed
|
||||
if (getAllMetadata == true)
|
||||
{
|
||||
if (Game.AlternativeNames != null)
|
||||
{
|
||||
foreach (long AlternativeNameId in Game.AlternativeNames.Ids)
|
||||
{
|
||||
AlternativeName GameAlternativeName = AlternativeNames.GetAlternativeNames(AlternativeNameId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Artworks != null)
|
||||
{
|
||||
foreach (long ArtworkId in Game.Artworks.Ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
Artwork GameArtwork = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch artwork id: " + ArtworkId, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (followSubGames)
|
||||
{
|
||||
List<long> gamesToFetch = new List<long>();
|
||||
if (Game.Bundles != null) { gamesToFetch.AddRange(Game.Bundles.Ids); }
|
||||
if (Game.Dlcs != null) { gamesToFetch.AddRange(Game.Dlcs.Ids); }
|
||||
if (Game.Expansions != null) { gamesToFetch.AddRange(Game.Expansions.Ids); }
|
||||
if (Game.ParentGame != null) { gamesToFetch.Add((long)Game.ParentGame.Id); }
|
||||
//if (Game.SimilarGames != null) { gamesToFetch.AddRange(Game.SimilarGames.Ids); }
|
||||
if (Game.StandaloneExpansions != null) { gamesToFetch.AddRange(Game.StandaloneExpansions.Ids); }
|
||||
if (Game.VersionParent != null) { gamesToFetch.Add((long)Game.VersionParent.Id); }
|
||||
|
||||
foreach (long gameId in gamesToFetch)
|
||||
{
|
||||
Game relatedGame = GetGame(gameId, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Collection != null)
|
||||
{
|
||||
Collection GameCollection = Collections.GetCollections(Game.Collection.Id);
|
||||
}
|
||||
|
||||
if (Game.ExternalGames != null)
|
||||
{
|
||||
foreach (long ExternalGameId in Game.ExternalGames.Ids)
|
||||
{
|
||||
ExternalGame GameExternalGame = ExternalGames.GetExternalGames(ExternalGameId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Franchise != null)
|
||||
{
|
||||
Franchise GameFranchise = Franchises.GetFranchises(Game.Franchise.Id);
|
||||
}
|
||||
|
||||
if (Game.Franchises != null)
|
||||
{
|
||||
foreach (long FranchiseId in Game.Franchises.Ids)
|
||||
{
|
||||
Franchise GameFranchise = Franchises.GetFranchises(FranchiseId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.InvolvedCompanies != null)
|
||||
{
|
||||
foreach (long involvedCompanyId in Game.InvolvedCompanies.Ids)
|
||||
{
|
||||
InvolvedCompany involvedCompany = InvolvedCompanies.GetInvolvedCompanies(involvedCompanyId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Platforms != null)
|
||||
{
|
||||
foreach (long PlatformId in Game.Platforms.Ids)
|
||||
{
|
||||
Platform GamePlatform = Platforms.GetPlatform(PlatformId);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Screenshots != null)
|
||||
{
|
||||
foreach (long ScreenshotId in Game.Screenshots.Ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
Screenshot GameScreenshot = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch screenshot id: " + ScreenshotId, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.Videos != null)
|
||||
{
|
||||
foreach (long GameVideoId in Game.Videos.Ids)
|
||||
{
|
||||
GameVideo gameVideo = GamesVideos.GetGame_Videos(GameVideoId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Game> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
// add artificial unknown platform mapping
|
||||
List<long> platformIds = new List<long>();
|
||||
platformIds.Add(0);
|
||||
if (result.Platforms != null)
|
||||
{
|
||||
if (result.Platforms.Ids != null)
|
||||
{
|
||||
platformIds.AddRange(result.Platforms.Ids.ToList());
|
||||
}
|
||||
}
|
||||
result.Platforms = new IdentitiesOrValues<Platform>(
|
||||
ids: platformIds.ToArray<long>()
|
||||
);
|
||||
Game? parentGame = null;
|
||||
|
||||
// get cover art from parent if this has no cover
|
||||
if (result.Cover == null)
|
||||
{
|
||||
if (result.ParentGame != null)
|
||||
{
|
||||
if (result.ParentGame.Id != null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no cover art, fetching cover art from parent game");
|
||||
Game parentGame = GetGame((long)result.ParentGame.Id, false, false, false);
|
||||
result.Cover = parentGame.Cover;
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no cover art, fetching cover art from parent game");
|
||||
parentGame = GetGame(result.MetadataSource, (long)result.ParentGame);
|
||||
result.Cover = parentGame.Cover;
|
||||
}
|
||||
}
|
||||
|
||||
// get missing metadata from parent if this is a port
|
||||
if (result.Category == Category.Port)
|
||||
if (result.Category == HasheousClient.Models.Metadata.IGDB.Category.Port)
|
||||
{
|
||||
if (result.Summary == null)
|
||||
{
|
||||
if (result.ParentGame != null)
|
||||
{
|
||||
if (result.ParentGame.Id != null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no summary, fetching summary from parent game");
|
||||
Game parentGame = GetGame((long)result.ParentGame.Id, false, false, false);
|
||||
result.Summary = parentGame.Summary;
|
||||
}
|
||||
Logging.Log(Logging.LogType.Information, "Game Metadata", "Game has no summary, fetching summary from parent game");
|
||||
result.Summary = parentGame.Summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void AssignAllGamesToPlatformIdZero()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Game;";
|
||||
DataTable gamesTable = db.ExecuteCMD(sql);
|
||||
foreach (DataRow gameRow in gamesTable.Rows)
|
||||
// populate age group data
|
||||
if (result.MetadataSource == HasheousClient.Models.MetadataSources.IGDB)
|
||||
{
|
||||
sql = "DELETE FROM Relation_Game_Platforms WHERE PlatformsId = 0 AND GameId = @Id; INSERT INTO Relation_Game_Platforms (GameId, PlatformsId) VALUES (@Id, 0);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("Id", (long)gameRow["Id"]);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
AgeGroups.GetAgeGroup(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool AllowNoPlatformSearch = false;
|
||||
@@ -429,7 +138,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
break;
|
||||
}
|
||||
|
||||
string sql = "SELECT Game.Id, Game.`Name`, Game.Slug, Relation_Game_Platforms.PlatformsId AS PlatformsId, Game.Summary FROM gaseous.Game JOIN Relation_Game_Platforms ON Game.Id = Relation_Game_Platforms.GameId WHERE " + whereClause + ";";
|
||||
string sql = "SELECT Game.Id, Game.`Name`, Game.Slug, Relation_Game_Platforms.PlatformsId AS PlatformsId, Game.Summary FROM gaseous.Game JOIN Relation_Game_Platforms ON Game.Id = Relation_Game_Platforms.GameId AND Game.SourceId = Relation_Game_Platforms.GameSourceId WHERE " + whereClause + ";";
|
||||
|
||||
|
||||
// get Game metadata
|
||||
@@ -459,69 +168,263 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
private static async Task<Game[]> _SearchForGameRemote(string SearchString, long PlatformId, SearchType searchType)
|
||||
{
|
||||
string searchBody = "";
|
||||
string searchFields = "fields id,name,slug,platforms,summary; ";
|
||||
bool allowSearch = true;
|
||||
switch (searchType)
|
||||
switch (Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
{
|
||||
case SearchType.searchNoPlatform:
|
||||
searchBody = "search \"" + SearchString + "\"; ";
|
||||
case HasheousClient.Models.MetadataSources.None:
|
||||
return new Game[0];
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
if (Config.IGDB.UseHasheousProxy == false)
|
||||
{
|
||||
string searchBody = "";
|
||||
string searchFields = "fields id,name,slug,platforms,summary; ";
|
||||
bool allowSearch = true;
|
||||
switch (searchType)
|
||||
{
|
||||
case SearchType.searchNoPlatform:
|
||||
searchBody = "search \"" + SearchString + "\"; ";
|
||||
|
||||
allowSearch = AllowNoPlatformSearch;
|
||||
break;
|
||||
case SearchType.search:
|
||||
searchBody = "search \"" + SearchString + "\"; where platforms = (" + PlatformId + ");";
|
||||
break;
|
||||
case SearchType.wherefuzzy:
|
||||
searchBody = "where platforms = (" + PlatformId + ") & name ~ *\"" + SearchString + "\"*;";
|
||||
break;
|
||||
case SearchType.where:
|
||||
searchBody = "where platforms = (" + PlatformId + ") & name ~ \"" + SearchString + "\";";
|
||||
break;
|
||||
}
|
||||
allowSearch = AllowNoPlatformSearch;
|
||||
break;
|
||||
case SearchType.search:
|
||||
searchBody = "search \"" + SearchString + "\"; where platforms = (" + PlatformId + ");";
|
||||
break;
|
||||
case SearchType.wherefuzzy:
|
||||
searchBody = "where platforms = (" + PlatformId + ") & name ~ *\"" + SearchString + "\"*;";
|
||||
break;
|
||||
case SearchType.where:
|
||||
searchBody = "where platforms = (" + PlatformId + ") & name ~ \"" + SearchString + "\";";
|
||||
break;
|
||||
}
|
||||
|
||||
// check search cache
|
||||
Game[]? games = Communications.GetSearchCache<Game[]?>(searchFields, searchBody);
|
||||
// check search cache
|
||||
Game[]? games = Communications.GetSearchCache<Game[]?>(searchFields, searchBody);
|
||||
|
||||
if (games == null)
|
||||
{
|
||||
// cache miss
|
||||
// get Game metadata
|
||||
Communications comms = new Communications();
|
||||
Game[]? results = new Game[0];
|
||||
if (allowSearch == true)
|
||||
{
|
||||
results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||
if (games == null)
|
||||
{
|
||||
// cache miss
|
||||
// get Game metadata
|
||||
Communications comms = new Communications();
|
||||
Game[]? results = new Game[0];
|
||||
if (allowSearch == true)
|
||||
{
|
||||
results = await comms.APIComm<Game>(IGDB.IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||
|
||||
Communications.SetSearchCache<Game[]?>(searchFields, searchBody, results);
|
||||
}
|
||||
Communications.SetSearchCache<Game[]?>(searchFields, searchBody, results);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
else
|
||||
{
|
||||
return games.ToArray();
|
||||
return results;
|
||||
}
|
||||
else
|
||||
{
|
||||
return games.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||
HasheousClient.Models.Metadata.IGDB.Game[] hResults = hasheous.GetMetadataProxy_SearchGame<HasheousClient.Models.Metadata.IGDB.Game>(HasheousClient.Hasheous.MetadataProvider.IGDB, PlatformId.ToString(), SearchString);
|
||||
|
||||
List<Game> hGames = new List<Game>();
|
||||
foreach (HasheousClient.Models.Metadata.IGDB.Game hResult in hResults)
|
||||
{
|
||||
hGames.Add(Communications.ConvertToIGDBModel<Game>(hResult));
|
||||
}
|
||||
|
||||
return hGames.ToArray();
|
||||
}
|
||||
default:
|
||||
return new Game[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static List<KeyValuePair<long, string>> GetAvailablePlatforms(long GameId)
|
||||
public static List<AvailablePlatformItem> GetAvailablePlatforms(string UserId, HasheousClient.Models.MetadataSources SourceType, long GameId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @gameid ORDER BY Platform.`Name`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("gameid", GameId);
|
||||
string sql = @"
|
||||
SELECT DISTINCT
|
||||
view_Games_Roms.MetadataMapId,
|
||||
view_Games_Roms.GameId,
|
||||
view_Games_Roms.PlatformId,
|
||||
view_Games_Roms.UserManualLink,
|
||||
Platform.`Name`,
|
||||
User_RecentPlayedRoms.UserId AS MostRecentUserId,
|
||||
User_RecentPlayedRoms.RomId AS MostRecentRomId,
|
||||
CASE User_RecentPlayedRoms.IsMediaGroup
|
||||
WHEN 0 THEN GMR.`Name`
|
||||
WHEN 1 THEN view_Games_Roms.`MetadataGameName`
|
||||
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 view_Games_Roms.`MetadataGameName`
|
||||
ELSE NULL
|
||||
END AS `FavouriteRomName`,
|
||||
User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup
|
||||
FROM
|
||||
view_Games_Roms
|
||||
LEFT JOIN
|
||||
Platform ON view_Games_Roms.PlatformId = Platform.Id AND Platform.SourceId = view_Games_Roms.GameIdType
|
||||
LEFT JOIN
|
||||
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||
AND User_RecentPlayedRoms.GameId = view_Games_Roms.MetadataMapId
|
||||
AND User_RecentPlayedRoms.PlatformId = view_Games_Roms.PlatformId
|
||||
LEFT JOIN
|
||||
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||
AND User_GameFavouriteRoms.GameId = view_Games_Roms.MetadataMapId
|
||||
AND User_GameFavouriteRoms.PlatformId = view_Games_Roms.PlatformId
|
||||
LEFT JOIN
|
||||
view_Games_Roms AS GMR ON GMR.Id = User_RecentPlayedRoms.RomId
|
||||
LEFT JOIN
|
||||
view_Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId
|
||||
WHERE
|
||||
view_Games_Roms.GameIdType = @sourcetype AND view_Games_Roms.GameId = @gameid
|
||||
ORDER BY Platform.`Name`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "sourcetype", (int)SourceType },
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId }
|
||||
};
|
||||
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)
|
||||
{
|
||||
KeyValuePair<long, string> valuePair = new KeyValuePair<long, string>((long)row["PlatformId"], (string)row["Name"]);
|
||||
HasheousClient.Models.Metadata.IGDB.Platform platform = Platforms.GetPlatform((long)row["PlatformId"]);
|
||||
|
||||
// get the user emulator configuration
|
||||
PlatformMapping.UserEmulatorConfiguration? emulatorConfiguration = platformMapping.GetUserEmulator(UserId, GameId, (long)platform.Id);
|
||||
|
||||
// if no user configuration, get the platform emulator configuration
|
||||
if (emulatorConfiguration == null)
|
||||
{
|
||||
if (platform.Id != 0)
|
||||
{
|
||||
Models.PlatformMapping.PlatformMapItem platformMap = PlatformMapping.GetPlatformMap((long)platform.Id);
|
||||
if (platformMap != null)
|
||||
{
|
||||
emulatorConfiguration = new PlatformMapping.UserEmulatorConfiguration
|
||||
{
|
||||
EmulatorType = platformMap.WebEmulator.Type,
|
||||
Core = platformMap.WebEmulator.Core,
|
||||
EnableBIOSFiles = platformMap.EnabledBIOSHashes
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if still no emulator configuration, create a blank one
|
||||
if (emulatorConfiguration == null)
|
||||
{
|
||||
emulatorConfiguration = new PlatformMapping.UserEmulatorConfiguration
|
||||
{
|
||||
EmulatorType = "",
|
||||
Core = "",
|
||||
EnableBIOSFiles = new List<string>()
|
||||
};
|
||||
}
|
||||
|
||||
long? LastPlayedRomId = null;
|
||||
bool? LastPlayedIsMediagroup = false;
|
||||
string? LastPlayedRomName = null;
|
||||
if (row["MostRecentRomId"] != DBNull.Value)
|
||||
{
|
||||
LastPlayedRomId = (long?)row["MostRecentRomId"];
|
||||
LastPlayedIsMediagroup = (bool)row["MostRecentRomIsMediaGroup"];
|
||||
if (row["MostRecentRomName"] != System.DBNull.Value)
|
||||
{
|
||||
LastPlayedRomName = string.IsNullOrEmpty((string?)row["MostRecentRomName"]) ? "" : (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"];
|
||||
if (row["FavouriteRomName"] != System.DBNull.Value)
|
||||
{
|
||||
FavouriteRomName = string.IsNullOrEmpty((string?)row["FavouriteRomName"]) ? "" : (string)row["FavouriteRomName"];
|
||||
}
|
||||
}
|
||||
|
||||
string? UserManualLink = null;
|
||||
if (row["UserManualLink"] != DBNull.Value)
|
||||
{
|
||||
UserManualLink = string.IsNullOrEmpty((string?)row["UserManualLink"]) ? "" : (string)row["UserManualLink"];
|
||||
}
|
||||
|
||||
AvailablePlatformItem valuePair = new AvailablePlatformItem
|
||||
{
|
||||
Id = platform.Id,
|
||||
Name = platform.Name,
|
||||
MetadataMapId = (long)row["MetadataMapId"],
|
||||
Category = platform.Category,
|
||||
emulatorConfiguration = emulatorConfiguration,
|
||||
LastPlayedRomId = LastPlayedRomId,
|
||||
LastPlayedRomIsMediagroup = LastPlayedIsMediagroup,
|
||||
LastPlayedRomName = LastPlayedRomName,
|
||||
FavouriteRomId = FavouriteRomId,
|
||||
FavouriteRomIsMediagroup = FavouriteRomIsMediagroup,
|
||||
FavouriteRomName = FavouriteRomName,
|
||||
UserManualLink = UserManualLink
|
||||
};
|
||||
platforms.Add(valuePair);
|
||||
}
|
||||
|
||||
// sort platforms by the Name attribute
|
||||
platforms.Sort((x, y) => x.Name.CompareTo(y.Name));
|
||||
|
||||
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 : HasheousClient.Models.Metadata.IGDB.Platform
|
||||
{
|
||||
public long MetadataMapId { get; set; }
|
||||
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 string? UserManualLink { get; set; }
|
||||
}
|
||||
|
||||
public enum SearchType
|
||||
{
|
||||
where = 0,
|
||||
@@ -540,8 +443,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
public MinimalGameItem(Game gameObject)
|
||||
{
|
||||
this.Id = gameObject.Id;
|
||||
this.MetadataMapId = gameObject.MetadataMapId;
|
||||
this.Name = gameObject.Name;
|
||||
this.Slug = gameObject.Slug;
|
||||
this.Summary = gameObject.Summary;
|
||||
this.TotalRating = gameObject.TotalRating;
|
||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||
this.Cover = gameObject.Cover;
|
||||
@@ -549,12 +454,12 @@ namespace gaseous_server.Classes.Metadata
|
||||
this.FirstReleaseDate = gameObject.FirstReleaseDate;
|
||||
|
||||
// compile age ratings
|
||||
this.AgeRatings = new List<AgeRating>();
|
||||
this.AgeRatings = new List<object>();
|
||||
if (gameObject.AgeRatings != null)
|
||||
{
|
||||
foreach (long ageRatingId in gameObject.AgeRatings.Ids)
|
||||
foreach (long ageRatingId in gameObject.AgeRatings)
|
||||
{
|
||||
AgeRating? rating = Classes.Metadata.AgeRatings.GetAgeRatings(ageRatingId);
|
||||
HasheousClient.Models.Metadata.IGDB.AgeRating? rating = Classes.Metadata.AgeRatings.GetAgeRating(gameObject.MetadataSource, ageRatingId);
|
||||
if (rating != null)
|
||||
{
|
||||
this.AgeRatings.Add(rating);
|
||||
@@ -564,17 +469,19 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
|
||||
public long? Id { get; set; }
|
||||
public long? MetadataMapId { get; set; }
|
||||
public long Index { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public double? TotalRating { get; set; }
|
||||
public int? TotalRatingCount { get; set; }
|
||||
public bool HasSavedGame { get; set; } = false;
|
||||
public bool IsFavourite { get; set; } = false;
|
||||
public DateTimeOffset? FirstReleaseDate { get; set; }
|
||||
public IGDB.IdentityOrValue<IGDB.Models.Cover> Cover { get; set; }
|
||||
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
||||
public List<IGDB.Models.AgeRating> AgeRatings { get; set; }
|
||||
public object Cover { get; set; }
|
||||
public List<long> Artworks { get; set; }
|
||||
public List<object> AgeRatings { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Genres
|
||||
public class Genres
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
public const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public Genres()
|
||||
{
|
||||
}
|
||||
|
||||
public static Genre? GetGenres(long? Id)
|
||||
public static Genre? GetGenres(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Genre> RetVal = _GetGenres(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
Genre? RetVal = Metadata.GetMetadata<Genre>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Genre GetGenres(string Slug)
|
||||
{
|
||||
Task<Genre> RetVal = _GetGenres(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Genre> _GetGenres(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Genre", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Genre", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Genre returnValue = new Genre();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Genre>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Genre>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Genre> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Genres metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Genre>(IGDBClient.Endpoints.Genres, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class InvolvedCompanies
|
||||
{
|
||||
const string fieldList = "fields *;";
|
||||
public class InvolvedCompanies
|
||||
{
|
||||
public const string fieldList = "fields *;";
|
||||
|
||||
public InvolvedCompanies()
|
||||
{
|
||||
@@ -20,106 +19,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<InvolvedCompany> RetVal = _GetInvolvedCompanies(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static InvolvedCompany GetInvolvedCompanies(string Slug)
|
||||
{
|
||||
Task<InvolvedCompany> RetVal = _GetInvolvedCompanies(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<InvolvedCompany> _GetInvolvedCompanies(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("InvolvedCompany", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("InvolvedCompany", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
InvolvedCompany returnValue = new InvolvedCompany();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<InvolvedCompany>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<InvolvedCompany>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(InvolvedCompany involvedCompany)
|
||||
{
|
||||
if (involvedCompany.Company != null)
|
||||
{
|
||||
Company company = Companies.GetCompanies(involvedCompany.Company.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<InvolvedCompany> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get InvolvedCompanies metadata
|
||||
try
|
||||
{
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<InvolvedCompany>(IGDBClient.Endpoints.InvolvedCompanies, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Involved Companies", "Failure when requesting involved companies.");
|
||||
Logging.Log(Logging.LogType.Critical, "Involved Companies", "Field list: " + fieldList);
|
||||
Logging.Log(Logging.LogType.Critical, "Involved Companies", "Where clause: " + WhereClause);
|
||||
Logging.Log(Logging.LogType.Critical, "Involved Companies", "Error", ex);
|
||||
throw;
|
||||
InvolvedCompany? RetVal = Metadata.GetMetadata<InvolvedCompany>(HasheousClient.Models.MetadataSources.IGDB, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
262
gaseous-server/Classes/Metadata/Metadata.cs
Normal file
262
gaseous-server/Classes/Metadata/Metadata.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System.Data;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Metadata
|
||||
{
|
||||
#region Exception Handling
|
||||
public class InvalidMetadataId : Exception
|
||||
{
|
||||
public InvalidMetadataId(long Id) : base("Invalid Metadata id: " + Id + " from source: " + HasheousClient.Models.MetadataSources.IGDB + " (default)")
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidMetadataId(HasheousClient.Models.MetadataSources SourceType, long Id) : base("Invalid Metadata id: " + Id + " from source: " + SourceType)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidMetadataId(string Id) : base("Invalid Metadata id: " + Id + " from source: " + HasheousClient.Models.MetadataSources.IGDB + " (default)")
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidMetadataId(HasheousClient.Models.MetadataSources SourceType, string Id) : base("Invalid Metadata id: " + Id + " from source: " + SourceType)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Get Metadata
|
||||
/// <summary>
|
||||
/// Get metadata from the default source
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type of metadata to get
|
||||
/// </typeparam>
|
||||
/// <param name="Id">
|
||||
/// The id of the metadata to get
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The metadata object
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidMetadataId">
|
||||
/// Thrown when the id is invalid
|
||||
/// </exception>
|
||||
public static T? GetMetadata<T>(long Id, Boolean ForceRefresh = false) where T : class
|
||||
{
|
||||
if (Id < 0)
|
||||
{
|
||||
throw new InvalidMetadataId(Id);
|
||||
}
|
||||
|
||||
return _GetMetadata<T>(HasheousClient.Models.MetadataSources.IGDB, Id, ForceRefresh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get metadata from the specified source
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type of metadata to get
|
||||
/// </typeparam>
|
||||
/// <param name="SourceType">
|
||||
/// The source of the metadata
|
||||
/// </param>
|
||||
/// <param name="Id">
|
||||
/// The id of the metadata to get
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The metadata object
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidMetadataId">
|
||||
/// Thrown when the id is invalid
|
||||
/// </exception>
|
||||
public static T? GetMetadata<T>(HasheousClient.Models.MetadataSources SourceType, long Id, Boolean ForceRefresh = false) where T : class
|
||||
{
|
||||
if (Id < 0)
|
||||
{
|
||||
throw new InvalidMetadataId(SourceType, Id);
|
||||
}
|
||||
|
||||
return _GetMetadata<T>(SourceType, Id, ForceRefresh);
|
||||
}
|
||||
|
||||
public static T? GetMetadata<T>(HasheousClient.Models.MetadataSources SourceType, string Slug, Boolean ForceRefresh = false) where T : class
|
||||
{
|
||||
return _GetMetadata<T>(SourceType, Slug, ForceRefresh);
|
||||
}
|
||||
|
||||
private static T? _GetMetadata<T>(HasheousClient.Models.MetadataSources SourceType, object Id, Boolean ForceRefresh) where T : class
|
||||
{
|
||||
// get T type as string
|
||||
string type = typeof(T).Name;
|
||||
|
||||
// get type of Id as string
|
||||
IdType idType = Id.GetType() == typeof(long) ? IdType.Long : IdType.String;
|
||||
|
||||
// check cached metadata status
|
||||
// if metadata is not cached or expired, get it from the source. Otherwise, return the cached metadata
|
||||
Storage.CacheStatus? cacheStatus;
|
||||
if (idType == IdType.Long)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus(SourceType, type, (long)Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus(SourceType, type, (string)Id);
|
||||
}
|
||||
|
||||
// if ForceRefresh is true, set cache status to expired if it is current
|
||||
if (ForceRefresh == true)
|
||||
{
|
||||
if (cacheStatus == Storage.CacheStatus.Current)
|
||||
{
|
||||
cacheStatus = Storage.CacheStatus.Expired;
|
||||
}
|
||||
}
|
||||
|
||||
// if the source is "none", cache status should be "current" or "not present"
|
||||
if (SourceType == HasheousClient.Models.MetadataSources.None)
|
||||
{
|
||||
if (cacheStatus == Storage.CacheStatus.Expired)
|
||||
{
|
||||
cacheStatus = Storage.CacheStatus.Current;
|
||||
}
|
||||
}
|
||||
|
||||
T? metadata = (T)Activator.CreateInstance(typeof(T));
|
||||
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.Current:
|
||||
if (idType == IdType.Long)
|
||||
{
|
||||
metadata = Storage.GetCacheValue<T>(SourceType, metadata, "Id", (long)Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata = Storage.GetCacheValue<T>(SourceType, metadata, "Slug", (string)Id);
|
||||
}
|
||||
break;
|
||||
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
if (idType == IdType.Long)
|
||||
{
|
||||
metadata = GetMetadataFromServer<T>(SourceType, (long)Id).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata = GetMetadataFromServer<T>(SourceType, (string)Id).Result;
|
||||
}
|
||||
Storage.NewCacheValue<T>(SourceType, metadata, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Fetch Metadata", "Failed to fetch metadata from source: " + SourceType + " for id: " + Id + " of type: " + type + ". Error: " + e.Message);
|
||||
metadata = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
try
|
||||
{
|
||||
if (idType == IdType.Long)
|
||||
{
|
||||
metadata = GetMetadataFromServer<T>(SourceType, (long)Id).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata = GetMetadataFromServer<T>(SourceType, (string)Id).Result;
|
||||
}
|
||||
Storage.NewCacheValue<T>(SourceType, metadata, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Fetch Metadata", "Failed to fetch metadata from source: " + SourceType + " for id: " + Id + " of type: " + type + ". Error: " + e.Message);
|
||||
metadata = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private enum IdType
|
||||
{
|
||||
Long,
|
||||
String
|
||||
}
|
||||
|
||||
private static async Task<T> GetMetadataFromServer<T>(HasheousClient.Models.MetadataSources SourceType, long Id) where T : class
|
||||
{
|
||||
// get T type as string
|
||||
string type = typeof(T).Name;
|
||||
|
||||
if (SourceType == HasheousClient.Models.MetadataSources.None)
|
||||
{
|
||||
// generate a dummy object
|
||||
var returnObject = (T)Activator.CreateInstance(typeof(T));
|
||||
returnObject.GetType().GetProperty("Id").SetValue(returnObject, Id);
|
||||
|
||||
// if returnObject has a property called "name", query the metadatamap view for the name
|
||||
if (returnObject.GetType().GetProperty("Name") != null)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM MetadataMap JOIN MetadataMapBridge ON MetadataMap.Id = MetadataMapBridge.ParentMapId WHERE MetadataSourceId = @id AND MetadataSourceType = 0;";
|
||||
DataTable dataTable = db.ExecuteCMD(sql, new Dictionary<string, object>
|
||||
{
|
||||
{ "@id", Id }
|
||||
});
|
||||
if (dataTable.Rows.Count > 0)
|
||||
{
|
||||
returnObject.GetType().GetProperty("Name").SetValue(returnObject, dataTable.Rows[0]["SignatureGameName"].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get metadata from the server
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<T>(SourceType, (Communications.MetadataEndpoint)Enum.Parse(typeof(Communications.MetadataEndpoint), type, true), Id);
|
||||
|
||||
// check for errors
|
||||
if (results == null)
|
||||
{
|
||||
throw new InvalidMetadataId(SourceType, Id);
|
||||
}
|
||||
|
||||
return results.FirstOrDefault<T>();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<T> GetMetadataFromServer<T>(HasheousClient.Models.MetadataSources SourceType, string Id) where T : class
|
||||
{
|
||||
// get T type as string
|
||||
string type = typeof(T).Name;
|
||||
|
||||
if (SourceType == HasheousClient.Models.MetadataSources.None)
|
||||
{
|
||||
// generate a dummy object
|
||||
return (T)Activator.CreateInstance(typeof(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
// get metadata from the server
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<T>(SourceType, (Communications.MetadataEndpoint)Enum.Parse(typeof(Communications.MetadataEndpoint), type, true), Id);
|
||||
|
||||
// check for errors
|
||||
if (results == null)
|
||||
{
|
||||
throw new InvalidMetadataId(SourceType, Id);
|
||||
}
|
||||
|
||||
return results.FirstOrDefault<T>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class MultiplayerModes
|
||||
{
|
||||
const string fieldList = "fields campaigncoop,checksum,dropin,game,lancoop,offlinecoop,offlinecoopmax,offlinemax,onlinecoop,onlinecoopmax,onlinemax,platform,splitscreen,splitscreenonline;";
|
||||
public const string fieldList = "fields campaigncoop,checksum,dropin,game,lancoop,offlinecoop,offlinecoopmax,offlinemax,onlinecoop,onlinecoopmax,onlinemax,platform,splitscreen,splitscreenonline;";
|
||||
|
||||
public MultiplayerModes()
|
||||
{
|
||||
}
|
||||
|
||||
public static MultiplayerMode? GetGame_MultiplayerModes(long? Id)
|
||||
public static MultiplayerMode? GetGame_MultiplayerModes(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<MultiplayerMode> RetVal = _GetGame_MultiplayerModes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
MultiplayerMode? RetVal = Metadata.GetMetadata<MultiplayerMode>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiplayerMode GetGame_MultiplayerModes(string Slug)
|
||||
{
|
||||
Task<MultiplayerMode> RetVal = _GetGame_MultiplayerModes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<MultiplayerMode> _GetGame_MultiplayerModes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
MultiplayerMode returnValue = new MultiplayerMode();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<MultiplayerMode>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<MultiplayerMode>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<MultiplayerMode> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_MultiplayerModes metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<MultiplayerMode>(IGDBClient.Endpoints.MultiplayerModes, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using static gaseous_server.Models.PlatformMapping;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class PlatformLogos
|
||||
public class PlatformLogos
|
||||
{
|
||||
const string fieldList = "fields alpha_channel,animated,checksum,height,image_id,url,width;";
|
||||
public const string fieldList = "fields alpha_channel,animated,checksum,height,image_id,url,width;";
|
||||
|
||||
public PlatformLogos()
|
||||
{
|
||||
}
|
||||
|
||||
public static PlatformLogo? GetPlatformLogo(long? Id, string ImagePath)
|
||||
public static PlatformLogo? GetPlatformLogo(long? Id, HasheousClient.Models.MetadataSources SourceType = HasheousClient.Models.MetadataSources.IGDB)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,107 +21,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.id, Id, ImagePath);
|
||||
return RetVal.Result;
|
||||
PlatformLogo? RetVal = Metadata.GetMetadata<PlatformLogo>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformLogo GetPlatformLogo(string Slug, string ImagePath)
|
||||
{
|
||||
Task<PlatformLogo> RetVal = _GetPlatformLogo(SearchUsing.slug, Slug, ImagePath);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<PlatformLogo> _GetPlatformLogo(SearchUsing searchUsing, object searchValue, string ImagePath)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlatformLogo", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlatformLogo", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
PlatformLogo returnValue = new PlatformLogo();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
if (returnValue != null)
|
||||
{
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<PlatformLogo>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<PlatformLogo>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
if (returnValue != null)
|
||||
{
|
||||
// check for presence of "original" quality file - download if absent or force download is true
|
||||
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Platform logo download forced.");
|
||||
|
||||
Communications comms = new Communications();
|
||||
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<PlatformLogo> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||
{
|
||||
// get Artwork metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<PlatformLogo>(IGDBClient.Endpoints.PlatformLogos, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
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;";
|
||||
public 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 static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform, bool GetImages = false)
|
||||
public static PlatformVersion? GetPlatformVersion(HasheousClient.Models.MetadataSources SourceType, long Id)
|
||||
{
|
||||
if (Id == 0)
|
||||
{
|
||||
@@ -21,113 +20,8 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages)
|
||||
{
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<PlatformVersion> _GetPlatformVersion(SearchUsing searchUsing, object searchValue, Platform ParentPlatform, bool GetImages)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlatformVersion", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlatformVersion", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
PlatformVersion returnValue = new PlatformVersion();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
if (returnValue != null)
|
||||
{
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||
}
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<PlatformVersion>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Current:
|
||||
return Storage.GetCacheValue<PlatformVersion>(returnValue, "id", (long)searchValue);
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion, bool GetImages)
|
||||
{
|
||||
if (GetImages == true)
|
||||
{
|
||||
if (platformVersion.PlatformLogo != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(ParentPlatform), "Versions", platformVersion.Slug));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<PlatformVersion?> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get PlatformVersion metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<PlatformVersion>(IGDBClient.Endpoints.PlatformVersions, fieldList, WhereClause);
|
||||
if (results.Length > 0)
|
||||
{
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
PlatformVersion? RetVal = Metadata.GetMetadata<PlatformVersion>(SourceType, Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +1,71 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Net;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Platforms
|
||||
{
|
||||
const string fieldList = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites;";
|
||||
public const string fieldList = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites;";
|
||||
|
||||
public Platforms()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static Platform? GetPlatform(long Id, bool forceRefresh = false, bool GetImages = false)
|
||||
public static Platform? GetPlatform(long Id, HasheousClient.Models.MetadataSources? SourceType = null)
|
||||
{
|
||||
if (Id == 0)
|
||||
HasheousClient.Models.MetadataSources Source = SourceType ?? Communications.MetadataSource;
|
||||
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
Platform returnValue = new Platform();
|
||||
if (Storage.GetCacheStatus("Platform", 0) == Storage.CacheStatus.NotPresent)
|
||||
if (Storage.GetCacheStatus(Source, "Platform", 0) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
returnValue = new Platform
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Unknown Platform",
|
||||
Slug = "Unknown"
|
||||
Slug = "unknown"
|
||||
};
|
||||
Storage.NewCacheValue(returnValue);
|
||||
Storage.NewCacheValue(Source, returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Storage.GetCacheValue<Platform>(returnValue, "id", 0);
|
||||
return Storage.GetCacheValue<Platform>(Source, returnValue, "id", 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
Platform? RetVal = new Platform();
|
||||
RetVal = (Platform?)Storage.GetCacheValue<Platform>(HasheousClient.Models.MetadataSources.None, RetVal, "Id", (long)Id);
|
||||
if (Source != HasheousClient.Models.MetadataSources.None)
|
||||
{
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata", "An error occurred fetching Platform Id " + Id, ex);
|
||||
return null;
|
||||
if (RetVal == null)
|
||||
{
|
||||
RetVal = Metadata.GetMetadata<Platform>(Source, (long)Id, false);
|
||||
}
|
||||
}
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Platform GetPlatform(string Slug, bool forceRefresh = false, bool GetImages = false)
|
||||
public static Platform GetPlatform(string Slug)
|
||||
{
|
||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.slug, Slug, forceRefresh, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Platform> _GetPlatform(SearchUsing searchUsing, object searchValue, bool forceRefresh, bool GetImages)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
// get platform id from slug - query Platform table
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string query = "SELECT Id FROM Platform WHERE slug = @slug AND SourceId = @sourceid;";
|
||||
DataTable result = db.ExecuteCMD(query, new Dictionary<string, object> { { "@slug", Slug }, { "@sourceid", HasheousClient.Models.MetadataSources.IGDB } });
|
||||
if (result.Rows.Count == 0)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Platform", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Platform", (string)searchValue);
|
||||
throw new Metadata.InvalidMetadataId(Slug);
|
||||
}
|
||||
|
||||
if (forceRefresh == true)
|
||||
{
|
||||
if (cacheStatus == Storage.CacheStatus.Current) { cacheStatus = Storage.CacheStatus.Expired; }
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
string searchField = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
searchField = "id";
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||
searchField = "slug";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Platform returnValue = new Platform();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
UpdateSubClasses(returnValue, GetImages);
|
||||
AddPlatformMapping(returnValue);
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
UpdateSubClasses(returnValue, GetImages);
|
||||
AddPlatformMapping(returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||
}
|
||||
case Storage.CacheStatus.Current:
|
||||
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateSubClasses(Platform platform, bool GetImages)
|
||||
{
|
||||
if (platform.Versions != null)
|
||||
{
|
||||
foreach (long PlatformVersionId in platform.Versions.Ids)
|
||||
{
|
||||
PlatformVersion platformVersion = PlatformVersions.GetPlatformVersion(PlatformVersionId, platform);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetImages == true)
|
||||
{
|
||||
if (platform.PlatformLogo != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
PlatformLogo platformLogo = PlatformLogos.GetPlatformLogo(platform.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platform));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Platform Update", "Unable to fetch platform logo", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
long Id = (long)result.Rows[0]["Id"];
|
||||
return GetPlatform(Id);
|
||||
}
|
||||
|
||||
private static void AddPlatformMapping(Platform platform)
|
||||
@@ -174,36 +93,6 @@ namespace gaseous_server.Classes.Metadata
|
||||
Models.PlatformMapping.WritePlatformMap(item, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Platform> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get platform metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void AssignAllPlatformsToGameIdZero()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Platform;";
|
||||
DataTable platformsTable = db.ExecuteCMD(sql);
|
||||
foreach (DataRow platformRow in platformsTable.Rows)
|
||||
{
|
||||
sql = "DELETE FROM Relation_Game_Platforms WHERE GameId = 0 AND PlatformsId = @Id; INSERT INTO Relation_Game_Platforms (GameId, PlatformsId) VALUES (0, @Id);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("Id", (long)platformRow["Id"]);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class PlayerPerspectives
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
public const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public PlayerPerspectives()
|
||||
{
|
||||
}
|
||||
|
||||
public static PlayerPerspective? GetGame_PlayerPerspectives(long? Id)
|
||||
public static PlayerPerspective? GetGame_PlayerPerspectives(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,90 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<PlayerPerspective> RetVal = _GetGame_PlayerPerspectives(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
PlayerPerspective? RetVal = Metadata.GetMetadata<PlayerPerspective>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlayerPerspective GetGame_PlayerPerspectives(string Slug)
|
||||
{
|
||||
Task<PlayerPerspective> RetVal = _GetGame_PlayerPerspectives(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<PlayerPerspective> _GetGame_PlayerPerspectives(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
PlayerPerspective returnValue = new PlayerPerspective();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<PlayerPerspective>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<PlayerPerspective>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<PlayerPerspective> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_PlayerPerspectives metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<PlayerPerspective>(IGDBClient.Endpoints.PlayerPerspectives, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class ReleaseDates
|
||||
public class ReleaseDates
|
||||
{
|
||||
const string fieldList = "fields category,checksum,created_at,date,game,human,m,platform,region,status,updated_at,y;";
|
||||
public const string fieldList = "fields category,checksum,created_at,date,game,human,m,platform,region,status,updated_at,y;";
|
||||
|
||||
public ReleaseDates()
|
||||
{
|
||||
}
|
||||
|
||||
public static ReleaseDate? GetReleaseDates(long? Id)
|
||||
public static ReleaseDate? GetReleaseDates(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,88 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<ReleaseDate> RetVal = _GetReleaseDates(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
ReleaseDate? RetVal = Metadata.GetMetadata<ReleaseDate>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReleaseDate GetReleaseDates(string Slug)
|
||||
{
|
||||
Task<ReleaseDate> RetVal = _GetReleaseDates(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<ReleaseDate> _GetReleaseDates(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("ReleaseDate", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("ReleaseDate", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
ReleaseDate returnValue = new ReleaseDate();
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<ReleaseDate>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<ReleaseDate>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<ReleaseDate> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get ReleaseDates metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<ReleaseDate>(IGDBClient.Endpoints.ReleaseDates, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
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;";
|
||||
public const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
||||
|
||||
public Screenshots()
|
||||
{
|
||||
}
|
||||
|
||||
public static Screenshot? GetScreenshot(long? Id, string ImagePath, bool GetImages)
|
||||
public static Screenshot? GetScreenshot(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,105 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.id, Id, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
Screenshot? RetVal = Metadata.GetMetadata<Screenshot>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Screenshot GetScreenshot(string Slug, string ImagePath, bool GetImages)
|
||||
{
|
||||
Task<Screenshot> RetVal = _GetScreenshot(SearchUsing.slug, Slug, ImagePath, GetImages);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Screenshot> _GetScreenshot(SearchUsing searchUsing, object searchValue, string ImagePath, bool GetImages = true)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Screenshot", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Screenshot", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Screenshot returnValue = new Screenshot();
|
||||
bool forceImageDownload = false;
|
||||
ImagePath = Path.Combine(ImagePath, "Screenshots");
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
forceImageDownload = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Screenshot>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
break;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Screenshot>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
// check for presence of "original" quality file - download if absent or force download is true
|
||||
string localFile = Path.Combine(ImagePath, Communications.IGDBAPI_ImageSize.original.ToString(), returnValue.ImageId + ".jpg");
|
||||
if (GetImages == true)
|
||||
{
|
||||
if ((!File.Exists(localFile)) || forceImageDownload == true)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata: " + returnValue.GetType().Name, "Screenshot download forced.");
|
||||
|
||||
Communications comms = new Communications();
|
||||
comms.GetSpecificImageFromServer(ImagePath, returnValue.ImageId, Communications.IGDBAPI_ImageSize.original, null);
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Screenshot> GetObjectFromServer(string WhereClause, string ImagePath)
|
||||
{
|
||||
// get Screenshot metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Screenshot>(IGDBClient.Endpoints.Screenshots, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,23 +9,79 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Storage
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache status of a record
|
||||
/// </summary>
|
||||
public enum CacheStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The record is not present in the database
|
||||
/// </summary>
|
||||
NotPresent,
|
||||
|
||||
/// <summary>
|
||||
/// The record is present in the database and is current
|
||||
/// </summary>
|
||||
Current,
|
||||
|
||||
/// <summary>
|
||||
/// The record is present in the database but is expired
|
||||
/// </summary>
|
||||
Expired
|
||||
}
|
||||
|
||||
public static CacheStatus GetCacheStatus(string Endpoint, string Slug)
|
||||
/// <summary>
|
||||
/// Get the cache status of a record in the database
|
||||
/// </summary>
|
||||
/// <param name="SourceType">
|
||||
/// The source of the metadata (IGDB, RAWG, etc.)
|
||||
/// </param>
|
||||
/// <param name="Endpoint">
|
||||
/// The endpoint of the metadata (games, companies, etc.)
|
||||
/// </param>
|
||||
/// <param name="Slug">
|
||||
/// The slug of the metadata record
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The cache status of the record
|
||||
/// </returns>
|
||||
public static CacheStatus GetCacheStatus(HasheousClient.Models.MetadataSources SourceType, string Endpoint, string Slug)
|
||||
{
|
||||
return _GetCacheStatus(Endpoint, "slug", Slug);
|
||||
return _GetCacheStatus(SourceType, Endpoint, "slug", Slug);
|
||||
}
|
||||
|
||||
public static CacheStatus GetCacheStatus(string Endpoint, long Id)
|
||||
/// <summary>
|
||||
/// Get the cache status of a record in the database
|
||||
/// </summary>
|
||||
/// <param name="SourceType">
|
||||
/// The source of the metadata (IGDB, RAWG, etc.)
|
||||
/// </param>
|
||||
/// <param name="Endpoint">
|
||||
/// The endpoint of the metadata (games, companies, etc.)
|
||||
/// </param>
|
||||
/// <param name="Id">
|
||||
/// The ID of the metadata record
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The cache status of the record
|
||||
/// </returns>
|
||||
public static CacheStatus GetCacheStatus(HasheousClient.Models.MetadataSources SourceType, string Endpoint, long Id)
|
||||
{
|
||||
return _GetCacheStatus(Endpoint, "id", Id);
|
||||
return _GetCacheStatus(SourceType, Endpoint, "id", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the cache status of a record in the database
|
||||
/// </summary>
|
||||
/// <param name="Row">
|
||||
/// The DataRow object to check
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The cache status of the record
|
||||
/// </returns>
|
||||
/// <exception cref="Exception">
|
||||
/// Thrown when the DataRow object does not contain a "lastUpdated" column
|
||||
/// </exception>
|
||||
public static CacheStatus GetCacheStatus(DataRow Row)
|
||||
{
|
||||
if (Row.Table.Columns.Contains("lastUpdated"))
|
||||
@@ -46,13 +102,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
private static CacheStatus _GetCacheStatus(string Endpoint, string SearchField, object SearchValue)
|
||||
private static CacheStatus _GetCacheStatus(HasheousClient.Models.MetadataSources SourceType, string Endpoint, string SearchField, object SearchValue)
|
||||
{
|
||||
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 SourceId = @SourceType AND " + SearchField + " = @" + SearchField;
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("SourceType", SourceType);
|
||||
dbDict.Add("Endpoint", Endpoint);
|
||||
dbDict.Add(SearchField, SearchValue);
|
||||
|
||||
@@ -76,16 +133,41 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
public static void NewCacheValue(object ObjectToCache, bool UpdateRecord = false)
|
||||
/// <summary>
|
||||
/// Add a new record to the cache
|
||||
/// </summary>
|
||||
/// <param name="SourceType">
|
||||
/// The source of the metadata (IGDB, RAWG, etc.)
|
||||
/// </param>
|
||||
/// <param name="ObjectToCache">
|
||||
/// The object to cache
|
||||
/// </param>
|
||||
/// <param name="UpdateRecord">
|
||||
/// Whether to update the record if it already exists
|
||||
/// </param>
|
||||
public static void NewCacheValue<T>(HasheousClient.Models.MetadataSources SourceType, T ObjectToCache, bool UpdateRecord = false)
|
||||
{
|
||||
// get the object type name
|
||||
string ObjectTypeName = ObjectToCache.GetType().Name;
|
||||
|
||||
// build dictionary
|
||||
string objectJson = Newtonsoft.Json.JsonConvert.SerializeObject(ObjectToCache);
|
||||
Dictionary<string, object?> objectDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object?>>(objectJson);
|
||||
objectDict.Add("dateAdded", DateTime.UtcNow);
|
||||
objectDict.Add("lastUpdated", DateTime.UtcNow);
|
||||
Dictionary<string, object?> objectDict = new Dictionary<string, object?>
|
||||
{
|
||||
{ "SourceId", SourceType },
|
||||
{ "dateAdded", DateTime.UtcNow },
|
||||
{ "lastUpdated", DateTime.UtcNow }
|
||||
};
|
||||
foreach (PropertyInfo property in ObjectToCache.GetType().GetProperties())
|
||||
{
|
||||
if (property.GetCustomAttribute<Models.NoDatabaseAttribute>() == null)
|
||||
{
|
||||
object? propertyValue = property.GetValue(ObjectToCache);
|
||||
if (propertyValue != null)
|
||||
{
|
||||
objectDict.Add(property.Name, propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate sql
|
||||
string fieldList = "";
|
||||
@@ -100,7 +182,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
fieldList = fieldList + key.Key;
|
||||
valueList = valueList + "@" + key.Key;
|
||||
if ((key.Key != "id") && (key.Key != "dateAdded"))
|
||||
if ((key.Key != "id") && (key.Key != "dateAdded") && (key.Key != "SourceId"))
|
||||
{
|
||||
if (updateFieldValueList.Length > 0)
|
||||
{
|
||||
@@ -135,7 +217,13 @@ namespace gaseous_server.Classes.Metadata
|
||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(newDict["Ids"]);
|
||||
objectDict[key.Key] = newObjectValue;
|
||||
|
||||
StoreRelations(ObjectTypeName, key.Key, (long)objectDict["Id"], newObjectValue);
|
||||
StoreRelations(SourceType, ObjectTypeName, key.Key, (long)objectDict["Id"], newObjectValue);
|
||||
break;
|
||||
case "list":
|
||||
newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(objectValue);
|
||||
objectDict[key.Key] = newObjectValue;
|
||||
|
||||
StoreRelations(SourceType, ObjectTypeName, key.Key, (long)objectDict["Id"], newObjectValue);
|
||||
|
||||
break;
|
||||
case "int32[]":
|
||||
@@ -151,11 +239,11 @@ namespace gaseous_server.Classes.Metadata
|
||||
string sql = "";
|
||||
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";
|
||||
sql = "UPDATE " + ObjectTypeName + " SET " + updateFieldValueList + " WHERE Id = @Id AND SourceId = @SourceId;";
|
||||
}
|
||||
|
||||
// execute sql
|
||||
@@ -163,19 +251,44 @@ namespace gaseous_server.Classes.Metadata
|
||||
db.ExecuteCMD(sql, objectDict);
|
||||
}
|
||||
|
||||
public static T GetCacheValue<T>(T EndpointType, string SearchField, object SearchValue)
|
||||
/// <summary>
|
||||
/// Get a record from the cache
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type of the object to return
|
||||
/// </typeparam>
|
||||
/// <param name="SourceType">
|
||||
/// The source of the metadata (IGDB, RAWG, etc.)
|
||||
/// </param>
|
||||
/// <param name="EndpointType">
|
||||
/// The type of the endpoint (games, companies, etc.)
|
||||
/// </param>
|
||||
/// <param name="SearchField">
|
||||
/// The field to search for the record by
|
||||
/// </param>
|
||||
/// <param name="SearchValue">
|
||||
/// The value to search for
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The object from the cache
|
||||
/// </returns>
|
||||
/// <exception cref="Exception">
|
||||
/// Thrown when no record is found that matches the search criteria
|
||||
/// </exception>
|
||||
public static T GetCacheValue<T>(HasheousClient.Models.MetadataSources SourceType, T? EndpointType, string SearchField, object SearchValue)
|
||||
{
|
||||
string Endpoint = EndpointType.GetType().Name;
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string sql = "SELECT * FROM " + Endpoint + " WHERE " + SearchField + " = @" + SearchField;
|
||||
string sql = "SELECT * FROM " + Endpoint + " WHERE SourceId = @SourceType AND " + SearchField + " = @" + SearchField;
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("SourceType", SourceType);
|
||||
dbDict.Add("Endpoint", Endpoint);
|
||||
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)
|
||||
{
|
||||
// no data stored for this item
|
||||
@@ -192,202 +305,66 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
public static T BuildCacheObject<T>(T EndpointType, DataRow dataRow)
|
||||
{
|
||||
// copy the DataRow to EndpointType
|
||||
foreach (PropertyInfo property in EndpointType.GetType().GetProperties())
|
||||
{
|
||||
if (dataRow.Table.Columns.Contains(property.Name))
|
||||
if (property.GetCustomAttribute<Models.NoDatabaseAttribute>() == null)
|
||||
{
|
||||
if (dataRow[property.Name] != DBNull.Value)
|
||||
// get the value from the DataRow with the same name as the property
|
||||
if (dataRow.Table.Columns.Contains(property.Name) == true)
|
||||
{
|
||||
string objectTypeName = property.PropertyType.Name.ToLower().Split("`")[0];
|
||||
string subObjectTypeName = "";
|
||||
object? objectToStore = null;
|
||||
if (objectTypeName == "nullable")
|
||||
object? value = dataRow[property.Name];
|
||||
|
||||
if (value != null && value != DBNull.Value)
|
||||
{
|
||||
objectTypeName = property.PropertyType.UnderlyingSystemType.ToString().Split("`1")[1].Replace("[System.", "").Replace("]", "").ToLower();
|
||||
}
|
||||
try
|
||||
{
|
||||
switch (objectTypeName)
|
||||
// check the property type - if it's a list or array, deserialize it. Otherwise, just set the value
|
||||
Type objectType = EndpointType.GetType();
|
||||
if (objectType != null)
|
||||
{
|
||||
//case "boolean":
|
||||
// Boolean storedBool = Convert.ToBoolean((int)dataRow[property.Name]);
|
||||
// property.SetValue(EndpointType, storedBool);
|
||||
// break;
|
||||
case "datetimeoffset":
|
||||
DateTimeOffset? storedDate = (DateTime?)dataRow[property.Name];
|
||||
property.SetValue(EndpointType, storedDate);
|
||||
break;
|
||||
//case "nullable":
|
||||
// Console.WriteLine("Nullable: " + property.PropertyType.UnderlyingSystemType);
|
||||
// break;
|
||||
case "identityorvalue":
|
||||
subObjectTypeName = property.PropertyType.UnderlyingSystemType.ToString().Split("`1")[1].Replace("[IGDB.Models.", "").Replace("]", "").ToLower();
|
||||
// fullname = System.Nullable`1[[System.DateTimeOffset,
|
||||
string propertyTypeName = property.PropertyType.FullName.Split(",")[0];
|
||||
bool isNullable = false;
|
||||
if (propertyTypeName.StartsWith("System.Nullable"))
|
||||
{
|
||||
isNullable = true;
|
||||
propertyTypeName = propertyTypeName.Split("[[")[1];
|
||||
}
|
||||
propertyTypeName = propertyTypeName.Split("`")[0];
|
||||
|
||||
switch (subObjectTypeName)
|
||||
{
|
||||
case "collection":
|
||||
objectToStore = new IdentityOrValue<Collection>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "company":
|
||||
objectToStore = new IdentityOrValue<Company>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "cover":
|
||||
objectToStore = new IdentityOrValue<Cover>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "franchise":
|
||||
objectToStore = new IdentityOrValue<Franchise>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "game":
|
||||
objectToStore = new IdentityOrValue<Game>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "platformfamily":
|
||||
objectToStore = new IdentityOrValue<PlatformFamily>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "platformlogo":
|
||||
objectToStore = new IdentityOrValue<PlatformLogo>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
case "platformversioncompany":
|
||||
objectToStore = new IdentityOrValue<PlatformVersionCompany>(id: (long)dataRow[property.Name]);
|
||||
break;
|
||||
}
|
||||
switch (propertyTypeName.ToLower())
|
||||
{
|
||||
case "system.collections.generic.list":
|
||||
var listArray = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(value.ToString());
|
||||
property.SetValue(EndpointType, listArray);
|
||||
break;
|
||||
|
||||
if (objectToStore != null)
|
||||
{
|
||||
property.SetValue(EndpointType, objectToStore);
|
||||
}
|
||||
case "system.int32[]":
|
||||
var int32array = Newtonsoft.Json.JsonConvert.DeserializeObject<int[]>(value.ToString());
|
||||
property.SetValue(EndpointType, int32array);
|
||||
break;
|
||||
|
||||
break;
|
||||
case "identitiesorvalues":
|
||||
subObjectTypeName = property.PropertyType.UnderlyingSystemType.ToString().Split("`1")[1].Replace("[IGDB.Models.", "").Replace("]", "").ToLower();
|
||||
case "system.datetimeoffset":
|
||||
property.SetValue(EndpointType, (DateTimeOffset)(DateTime?)value);
|
||||
break;
|
||||
|
||||
long[] fromJsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<long[]>((string)dataRow[property.Name]);
|
||||
|
||||
switch (subObjectTypeName)
|
||||
{
|
||||
case "agerating":
|
||||
objectToStore = new IdentitiesOrValues<AgeRating>(ids: fromJsonObject);
|
||||
break;
|
||||
case "alternativename":
|
||||
objectToStore = new IdentitiesOrValues<AlternativeName>(ids: fromJsonObject);
|
||||
break;
|
||||
case "artwork":
|
||||
objectToStore = new IdentitiesOrValues<Artwork>(ids: fromJsonObject);
|
||||
break;
|
||||
case "ageratingcontentdescription":
|
||||
objectToStore = new IdentitiesOrValues<AgeRatingContentDescription>(ids: fromJsonObject);
|
||||
break;
|
||||
case "game":
|
||||
objectToStore = new IdentitiesOrValues<Game>(ids: fromJsonObject);
|
||||
break;
|
||||
case "externalgame":
|
||||
objectToStore = new IdentitiesOrValues<ExternalGame>(ids: fromJsonObject);
|
||||
break;
|
||||
case "franchise":
|
||||
objectToStore = new IdentitiesOrValues<Franchise>(ids: fromJsonObject);
|
||||
break;
|
||||
case "gameengine":
|
||||
objectToStore = new IdentitiesOrValues<GameEngine>(ids: fromJsonObject);
|
||||
break;
|
||||
case "gamemode":
|
||||
objectToStore = new IdentitiesOrValues<GameMode>(ids: fromJsonObject);
|
||||
break;
|
||||
case "gamevideo":
|
||||
objectToStore = new IdentitiesOrValues<GameVideo>(ids: fromJsonObject);
|
||||
break;
|
||||
case "genre":
|
||||
objectToStore = new IdentitiesOrValues<Genre>(ids: fromJsonObject);
|
||||
break;
|
||||
case "involvedcompany":
|
||||
objectToStore = new IdentitiesOrValues<InvolvedCompany>(ids: fromJsonObject);
|
||||
break;
|
||||
case "multiplayermode":
|
||||
objectToStore = new IdentitiesOrValues<MultiplayerMode>(ids: fromJsonObject);
|
||||
break;
|
||||
case "platform":
|
||||
objectToStore = new IdentitiesOrValues<Platform>(ids: fromJsonObject);
|
||||
break;
|
||||
case "platformversion":
|
||||
objectToStore = new IdentitiesOrValues<PlatformVersion>(ids: fromJsonObject);
|
||||
break;
|
||||
case "platformwebsite":
|
||||
objectToStore = new IdentitiesOrValues<PlatformWebsite>(ids: fromJsonObject);
|
||||
break;
|
||||
case "platformversioncompany":
|
||||
objectToStore = new IdentitiesOrValues<PlatformVersionCompany>(ids: fromJsonObject);
|
||||
break;
|
||||
case "platformversionreleasedate":
|
||||
objectToStore = new IdentitiesOrValues<PlatformVersionReleaseDate>(ids: fromJsonObject);
|
||||
break;
|
||||
case "playerperspective":
|
||||
objectToStore = new IdentitiesOrValues<PlayerPerspective>(ids: fromJsonObject);
|
||||
break;
|
||||
case "releasedate":
|
||||
objectToStore = new IdentitiesOrValues<ReleaseDate>(ids: fromJsonObject);
|
||||
break;
|
||||
case "screenshot":
|
||||
objectToStore = new IdentitiesOrValues<Screenshot>(ids: fromJsonObject);
|
||||
break;
|
||||
case "theme":
|
||||
objectToStore = new IdentitiesOrValues<Theme>(ids: fromJsonObject);
|
||||
break;
|
||||
case "website":
|
||||
objectToStore = new IdentitiesOrValues<Website>(ids: fromJsonObject);
|
||||
break;
|
||||
}
|
||||
|
||||
if (objectToStore != null)
|
||||
{
|
||||
property.SetValue(EndpointType, objectToStore);
|
||||
}
|
||||
|
||||
break;
|
||||
case "int32[]":
|
||||
Int32[] fromJsonObject_int32Array = Newtonsoft.Json.JsonConvert.DeserializeObject<Int32[]>((string)dataRow[property.Name]);
|
||||
if (fromJsonObject_int32Array != null)
|
||||
{
|
||||
property.SetValue(EndpointType, fromJsonObject_int32Array);
|
||||
}
|
||||
break;
|
||||
case "[igdb.models.category":
|
||||
property.SetValue(EndpointType, (Category)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.gamestatus":
|
||||
property.SetValue(EndpointType, (GameStatus)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.ageratingcategory":
|
||||
property.SetValue(EndpointType, (AgeRatingCategory)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.ageratingcontentdescriptioncategory":
|
||||
property.SetValue(EndpointType, (AgeRatingContentDescriptionCategory)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.ageratingtitle":
|
||||
property.SetValue(EndpointType, (AgeRatingTitle)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.externalcategory":
|
||||
property.SetValue(EndpointType, (ExternalCategory)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.startdatecategory":
|
||||
property.SetValue(EndpointType, (StartDateCategory)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.releasedateregion":
|
||||
property.SetValue(EndpointType, (ReleaseDateRegion)dataRow[property.Name]);
|
||||
break;
|
||||
case "[igdb.models.releasedatecategory":
|
||||
property.SetValue(EndpointType, (ReleaseDateCategory)dataRow[property.Name]);
|
||||
break;
|
||||
case "[gaseous_server.classes.metadata.agegroups+agerestrictiongroupings":
|
||||
property.SetValue(EndpointType, (AgeGroups.AgeRestrictionGroupings)dataRow[property.Name]);
|
||||
break;
|
||||
default:
|
||||
property.SetValue(EndpointType, dataRow[property.Name]);
|
||||
break;
|
||||
default:
|
||||
// check if property is an enum
|
||||
if (property.PropertyType.IsEnum)
|
||||
{
|
||||
property.SetValue(EndpointType, Enum.Parse(property.PropertyType, value.ToString()));
|
||||
}
|
||||
else if (Common.IsNullableEnum(property.PropertyType))
|
||||
{
|
||||
property.SetValue(EndpointType, Enum.Parse(Nullable.GetUnderlyingType(property.PropertyType), value.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
property.SetValue(EndpointType, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error occurred in column " + property.Name);
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,7 +372,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
return EndpointType;
|
||||
}
|
||||
|
||||
private static void StoreRelations(string PrimaryTable, string SecondaryTable, long ObjectId, string Relations)
|
||||
private static void StoreRelations(HasheousClient.Models.MetadataSources SourceType, string PrimaryTable, string SecondaryTable, long ObjectId, string Relations)
|
||||
{
|
||||
string TableName = "Relation_" + PrimaryTable + "_" + SecondaryTable;
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
@@ -404,7 +381,13 @@ namespace gaseous_server.Classes.Metadata
|
||||
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);";
|
||||
sql = @"
|
||||
CREATE TABLE
|
||||
`" + Config.DatabaseConfiguration.DatabaseName + "`.`" + TableName + @"`
|
||||
(`" + PrimaryTable + @"SourceId` INT NOT NULL,
|
||||
`" + PrimaryTable + @"Id` BIGINT NOT NULL,
|
||||
`" + SecondaryTable + @"Id` BIGINT NOT NULL,
|
||||
PRIMARY KEY (`" + PrimaryTable + "SourceId`, `" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`), INDEX `idx_PrimaryColumn` (`" + PrimaryTable + "Id` ASC) VISIBLE);";
|
||||
db.ExecuteCMD(sql);
|
||||
}
|
||||
else
|
||||
@@ -420,10 +403,13 @@ namespace gaseous_server.Classes.Metadata
|
||||
long[] RelationValues = Newtonsoft.Json.JsonConvert.DeserializeObject<long[]>(Relations);
|
||||
foreach (long RelationValue in RelationValues)
|
||||
{
|
||||
sql = "INSERT INTO " + TableName + " (`" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`) VALUES (@objectid, @relationvalue);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("objectid", ObjectId);
|
||||
dbDict.Add("relationvalue", RelationValue);
|
||||
sql = "INSERT INTO " + TableName + " (`" + PrimaryTable + "SourceId`, `" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`) VALUES (@sourceid, @objectid, @relationvalue);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "sourceid", SourceType },
|
||||
{ "objectid", ObjectId },
|
||||
{ "relationvalue", RelationValue }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
@@ -445,7 +431,13 @@ namespace gaseous_server.Classes.Metadata
|
||||
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);";
|
||||
sql = @"
|
||||
CREATE TABLE
|
||||
`" + Config.DatabaseConfiguration.DatabaseName + "`.`" + TableName + @"`
|
||||
(`" + PrimaryTable + @"SourceId` INT NOT NULL,
|
||||
`" + PrimaryTable + @"Id` BIGINT NOT NULL,
|
||||
`" + SecondaryTable + @"Id` BIGINT NOT NULL,
|
||||
PRIMARY KEY (`" + PrimaryTable + "SourceId`, `" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`), INDEX `idx_PrimaryColumn` (`" + PrimaryTable + "Id` ASC) VISIBLE);";
|
||||
db.ExecuteCMD(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
|
||||
namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Themes
|
||||
{
|
||||
const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
public const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;";
|
||||
|
||||
public Themes()
|
||||
{
|
||||
}
|
||||
|
||||
public static Theme? GetGame_Themes(long? Id)
|
||||
public static Theme? GetGame_Themes(HasheousClient.Models.MetadataSources SourceType, long? Id)
|
||||
{
|
||||
if ((Id == 0) || (Id == null))
|
||||
{
|
||||
@@ -21,90 +20,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<Theme> RetVal = _GetGame_Themes(SearchUsing.id, Id);
|
||||
return RetVal.Result;
|
||||
Theme? RetVal = Metadata.GetMetadata<Theme>(SourceType, (long)Id, false);
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static Theme GetGame_Themes(string Slug)
|
||||
{
|
||||
Task<Theme> RetVal = _GetGame_Themes(SearchUsing.slug, Slug);
|
||||
return RetVal.Result;
|
||||
}
|
||||
|
||||
private static async Task<Theme> _GetGame_Themes(SearchUsing searchUsing, object searchValue)
|
||||
{
|
||||
// check database first
|
||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||
if (searchUsing == SearchUsing.id)
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Theme", (long)searchValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheStatus = Storage.GetCacheStatus("Theme", (string)searchValue);
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
}
|
||||
|
||||
Theme returnValue = new Theme();
|
||||
bool forceImageDownload = false;
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue);
|
||||
forceImageDownload = true;
|
||||
break;
|
||||
case Storage.CacheStatus.Expired:
|
||||
try
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
return returnValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
return Storage.GetCacheValue<Theme>(returnValue, "id", (long)searchValue);
|
||||
}
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Theme>(returnValue, "id", (long)searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private enum SearchUsing
|
||||
{
|
||||
id,
|
||||
slug
|
||||
}
|
||||
|
||||
private static async Task<Theme> GetObjectFromServer(string WhereClause)
|
||||
{
|
||||
// get Game_Themes metadata
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Theme>(IGDBClient.Endpoints.Themes, fieldList, WhereClause);
|
||||
var result = results.First();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,364 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using HasheousClient.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class MetadataManagement : QueueItemStatus
|
||||
{
|
||||
private static bool Processing = false;
|
||||
|
||||
public enum MetadataMapSupportDataTypes
|
||||
{
|
||||
UserManualLink
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new metadata map, if one with the same platformId and name does not already exist.
|
||||
/// </summary>
|
||||
/// <param name="platformId">
|
||||
/// The ID of the platform to which the metadata map belongs.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// The name of the metadata map.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The ID of the new metadata map, or the ID of the existing metadata map if one already exists.
|
||||
/// </returns>
|
||||
public static MetadataMap? NewMetadataMap(long platformId, string name)
|
||||
{
|
||||
if (Processing == true)
|
||||
{
|
||||
// loop until processing = false
|
||||
while (Processing == true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
Processing = true;
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@platformId", platformId },
|
||||
{ "@name", name }
|
||||
};
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
// check if the metadata map already exists
|
||||
MetadataMap? existingMetadataMap = GetMetadataMap(platformId, name);
|
||||
if (existingMetadataMap != null)
|
||||
{
|
||||
Processing = false;
|
||||
return existingMetadataMap;
|
||||
}
|
||||
|
||||
// create the metadata map
|
||||
sql = "INSERT INTO MetadataMap (PlatformId, SignatureGameName) VALUES (@platformId, @name); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
long metadataMapId = (long)dt.Rows[0][0];
|
||||
|
||||
// create dummy game metadata item and capture id
|
||||
sql = "INSERT INTO Game (SourceId, Name, dateAdded, lastUpdated) VALUES (@sourceid, @name, @dateadded, @lastupdated); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@sourceid", HasheousClient.Models.MetadataSources.None },
|
||||
{ "@name", name },
|
||||
{ "@dateadded", DateTime.UtcNow },
|
||||
{ "@lastupdated", DateTime.UtcNow }
|
||||
};
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
long gameId = (long)dt.Rows[0][0];
|
||||
|
||||
// add default metadata sources
|
||||
AddMetadataMapItem(metadataMapId, HasheousClient.Models.MetadataSources.None, gameId, true);
|
||||
|
||||
// return the new metadata map
|
||||
MetadataMap RetVal = GetMetadataMap(metadataMapId);
|
||||
Processing = false;
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a metadata map item to the database.
|
||||
/// </summary>
|
||||
/// <param name="metadataMapId">
|
||||
/// The ID of the metadata map to which the item belongs.
|
||||
/// </param>
|
||||
/// <param name="sourceType">
|
||||
/// The type of the metadata source.
|
||||
/// </param>
|
||||
/// <param name="sourceId">
|
||||
/// The ID of the metadata source.
|
||||
/// </param>
|
||||
/// <param name="preferred">
|
||||
/// Whether the metadata source is preferred.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// If the metadata source is preferred, all other metadata sources for the same metadata map will be set to not preferred.
|
||||
/// </remarks>
|
||||
public static void AddMetadataMapItem(long metadataMapId, HasheousClient.Models.MetadataSources sourceType, long sourceId, bool preferred)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@metadataMapId", metadataMapId },
|
||||
{ "@sourceType", sourceType },
|
||||
{ "@sourceId", sourceId },
|
||||
{ "@preferred", preferred },
|
||||
{ "@processedatimport", false }
|
||||
};
|
||||
|
||||
if (preferred == true)
|
||||
{
|
||||
// set all other items to not preferred
|
||||
sql = "UPDATE MetadataMapBridge SET Preferred = 0 WHERE ParentMapId = @metadataMapId;";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
sql = "INSERT INTO MetadataMapBridge (ParentMapId, MetadataSourceType, MetadataSourceId, Preferred, ProcessedAtImport) VALUES (@metadataMapId, @sourceType, @sourceId, @preferred, @processedatimport);";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public static void UpdateMetadataMapItem(long metadataMapId, HasheousClient.Models.MetadataSources SourceType, long sourceId, bool? preferred = null)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@metadataMapId", metadataMapId },
|
||||
{ "@sourceType", SourceType },
|
||||
{ "@sourceId", sourceId },
|
||||
{ "@preferred", preferred }
|
||||
};
|
||||
|
||||
if (preferred == true)
|
||||
{
|
||||
// set all other items to not preferred
|
||||
sql = "UPDATE MetadataMapBridge SET Preferred = 0 WHERE ParentMapId = @metadataMapId; UPDATE MetadataMapBridge SET MetadataSourceId = @sourceId, Preferred = @preferred WHERE ParentMapId = @metadataMapId AND MetadataSourceType = @sourceType;";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "UPDATE MetadataMapBridge SET MetadataSourceId = @sourceId WHERE ParentMapId = @metadataMapId AND MetadataSourceType = @sourceType;";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a metadata map from the database.
|
||||
/// </summary>
|
||||
/// <param name="platformId">
|
||||
/// The ID of the platform to which the metadata map belongs.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// The name of the metadata map.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The metadata map, or null if it does not exist.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method will return the first metadata map found with the given platformId and name.
|
||||
/// </remarks>
|
||||
public static MetadataMap? GetMetadataMap(long platformId, string name)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@platformId", platformId },
|
||||
{ "@name", name.Trim() }
|
||||
};
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
sql = "SELECT Id FROM MetadataMap WHERE PlatformId = @platformId AND SignatureGameName = @name;";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
return GetMetadataMap((long)dt.Rows[0]["Id"]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a metadata map from the database.
|
||||
/// </summary>
|
||||
/// <param name="metadataMapId">
|
||||
/// The ID of the metadata map.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The metadata map, or null if it does not exist.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method will return the metadata map with the given ID.
|
||||
/// </remarks>
|
||||
public static MetadataMap? GetMetadataMap(long metadataMapId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@metadataMapId", metadataMapId }
|
||||
};
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
sql = "SELECT * FROM MetadataMap WHERE Id = @metadataMapId;";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
MetadataMap metadataMap = new MetadataMap()
|
||||
{
|
||||
Id = (long)dt.Rows[0]["Id"],
|
||||
PlatformId = (long)dt.Rows[0]["PlatformId"],
|
||||
SignatureGameName = dt.Rows[0]["SignatureGameName"].ToString(),
|
||||
MetadataMapItems = new List<MetadataMap.MetadataMapItem>()
|
||||
};
|
||||
|
||||
sql = "SELECT * FROM MetadataMapBridge WHERE ParentMapId = @metadataMapId;";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
MetadataMap.MetadataMapItem metadataMapItem = new MetadataMap.MetadataMapItem()
|
||||
{
|
||||
SourceType = (HasheousClient.Models.MetadataSources)dr["MetadataSourceType"],
|
||||
SourceId = (long)dr["MetadataSourceId"],
|
||||
Preferred = (bool)dr["Preferred"]
|
||||
};
|
||||
|
||||
metadataMap.MetadataMapItems.Add(metadataMapItem);
|
||||
}
|
||||
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetMetadataSupportData(long metadataMapId, MetadataMapSupportDataTypes dataType, string data)
|
||||
{
|
||||
// verify the metadata map exists
|
||||
MetadataMap? metadataMap = GetMetadataMap(metadataMapId);
|
||||
if (metadataMap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@metadataMapId", metadataMapId },
|
||||
{ "@data", data }
|
||||
};
|
||||
|
||||
switch (dataType)
|
||||
{
|
||||
case MetadataMapSupportDataTypes.UserManualLink:
|
||||
sql = "UPDATE MetadataMap SET UserManualLink = @data WHERE Id = @metadataMapId;";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MetadataMapItem for the provided metadata source, and source id
|
||||
/// </summary>
|
||||
/// <param name="sourceType">
|
||||
/// The type of the metadata source.
|
||||
/// </param>
|
||||
/// <param name="sourceId">
|
||||
/// The ID of the metadata source.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The MetadataMapItem, or null if it does not exist.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method will return the MetadataMapItem with the given sourceType and sourceId.
|
||||
/// </remarks>
|
||||
public static MetadataMap.MetadataMapItem? GetMetadataMapFromSourceId(HasheousClient.Models.MetadataSources sourceType, long sourceId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@sourceType", sourceType },
|
||||
{ "@sourceId", sourceId }
|
||||
};
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
sql = "SELECT * FROM MetadataMapBridge WHERE MetadataSourceType = @sourceType AND MetadataSourceId = @sourceId;";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
MetadataMap.MetadataMapItem metadataMapItem = new MetadataMap.MetadataMapItem()
|
||||
{
|
||||
SourceType = (HasheousClient.Models.MetadataSources)dt.Rows[0]["MetadataSourceType"],
|
||||
SourceId = (long)dt.Rows[0]["MetadataSourceId"],
|
||||
Preferred = (bool)dt.Rows[0]["Preferred"]
|
||||
};
|
||||
|
||||
return metadataMapItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Id of the MetadataMap for the provided metadata source, and source id
|
||||
/// </summary>
|
||||
/// <param name="sourceType">
|
||||
/// The type of the metadata source.
|
||||
/// </param>
|
||||
/// <param name="sourceId">
|
||||
/// The ID of the metadata source.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The ID of the MetadataMap, or null if it does not exist.
|
||||
/// </returns>
|
||||
public static long? GetMetadataMapIdFromSourceId(HasheousClient.Models.MetadataSources sourceType, long sourceId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>()
|
||||
{
|
||||
{ "@sourceType", sourceType },
|
||||
{ "@sourceId", sourceId }
|
||||
};
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
sql = "SELECT * FROM MetadataMapBridge WHERE MetadataSourceType = @sourceType AND MetadataSourceId = @sourceId;";
|
||||
dt = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
return (long)dt.Rows[0]["ParentMapId"];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RefreshMetadata(bool forceRefresh = false)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
DataTable dt = new DataTable();
|
||||
|
||||
|
||||
// disabling forceRefresh
|
||||
forceRefresh = false;
|
||||
|
||||
// update platforms
|
||||
// update platform metadata
|
||||
sql = "SELECT Id, `Name` FROM Platform;";
|
||||
dt = db.ExecuteCMD(sql);
|
||||
|
||||
@@ -27,7 +370,23 @@ namespace gaseous_server.Classes
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing metadata for platform " + dr["name"] + " (" + dr["id"] + ")");
|
||||
Metadata.Platforms.GetPlatform((long)dr["id"], true);
|
||||
|
||||
HasheousClient.Models.MetadataSources metadataSource = HasheousClient.Models.MetadataSources.None;
|
||||
|
||||
// fetch the platform metadata
|
||||
Platform platform = Metadata.Platforms.GetPlatform((long)dr["id"], metadataSource);
|
||||
|
||||
// fetch the platform metadata from Hasheous
|
||||
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||
{
|
||||
Communications.PopulateHasheousPlatformData((long)dr["id"]);
|
||||
}
|
||||
|
||||
// force platformLogo refresh
|
||||
if (platform.PlatformLogo != null)
|
||||
{
|
||||
Metadata.PlatformLogos.GetPlatformLogo(platform.PlatformLogo, metadataSource);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -38,7 +397,68 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
ClearStatus();
|
||||
|
||||
// update games
|
||||
// update rom signatures - only valid if Haseheous is enabled
|
||||
if (Config.MetadataConfiguration.SignatureSource == MetadataModel.SignatureSources.Hasheous)
|
||||
{
|
||||
// get all ROMs in the database
|
||||
sql = "SELECT * FROM view_Games_Roms;";
|
||||
dt = db.ExecuteCMD(sql);
|
||||
|
||||
StatusCounter = 1;
|
||||
foreach (DataRow dr in dt.Rows)
|
||||
{
|
||||
SetStatus(StatusCounter, dt.Rows.Count, "Refreshing signature for ROM " + dr["Name"]);
|
||||
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing signature for ROM " + dr["Name"] + " (" + dr["Id"] + ")");
|
||||
|
||||
// get the hash of the ROM from the datarow
|
||||
string? md5 = dr["MD5"] == DBNull.Value ? null : dr["MD5"].ToString();
|
||||
string? sha1 = dr["SHA1"] == DBNull.Value ? null : dr["SHA1"].ToString();
|
||||
Common.hashObject hash = new Common.hashObject();
|
||||
if (md5 != null)
|
||||
{
|
||||
hash.md5hash = md5;
|
||||
}
|
||||
if (sha1 != null)
|
||||
{
|
||||
hash.sha1hash = sha1;
|
||||
}
|
||||
|
||||
// get the library for the ROM
|
||||
GameLibrary.LibraryItem library = GameLibrary.GetLibrary((int)dr["LibraryId"]);
|
||||
|
||||
// get the signature for the ROM
|
||||
FileInfo fi = new FileInfo(dr["Path"].ToString());
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
gaseous_server.Models.Signatures_Games signature = fileSignature.GetFileSignature(library, hash, fi, fi.FullName);
|
||||
|
||||
// validate the signature - if it is invalid, skip the rest of the loop
|
||||
// validation rules: 1) signature must not be null, 2) signature must have a platform ID
|
||||
if (signature == null || signature.Flags.PlatformId == null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "Signature for " + dr["RomName"] + " is invalid - skipping metadata refresh");
|
||||
StatusCounter += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// update the signature in the database
|
||||
Platform? signaturePlatform = Metadata.Platforms.GetPlatform((long)signature.Flags.PlatformId);
|
||||
ImportGame.StoreGame(library, hash, signature, signaturePlatform, fi.FullName, (long)dr["Id"], false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Metadata Refresh", "An error occurred while refreshing metadata for " + dr["RomName"], ex);
|
||||
}
|
||||
|
||||
StatusCounter += 1;
|
||||
}
|
||||
ClearStatus();
|
||||
}
|
||||
|
||||
|
||||
// update game metadata
|
||||
if (forceRefresh == true)
|
||||
{
|
||||
// when forced, only update games with ROMs for
|
||||
@@ -47,7 +467,7 @@ namespace gaseous_server.Classes
|
||||
else
|
||||
{
|
||||
// when run normally, update all games (since this will honour cache timeouts)
|
||||
sql = "SELECT Id, `Name` FROM Game;";
|
||||
sql = "SELECT DISTINCT MetadataSourceId AS `Id`, MetadataSourceType AS `GameIdType`, SignatureGameName AS `Name` FROM gaseous.view_MetadataMap;";
|
||||
}
|
||||
dt = db.ExecuteCMD(sql);
|
||||
|
||||
@@ -58,8 +478,111 @@ namespace gaseous_server.Classes
|
||||
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing metadata for game " + dr["name"] + " (" + dr["id"] + ")");
|
||||
Metadata.Games.GetGame((long)dr["id"], true, false, true);
|
||||
MetadataSources metadataSource;
|
||||
if (dr["GameIdType"] == DBNull.Value)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Unable to refresh metadata for game " + dr["name"] + " (" + dr["id"] + ") - no source type specified");
|
||||
}
|
||||
else
|
||||
{
|
||||
metadataSource = (MetadataSources)Enum.Parse(typeof(MetadataSources), dr["GameIdType"].ToString());
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Metadata Refresh", "(" + StatusCounter + "/" + dt.Rows.Count + "): Refreshing metadata for game " + dr["name"] + " (" + dr["id"] + ") using source " + metadataSource.ToString());
|
||||
HasheousClient.Models.Metadata.IGDB.Game game = Metadata.Games.GetGame(metadataSource, (long)dr["id"]);
|
||||
|
||||
// get supporting metadata
|
||||
if (game != null)
|
||||
{
|
||||
if (game.AgeRatings != null)
|
||||
{
|
||||
foreach (long ageRatingId in game.AgeRatings)
|
||||
{
|
||||
AgeRating ageRating = Metadata.AgeRatings.GetAgeRating(metadataSource, ageRatingId);
|
||||
if (ageRating.ContentDescriptions != null)
|
||||
{
|
||||
foreach (long ageRatingContentDescriptionId in ageRating.ContentDescriptions)
|
||||
{
|
||||
Metadata.AgeRatingContentDescriptions.GetAgeRatingContentDescriptions(metadataSource, ageRatingContentDescriptionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (game.AlternativeNames != null)
|
||||
{
|
||||
foreach (long alternateNameId in game.AlternativeNames)
|
||||
{
|
||||
Metadata.AlternativeNames.GetAlternativeNames(metadataSource, alternateNameId);
|
||||
}
|
||||
}
|
||||
if (game.Artworks != null)
|
||||
{
|
||||
foreach (long artworkId in game.Artworks)
|
||||
{
|
||||
Metadata.Artworks.GetArtwork(metadataSource, artworkId);
|
||||
}
|
||||
}
|
||||
if (game.Cover != null)
|
||||
{
|
||||
Metadata.Covers.GetCover(metadataSource, (long?)game.Cover);
|
||||
}
|
||||
if (game.GameModes != null)
|
||||
{
|
||||
foreach (long gameModeId in game.GameModes)
|
||||
{
|
||||
Metadata.GameModes.GetGame_Modes(metadataSource, gameModeId);
|
||||
}
|
||||
}
|
||||
if (game.Genres != null)
|
||||
{
|
||||
foreach (long genreId in game.Genres)
|
||||
{
|
||||
Metadata.Genres.GetGenres(metadataSource, genreId);
|
||||
}
|
||||
}
|
||||
if (game.Videos != null)
|
||||
{
|
||||
foreach (long gameVideoId in game.Videos)
|
||||
{
|
||||
Metadata.GamesVideos.GetGame_Videos(metadataSource, gameVideoId);
|
||||
}
|
||||
}
|
||||
if (game.MultiplayerModes != null)
|
||||
{
|
||||
foreach (long multiplayerModeId in game.MultiplayerModes)
|
||||
{
|
||||
Metadata.MultiplayerModes.GetGame_MultiplayerModes(metadataSource, multiplayerModeId);
|
||||
}
|
||||
}
|
||||
if (game.PlayerPerspectives != null)
|
||||
{
|
||||
foreach (long playerPerspectiveId in game.PlayerPerspectives)
|
||||
{
|
||||
Metadata.PlayerPerspectives.GetGame_PlayerPerspectives(metadataSource, playerPerspectiveId);
|
||||
}
|
||||
}
|
||||
if (game.ReleaseDates != null)
|
||||
{
|
||||
foreach (long releaseDateId in game.ReleaseDates)
|
||||
{
|
||||
Metadata.ReleaseDates.GetReleaseDates(metadataSource, releaseDateId);
|
||||
}
|
||||
}
|
||||
if (game.Screenshots != null)
|
||||
{
|
||||
foreach (long screenshotId in game.Screenshots)
|
||||
{
|
||||
Metadata.Screenshots.GetScreenshot(metadataSource, screenshotId);
|
||||
}
|
||||
}
|
||||
if (game.Themes != null)
|
||||
{
|
||||
foreach (long themeId in game.Themes)
|
||||
{
|
||||
Metadata.Themes.GetGame_Themes(metadataSource, themeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -69,7 +592,7 @@ namespace gaseous_server.Classes
|
||||
StatusCounter += 1;
|
||||
}
|
||||
ClearStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,21 @@ using System;
|
||||
using System.Data;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using Microsoft.VisualBasic;
|
||||
using IGDB.Models;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using System.IO.Compression;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
using gaseous_server.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class RomMediaGroup
|
||||
public class RomMediaGroup
|
||||
{
|
||||
public class InvalidMediaGroupId : Exception
|
||||
{
|
||||
{
|
||||
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
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);
|
||||
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>
|
||||
{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", userid }
|
||||
{ "userid", userid },
|
||||
{ "platformid", PlatformId }
|
||||
};
|
||||
|
||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -165,7 +193,7 @@ namespace gaseous_server.Classes
|
||||
public static void DeleteMediaGroup(long Id)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; 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; DELETE FROM User_GameFavouriteRoms WHERE RomId = @id AND IsMediaGroup = 1; DELETE FROM User_RecentPlayedRoms 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>();
|
||||
dbDict.Add("id", Id);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -180,22 +208,42 @@ namespace gaseous_server.Classes
|
||||
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
||||
{
|
||||
bool hasSaveStates = false;
|
||||
if (row.Table.Columns.Contains("GameStateRomId"))
|
||||
{
|
||||
if (row["GameStateRomId"] != DBNull.Value)
|
||||
{
|
||||
hasSaveStates = true;
|
||||
}
|
||||
}
|
||||
if (row.Table.Columns.Contains("GameStateRomId"))
|
||||
{
|
||||
if (row["GameStateRomId"] != DBNull.Value)
|
||||
{
|
||||
hasSaveStates = true;
|
||||
}
|
||||
}
|
||||
|
||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
||||
mediaGroupItem.Id = (long)row["Id"];
|
||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
||||
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
||||
mediaGroupItem.GameId = (long)row["GameId"];
|
||||
mediaGroupItem.RomIds = new List<long>();
|
||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
||||
mediaGroupItem.HasSaveStates = hasSaveStates;
|
||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem
|
||||
{
|
||||
Id = (long)row["Id"],
|
||||
Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"],
|
||||
PlatformId = (long)row["PlatformId"],
|
||||
GameId = (long)row["GameId"],
|
||||
RomIds = new List<long>(),
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -260,8 +296,9 @@ namespace gaseous_server.Classes
|
||||
GameRomMediaGroupItem mediaGroupItem = GetMediaGroup(Id);
|
||||
if (mediaGroupItem.Status == GameRomMediaGroupItem.GroupBuildStatus.WaitingForBuild)
|
||||
{
|
||||
Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false);
|
||||
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false);
|
||||
MetadataMap.MetadataMapItem metadataMap = Classes.MetadataManagement.GetMetadataMap(mediaGroupItem.GameId).PreferredMetadataMapItem;
|
||||
Models.Game GameObject = Games.GetGame(metadataMap.SourceType, metadataMap.SourceId);
|
||||
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId);
|
||||
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(mediaGroupItem.PlatformId);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name);
|
||||
@@ -301,7 +338,7 @@ namespace gaseous_server.Classes
|
||||
if (File.Exists(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);
|
||||
|
||||
@@ -511,16 +548,17 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
public class GameRomMediaGroupItem
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public long PlatformId { get; set; }
|
||||
public string Platform {
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public long PlatformId { get; set; }
|
||||
public string Platform
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Platforms.GetPlatform(PlatformId, false).Name;
|
||||
return Platforms.GetPlatform(PlatformId).Name;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -528,37 +566,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 bool HasSaveStates { get; set; } = false;
|
||||
private GroupBuildStatus _Status { get; set; }
|
||||
public GroupBuildStatus Status {
|
||||
get
|
||||
{
|
||||
if (_Status == GroupBuildStatus.Completed)
|
||||
{
|
||||
if (File.Exists(MediaGroupZipPath))
|
||||
{
|
||||
return GroupBuildStatus.Completed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GroupBuildStatus.NoStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _Status;
|
||||
}
|
||||
}
|
||||
public bool RomUserLastUsed { get; set; }
|
||||
public bool RomUserFavourite { get; set; }
|
||||
private GroupBuildStatus _Status { get; set; }
|
||||
public GroupBuildStatus Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Status == GroupBuildStatus.Completed)
|
||||
{
|
||||
if (File.Exists(MediaGroupZipPath))
|
||||
{
|
||||
return GroupBuildStatus.Completed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GroupBuildStatus.NoStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _Status;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
_Status = value;
|
||||
}
|
||||
}
|
||||
public long? Size {
|
||||
get
|
||||
}
|
||||
public long? Size
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Status == GroupBuildStatus.Completed)
|
||||
{
|
||||
@@ -577,15 +618,15 @@ namespace gaseous_server.Classes
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal string MediaGroupZipPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, Id + ".zip");
|
||||
}
|
||||
}
|
||||
public enum GroupBuildStatus
|
||||
}
|
||||
internal string MediaGroupZipPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, Id + ".zip");
|
||||
}
|
||||
}
|
||||
public enum GroupBuildStatus
|
||||
{
|
||||
NoStatus = 0,
|
||||
WaitingForBuild = 1,
|
||||
@@ -593,6 +634,6 @@ namespace gaseous_server.Classes
|
||||
Completed = 3,
|
||||
Failed = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ using System.Data;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using static gaseous_server.Classes.RomMediaGroup;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using static HasheousClient.Models.FixMatchModel;
|
||||
using NuGet.Protocol.Core.Types;
|
||||
using static gaseous_server.Classes.FileSignature;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -40,43 +42,88 @@ namespace gaseous_server.Classes
|
||||
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.MetadataMapId
|
||||
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.MetadataMapId
|
||||
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId
|
||||
AND User_GameFavouriteRoms.RomId = Games_Roms.Id
|
||||
AND User_GameFavouriteRoms.IsMediaGroup = 0
|
||||
";
|
||||
}
|
||||
|
||||
// platform query
|
||||
sqlPlatform = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;";
|
||||
|
||||
if (PlatformId == -1)
|
||||
{
|
||||
// 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 view_Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON view_Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (view_Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE view_Games_Roms.MetadataMapId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, view_Games_Roms.`Name`;";
|
||||
|
||||
// count query
|
||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
||||
sqlCount = "SELECT COUNT(view_Games_Roms.Id) AS RomCount FROM view_Games_Roms WHERE view_Games_Roms.MetadataMapId = @id" + NameSearchWhere + ";";
|
||||
}
|
||||
else
|
||||
{
|
||||
// data query
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, GameState.RomId AS SavedStateRomId FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
sql = @"
|
||||
SELECT DISTINCT
|
||||
Games_Roms.*,
|
||||
Platform.`Name` AS platformname,
|
||||
view_GamesWithRoms.`Name` AS gamename,
|
||||
GameState.RomId AS SavedStateRomId,
|
||||
CONCAT(`GameLibraries`.`Path`,
|
||||
'/',
|
||||
`Games_Roms`.`RelativePath`) AS `Path`,
|
||||
`GameLibraries`.`Name` AS `LibraryName`
|
||||
" + UserFields + @"
|
||||
FROM
|
||||
Games_Roms
|
||||
JOIN
|
||||
GameLibraries ON Games_Roms.LibraryId = GameLibraries.Id
|
||||
LEFT JOIN
|
||||
Platform ON Games_Roms.PlatformId = Platform.Id AND Platform.SourceId = @platformsource
|
||||
LEFT JOIN
|
||||
view_GamesWithRoms ON view_GamesWithRoms.MetadataMapId = Games_Roms.MetadataMapId
|
||||
LEFT JOIN
|
||||
GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + @"
|
||||
WHERE
|
||||
Games_Roms.MetadataMapId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + @"
|
||||
ORDER BY
|
||||
Platform.`Name`, Games_Roms.`Name`;
|
||||
";
|
||||
|
||||
// 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.MetadataMapId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
||||
|
||||
dbDict.Add("platformid", PlatformId);
|
||||
dbDict.Add("platformsource", (int)HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict)[0];
|
||||
DataTable platformDT = db.ExecuteCMD(sqlPlatform, dbDict);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks));
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
// set count of roms
|
||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks))[0];
|
||||
GameRoms.Count = int.Parse((string)rowCount["RomCount"]);
|
||||
|
||||
int pageOffset = pageSize * (pageNumber - 1);
|
||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||
{
|
||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||
|
||||
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
||||
{
|
||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||
GameRoms.GameRomItems.Add(gameRomItem);
|
||||
}
|
||||
}
|
||||
@@ -92,7 +139,7 @@ namespace gaseous_server.Classes
|
||||
public static GameRomItem GetRom(long RomId)
|
||||
{
|
||||
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 DISTINCT view_Games_Roms.*, Platform.`Name` AS platformname, view_GamesWithRoms.`Name` AS gamename FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN view_GamesWithRoms ON view_Games_Roms.MetadataMapId = view_GamesWithRoms.MetadataMapId WHERE view_Games_Roms.Id = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -112,7 +159,7 @@ namespace gaseous_server.Classes
|
||||
public static GameRomItem GetRom(string MD5)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.MD5 = @id";
|
||||
string sql = "SELECT DISTINCT view_Games_Roms.*, Platform.`Name` AS platformname, view_GamesWithRoms.`Name` AS gamename FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN view_GamesWithRoms ON view_Games_Roms.MetadataMapId = view_GamesWithRoms.MetadataMapId WHERE view_Games_Roms.MD5 = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", MD5);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -132,13 +179,13 @@ namespace gaseous_server.Classes
|
||||
public static GameRomItem UpdateRom(long RomId, long PlatformId, long GameId)
|
||||
{
|
||||
// ensure metadata for platformid is present
|
||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
HasheousClient.Models.Metadata.IGDB.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
// ensure metadata for gameid is present
|
||||
IGDB.Models.Game game = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
Models.Game game = Classes.Metadata.Games.GetGame(HasheousClient.Models.MetadataSources.IGDB, GameId);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid WHERE Id = @id";
|
||||
string sql = "UPDATE Games_Roms SET PlatformId=@platformid, MetadataMapId=@gameid WHERE Id = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
dbDict.Add("platformid", PlatformId);
|
||||
@@ -147,6 +194,54 @@ namespace gaseous_server.Classes
|
||||
|
||||
GameRomItem rom = GetRom(RomId);
|
||||
|
||||
// send update to Hasheous if enabled
|
||||
if (PlatformId != 0 && GameId != 0)
|
||||
{
|
||||
if (Config.MetadataConfiguration.HasheousSubmitFixes == true)
|
||||
{
|
||||
if (
|
||||
Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous &&
|
||||
(
|
||||
Config.MetadataConfiguration.HasheousAPIKey != null &&
|
||||
Config.MetadataConfiguration.HasheousAPIKey != "")
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
// find signature used for identifing the rom
|
||||
string md5String = rom.Md5;
|
||||
string sha1String = rom.Sha1;
|
||||
if (rom.Attributes.ContainsKey("ZipContents"))
|
||||
{
|
||||
bool selectorFound = false;
|
||||
List<ArchiveData> archiveDataValues = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ArchiveData>>(rom.Attributes["ZipContents"].ToString());
|
||||
foreach (ArchiveData archiveData in archiveDataValues)
|
||||
{
|
||||
if (archiveData.isSignatureSelector == true)
|
||||
{
|
||||
md5String = archiveData.MD5;
|
||||
sha1String = archiveData.SHA1;
|
||||
selectorFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HasheousClient.WebApp.HttpHelper.APIKey = Config.MetadataConfiguration.HasheousAPIKey;
|
||||
HasheousClient.WebApp.HttpHelper.ClientKey = Config.MetadataConfiguration.HasheousClientAPIKey;
|
||||
HasheousClient.Hasheous hasheousClient = new HasheousClient.Hasheous();
|
||||
List<MetadataMatch> metadataMatchList = new List<MetadataMatch>();
|
||||
metadataMatchList.Add(new MetadataMatch(HasheousClient.Models.MetadataSources.IGDB, platform.Slug, game.Slug));
|
||||
hasheousClient.FixMatch(new HasheousClient.Models.FixMatchModel(md5String, sha1String, metadataMatchList));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Fix Match", "An error occurred while sending a fixed match to Hasheous.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
@@ -161,7 +256,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
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; DELETE FROM User_GameFavouriteRoms WHERE RomId = @id AND IsMediaGroup = 0; DELETE FROM User_RecentPlayedRoms WHERE RomId = @id AND IsMediaGroup = 0; UPDATE UserTimeTracking SET PlatformId = NULL, IsMediaGroup = NULL, RomId = NULL WHERE RomId = @id AND IsMediaGroup = 0;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -179,38 +274,64 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, object> romAttributes = new Dictionary<string, object>();
|
||||
if (romDR["attributes"] != DBNull.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((string)romDR["attributes"] != "[ ]")
|
||||
{
|
||||
romAttributes = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>((string)romDR["attributes"]);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Roms", "Error parsing rom attributes: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
GameRomItem romItem = new GameRomItem
|
||||
{
|
||||
Id = (long)romDR["id"],
|
||||
PlatformId = (long)romDR["platformid"],
|
||||
Platform = (string)romDR["platformname"],
|
||||
MetadataMapId = (long)romDR["metadatamapid"],
|
||||
MetadataSource = (HasheousClient.Models.MetadataSources)(int)romDR["metadatasource"],
|
||||
GameId = (long)romDR["gameid"],
|
||||
Game = (string)Common.ReturnValueIfNull(romDR["gamename"], ""),
|
||||
Name = (string)romDR["name"],
|
||||
Size = (long)romDR["size"],
|
||||
Crc = ((string)romDR["crc"]).ToLower(),
|
||||
Md5 = ((string)romDR["md5"]).ToLower(),
|
||||
Sha1 = ((string)romDR["sha1"]).ToLower(),
|
||||
DevelopmentStatus = (string)romDR["developmentstatus"],
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(romDR["attributes"], "[ ]")),
|
||||
RomType = (HasheousClient.Models.LookupResponseModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||
Attributes = romAttributes,
|
||||
RomType = (HasheousClient.Models.SignatureModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||
RomTypeMedia = (string)romDR["romtypemedia"],
|
||||
MediaLabel = (string)romDR["medialabel"],
|
||||
Path = (string)romDR["path"],
|
||||
RelativePath = (string)romDR["relativepath"],
|
||||
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
|
||||
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
||||
HasSaveStates = hasSaveStates,
|
||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||
};
|
||||
|
||||
// check for a web emulator and update the romItem
|
||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
||||
romItem.RomUserLastUsed = false;
|
||||
if (romDR.Table.Columns.Contains("MostRecentRomId"))
|
||||
{
|
||||
if (platformMapping.IGDBId == romItem.PlatformId)
|
||||
if (romDR["MostRecentRomId"] != DBNull.Value)
|
||||
{
|
||||
if (platformMapping.WebEmulator != null)
|
||||
{
|
||||
romItem.Emulator = platformMapping.WebEmulator;
|
||||
}
|
||||
romItem.RomUserLastUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
romItem.RomUserFavourite = false;
|
||||
if (romDR.Table.Columns.Contains("FavouriteRomId"))
|
||||
{
|
||||
if (romDR["FavouriteRomId"] != DBNull.Value)
|
||||
{
|
||||
romItem.RomUserFavourite = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,16 +344,22 @@ namespace gaseous_server.Classes
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class GameRomItem : HasheousClient.Models.LookupResponseModel.RomItem
|
||||
public class GameRomItem : HasheousClient.Models.SignatureModel.RomItem
|
||||
{
|
||||
public long PlatformId { get; set; }
|
||||
public string Platform { get; set; }
|
||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||
public long MetadataMapId { get; set; }
|
||||
public HasheousClient.Models.MetadataSources MetadataSource { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public string Game { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public string? RelativePath { get; set; }
|
||||
public string? SignatureSourceGameTitle { get; set; }
|
||||
public bool HasSaveStates { get; set; } = false;
|
||||
public GameLibrary.LibraryItem Library { get; set; }
|
||||
public bool RomUserLastUsed { get; set; }
|
||||
public bool RomUserFavourite { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,21 +8,49 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
{
|
||||
public class XMLIngestor : QueueItemStatus
|
||||
{
|
||||
public void Import(string SearchPath, gaseous_signature_parser.parser.SignatureParser XMLType)
|
||||
public void Import(string SearchPath, string ProcessedDirectory, gaseous_signature_parser.parser.SignatureParser XMLType)
|
||||
{
|
||||
// connect to database
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string? XMLDBSearchPath = null;
|
||||
string? XMLDBProcessedDirectory = null;
|
||||
if (XMLType == gaseous_signature_parser.parser.SignatureParser.NoIntro)
|
||||
{
|
||||
XMLDBSearchPath = Path.Combine(SearchPath, "DB");
|
||||
XMLDBProcessedDirectory = Path.Combine(ProcessedDirectory, "DB");
|
||||
SearchPath = Path.Combine(SearchPath, "DAT");
|
||||
ProcessedDirectory = Path.Combine(ProcessedDirectory, "DAT");
|
||||
}
|
||||
|
||||
// process provided files
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing from " + SearchPath);
|
||||
if (!Directory.Exists(SearchPath))
|
||||
{
|
||||
Directory.CreateDirectory(SearchPath);
|
||||
}
|
||||
if (!Directory.Exists(ProcessedDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(ProcessedDirectory);
|
||||
}
|
||||
|
||||
string[] PathContents = Directory.GetFiles(SearchPath);
|
||||
Array.Sort(PathContents);
|
||||
|
||||
string[]? DBPathContents = null;
|
||||
if (XMLDBSearchPath != null)
|
||||
{
|
||||
if (!Directory.Exists(XMLDBSearchPath))
|
||||
{
|
||||
Directory.CreateDirectory(XMLDBSearchPath);
|
||||
}
|
||||
if (!Directory.Exists(XMLDBProcessedDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(XMLDBProcessedDirectory);
|
||||
}
|
||||
|
||||
DBPathContents = Directory.GetFiles(XMLDBSearchPath);
|
||||
}
|
||||
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
System.Data.DataTable sigDB;
|
||||
@@ -33,226 +61,380 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
|
||||
SetStatus(i + 1, PathContents.Length, "Processing signature file: " + XMLFile);
|
||||
|
||||
if (Common.SkippableFiles.Contains(Path.GetFileName(XMLFile), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Skipping file: " + XMLFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check xml file md5
|
||||
Common.hashObject hashObject = new Common.hashObject(XMLFile);
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("sourcemd5", hashObject.md5hash);
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "(" + (i + 1) + " / " + PathContents.Length + ") Processing " + XMLType.ToString() + " DAT file: " + XMLFile);
|
||||
|
||||
if (sigDB.Rows.Count == 0)
|
||||
string? DBFile = null;
|
||||
if (XMLDBSearchPath != null)
|
||||
{
|
||||
switch (XMLType)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing file: " + XMLFile);
|
||||
|
||||
// start parsing file
|
||||
gaseous_signature_parser.parser Parser = new gaseous_signature_parser.parser();
|
||||
RomSignatureObject Object = Parser.ParseSignatureDAT(XMLFile, XMLType);
|
||||
|
||||
// store in database
|
||||
string[] flipNameAndDescription = {
|
||||
"MAMEArcade",
|
||||
"MAMEMess"
|
||||
};
|
||||
|
||||
// store source object
|
||||
bool processGames = false;
|
||||
if (Object.SourceMd5 != null)
|
||||
case gaseous_signature_parser.parser.SignatureParser.NoIntro:
|
||||
for (UInt16 x = 0; x < DBPathContents.Length; x++)
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
string sourceUriStr = "";
|
||||
if (Object.Url != null)
|
||||
string tempDBFileName = Path.GetFileNameWithoutExtension(DBPathContents[x].Replace(" (DB Export)", ""));
|
||||
if (tempDBFileName == Path.GetFileNameWithoutExtension(XMLFile))
|
||||
{
|
||||
sourceUriStr = Object.Url.ToString();
|
||||
DBFile = DBPathContents[x];
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "Using DB file: " + DBFile);
|
||||
break;
|
||||
}
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(Object.Name, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(Object.Description, ""));
|
||||
dbDict.Add("category", Common.ReturnValueIfNull(Object.Category, ""));
|
||||
dbDict.Add("version", Common.ReturnValueIfNull(Object.Version, ""));
|
||||
dbDict.Add("author", Common.ReturnValueIfNull(Object.Author, ""));
|
||||
dbDict.Add("email", Common.ReturnValueIfNull(Object.Email, ""));
|
||||
dbDict.Add("homepage", Common.ReturnValueIfNull(Object.Homepage, ""));
|
||||
dbDict.Add("uri", sourceUriStr);
|
||||
dbDict.Add("sourcetype", Common.ReturnValueIfNull(Object.SourceType, ""));
|
||||
dbDict.Add("sourcemd5", Object.SourceMd5);
|
||||
dbDict.Add("sourcesha1", Object.SourceSHA1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check xml file md5
|
||||
Common.hashObject hashObject = new Common.hashObject(XMLFile);
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("sourcemd5", hashObject.md5hash);
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// start parsing file
|
||||
gaseous_signature_parser.parser Parser = new gaseous_signature_parser.parser();
|
||||
RomSignatureObject Object = Parser.ParseSignatureDAT(XMLFile, DBFile, XMLType);
|
||||
|
||||
// store in database
|
||||
string[] flipNameAndDescription = {
|
||||
"MAMEArcade",
|
||||
"MAMEMess"
|
||||
};
|
||||
|
||||
// store source object
|
||||
bool processGames = false;
|
||||
if (Object.SourceMd5 != null)
|
||||
{
|
||||
int sourceId = 0;
|
||||
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE `SourceMD5`=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "name", Common.ReturnValueIfNull(Object.Name, "") },
|
||||
{ "description", Common.ReturnValueIfNull(Object.Description, "") },
|
||||
{ "category", Common.ReturnValueIfNull(Object.Category, "") },
|
||||
{ "version", Common.ReturnValueIfNull(Object.Version, "") },
|
||||
{ "author", Common.ReturnValueIfNull(Object.Author, "") },
|
||||
{ "email", Common.ReturnValueIfNull(Object.Email, "") },
|
||||
{ "homepage", Common.ReturnValueIfNull(Object.Homepage, "") }
|
||||
};
|
||||
if (Object.Url == null)
|
||||
{
|
||||
dbDict.Add("uri", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("uri", Common.ReturnValueIfNull(Object.Url.ToString(), ""));
|
||||
}
|
||||
dbDict.Add("sourcetype", Common.ReturnValueIfNull(Object.SourceType, ""));
|
||||
dbDict.Add("sourcemd5", Object.SourceMd5);
|
||||
dbDict.Add("sourcesha1", Object.SourceSHA1);
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Sources (`Name`, `Description`, `Category`, `Version`, `Author`, `Email`, `Homepage`, `Url`, `SourceType`, `SourceMD5`, `SourceSHA1`) VALUES (@name, @description, @category, @version, @author, @email, @homepage, @uri, @sourcetype, @sourcemd5, @sourcesha1); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
|
||||
sourceId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
|
||||
processGames = true;
|
||||
}
|
||||
|
||||
if (processGames == true)
|
||||
{
|
||||
for (int x = 0; x < Object.Games.Count; ++x)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Sources (Name, Description, Category, Version, Author, Email, Homepage, Url, SourceType, SourceMD5, SourceSHA1) VALUES (@name, @description, @category, @version, @author, @email, @homepage, @uri, @sourcetype, @sourcemd5, @sourcesha1)";
|
||||
RomSignatureObject.Game gameObject = Object.Games[x];
|
||||
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
processGames = true;
|
||||
}
|
||||
|
||||
if (processGames == true)
|
||||
{
|
||||
for (int x = 0; x < Object.Games.Count; ++x)
|
||||
// set up game dictionary
|
||||
dbDict = new Dictionary<string, object>();
|
||||
if (flipNameAndDescription.Contains(Object.SourceType))
|
||||
{
|
||||
RomSignatureObject.Game gameObject = Object.Games[x];
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(gameObject.Description, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(gameObject.Name, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(gameObject.Name, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(gameObject.Description, ""));
|
||||
}
|
||||
dbDict.Add("year", Common.ReturnValueIfNull(gameObject.Year, ""));
|
||||
dbDict.Add("publisher", Common.ReturnValueIfNull(gameObject.Publisher, ""));
|
||||
dbDict.Add("demo", (int)gameObject.Demo);
|
||||
dbDict.Add("system", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||
dbDict.Add("platform", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||
dbDict.Add("systemvariant", Common.ReturnValueIfNull(gameObject.SystemVariant, ""));
|
||||
dbDict.Add("video", Common.ReturnValueIfNull(gameObject.Video, ""));
|
||||
|
||||
// set up game dictionary
|
||||
dbDict = new Dictionary<string, object>();
|
||||
if (flipNameAndDescription.Contains(Object.SourceType))
|
||||
List<int> gameCountries = new List<int>();
|
||||
if (
|
||||
gameObject.Country != null &&
|
||||
gameObject.Country != "Unknown"
|
||||
)
|
||||
{
|
||||
string[] countries = gameObject.Country.Split(",");
|
||||
foreach (string country in countries)
|
||||
{
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(gameObject.Description, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(gameObject.Name, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(gameObject.Name, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(gameObject.Description, ""));
|
||||
}
|
||||
dbDict.Add("year", Common.ReturnValueIfNull(gameObject.Year, ""));
|
||||
dbDict.Add("publisher", Common.ReturnValueIfNull(gameObject.Publisher, ""));
|
||||
dbDict.Add("demo", (int)gameObject.Demo);
|
||||
dbDict.Add("system", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||
dbDict.Add("platform", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||
dbDict.Add("systemvariant", Common.ReturnValueIfNull(gameObject.SystemVariant, ""));
|
||||
dbDict.Add("video", Common.ReturnValueIfNull(gameObject.Video, ""));
|
||||
dbDict.Add("country", Common.ReturnValueIfNull(gameObject.Country, ""));
|
||||
dbDict.Add("language", Common.ReturnValueIfNull(gameObject.Language, ""));
|
||||
dbDict.Add("copyright", Common.ReturnValueIfNull(gameObject.Copyright, ""));
|
||||
|
||||
// store platform
|
||||
int gameSystem = 0;
|
||||
if (gameObject.System != null)
|
||||
{
|
||||
sql = "SELECT Id FROM Signatures_Platforms WHERE Platform=@platform";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
int countryId = -1;
|
||||
countryId = Common.GetLookupByCode(Common.LookupTypes.Country, (string)Common.ReturnValueIfNull(country.Trim(), ""));
|
||||
if (countryId == -1)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Platforms (Platform) VALUES (@platform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
countryId = Common.GetLookupByValue(Common.LookupTypes.Country, (string)Common.ReturnValueIfNull(country.Trim(), ""));
|
||||
|
||||
gameSystem = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
if (countryId == -1)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Unable to locate country id for " + country.Trim());
|
||||
sql = "INSERT INTO Country (`Code`, `Value`) VALUES (@code, @name); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
Dictionary<string, object> countryDict = new Dictionary<string, object>{
|
||||
{ "code", country.Trim() },
|
||||
{ "name", country.Trim() }
|
||||
};
|
||||
countryId = int.Parse(db.ExecuteCMD(sql, countryDict).Rows[0][0].ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (countryId > 0)
|
||||
{
|
||||
gameSystem = (int)sigDB.Rows[0][0];
|
||||
gameCountries.Add(countryId);
|
||||
}
|
||||
}
|
||||
dbDict.Add("systemid", gameSystem);
|
||||
}
|
||||
|
||||
// store publisher
|
||||
int gamePublisher = 0;
|
||||
if (gameObject.Publisher != null)
|
||||
List<int> gameLanguages = new List<int>();
|
||||
if (
|
||||
gameObject.Language != null &&
|
||||
gameObject.Language != "nolang"
|
||||
)
|
||||
{
|
||||
string[] languages = gameObject.Language.Split(",");
|
||||
foreach (string language in languages)
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Publishers WHERE Publisher=@publisher";
|
||||
int languageId = -1;
|
||||
languageId = Common.GetLookupByCode(Common.LookupTypes.Language, (string)Common.ReturnValueIfNull(language.Trim(), ""));
|
||||
if (languageId == -1)
|
||||
{
|
||||
languageId = Common.GetLookupByValue(Common.LookupTypes.Language, (string)Common.ReturnValueIfNull(language.Trim(), ""));
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Publishers (Publisher) VALUES (@publisher); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
gamePublisher = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
if (languageId == -1)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Unable to locate language id for " + language.Trim());
|
||||
sql = "INSERT INTO Language (`Code`, `Value`) VALUES (@code, @name); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
Dictionary<string, object> langDict = new Dictionary<string, object>{
|
||||
{ "code", language.Trim() },
|
||||
{ "name", language.Trim() }
|
||||
};
|
||||
languageId = int.Parse(db.ExecuteCMD(sql, langDict).Rows[0][0].ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (languageId > 0)
|
||||
{
|
||||
gamePublisher = (int)sigDB.Rows[0][0];
|
||||
gameLanguages.Add(languageId);
|
||||
}
|
||||
}
|
||||
dbDict.Add("publisherid", gamePublisher);
|
||||
}
|
||||
|
||||
// store game
|
||||
int gameId = 0;
|
||||
sql = "SELECT * FROM Signatures_Games WHERE Name=@name AND Year=@year AND Publisherid=@publisher AND Systemid=@systemid AND Country=@country AND Language=@language";
|
||||
dbDict.Add("copyright", Common.ReturnValueIfNull(gameObject.Copyright, ""));
|
||||
|
||||
// store platform
|
||||
int gameSystem = 0;
|
||||
if (gameObject.System != null)
|
||||
{
|
||||
sql = "SELECT `Id` FROM Signatures_Platforms WHERE `Platform`=@platform";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Games " +
|
||||
"(Name, Description, Year, PublisherId, Demo, SystemId, SystemVariant, Video, Country, Language, Copyright) VALUES " +
|
||||
"(@name, @description, @year, @publisherid, @demo, @systemid, @systemvariant, @video, @country, @language, @copyright); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sql = "INSERT INTO Signatures_Platforms (`Platform`) VALUES (@platform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
gameId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
gameSystem = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameId = (int)sigDB.Rows[0][0];
|
||||
gameSystem = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
}
|
||||
dbDict.Add("systemid", gameSystem);
|
||||
|
||||
// store rom
|
||||
foreach (RomSignatureObject.Game.Rom romObject in gameObject.Roms)
|
||||
// store publisher
|
||||
int gamePublisher = 0;
|
||||
if (gameObject.Publisher != null)
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Publishers WHERE `Publisher`=@publisher";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
if (romObject.Md5 != null || romObject.Sha1 != null)
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Publishers (`Publisher`) VALUES (@publisher); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
gamePublisher = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gamePublisher = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
}
|
||||
dbDict.Add("publisherid", gamePublisher);
|
||||
|
||||
// store game
|
||||
long gameId = 0;
|
||||
sql = "SELECT * FROM Signatures_Games WHERE `Name`=@name AND `Year`=@year AND `PublisherId`=@publisherid AND `SystemId`=@systemid";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Games " +
|
||||
"(`Name`, `Description`, `Year`, `PublisherId`, `Demo`, `SystemId`, `SystemVariant`, `Video`, `Copyright`) VALUES " +
|
||||
"(@name, @description, @year, @publisherid, @demo, @systemid, @systemvariant, @video, @copyright); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
gameId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameId = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
|
||||
// insert countries
|
||||
foreach (int gameCountry in gameCountries)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Games_Countries WHERE GameId = @gameid AND CountryId = @Countryid";
|
||||
Dictionary<string, object> countryDict = new Dictionary<string, object>{
|
||||
{ "gameid", gameId },
|
||||
{ "Countryid", gameCountry }
|
||||
};
|
||||
if (db.ExecuteCMD(sql, countryDict).Rows.Count == 0)
|
||||
{
|
||||
int romId = 0;
|
||||
sql = "SELECT * FROM Signatures_Roms WHERE GameId=@gameid AND MD5=@md5";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("gameid", gameId);
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(romObject.Name, ""));
|
||||
dbDict.Add("size", Common.ReturnValueIfNull(romObject.Size, ""));
|
||||
dbDict.Add("crc", Common.ReturnValueIfNull(romObject.Crc, "").ToString().ToLower());
|
||||
dbDict.Add("md5", Common.ReturnValueIfNull(romObject.Md5, "").ToString().ToLower());
|
||||
dbDict.Add("sha1", Common.ReturnValueIfNull(romObject.Sha1, "").ToString().ToLower());
|
||||
dbDict.Add("developmentstatus", Common.ReturnValueIfNull(romObject.DevelopmentStatus, ""));
|
||||
sql = "INSERT INTO Signatures_Games_Countries (GameId, CountryId) VALUES (@gameid, @Countryid)";
|
||||
db.ExecuteCMD(sql, countryDict);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Game id: " + gameId + " with Country " + gameCountry);
|
||||
}
|
||||
}
|
||||
|
||||
if (romObject.Attributes != null)
|
||||
// insert languages
|
||||
foreach (int gameLanguage in gameLanguages)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Games_Languages WHERE GameId = @gameid AND LanguageId = @languageid";
|
||||
Dictionary<string, object> langDict = new Dictionary<string, object>{
|
||||
{ "gameid", gameId },
|
||||
{ "languageid", gameLanguage }
|
||||
};
|
||||
if (db.ExecuteCMD(sql, langDict).Rows.Count == 0)
|
||||
{
|
||||
sql = "INSERT INTO Signatures_Games_Languages (GameId, LanguageId) VALUES (@gameid, @languageid)";
|
||||
db.ExecuteCMD(sql, langDict);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Game id: " + gameId + " with language " + gameLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
// store rom
|
||||
foreach (RomSignatureObject.Game.Rom romObject in gameObject.Roms)
|
||||
{
|
||||
if (romObject.Md5 != null || romObject.Sha1 != null)
|
||||
{
|
||||
long romId = 0;
|
||||
sql = "SELECT * FROM Signatures_Roms WHERE `GameId`=@gameid AND (`MD5`=@md5 OR `SHA1`=@sha1)";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("gameid", gameId);
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(romObject.Name, ""));
|
||||
dbDict.Add("size", Common.ReturnValueIfNull(romObject.Size, ""));
|
||||
dbDict.Add("crc", Common.ReturnValueIfNull(romObject.Crc, "").ToString().ToLower());
|
||||
dbDict.Add("md5", Common.ReturnValueIfNull(romObject.Md5, "").ToString().ToLower());
|
||||
dbDict.Add("sha1", Common.ReturnValueIfNull(romObject.Sha1, "").ToString().ToLower());
|
||||
dbDict.Add("developmentstatus", Common.ReturnValueIfNull(romObject.DevelopmentStatus, ""));
|
||||
|
||||
if (romObject.Attributes != null)
|
||||
{
|
||||
if (romObject.Attributes.Count > 0)
|
||||
{
|
||||
if (romObject.Attributes.Count > 0)
|
||||
{
|
||||
dbDict.Add("attributes", Newtonsoft.Json.JsonConvert.SerializeObject(romObject.Attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
}
|
||||
dbDict.Add("attributes", Newtonsoft.Json.JsonConvert.SerializeObject(romObject.Attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
dbDict.Add("attributes", "");
|
||||
}
|
||||
dbDict.Add("romtype", (int)romObject.RomType);
|
||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(romObject.RomTypeMedia, ""));
|
||||
dbDict.Add("medialabel", Common.ReturnValueIfNull(romObject.MediaLabel, ""));
|
||||
dbDict.Add("metadatasource", romObject.SignatureSource);
|
||||
dbDict.Add("ingestorversion", 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "");
|
||||
}
|
||||
dbDict.Add("romtype", (int)romObject.RomType);
|
||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(romObject.RomTypeMedia, ""));
|
||||
dbDict.Add("medialabel", Common.ReturnValueIfNull(romObject.MediaLabel, ""));
|
||||
dbDict.Add("metadatasource", romObject.SignatureSource);
|
||||
dbDict.Add("ingestorversion", 2);
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Roms (`GameId`, `Name`, `Size`, `CRC`, `MD5`, `SHA1`, `DevelopmentStatus`, `Attributes`, `RomType`, `RomTypeMedia`, `MediaLabel`, `MetadataSource`, `IngestorVersion`) VALUES (@gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @attributes, @romtype, @romtypemedia, @medialabel, @metadatasource, @ingestorversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Roms (GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, MetadataSource, IngestorVersion) VALUES (@gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @attributes, @romtype, @romtypemedia, @medialabel, @metadatasource, @ingestorversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
romId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
romId = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
|
||||
romId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
romId = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
// map the rom to the source
|
||||
sql = "SELECT * FROM Signatures_RomToSource WHERE SourceId=@sourceid AND RomId=@romid;";
|
||||
dbDict.Add("romid", romId);
|
||||
dbDict.Add("sourceId", sourceId);
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
sql = "INSERT INTO Signatures_RomToSource (`SourceId`, `RomId`) VALUES (@sourceid, @romid);";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
File.Move(XMLFile, Path.Combine(ProcessedDirectory, Path.GetFileName(XMLFile)));
|
||||
if (DBFile != null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingestor - XML", "Invalid import file: " + XMLFile, ex);
|
||||
File.Move(DBFile, Path.Combine(XMLDBProcessedDirectory, Path.GetFileName(DBFile)));
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Ingestor - XML", "Rejecting already imported file: " + XMLFile);
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Error ingesting " + XMLType.ToString() + " file: " + XMLFile, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "Rejecting already imported " + XMLType.ToString() + " file: " + XMLFile);
|
||||
File.Move(XMLFile, Path.Combine(ProcessedDirectory, Path.GetFileName(XMLFile)));
|
||||
if (DBFile != null)
|
||||
{
|
||||
File.Move(DBFile, Path.Combine(XMLDBProcessedDirectory, Path.GetFileName(DBFile)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Data;
|
||||
using gaseous_server.Models;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using static gaseous_server.Classes.Common;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -46,7 +48,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
Game = new gaseous_server.Models.Signatures_Games.GameItem
|
||||
{
|
||||
Id = (Int32)sigDbRow["Id"],
|
||||
Id = (long)(int)sigDbRow["Id"],
|
||||
Name = (string)sigDbRow["Name"],
|
||||
Description = (string)sigDbRow["Description"],
|
||||
Year = (string)sigDbRow["Year"],
|
||||
@@ -55,20 +57,20 @@ namespace gaseous_server.Classes
|
||||
System = (string)sigDbRow["Platform"],
|
||||
SystemVariant = (string)sigDbRow["SystemVariant"],
|
||||
Video = (string)sigDbRow["Video"],
|
||||
Country = (string)sigDbRow["Country"],
|
||||
Language = (string)sigDbRow["Language"],
|
||||
Countries = new Dictionary<string, string>(GetLookup(LookupTypes.Country, (long)(int)sigDbRow["Id"])),
|
||||
Languages = new Dictionary<string, string>(GetLookup(LookupTypes.Language, (long)(int)sigDbRow["Id"])),
|
||||
Copyright = (string)sigDbRow["Copyright"]
|
||||
},
|
||||
Rom = new gaseous_server.Models.Signatures_Games.RomItem
|
||||
{
|
||||
Id = (Int32)sigDbRow["romid"],
|
||||
Id = (long)(int)sigDbRow["romid"],
|
||||
Name = (string)sigDbRow["romname"],
|
||||
Size = (Int64)sigDbRow["Size"],
|
||||
Crc = (string)sigDbRow["CRC"],
|
||||
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
||||
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
||||
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
||||
RomType = (gaseous_server.Models.Signatures_Games.RomItem.RomTypes)(int)sigDbRow["RomType"],
|
||||
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
||||
MediaLabel = (string)sigDbRow["MediaLabel"],
|
||||
@@ -79,5 +81,77 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
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)
|
||||
{
|
||||
string tableName = "";
|
||||
switch (LookupType)
|
||||
{
|
||||
case LookupTypes.Country:
|
||||
tableName = "Countries";
|
||||
break;
|
||||
|
||||
case LookupTypes.Language:
|
||||
tableName = "Languages";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT " + LookupType.ToString() + ".Code, " + LookupType.ToString() + ".Value FROM Signatures_Games_" + tableName + " JOIN " + LookupType.ToString() + " ON Signatures_Games_" + tableName + "." + LookupType.ToString() + "Id = " + LookupType.ToString() + ".Id WHERE Signatures_Games_" + tableName + ".GameId = @id;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "id", GameId }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
Dictionary<string, string> returnDict = new Dictionary<string, string>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
returnDict.Add((string)row["Code"], (string)row["Value"]);
|
||||
}
|
||||
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,29 +5,45 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
// new session required
|
||||
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>{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId },
|
||||
{ "sessionid", SessionId },
|
||||
{ "sessiontime", DateTime.UtcNow },
|
||||
{ "sessionlength", 1 }
|
||||
{ "sessionlength", 1 },
|
||||
{ "platformid", PlatformId },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "romid", RomId }
|
||||
};
|
||||
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = GameId,
|
||||
SessionId = SessionId,
|
||||
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;";
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = (long)data.Rows[0]["GameId"],
|
||||
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||
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;";
|
||||
data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = GameId,
|
||||
SessionLength = TotalTime,
|
||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
||||
|
||||
218
gaseous-server/Classes/UserProfile.cs
Normal file
218
gaseous-server/Classes/UserProfile.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System.Data;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using HasheousClient.Models;
|
||||
|
||||
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)
|
||||
{
|
||||
// build the user profile object
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id, UserId, 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()
|
||||
};
|
||||
}
|
||||
|
||||
// get now playing game - if available
|
||||
Models.UserProfile.NowPlayingItem? NowPlaying = null;
|
||||
sql = "SELECT * FROM `view_UserTimeTracking` WHERE UserId = @userid AND UTC_TIMESTAMP() BETWEEN SessionTime AND DATE_ADD(SessionEnd, INTERVAL 2 MINUTE) ORDER BY SessionEnd DESC LIMIT 1;";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "userid", data.Rows[0]["UserId"].ToString() }
|
||||
};
|
||||
DataTable nowPlayingData = db.ExecuteCMD(sql, dbDict);
|
||||
if (nowPlayingData.Rows.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
gaseous_server.Models.MetadataMap.MetadataMapItem metadataMap = Classes.MetadataManagement.GetMetadataMap((long)nowPlayingData.Rows[0]["GameId"]).PreferredMetadataMapItem;
|
||||
NowPlaying = new Models.UserProfile.NowPlayingItem
|
||||
{
|
||||
Game = Games.GetGame(metadataMap.SourceType, metadataMap.SourceId),
|
||||
Platform = Platforms.GetPlatform((long)nowPlayingData.Rows[0]["PlatformId"]),
|
||||
Duration = Convert.ToInt64(nowPlayingData.Rows[0]["SessionLength"])
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// return the user profile object
|
||||
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,
|
||||
NowPlaying = NowPlaying,
|
||||
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.SecurityProfile = user.SecurityProfile;
|
||||
profile.UserPreferences = user.UserPreferences;
|
||||
profile.Avatar = user.Avatar;
|
||||
profile.ProfileId = user.ProfileId;
|
||||
profile.Roles.Sort();
|
||||
|
||||
return Ok(profile);
|
||||
@@ -122,7 +122,7 @@ namespace gaseous_server.Controllers
|
||||
profile.SecurityProfile = user.SecurityProfile;
|
||||
profile.UserPreferences = user.UserPreferences;
|
||||
profile.Roles.Sort();
|
||||
|
||||
|
||||
string profileString = "var userProfile = " + Newtonsoft.Json.JsonConvert.SerializeObject(profile, Newtonsoft.Json.Formatting.Indented) + ";";
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(profileString);
|
||||
@@ -188,8 +188,8 @@ namespace gaseous_server.Controllers
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
user.Avatar = rawUser.Avatar;
|
||||
|
||||
user.ProfileId = rawUser.ProfileId;
|
||||
|
||||
// get roles
|
||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||
if (aUser != null)
|
||||
@@ -214,12 +214,16 @@ namespace gaseous_server.Controllers
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
UserName = model.UserName,
|
||||
{
|
||||
UserName = model.UserName,
|
||||
NormalizedUserName = model.UserName.ToUpper(),
|
||||
Email = model.Email,
|
||||
NormalizedEmail = model.Email.ToUpper()
|
||||
};
|
||||
if (await _userManager.FindByEmailAsync(model.Email) != null)
|
||||
{
|
||||
return NotFound("User already exists");
|
||||
}
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
@@ -234,20 +238,37 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[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]
|
||||
[Route("Users/{UserId}")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> GetUser(string UserId)
|
||||
{
|
||||
ApplicationUser? rawUser = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
|
||||
if (rawUser != null)
|
||||
{
|
||||
UserViewModel user = new UserViewModel();
|
||||
@@ -256,7 +277,8 @@ namespace gaseous_server.Controllers
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
|
||||
user.ProfileId = rawUser.ProfileId;
|
||||
|
||||
// get roles
|
||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
||||
user.Roles = aUserRoles.ToList();
|
||||
@@ -297,16 +319,16 @@ namespace gaseous_server.Controllers
|
||||
public async Task<IActionResult> SetUserRoles(string UserId, string RoleName)
|
||||
{
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
// get roles
|
||||
List<string> userRoles = (await _userManager.GetRolesAsync(user)).ToList();
|
||||
|
||||
|
||||
// delete all roles
|
||||
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);
|
||||
}
|
||||
@@ -331,7 +353,7 @@ namespace gaseous_server.Controllers
|
||||
await _userManager.AddToRoleAsync(user, RoleName);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
@@ -348,12 +370,12 @@ namespace gaseous_server.Controllers
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
ApplicationUser? user = await _userManager.FindByIdAsync(UserId);
|
||||
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
user.SecurityProfile = securityProfile;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
@@ -413,7 +435,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
user.UserPreferences = model;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Asp.Versioning;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using gaseous_server.Models;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
@@ -17,6 +22,15 @@ namespace gaseous_server.Controllers
|
||||
[Authorize]
|
||||
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.1")]
|
||||
[HttpGet]
|
||||
@@ -43,24 +57,55 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("zip/{PlatformId}")]
|
||||
[Route("zip/{PlatformId}/{GameId}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetBiosCompressed(long PlatformId)
|
||||
public async Task<ActionResult> GetBiosCompressedAsync(long PlatformId, long GameId = -1, bool filtered = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
Platform platform = Platforms.GetPlatform(PlatformId);
|
||||
PlatformMapping.PlatformMapItem platformMap = PlatformMapping.GetPlatformMap(PlatformId);
|
||||
|
||||
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platform.Slug);
|
||||
List<string> biosHashes = new List<string>();
|
||||
|
||||
if (GameId == -1 || filtered == false)
|
||||
{
|
||||
// get all bios files for selected platform
|
||||
biosHashes.AddRange(platformMap.EnabledBIOSHashes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get user platform map
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
PlatformMapping.PlatformMapItem userPlatformMap = platformMapping.GetUserPlatformMap(user.Id, PlatformId, GameId);
|
||||
|
||||
biosHashes.AddRange(userPlatformMap.EnabledBIOSHashes);
|
||||
}
|
||||
|
||||
// build zip file
|
||||
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))
|
||||
foreach (string hash in biosHashes)
|
||||
{
|
||||
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
|
||||
// get the bios data for the hash
|
||||
foreach (PlatformMapping.PlatformMapItem.EmulatorBiosItem bios in platformMap.Bios)
|
||||
{
|
||||
if (bios.hash == hash)
|
||||
{
|
||||
// add the bios file to the zip
|
||||
string biosFilePath = Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, hash + ".bios");
|
||||
if (System.IO.File.Exists(biosFilePath))
|
||||
{
|
||||
zipArchive.CreateEntryFromFile(biosFilePath, bios.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,5 +86,24 @@ namespace gaseous_server.Controllers
|
||||
return NotFound(exLNF.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost("{LibraryId}/Scan")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult ScanLibrary(int LibraryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameLibrary.ScanLibrary(LibraryId);
|
||||
return Ok();
|
||||
}
|
||||
catch (GameLibrary.LibraryNotFound exLNF)
|
||||
{
|
||||
return NotFound(exLNF.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,35 +149,6 @@ namespace gaseous_server.Controllers
|
||||
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.1")]
|
||||
[HttpPatch]
|
||||
|
||||
@@ -8,12 +8,12 @@ using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using Asp.Versioning;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
@@ -37,7 +37,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string sql = "SELECT * FROM Platform WHERE Id IN (SELECT DISTINCT PlatformId FROM Games_Roms) ORDER BY `Name` ASC;";
|
||||
string sql = "SELECT * FROM Platform WHERE Id IN (SELECT DISTINCT PlatformId FROM view_Games_Roms) ORDER BY `Name` ASC;";
|
||||
|
||||
List<Platform> RetVal = new List<Platform>();
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
if (platformObject != null)
|
||||
{
|
||||
@@ -77,59 +77,166 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// [MapToApiVersion("1.0")]
|
||||
// [MapToApiVersion("1.1")]
|
||||
// [HttpGet]
|
||||
// [Route("{PlatformId}/platformlogo")]
|
||||
// [ProducesResponseType(typeof(PlatformLogo), StatusCodes.Status200OK)]
|
||||
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
// public ActionResult PlatformLogo(long PlatformId)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
// if (platformObject != null)
|
||||
// {
|
||||
// PlatformLogo logoObjectParent = (PlatformLogo)platformObject.PlatformLogo;
|
||||
// PlatformLogo logoObject = PlatformLogos.GetPlatformLogo(logoObjectParent.Id);
|
||||
// if (logoObject != null)
|
||||
// {
|
||||
// return Ok(logoObject);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}/platformlogo")]
|
||||
[ProducesResponseType(typeof(PlatformLogo), StatusCodes.Status200OK)]
|
||||
[Route("{PlatformId}/platformlogo/{size}/")]
|
||||
[Route("{PlatformId}/platformlogo/{size}/logo.png")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult PlatformLogo(long PlatformId)
|
||||
public async Task<ActionResult> GameImage(long PlatformId, Communications.IGDBAPI_ImageSize size)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
if (platformObject != null)
|
||||
HasheousClient.Models.MetadataSources metadataSources = HasheousClient.Models.MetadataSources.None;
|
||||
|
||||
Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId, metadataSources);
|
||||
PlatformLogo? logoObject = null;
|
||||
|
||||
logoObject = PlatformLogos.GetPlatformLogo((long)platformObject.PlatformLogo, metadataSources);
|
||||
|
||||
if (logoObject == null)
|
||||
{
|
||||
IGDB.Models.PlatformLogo logoObject = PlatformLogos.GetPlatformLogo(platformObject.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||
if (logoObject != null)
|
||||
// getting the logo failed, so we'll try a platform variant if available
|
||||
if (platformObject.Versions != null)
|
||||
{
|
||||
return Ok(logoObject);
|
||||
if (platformObject.Versions.Count > 0)
|
||||
{
|
||||
PlatformVersion platformVersion = Classes.Metadata.PlatformVersions.GetPlatformVersion(metadataSources, (long)platformObject.Versions[0]);
|
||||
logoObject = PlatformLogos.GetPlatformLogo((long)platformVersion.PlatformLogo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetDummyImage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
return GetDummyImage();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), metadataSources.ToString());
|
||||
string imagePath = Path.Combine(basePath, size.ToString(), logoObject.ImageId);
|
||||
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
return NotFound();
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(metadataSources, 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;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}/platformlogo/image")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult PlatformLogoImage(long PlatformId)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
string logoFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), "Logo_Medium.png");
|
||||
if (System.IO.File.Exists(logoFilePath))
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
string filename = "Logo.png";
|
||||
string filepath = logoFilePath;
|
||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
string contentType = "image/png";
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(metadataSources, 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))
|
||||
{
|
||||
// get image info
|
||||
var info = new ImageMagick.MagickImageInfo(imagePath);
|
||||
string extension = ".jpg";
|
||||
string mimeType = "image/jpg";
|
||||
switch (info.Format)
|
||||
{
|
||||
case ImageMagick.MagickFormat.Jpeg:
|
||||
extension = ".jpg";
|
||||
mimeType = "image/jpg";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Png:
|
||||
extension = ".png";
|
||||
mimeType = "image/png";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Gif:
|
||||
extension = ".gif";
|
||||
mimeType = "image/gif";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Bmp:
|
||||
extension = ".bmp";
|
||||
mimeType = "image/bmp";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Tiff:
|
||||
extension = ".tiff";
|
||||
mimeType = "image/tiff";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Unknown:
|
||||
extension = ".jpg";
|
||||
mimeType = "image/jpg";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.WebP:
|
||||
extension = ".webp";
|
||||
mimeType = "image/webp";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Heic:
|
||||
extension = ".heic";
|
||||
mimeType = "image/heic";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Heif:
|
||||
extension = ".heif";
|
||||
mimeType = "image/heif";
|
||||
break;
|
||||
|
||||
case ImageMagick.MagickFormat.Svg:
|
||||
extension = ".svg";
|
||||
mimeType = "image/svg+xml";
|
||||
break;
|
||||
|
||||
default:
|
||||
extension = ".jpg";
|
||||
mimeType = "image/jpg";
|
||||
break;
|
||||
}
|
||||
|
||||
string filename = logoObject.ImageId + extension;
|
||||
string filepath = imagePath;
|
||||
string contentType = mimeType;
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
@@ -138,6 +245,16 @@ namespace gaseous_server.Controllers
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -151,6 +268,50 @@ namespace gaseous_server.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
private ActionResult GetDummyImage()
|
||||
{
|
||||
// return resource named DefaultPlatformLogo.svg
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
string resourceName = "gaseous_server.Support.DefaultPlatformLogo.svg";
|
||||
string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
if (resources.Contains(resourceName))
|
||||
{
|
||||
string svgData = "";
|
||||
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
svgData = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = "DefaultPlatformLogo.svg",
|
||||
Inline = true,
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
byte[] filedata = null;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(ms))
|
||||
{
|
||||
writer.Write(svgData);
|
||||
writer.Flush();
|
||||
ms.Position = 0;
|
||||
filedata = ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return File(filedata, "image/svg+xml");
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ 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;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
@@ -31,63 +31,70 @@ namespace gaseous_server.Controllers
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[Consumes("multipart/form-data")]
|
||||
[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();
|
||||
|
||||
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
||||
|
||||
long size = files.Sum(f => f.Length);
|
||||
|
||||
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
|
||||
|
||||
foreach (IFormFile formFile in files)
|
||||
if (file.Length > 0)
|
||||
{
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
Directory.CreateDirectory(workPath);
|
||||
}
|
||||
}
|
||||
|
||||
// get override platform if specified
|
||||
IGDB.Models.Platform? OverridePlatform = null;
|
||||
if (OverridePlatformId != null)
|
||||
{
|
||||
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
||||
}
|
||||
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
||||
|
||||
// Process uploaded files
|
||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
||||
{
|
||||
using (var stream = System.IO.File.Create(filePath))
|
||||
{
|
||||
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
|
||||
Platform? OverridePlatform = null;
|
||||
if (OverridePlatformId != null)
|
||||
{
|
||||
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
||||
}
|
||||
|
||||
// Process uploaded file
|
||||
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")
|
||||
{
|
||||
gaseous_server.Models.Game? game = (gaseous_server.Models.Game)RetVal["game"];
|
||||
if (game == null || game.Id == null)
|
||||
{
|
||||
RetVal["game"] = Games.GetGame(HasheousClient.Models.MetadataSources.IGDB, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (Directory.Exists(workPath))
|
||||
{
|
||||
Directory.Delete(workPath, true);
|
||||
}
|
||||
|
||||
return Ok(RetVal);
|
||||
}
|
||||
|
||||
if (Directory.Exists(workPath))
|
||||
{
|
||||
Directory.Delete(workPath, true);
|
||||
}
|
||||
|
||||
return Ok(new { count = files.Count, size });
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,7 @@ using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NuGet.Common;
|
||||
@@ -36,93 +35,112 @@ namespace gaseous_server.Controllers
|
||||
|
||||
private static async Task<List<Platform>> _SearchForPlatform(string SearchString)
|
||||
{
|
||||
string searchBody = "";
|
||||
string searchFields = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
|
||||
searchBody += "where name ~ *\"" + SearchString + "\"*;";
|
||||
// search the database for the requested platforms
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string query = "SELECT `Id` FROM Platform WHERE `Name` LIKE '%" + SearchString + "%';";
|
||||
DataTable data = db.ExecuteCMD(query);
|
||||
|
||||
List<Platform>? searchCache = Communications.GetSearchCache<List<Platform>>(searchFields, searchBody);
|
||||
|
||||
if (searchCache == null)
|
||||
List<Platform> platforms = new List<Platform>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
// cache miss
|
||||
// get Platform metadata from data source
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, searchFields, searchBody);
|
||||
Platform platform = Platforms.GetPlatform((long)row["Id"]);
|
||||
|
||||
Communications.SetSearchCache<List<Platform>>(searchFields, searchBody, results.ToList());
|
||||
platforms.Add(platform);
|
||||
}
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return searchCache;
|
||||
}
|
||||
return platforms;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("Game")]
|
||||
[ProducesResponseType(typeof(List<GaseousGame>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(List<gaseous_server.Models.Game>), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
|
||||
{
|
||||
List<GaseousGame> RetVal = await _SearchForGame(PlatformId, SearchString);
|
||||
List<gaseous_server.Models.Game> RetVal = await _SearchForGame(PlatformId, SearchString);
|
||||
return Ok(RetVal);
|
||||
}
|
||||
|
||||
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||
private static async Task<List<gaseous_server.Models.Game>> _SearchForGame(long PlatformId, string SearchString)
|
||||
{
|
||||
string searchBody = "";
|
||||
// string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||
string searchFields = "fields *; ";
|
||||
searchBody += "search \"" + SearchString + "\";";
|
||||
searchBody += "where platforms = (" + PlatformId + ");";
|
||||
searchBody += "limit 100;";
|
||||
|
||||
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
||||
|
||||
if (searchCache == null)
|
||||
switch (Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
{
|
||||
// cache miss
|
||||
// get Game metadata from data source
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||
|
||||
List<GaseousGame> games = new List<GaseousGame>();
|
||||
foreach (Game game in results.ToList())
|
||||
{
|
||||
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
||||
switch (cacheStatus)
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
if (Config.IGDB.UseHasheousProxy == false)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
Storage.NewCacheValue(game, false);
|
||||
break;
|
||||
string searchBody = "";
|
||||
string searchFields = "fields *; ";
|
||||
searchBody += "search \"" + SearchString + "\";";
|
||||
searchBody += "where platforms = (" + PlatformId + ");";
|
||||
searchBody += "limit 100;";
|
||||
|
||||
case Storage.CacheStatus.Expired:
|
||||
Storage.NewCacheValue(game, true);
|
||||
break;
|
||||
List<gaseous_server.Models.Game>? searchCache = Communications.GetSearchCache<List<gaseous_server.Models.Game>>(searchFields, searchBody);
|
||||
|
||||
if (searchCache == null)
|
||||
{
|
||||
// cache miss
|
||||
// get Game metadata from data source
|
||||
Communications comms = new Communications();
|
||||
var results = await comms.APIComm<gaseous_server.Models.Game>("Game", searchFields, searchBody);
|
||||
|
||||
List<gaseous_server.Models.Game> games = new List<gaseous_server.Models.Game>();
|
||||
foreach (gaseous_server.Models.Game game in results.ToList())
|
||||
{
|
||||
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus(HasheousClient.Models.MetadataSources.IGDB, "Game", (long)game.Id);
|
||||
switch (cacheStatus)
|
||||
{
|
||||
case Storage.CacheStatus.NotPresent:
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.IGDB, game, false);
|
||||
break;
|
||||
|
||||
case Storage.CacheStatus.Expired:
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.IGDB, game, true);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
games.Add(game);
|
||||
}
|
||||
|
||||
Communications.SetSearchCache<List<gaseous_server.Models.Game>>(searchFields, searchBody, games);
|
||||
|
||||
return games;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get full version of results from database
|
||||
// this is a hacky workaround due to the readonly nature of IGDB.Model.Game IdentityOrValue fields
|
||||
List<gaseous_server.Models.Game> gamesToReturn = new List<gaseous_server.Models.Game>();
|
||||
foreach (gaseous_server.Models.Game game in searchCache)
|
||||
{
|
||||
gaseous_server.Models.Game? tempGame = Games.GetGame(Communications.MetadataSource, (long)game.Id);
|
||||
if (tempGame != null)
|
||||
{
|
||||
gamesToReturn.Add(tempGame);
|
||||
}
|
||||
}
|
||||
|
||||
return gamesToReturn;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||
Communications.ConfigureHasheousClient(ref hasheous);
|
||||
List<gaseous_server.Models.Game> hSearch = hasheous.GetMetadataProxy_SearchGame<gaseous_server.Models.Game>(HasheousClient.Hasheous.MetadataProvider.IGDB, PlatformId.ToString(), SearchString).ToList<gaseous_server.Models.Game>();
|
||||
|
||||
List<gaseous_server.Models.Game> hGamesToReturn = new List<gaseous_server.Models.Game>();
|
||||
foreach (gaseous_server.Models.Game game in hSearch)
|
||||
{
|
||||
hGamesToReturn.Add(game);
|
||||
}
|
||||
|
||||
return hGamesToReturn;
|
||||
}
|
||||
|
||||
games.Add(new GaseousGame(game));
|
||||
}
|
||||
|
||||
Communications.SetSearchCache<List<GaseousGame>>(searchFields, searchBody, games);
|
||||
|
||||
return games;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get full version of results from database
|
||||
// this is a hacky workaround due to the readonly nature of IGDB.Model.Game IdentityOrValue fields
|
||||
List<GaseousGame> gamesToReturn = new List<GaseousGame>();
|
||||
foreach (GaseousGame game in searchCache)
|
||||
{
|
||||
Game tempGame = Games.GetGame((long)game.Id, false, false, false);
|
||||
gamesToReturn.Add(new GaseousGame(tempGame));
|
||||
}
|
||||
|
||||
return gamesToReturn;
|
||||
default:
|
||||
return new List<gaseous_server.Models.Game>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Asp.Versioning;
|
||||
using gaseous_server.Models;
|
||||
|
||||
// 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();
|
||||
return signatureManagement.GetByTosecName(TosecName);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
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>();
|
||||
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;
|
||||
|
||||
@@ -48,7 +51,19 @@ namespace gaseous_server.Controllers
|
||||
ReturnValue.DatabaseSize = (long)(System.Decimal)dbResponse.Rows[0][1];
|
||||
|
||||
// platform statistics
|
||||
sql = "SELECT Platform.`name`, grc.Count, grs.Size FROM Platform INNER JOIN (SELECT Platform.`name` AS `Name`, SUM(grs.Size) AS Size FROM Platform JOIN Games_Roms AS grs ON (grs.PlatformId = Platform.Id) GROUP BY Platform.`name`) grs ON (grs.`Name` = Platform.`name`) INNER JOIN (SELECT Platform.`name` AS `Name`, COUNT(grc.Size) AS Count FROM Platform JOIN Games_Roms AS grc ON (grc.PlatformId = Platform.Id) GROUP BY Platform.`name`) grc ON (grc.`Name` = Platform.`name`) ORDER BY Platform.`name`;";
|
||||
sql = @"
|
||||
SELECT
|
||||
view_Games_Roms.PlatformId,
|
||||
Platform.`Name`,
|
||||
SUM(view_Games_Roms.Size) AS Size,
|
||||
COUNT(view_Games_Roms.`Id`) AS Count
|
||||
FROM
|
||||
view_Games_Roms
|
||||
LEFT JOIN
|
||||
Platform ON view_Games_Roms.PlatformId = Platform.`Id`
|
||||
AND Platform.SourceId = 0
|
||||
GROUP BY Platform.`Name`
|
||||
ORDER BY Platform.`Name`; ";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
ReturnValue.PlatformStatistics = new List<SystemInfo.PlatformStatisticsItem>();
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
@@ -69,10 +84,51 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("Version")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Version GetSystemVersion()
|
||||
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
|
||||
[AllowAnonymous]
|
||||
public ActionResult GetSystemVersion()
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// get age ratings dictionary
|
||||
Dictionary<int, string> ClassificationBoardsStrings = new Dictionary<int, string>();
|
||||
foreach (IGDB.Models.AgeRatingCategory ageRatingCategory in Enum.GetValues(typeof(IGDB.Models.AgeRatingCategory)))
|
||||
{
|
||||
ClassificationBoardsStrings.Add((int)ageRatingCategory, ageRatingCategory.ToString());
|
||||
}
|
||||
|
||||
Dictionary<int, string> AgeRatingsStrings = new Dictionary<int, string>();
|
||||
foreach (IGDB.Models.AgeRatingTitle ageRatingTitle in Enum.GetValues(typeof(IGDB.Models.AgeRatingTitle)))
|
||||
{
|
||||
AgeRatingsStrings.Add((int)ageRatingTitle, ageRatingTitle.ToString());
|
||||
}
|
||||
|
||||
Dictionary<string, object> retVal = new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"AppVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString()
|
||||
},
|
||||
{
|
||||
"DBSchemaVersion", db.GetDatabaseSchemaVersion().ToString()
|
||||
},
|
||||
{
|
||||
"FirstRunStatus", Config.ReadSetting<string>("FirstRunStatus", "0")
|
||||
},
|
||||
{
|
||||
"AgeRatingBoardsStrings", ClassificationBoardsStrings
|
||||
},
|
||||
{
|
||||
"AgeRatingStrings", AgeRatingsStrings
|
||||
},
|
||||
{
|
||||
"AgeRatingGroups", AgeGroups.AgeGroupingsFlat
|
||||
},
|
||||
{
|
||||
"emulatorDebugMode", Config.ReadSetting<string>("emulatorDebugMode", false.ToString()).ToLower()
|
||||
}
|
||||
};
|
||||
|
||||
return Ok(retVal);
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
@@ -260,7 +316,19 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
AlwaysLogToDisk = Config.LoggingConfiguration.AlwaysLogToDisk,
|
||||
MinimumLogRetentionPeriod = Config.LoggingConfiguration.LogRetention,
|
||||
EmulatorDebugMode = Boolean.Parse(Config.ReadSetting<string>("emulatorDebugMode", false.ToString()))
|
||||
EmulatorDebugMode = Boolean.Parse(Config.ReadSetting<string>("emulatorDebugMode", false.ToString())),
|
||||
SignatureSource = new SystemSettingsModel.SignatureSourceItem()
|
||||
{
|
||||
Source = Config.MetadataConfiguration.SignatureSource,
|
||||
HasheousHost = Config.MetadataConfiguration.HasheousHost,
|
||||
HasheousSubmitFixes = (bool)Config.MetadataConfiguration.HasheousSubmitFixes,
|
||||
HasheousAPIKey = Config.MetadataConfiguration.HasheousAPIKey
|
||||
},
|
||||
MetadataSources = new List<SystemSettingsModel.MetadataSourceItem>
|
||||
{
|
||||
new SystemSettingsModel.MetadataSourceItem(HasheousClient.Models.MetadataSources.None, false, "", "", Config.MetadataConfiguration.DefaultMetadataSource),
|
||||
new SystemSettingsModel.MetadataSourceItem(HasheousClient.Models.MetadataSources.IGDB, Config.IGDB.UseHasheousProxy, Config.IGDB.ClientId, Config.IGDB.Secret, Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
}
|
||||
};
|
||||
|
||||
return Ok(systemSettingsModel);
|
||||
@@ -279,6 +347,38 @@ namespace gaseous_server.Controllers
|
||||
Config.LoggingConfiguration.AlwaysLogToDisk = model.AlwaysLogToDisk;
|
||||
Config.LoggingConfiguration.LogRetention = model.MinimumLogRetentionPeriod;
|
||||
Config.SetSetting<string>("emulatorDebugMode", model.EmulatorDebugMode.ToString());
|
||||
Config.MetadataConfiguration.SignatureSource = model.SignatureSource.Source;
|
||||
Config.MetadataConfiguration.HasheousHost = model.SignatureSource.HasheousHost;
|
||||
Config.MetadataConfiguration.HasheousAPIKey = model.SignatureSource.HasheousAPIKey;
|
||||
Config.MetadataConfiguration.HasheousSubmitFixes = model.SignatureSource.HasheousSubmitFixes;
|
||||
foreach (SystemSettingsModel.MetadataSourceItem metadataSourceItem in model.MetadataSources)
|
||||
{
|
||||
// configure the default metadata source
|
||||
if (metadataSourceItem.Default == true)
|
||||
{
|
||||
Config.MetadataConfiguration.DefaultMetadataSource = metadataSourceItem.Source;
|
||||
}
|
||||
else
|
||||
{
|
||||
Config.MetadataConfiguration.DefaultMetadataSource = HasheousClient.Models.MetadataSources.None;
|
||||
}
|
||||
|
||||
// configure the metadata source
|
||||
switch (metadataSourceItem.Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.None:
|
||||
break;
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
Config.IGDB.UseHasheousProxy = metadataSourceItem.UseHasheousProxy;
|
||||
Config.IGDB.ClientId = metadataSourceItem.ClientId;
|
||||
Config.IGDB.Secret = metadataSourceItem.Secret;
|
||||
break;
|
||||
case HasheousClient.Models.MetadataSources.TheGamesDb:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Config.UpdateConfig();
|
||||
}
|
||||
|
||||
@@ -313,6 +413,7 @@ namespace gaseous_server.Controllers
|
||||
|
||||
public class PathItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string LibraryPath { get; set; }
|
||||
public long SpaceUsed { get; set; }
|
||||
public long SpaceAvailable { get; set; }
|
||||
@@ -424,8 +525,7 @@ namespace gaseous_server.Controllers
|
||||
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||
ProcessQueue.QueueItemType.LibraryScan,
|
||||
ProcessQueue.QueueItemType.LibraryScanWorker,
|
||||
ProcessQueue.QueueItemType.TitleIngestor,
|
||||
ProcessQueue.QueueItemType.Rematcher
|
||||
ProcessQueue.QueueItemType.TitleIngestor
|
||||
};
|
||||
break;
|
||||
|
||||
@@ -447,32 +547,7 @@ namespace gaseous_server.Controllers
|
||||
this.DefaultAllowedEndHours = 23;
|
||||
this.DefaultAllowedEndMinutes = 59;
|
||||
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||
ProcessQueue.QueueItemType.Rematcher
|
||||
};
|
||||
break;
|
||||
|
||||
case ProcessQueue.QueueItemType.Rematcher:
|
||||
this._UserManageable = true;
|
||||
this.DefaultInterval = 1440;
|
||||
this.MinimumAllowedInterval = 360;
|
||||
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||
DayOfWeek.Sunday,
|
||||
DayOfWeek.Monday,
|
||||
DayOfWeek.Tuesday,
|
||||
DayOfWeek.Wednesday,
|
||||
DayOfWeek.Thursday,
|
||||
DayOfWeek.Friday,
|
||||
DayOfWeek.Saturday
|
||||
};
|
||||
this.DefaultAllowedStartHours = 0;
|
||||
this.DefaultAllowedStartMinutes = 0;
|
||||
this.DefaultAllowedEndHours = 23;
|
||||
this.DefaultAllowedEndMinutes = 59;
|
||||
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||
ProcessQueue.QueueItemType.LibraryScan,
|
||||
ProcessQueue.QueueItemType.LibraryScanWorker
|
||||
ProcessQueue.QueueItemType.OrganiseLibrary
|
||||
};
|
||||
break;
|
||||
|
||||
@@ -719,5 +794,110 @@ namespace gaseous_server.Controllers
|
||||
public bool AlwaysLogToDisk { get; set; }
|
||||
public int MinimumLogRetentionPeriod { get; set; }
|
||||
public bool EmulatorDebugMode { get; set; }
|
||||
public SignatureSourceItem SignatureSource { get; set; }
|
||||
public List<MetadataSourceItem> MetadataSources { get; set; }
|
||||
|
||||
public class SignatureSourceItem
|
||||
{
|
||||
public HasheousClient.Models.MetadataModel.SignatureSources Source { get; set; }
|
||||
public string HasheousHost { get; set; }
|
||||
public string HasheousAPIKey { get; set; }
|
||||
public bool HasheousSubmitFixes { get; set; }
|
||||
}
|
||||
|
||||
public class MetadataSourceItem
|
||||
{
|
||||
public MetadataSourceItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MetadataSourceItem(HasheousClient.Models.MetadataSources source, bool useHasheousProxy, string clientId, string secret, HasheousClient.Models.MetadataSources defaultSource)
|
||||
{
|
||||
Source = source;
|
||||
UseHasheousProxy = useHasheousProxy;
|
||||
ClientId = clientId;
|
||||
Secret = secret;
|
||||
if (Source == defaultSource)
|
||||
{
|
||||
Default = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Default = false;
|
||||
}
|
||||
}
|
||||
|
||||
public HasheousClient.Models.MetadataSources Source { get; set; }
|
||||
public bool UseHasheousProxy { get; set; }
|
||||
public string ClientId { get; set; }
|
||||
public string Secret { get; set; }
|
||||
public bool Default { get; set; }
|
||||
public bool? Configured
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.None:
|
||||
return true;
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
if ((!String.IsNullOrEmpty(ClientId) && !String.IsNullOrEmpty(Secret)) || UseHasheousProxy == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case HasheousClient.Models.MetadataSources.TheGamesDb:
|
||||
if ((!String.IsNullOrEmpty(ClientId) && !String.IsNullOrEmpty(Secret)) || UseHasheousProxy == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool? UsesProxy
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.None:
|
||||
return false;
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
return true;
|
||||
case HasheousClient.Models.MetadataSources.TheGamesDb:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool? UsesClientIdAndSecret
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.None:
|
||||
return false;
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
return true;
|
||||
case HasheousClient.Models.MetadataSources.TheGamesDb:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
gaseous-server/Controllers/V1.1/FileSystemController.cs
Normal file
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@@ -19,6 +18,8 @@ using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
using Asp.Versioning;
|
||||
using Humanizer;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
@@ -26,11 +27,11 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class GamesController: ControllerBase
|
||||
public class GamesController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
|
||||
public GamesController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager)
|
||||
@@ -42,7 +43,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(GameReturnPackage), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Game_v1_1(GameSearchModel model, int pageNumber = 0, int pageSize = 0)
|
||||
public async Task<IActionResult> Game_v1_1(GameSearchModel model, int pageNumber = 0, int pageSize = 0, bool returnSummary = true, bool returnGames = true)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
@@ -87,7 +88,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
model.GameAgeRating.IncludeUnrated = false;
|
||||
}
|
||||
|
||||
return Ok(GetGames(model, user.Id, pageNumber, pageSize));
|
||||
return Ok(GetGames(model, user.Id, pageNumber, pageSize, returnSummary, returnGames));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -97,32 +98,34 @@ namespace gaseous_server.Controllers.v1_1
|
||||
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/Related")]
|
||||
[Route("{MetadataMapId}/Related")]
|
||||
[ProducesResponseType(typeof(GameReturnPackage), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GameRelated(long GameId)
|
||||
public async Task<IActionResult> GameRelated(long MetadataMapId)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
string IncludeUnrated = "";
|
||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true) {
|
||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true)
|
||||
{
|
||||
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT view_Games.Id, view_Games.AgeGroupId, Relation_Game_SimilarGames.SimilarGamesId FROM view_Games JOIN Relation_Game_SimilarGames ON view_Games.Id = Relation_Game_SimilarGames.GameId AND Relation_Game_SimilarGames.SimilarGamesId IN (SELECT Id FROM view_Games) WHERE view_Games.Id = @id AND (view_Games.AgeGroupId <= @agegroupid" + IncludeUnrated + ")";
|
||||
string sql = "SELECT view_Games.Id, view_Games.AgeGroupId, Relation_Game_SimilarGames.SimilarGamesId FROM view_Games JOIN Relation_Game_SimilarGames ON view_Games.Id = Relation_Game_SimilarGames.GameId AND view_Games.GameIdType = Relation_Game_SimilarGames.GameSourceId AND Relation_Game_SimilarGames.SimilarGamesId IN (SELECT Id FROM view_Games) WHERE view_Games.Id = @id AND (view_Games.AgeGroupId <= @agegroupid" + IncludeUnrated + ")";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", GameId);
|
||||
dbDict.Add("id", MetadataMapId);
|
||||
dbDict.Add("agegroupid", (int)user.SecurityProfile.AgeRestrictionPolicy.MaximumAgeRestriction);
|
||||
|
||||
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
||||
List<Models.Game> RetVal = new List<Models.Game>();
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
RetVal.Add(Classes.Metadata.Games.GetGame((long)dr["SimilarGamesId"], false, false, false));
|
||||
MetadataMap.MetadataMapItem metadataMap = Classes.MetadataManagement.GetMetadataMap(MetadataMapId).PreferredMetadataMapItem;
|
||||
RetVal.Add(Classes.Metadata.Games.GetGame(metadataMap.SourceType, (long)dr["SimilarGamesId"]));
|
||||
}
|
||||
|
||||
GameReturnPackage gameReturn = new GameReturnPackage(RetVal.Count, RetVal);
|
||||
@@ -150,7 +153,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
||||
public bool HasSavedGame { get; set; }
|
||||
public bool IsFavourite { get; set; }
|
||||
|
||||
|
||||
|
||||
public class GameRatingItem
|
||||
{
|
||||
@@ -163,7 +166,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
|
||||
public class GameAgeRatingItem
|
||||
{
|
||||
public List<AgeGroups.AgeRestrictionGroupings> AgeGroupings { get; set; } = new List<AgeGroups.AgeRestrictionGroupings>{
|
||||
public List<AgeGroups.AgeRestrictionGroupings> AgeGroupings { get; set; } = new List<AgeGroups.AgeRestrictionGroupings>{
|
||||
AgeGroups.AgeRestrictionGroupings.Child,
|
||||
AgeGroups.AgeRestrictionGroupings.Teen,
|
||||
AgeGroups.AgeRestrictionGroupings.Mature,
|
||||
@@ -186,8 +189,8 @@ namespace gaseous_server.Controllers.v1_1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GameReturnPackage GetGames(GameSearchModel model, string userid, int pageNumber = 0, int pageSize = 0)
|
||||
|
||||
public static GameReturnPackage GetGames(GameSearchModel model, string userid, int pageNumber = 0, int pageSize = 0, bool returnSummary = true, bool returnGames = true)
|
||||
{
|
||||
string whereClause = "";
|
||||
string havingClause = "";
|
||||
@@ -302,7 +305,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
string platformWhereClause = "";
|
||||
if (model.Platform.Count > 0)
|
||||
{
|
||||
tempVal = " AND Games_Roms.PlatformId IN (";
|
||||
tempVal = " AND view_Games_Roms.PlatformId IN (";
|
||||
for (int i = 0; i < model.Platform.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
@@ -446,7 +449,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
string orderByOrder = "ASC";
|
||||
if (model.Sorting != null)
|
||||
{
|
||||
switch(model.Sorting.SortBy)
|
||||
switch (model.Sorting.SortBy)
|
||||
{
|
||||
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
||||
orderByField = "NameThe";
|
||||
@@ -477,14 +480,17 @@ namespace gaseous_server.Controllers.v1_1
|
||||
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
|
||||
string sql = @"
|
||||
SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
|
||||
SELECT DISTINCT
|
||||
Game.Id,
|
||||
Game.MetadataMapId,
|
||||
Game.GameIdType,
|
||||
Game.`Name`,
|
||||
Game.NameThe,
|
||||
Game.Slug,
|
||||
Game.Summary,
|
||||
Game.PlatformId,
|
||||
Game.TotalRating,
|
||||
Game.TotalRatingCount,
|
||||
@@ -505,30 +511,26 @@ SELECT DISTINCT
|
||||
FROM
|
||||
(SELECT DISTINCT
|
||||
Game.*,
|
||||
CASE
|
||||
WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The')
|
||||
ELSE Game.`Name`
|
||||
END AS NameThe,
|
||||
Games_Roms.PlatformId,
|
||||
view_Games_Roms.PlatformId,
|
||||
AgeGroup.AgeGroupId,
|
||||
COUNT(Games_Roms.Id) AS RomCount
|
||||
COUNT(view_Games_Roms.Id) AS RomCount
|
||||
FROM
|
||||
Game
|
||||
view_GamesWithRoms AS Game
|
||||
LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId
|
||||
LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId" + platformWhereClause + @"
|
||||
LEFT JOIN view_Games_Roms ON Game.Id = view_Games_Roms.GameId" + platformWhereClause + @"
|
||||
LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + @"
|
||||
GROUP BY Game.Id
|
||||
HAVING RomCount > 0) Game
|
||||
LEFT JOIN
|
||||
(SELECT
|
||||
Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount
|
||||
view_Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount
|
||||
FROM
|
||||
GameState
|
||||
JOIN Games_Roms ON GameState.RomId = Games_Roms.Id
|
||||
JOIN view_Games_Roms ON GameState.RomId = view_Games_Roms.Id
|
||||
WHERE
|
||||
GameState.IsMediaGroup = 0
|
||||
AND GameState.UserId = @userid
|
||||
GROUP BY Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId
|
||||
GROUP BY view_Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId
|
||||
LEFT JOIN
|
||||
(SELECT
|
||||
RomMediaGroup.GameId,
|
||||
@@ -538,83 +540,112 @@ FROM
|
||||
JOIN GameState ON RomMediaGroup.Id = GameState.RomId
|
||||
AND GameState.IsMediaGroup = 1
|
||||
AND GameState.UserId = @userid
|
||||
GROUP BY RomMediaGroup.GameId) RomGroupSavedStates ON Game.Id = RomGroupSavedStates.GameId
|
||||
GROUP BY RomMediaGroup.GameId) RomGroupSavedStates ON Game.MetadataMapId = RomGroupSavedStates.GameId
|
||||
LEFT JOIN
|
||||
Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId
|
||||
Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId AND Relation_Game_Genres.GameSourceId = Game.GameIdType
|
||||
LEFT JOIN
|
||||
Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId
|
||||
Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId AND Relation_Game_GameModes.GameSourceId = Game.GameIdType
|
||||
LEFT JOIN
|
||||
Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId
|
||||
Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId AND Relation_Game_PlayerPerspectives.GameSourceId = Game.GameIdType
|
||||
LEFT JOIN
|
||||
Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId
|
||||
Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId AND Relation_Game_Themes.GameSourceId = Game.GameIdType
|
||||
LEFT JOIN
|
||||
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
||||
Favourites ON Game.MetadataMapId = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||
// if (returnGames == true)
|
||||
// {
|
||||
// sql += " LIMIT @pageOffset, @pageSize";
|
||||
// whereParams.Add("pageOffset", pageSize * (pageNumber - 1));
|
||||
// whereParams.Add("pageSize", pageSize);
|
||||
// }
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 60));
|
||||
|
||||
// get count
|
||||
int RecordCount = dbResponse.Rows.Count;
|
||||
|
||||
// compile data for return
|
||||
int pageOffset = pageSize * (pageNumber - 1);
|
||||
for (int i = pageOffset; i < dbResponse.Rows.Count; i++)
|
||||
int? RecordCount = null;
|
||||
if (returnSummary == true)
|
||||
{
|
||||
if (pageNumber != 0 && pageSize != 0)
|
||||
{
|
||||
if (i >= (pageOffset + pageSize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
||||
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||
retMinGame.Index = i;
|
||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||
{
|
||||
retMinGame.HasSavedGame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
retMinGame.HasSavedGame = false;
|
||||
}
|
||||
if ((int)dbResponse.Rows[i]["Favourite"] == 0)
|
||||
{
|
||||
retMinGame.IsFavourite = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
retMinGame.IsFavourite = true;
|
||||
}
|
||||
|
||||
RetVal.Add(retMinGame);
|
||||
RecordCount = dbResponse.Rows.Count;
|
||||
}
|
||||
|
||||
// build alpha list
|
||||
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||
int CurrentPage = 1;
|
||||
int NextPageIndex = pageSize;
|
||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||
// compile data for return
|
||||
List<Games.MinimalGameItem>? RetVal = null;
|
||||
if (returnGames == true)
|
||||
{
|
||||
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
|
||||
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||
RetVal = new List<Games.MinimalGameItem>();
|
||||
foreach (int i in Enumerable.Range(0, dbResponse.Rows.Count))
|
||||
{
|
||||
if (!AlphaList.ContainsKey("#"))
|
||||
Models.Game retGame = Storage.BuildCacheObject<Models.Game>(new Models.Game(), dbResponse.Rows[i]);
|
||||
retGame.MetadataMapId = (long)dbResponse.Rows[i]["MetadataMapId"];
|
||||
retGame.MetadataSource = (HasheousClient.Models.MetadataSources)dbResponse.Rows[i]["GameIdType"];
|
||||
|
||||
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||
retMinGame.Index = i;
|
||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||
{
|
||||
AlphaList.Add("#", 1);
|
||||
retMinGame.HasSavedGame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
retMinGame.HasSavedGame = false;
|
||||
}
|
||||
if ((int)dbResponse.Rows[i]["Favourite"] == 0)
|
||||
{
|
||||
retMinGame.IsFavourite = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
retMinGame.IsFavourite = true;
|
||||
}
|
||||
|
||||
RetVal.Add(retMinGame);
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
Dictionary<string, int>? AlphaList = null;
|
||||
if (returnSummary == true)
|
||||
{
|
||||
AlphaList = new Dictionary<string, int>();
|
||||
|
||||
// build alpha list
|
||||
if (orderByField == "NameThe" || orderByField == "Name")
|
||||
{
|
||||
if (!AlphaList.ContainsKey(firstChar))
|
||||
int CurrentPage = 1;
|
||||
int NextPageIndex = pageSize;
|
||||
|
||||
string alphaSearchField;
|
||||
if (orderByField == "NameThe")
|
||||
{
|
||||
AlphaList.Add(firstChar, CurrentPage);
|
||||
alphaSearchField = "NameThe";
|
||||
}
|
||||
if (NextPageIndex == i + 1)
|
||||
else
|
||||
{
|
||||
NextPageIndex += pageSize;
|
||||
CurrentPage += 1;
|
||||
alphaSearchField = "Name";
|
||||
}
|
||||
|
||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||
{
|
||||
if (NextPageIndex == i + 1)
|
||||
{
|
||||
NextPageIndex += pageSize;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -636,12 +667,12 @@ FROM
|
||||
|
||||
}
|
||||
|
||||
public GameReturnPackage(int Count, List<Game> Games)
|
||||
public GameReturnPackage(int Count, List<Models.Game> Games)
|
||||
{
|
||||
this.Count = Count;
|
||||
|
||||
List<Games.MinimalGameItem> minimalGames = new List<Games.MinimalGameItem>();
|
||||
foreach (Game game in Games)
|
||||
foreach (Models.Game game in Games)
|
||||
{
|
||||
minimalGames.Add(new Classes.Metadata.Games.MinimalGameItem(game));
|
||||
}
|
||||
@@ -649,9 +680,9 @@ FROM
|
||||
this.Games = minimalGames;
|
||||
}
|
||||
|
||||
public int Count { get; set; }
|
||||
public List<Games.MinimalGameItem> Games { get; set; } = new List<Games.MinimalGameItem>();
|
||||
public Dictionary<string, int> AlphaList { get; set; }
|
||||
public int? Count { get; set; }
|
||||
public List<Games.MinimalGameItem>? Games { get; set; } = new List<Games.MinimalGameItem>();
|
||||
public Dictionary<string, int>? AlphaList { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Identity;
|
||||
using System.Data;
|
||||
using Asp.Versioning;
|
||||
using System.IO.Compression;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
@@ -256,7 +257,25 @@ namespace gaseous_server.Controllers.v1_1
|
||||
else
|
||||
{
|
||||
// get rom data
|
||||
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||
string romName = "";
|
||||
string romMd5 = "";
|
||||
string romSha1 = "";
|
||||
if (IsMediaGroup == false)
|
||||
{
|
||||
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||
romName = romItem.Name;
|
||||
romMd5 = romItem.Md5;
|
||||
romSha1 = romItem.Sha1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RomMediaGroup.GameRomMediaGroupItem mediaGroupItem = RomMediaGroup.GetMediaGroup(RomId);
|
||||
Models.Game game = Games.GetGame(Communications.MetadataSource, mediaGroupItem.GameId);
|
||||
Classes.Common.hashObject hashObject = new Classes.Common.hashObject(Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, mediaGroupItem.Id.ToString() + ".zip"));
|
||||
romName = game.Name;
|
||||
romMd5 = hashObject.md5hash;
|
||||
romSha1 = hashObject.sha1hash;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||
@@ -267,9 +286,8 @@ namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
||||
}
|
||||
|
||||
string contentType = "";
|
||||
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romItem.Name);
|
||||
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romName);
|
||||
|
||||
|
||||
if (StateOnly == true)
|
||||
@@ -283,15 +301,15 @@ namespace gaseous_server.Controllers.v1_1
|
||||
filename = filename + ".zip";
|
||||
|
||||
Dictionary<string, object> RomInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", romItem.Name },
|
||||
{ "StateDateTime", data.Rows[0]["StateDateTime"] },
|
||||
{ "StateName", data.Rows[0]["Name"] }
|
||||
};
|
||||
{
|
||||
{ "Name", romName },
|
||||
{ "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("MD5", romMd5);
|
||||
RomInfo.Add("SHA1", romSha1);
|
||||
RomInfo.Add("Type", "ROM");
|
||||
}
|
||||
else
|
||||
@@ -306,24 +324,24 @@ namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
List<Dictionary<string, object>> Attachments = new List<Dictionary<string, object>>();
|
||||
Attachments.Add(new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", "savestate.state" },
|
||||
{ "Body", bytes }
|
||||
});
|
||||
{
|
||||
{ "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"] }
|
||||
});
|
||||
{
|
||||
{ "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) }
|
||||
});
|
||||
{
|
||||
{ "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))
|
||||
@@ -438,16 +456,16 @@ namespace gaseous_server.Controllers.v1_1
|
||||
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 }
|
||||
};
|
||||
{
|
||||
{ "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);
|
||||
@@ -481,23 +499,23 @@ namespace gaseous_server.Controllers.v1_1
|
||||
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 }
|
||||
};
|
||||
{
|
||||
{ "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" }
|
||||
});
|
||||
{
|
||||
{ "RomId", RomId },
|
||||
{ "Management", "Unmanaged" }
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class StatisticsController: ControllerBase
|
||||
public class StatisticsController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
@@ -32,15 +32,15 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/")]
|
||||
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
||||
[Route("Games/{GameId}/{PlatformId}/{RomId}")]
|
||||
public async Task<ActionResult> NewRecordStatistics(long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
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
|
||||
{
|
||||
@@ -54,15 +54,15 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/{SessionId}")]
|
||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
||||
[Route("Games/{GameId}/{PlatformId}/{RomId}/{SessionId}")]
|
||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, long PlatformId, long RomId, Guid SessionId, bool IsMediaGroup)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
||||
return Ok(statistics.RecordSession(SessionId, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
137
gaseous-server/Controllers/V1.1/UserProfileController.cs
Normal file
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 = "Default30")]
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,52 +5,22 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class GaseousGame : IGDB.Models.Game
|
||||
public class Game : HasheousClient.Models.Metadata.IGDB.Game
|
||||
{
|
||||
public GaseousGame()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GaseousGame(IGDB.Models.Game game)
|
||||
{
|
||||
var targetType = this.GetType();
|
||||
var sourceType = game.GetType();
|
||||
foreach (var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty))
|
||||
{
|
||||
// check whether source object has the the property
|
||||
var sp = sourceType.GetProperty(prop.Name);
|
||||
if (sp != null)
|
||||
{
|
||||
// if yes, copy the value to the matching property
|
||||
var value = sp.GetValue(game, null);
|
||||
prop.SetValue(this, value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
[NoDatabase]
|
||||
public bool IsFavourite { get; set; } = false;
|
||||
|
||||
[NoDatabase]
|
||||
public bool HasSavedGame { get; set; } = false;
|
||||
|
||||
public IGDB.Models.Cover? CoverItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Cover != null)
|
||||
{
|
||||
if (this.Cover.Id != null)
|
||||
{
|
||||
// IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
||||
IGDB.Models.Cover cover = new IGDB.Models.Cover()
|
||||
{
|
||||
Id = this.Cover.Id
|
||||
};
|
||||
[NoDatabase]
|
||||
public long MetadataMapId { get; set; }
|
||||
|
||||
return cover;
|
||||
}
|
||||
}
|
||||
[NoDatabase]
|
||||
public HasheousClient.Models.MetadataSources MetadataSource { get; set; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
internal class NoDatabaseAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
9
gaseous-server/Models/ImageItem.cs
Normal file
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; }
|
||||
}
|
||||
}
|
||||
77
gaseous-server/Models/MetadataMap.cs
Normal file
77
gaseous-server/Models/MetadataMap.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using HasheousClient.Models;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class MetadataMap
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlatformId { get; set; }
|
||||
public string SignatureGameName { get; set; }
|
||||
public List<MetadataMapItem> MetadataMapItems { get; set; }
|
||||
public MetadataMapItem? PreferredMetadataMapItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MetadataMapItems == null || MetadataMapItems.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return MetadataMapItems.FirstOrDefault(mmi => mmi.Preferred);
|
||||
}
|
||||
}
|
||||
|
||||
public class MetadataMapItem
|
||||
{
|
||||
public HasheousClient.Models.MetadataSources SourceType { get; set; }
|
||||
public long SourceId { get; set; }
|
||||
public bool Preferred { get; set; }
|
||||
public string SourceSlug
|
||||
{
|
||||
get
|
||||
{
|
||||
string slug = "";
|
||||
switch (SourceType)
|
||||
{
|
||||
case MetadataSources.IGDB:
|
||||
Game game = Games.GetGame(SourceType, (long)SourceId);
|
||||
if (game != null)
|
||||
{
|
||||
slug = game.Slug;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
slug = SourceId.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
return slug;
|
||||
}
|
||||
}
|
||||
public string link
|
||||
{
|
||||
get
|
||||
{
|
||||
string link = "";
|
||||
switch (SourceType)
|
||||
{
|
||||
case MetadataSources.IGDB:
|
||||
link = $"https://www.igdb.com/games/{SourceSlug}";
|
||||
break;
|
||||
|
||||
case MetadataSources.TheGamesDb:
|
||||
link = $"https://thegamesdb.net/game.php?id={SourceId}";
|
||||
break;
|
||||
|
||||
default:
|
||||
link = "";
|
||||
break;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,13 @@ using System.Web;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Controllers;
|
||||
using IGDB.Models;
|
||||
using HasheousClient.Models.Metadata.IGDB;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class PlatformMapping
|
||||
{
|
||||
private static Dictionary<string, PlatformMapItem> PlatformMapCache = new Dictionary<string, PlatformMapItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the platform map from the embedded platform map resource
|
||||
/// </summary>
|
||||
@@ -48,7 +46,7 @@ namespace gaseous_server.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
WritePlatformMap(mapItem, true, true);
|
||||
WritePlatformMap(mapItem, true, true, true);
|
||||
Logging.Log(Logging.LogType.Information, "Platform Map", "Overwriting " + mapItem.IGDBName + " with default values.");
|
||||
}
|
||||
}
|
||||
@@ -56,7 +54,7 @@ namespace gaseous_server.Models
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Platform Map", "Importing " + mapItem.IGDBName + " from predefined data.");
|
||||
// doesn't exist - add it
|
||||
WritePlatformMap(mapItem, false, true);
|
||||
WritePlatformMap(mapItem, false, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,8 +72,8 @@ namespace gaseous_server.Models
|
||||
|
||||
foreach (PlatformMapItem mapItem in platforms)
|
||||
{
|
||||
// get the IGDB platform data
|
||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId, false);
|
||||
// insert dummy platform data - it'll be cleaned up on the first metadata refresh
|
||||
Platform platform = CreateDummyPlatform(mapItem);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -94,73 +92,87 @@ namespace gaseous_server.Models
|
||||
}
|
||||
}
|
||||
|
||||
private static Platform CreateDummyPlatform(PlatformMapItem mapItem)
|
||||
{
|
||||
Platform platform = new Platform
|
||||
{
|
||||
Id = mapItem.IGDBId,
|
||||
Name = mapItem.IGDBName,
|
||||
Slug = mapItem.IGDBSlug,
|
||||
AlternativeName = mapItem.AlternateNames.FirstOrDefault()
|
||||
};
|
||||
|
||||
if (Storage.GetCacheStatus(HasheousClient.Models.MetadataSources.None, "Platform", mapItem.IGDBId) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.None, platform);
|
||||
}
|
||||
|
||||
if (Storage.GetCacheStatus(HasheousClient.Models.MetadataSources.IGDB, "Platform", mapItem.IGDBId) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
Storage.NewCacheValue(HasheousClient.Models.MetadataSources.IGDB, platform);
|
||||
}
|
||||
|
||||
return platform;
|
||||
}
|
||||
|
||||
public static List<PlatformMapItem> PlatformMap
|
||||
{
|
||||
get
|
||||
{
|
||||
// if (Database.DatabaseMemoryCache.GetCacheObject("PlatformMap") != null)
|
||||
// {
|
||||
// return (List<PlatformMapItem>)Database.DatabaseMemoryCache.GetCacheObject("PlatformMap");
|
||||
// }
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
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>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
long mapId = (long)row["Id"];
|
||||
if (PlatformMapCache.ContainsKey(mapId.ToString()))
|
||||
|
||||
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||
if (mapItem != null)
|
||||
{
|
||||
PlatformMapItem mapItem = PlatformMapCache[mapId.ToString()];
|
||||
if (mapItem != null)
|
||||
{
|
||||
platformMaps.Add(mapItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||
if (mapItem != null)
|
||||
{
|
||||
platformMaps.Add(mapItem);
|
||||
}
|
||||
platformMaps.Add(mapItem);
|
||||
}
|
||||
}
|
||||
|
||||
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
||||
|
||||
//Database.DatabaseMemoryCache.SetCacheObject("PlatformMap", platformMaps, 600);
|
||||
|
||||
return platformMaps;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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, bool overwriteBios = false)
|
||||
{
|
||||
CreateDummyPlatform(item);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -239,20 +251,36 @@ namespace gaseous_server.Models
|
||||
{
|
||||
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 (overwriteBios == true)
|
||||
{
|
||||
isEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.Add("Id", item.IGDBId);
|
||||
dbDict.Add("Filename", biosItem.filename);
|
||||
dbDict.Add("Description", biosItem.description);
|
||||
dbDict.Add("Hash", biosItem.hash);
|
||||
dbDict.Add("Enabled", isEnabled);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
|
||||
if (PlatformMapCache.ContainsKey(item.IGDBId.ToString()))
|
||||
{
|
||||
PlatformMapCache.Remove(item.IGDBId.ToString());
|
||||
}
|
||||
// clear cache
|
||||
Database.DatabaseMemoryCache.RemoveCacheObject("PlatformMap");
|
||||
}
|
||||
|
||||
public static void WriteAvailableEmulators(PlatformMapItem item)
|
||||
@@ -287,7 +315,16 @@ namespace gaseous_server.Models
|
||||
string sql = "";
|
||||
|
||||
// get platform data
|
||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId, false);
|
||||
Platform? platform = null;
|
||||
if (Storage.GetCacheStatus(HasheousClient.Models.MetadataSources.None, "Platform", IGDBId) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
//platform = Platforms.GetPlatform(IGDBId, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// platform = (Platform)Storage.GetCacheValue<Platform>(HasheousClient.Models.MetadataSources.None, new Platform(), "id", IGDBId);
|
||||
platform = Platforms.GetPlatform(IGDBId, HasheousClient.Models.MetadataSources.None);
|
||||
}
|
||||
|
||||
if (platform != null)
|
||||
{
|
||||
@@ -353,6 +390,7 @@ namespace gaseous_server.Models
|
||||
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
||||
List<string> enabledBios = new List<string>();
|
||||
foreach (DataRow biosRow in biosTable.Rows)
|
||||
{
|
||||
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
||||
@@ -362,6 +400,11 @@ namespace gaseous_server.Models
|
||||
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
||||
};
|
||||
bioss.Add(bios);
|
||||
|
||||
if ((bool)Common.ReturnValueIfNull(biosRow["Enabled"], true) == true)
|
||||
{
|
||||
enabledBios.Add(bios.hash);
|
||||
}
|
||||
}
|
||||
|
||||
// build item
|
||||
@@ -383,15 +426,7 @@ namespace gaseous_server.Models
|
||||
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
||||
};
|
||||
mapItem.Bios = bioss;
|
||||
|
||||
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
||||
{
|
||||
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
||||
}
|
||||
mapItem.EnabledBIOSHashes = enabledBios;
|
||||
|
||||
return mapItem;
|
||||
}
|
||||
@@ -417,8 +452,8 @@ namespace gaseous_server.Models
|
||||
{
|
||||
if (Signature.Game != null) { Signature.Game.System = PlatformMapping.IGDBName; }
|
||||
}
|
||||
Signature.Flags.IGDBPlatformId = PlatformMapping.IGDBId;
|
||||
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
||||
Signature.Flags.PlatformId = PlatformMapping.IGDBId;
|
||||
Signature.Flags.PlatformName = PlatformMapping.IGDBName;
|
||||
|
||||
PlatformFound = true;
|
||||
|
||||
@@ -441,8 +476,8 @@ namespace gaseous_server.Models
|
||||
{
|
||||
if (Signature.Game != null) { Signature.Game.System = PlatformMapping.IGDBName; }
|
||||
}
|
||||
Signature.Flags.IGDBPlatformId = PlatformMapping.IGDBId;
|
||||
Signature.Flags.IGDBPlatformName = PlatformMapping.IGDBName;
|
||||
Signature.Flags.PlatformId = PlatformMapping.IGDBId;
|
||||
Signature.Flags.PlatformName = PlatformMapping.IGDBName;
|
||||
|
||||
PlatformFound = true;
|
||||
|
||||
@@ -458,6 +493,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 long IGDBId { get; set; }
|
||||
@@ -505,6 +608,15 @@ namespace gaseous_server.Models
|
||||
public string description { 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,366 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using HasheousClient.Models;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
||||
public class Signatures_Games : HasheousClient.Models.SignatureModel
|
||||
{
|
||||
public Signatures_Games()
|
||||
{
|
||||
}
|
||||
|
||||
public SignatureFlags Flags = new SignatureFlags();
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
int _score = 0;
|
||||
|
||||
if (Game != null)
|
||||
{
|
||||
_score = _score + Game.Score;
|
||||
}
|
||||
|
||||
if (Rom != null)
|
||||
{
|
||||
_score = _score + Rom.Score;
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
|
||||
public GameItem Game = new GameItem();
|
||||
public RomItem Rom = new RomItem();
|
||||
|
||||
public SignatureFlags Flags
|
||||
{
|
||||
get
|
||||
{
|
||||
SignatureFlags _flags = new SignatureFlags();
|
||||
|
||||
foreach (SourceValues.SourceValueItem source in MetadataSources.Platforms)
|
||||
{
|
||||
if (source.Source == Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
{
|
||||
_flags.PlatformId = source.Id;
|
||||
_flags.PlatformName = source.Name;
|
||||
_flags.PlatformMetadataSource = source.Source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_flags.PlatformId == 0)
|
||||
{
|
||||
// fall back to the IGDB source if present
|
||||
foreach (SourceValues.SourceValueItem source in MetadataSources.Platforms)
|
||||
{
|
||||
if (source.Source == HasheousClient.Models.MetadataSources.IGDB)
|
||||
{
|
||||
_flags.PlatformId = source.Id;
|
||||
_flags.PlatformName = source.Name;
|
||||
_flags.PlatformMetadataSource = source.Source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SourceValues.SourceValueItem source in MetadataSources.Games)
|
||||
{
|
||||
if (source.Source == Config.MetadataConfiguration.DefaultMetadataSource)
|
||||
{
|
||||
_flags.GameId = source.Id;
|
||||
_flags.GameName = source.Name;
|
||||
_flags.GameMetadataSource = source.Source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_flags.GameId == null || _flags.GameId == 0)
|
||||
{
|
||||
_flags.GameId = 0;
|
||||
_flags.GameName = "Unknown Game";
|
||||
_flags.GameMetadataSource = HasheousClient.Models.MetadataSources.None;
|
||||
}
|
||||
|
||||
return _flags;
|
||||
}
|
||||
}
|
||||
|
||||
public SourceValues MetadataSources = new SourceValues();
|
||||
|
||||
public class SourceValues
|
||||
{
|
||||
public List<SourceValueItem> Platforms = new List<SourceValueItem>();
|
||||
public List<SourceValueItem> Games = new List<SourceValueItem>();
|
||||
|
||||
public class SourceValueItem
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public HasheousClient.Models.MetadataSources Source { get; set; }
|
||||
}
|
||||
|
||||
public void AddPlatform(long Id, string Name, HasheousClient.Models.MetadataSources Source)
|
||||
{
|
||||
// check that the platform doesn't already exist
|
||||
foreach (SourceValueItem item in Platforms)
|
||||
{
|
||||
if (item.Id == Id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SourceValueItem newItem = new SourceValueItem();
|
||||
newItem.Id = Id;
|
||||
newItem.Name = Name;
|
||||
newItem.Source = Source;
|
||||
Platforms.Add(newItem);
|
||||
}
|
||||
|
||||
public void AddGame(long Id, string Name, HasheousClient.Models.MetadataSources Source)
|
||||
{
|
||||
// check that the game doesn't already exist
|
||||
foreach (SourceValueItem item in Games)
|
||||
{
|
||||
if (item.Id == Id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SourceValueItem newItem = new SourceValueItem();
|
||||
newItem.Id = Id;
|
||||
newItem.Name = Name;
|
||||
newItem.Source = Source;
|
||||
Games.Add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
public class SignatureFlags
|
||||
{
|
||||
public long IGDBPlatformId { get; set; }
|
||||
public string IGDBPlatformName { get; set; }
|
||||
public long IGDBGameId { get; set; }
|
||||
public long PlatformId { get; set; }
|
||||
public string PlatformName { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public string GameName { get; set; }
|
||||
public HasheousClient.Models.MetadataSources PlatformMetadataSource { get; set; }
|
||||
public HasheousClient.Models.MetadataSources GameMetadataSource { get; set; }
|
||||
}
|
||||
|
||||
public class GameItem : HasheousClient.Models.SignatureModel.GameItem
|
||||
{
|
||||
public GameItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string UserManual { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate a score based on the availablility of data
|
||||
int _score = 0;
|
||||
var properties = this.GetType().GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
if (prop.GetGetMethod() != null)
|
||||
{
|
||||
switch (prop.Name.ToLower())
|
||||
{
|
||||
case "id":
|
||||
case "score":
|
||||
break;
|
||||
case "name":
|
||||
case "year":
|
||||
case "publisher":
|
||||
case "system":
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RomItem : HasheousClient.Models.SignatureModel.RomItem
|
||||
{
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate a score based on the availablility of data
|
||||
int _score = 0;
|
||||
var properties = this.GetType().GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
if (prop.GetGetMethod() != null)
|
||||
{
|
||||
switch (prop.Name.ToLower())
|
||||
{
|
||||
case "name":
|
||||
case "size":
|
||||
case "crc":
|
||||
case "developmentstatus":
|
||||
case "flags":
|
||||
case "attributes":
|
||||
case "romtypemedia":
|
||||
case "medialabel":
|
||||
if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(Int64) || prop.PropertyType == typeof(List<string>))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaType
|
||||
{
|
||||
public MediaType(SignatureSourceType Source, string MediaTypeString)
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case RomItem.SignatureSourceType.TOSEC:
|
||||
string[] typeString = MediaTypeString.Split(" ");
|
||||
|
||||
string inType = "";
|
||||
foreach (string typeStringVal in typeString)
|
||||
{
|
||||
if (inType == "")
|
||||
{
|
||||
switch (typeStringVal.ToLower())
|
||||
{
|
||||
case "disk":
|
||||
Media = RomItem.RomTypes.Disk;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "disc":
|
||||
Media = RomItem.RomTypes.Disc;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "file":
|
||||
Media = RomItem.RomTypes.File;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "part":
|
||||
Media = RomItem.RomTypes.Part;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "tape":
|
||||
Media = RomItem.RomTypes.Tape;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "of":
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "side":
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (inType.ToLower())
|
||||
{
|
||||
case "disk":
|
||||
case "disc":
|
||||
case "file":
|
||||
case "part":
|
||||
case "tape":
|
||||
Number = int.Parse(typeStringVal);
|
||||
break;
|
||||
case "of":
|
||||
Count = int.Parse(typeStringVal);
|
||||
break;
|
||||
case "side":
|
||||
Side = typeStringVal;
|
||||
break;
|
||||
}
|
||||
inType = "";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public RomItem.RomTypes? Media { get; set; }
|
||||
|
||||
public int? Number { get; set; }
|
||||
|
||||
public int? Count { get; set; }
|
||||
|
||||
public string? Side { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
20
gaseous-server/Models/Signatures_Sources.cs
Normal file
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; }
|
||||
}
|
||||
}
|
||||
24
gaseous-server/Models/UserProfile.cs
Normal file
24
gaseous-server/Models/UserProfile.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class UserProfile
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Quip { get; set; }
|
||||
public NowPlayingItem? NowPlaying { get; set; }
|
||||
public class NowPlayingItem
|
||||
{
|
||||
public Game Game { get; set; }
|
||||
public HasheousClient.Models.Metadata.IGDB.Platform Platform { get; set; }
|
||||
public long Duration { 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user