Compare commits

..

8 Commits

Author SHA1 Message Date
5f34a1b49f .gitea/workflows/registry.yml hinzugefügt
All checks were successful
release-tag / release-image (push) Successful in 2m6s
2025-01-19 16:52:16 +00:00
Michael Green
2d63a1c416 Nightly build (#450) 2024-10-26 20:10:11 +11:00
Michael Green
146597dd4b Minor UI tweaks (#431) 2024-09-20 15:00:44 -07:00
Michael Green
f4ba84a54f Update README.MD (#428) 2024-09-17 11:30:52 +10:00
Michael Green
64fb76484b Update to profile cards to display now-playing (#427) 2024-09-17 10:48:49 +10:00
Michael Green
bfade006bd New UI Styling Fixes (#426)
Resolve some issues with how the new UI renders.
2024-09-16 16:25:36 +10:00
Michael Green
c8140d7178 Revamp of BIOS handling (#423)
Many of the platforms are similar enough to other platforms that they'll
share the same BIOS files.

The current storage method stores BIOS files per platform, meaning that
files can be duplicated multiple times to satisfy the requirements of
each platform.

This change stores the files as their hash with a .bios extension
(example: `85ad74194e87c08904327de1a9443b7a.bios`) in a flat directory
structure. This allows BIOS files that are used by multiple platforms to
be shared without duplication.
2024-09-15 20:35:36 +10:00
Michael Green
070589f718 Fix for home path change (#422)
The migration of the docker container to a rootless one requires the
default library to move.

This change strips the library path from the path to the ROM and
replaces it with an SQL view that concatenates the library path and ROM
path.
2024-09-14 01:32:18 +10:00
33 changed files with 681 additions and 293 deletions

View File

@@ -0,0 +1,51 @@
name: release-tag
on:
push:
branches:
- 'main'
jobs:
release-image:
runs-on: ubuntu-latest
env:
DOCKER_ORG: sendnrw
DOCKER_LATEST: latest
RUNNER_TOOL_CACHE: /toolcache
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v2
with: # replace it with your local IP
config-inline: |
[registry."git.send.nrw"]
http = true
insecure = true
- name: Login to DockerHub
uses: docker/login-action@v2
with:
registry: git.send.nrw # replace it with your local IP
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get Meta
id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./build/Dockerfile
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}

61
.github/workflows/BuildNightly.yml vendored Normal file
View 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

View File

@@ -1,17 +1,9 @@
[![.NET](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml) [![CodeQL](https://github.com/gaseous-project/gaseous-server/actions/workflows/codeql.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/codeql.yml) [![Build Release Docker Image](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml) [![.NET](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml) [![Nightly](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildNightly.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildNightly.yml) [![Build Release Docker Image](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml/badge.svg)](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml)
# Gaseous Server # <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. 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 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.
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.
While we do our best to stay on top of server security, if you expose the server to the internet **you do so at your own risk**. While we do our best to stay on top of server security, if you expose the server to the internet **you do so at your own risk**.
@@ -20,15 +12,19 @@ While we do our best to stay on top of server security, if you expose the server
![Game](./gaseous-server/wwwroot/screenshots/Game.png) ![Game](./gaseous-server/wwwroot/screenshots/Game.png)
![Emulator](./gaseous-server/wwwroot/screenshots/Emulator.png) ![Emulator](./gaseous-server/wwwroot/screenshots/Emulator.png)
## Requirements ## 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. * 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). * 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. * 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 * 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 ## 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 * [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) * [EmulatorJS](https://github.com/EmulatorJS/EmulatorJS)
## Discord Server ## Discord Server
[![Join our Discord server!](https://invite.casperiv.dev/?inviteCode=Nhu7wpT3k4&format=svg)](https://discord.gg/Nhu7wpT3k4) Join our 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

View File

@@ -5,6 +5,9 @@ echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
groupadd -g ${PGID} gaseous groupadd -g ${PGID} gaseous
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
usermod -p "*" gaseous 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 mkdir -p /home/gaseous/.gaseous-server
chown -R ${PUID} /App /home/gaseous/.gaseous-server chown -R ${PUID} /App /home/gaseous/.gaseous-server
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server chgrp -R ${PGID} /App /home/gaseous/.gaseous-server

View File

@@ -5,6 +5,9 @@ echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
groupadd -g ${PGID} gaseous groupadd -g ${PGID} gaseous
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
usermod -p "*" gaseous 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 mkdir -p /home/gaseous/.gaseous-server
chown -R ${PUID} /App /home/gaseous/.gaseous-server chown -R ${PUID} /App /home/gaseous/.gaseous-server
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server chgrp -R ${PGID} /App /home/gaseous/.gaseous-server

View File

@@ -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:/home/gaseous/.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:

View File

@@ -4,12 +4,39 @@ using System.Security.Cryptography;
namespace gaseous_server.Classes namespace gaseous_server.Classes
{ {
public class Bios public class Bios
{ {
public Bios() public Bios()
{ {
} }
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) public static Models.PlatformMapping.PlatformMapItem? BiosHashSignatureLookup(string MD5)
{ {
@@ -96,10 +123,11 @@ namespace gaseous_server.Classes
{ {
get 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 get
{ {
bool fileExists = File.Exists(biosPath); bool fileExists = File.Exists(biosPath);

View File

@@ -531,11 +531,7 @@ namespace gaseous_server.Classes
{ {
get get
{ {
return ReadSetting<string>("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data")); return Path.Combine(Config.ConfigurationPath, "Data");
}
set
{
SetSetting<string>("LibraryRootDirectory", value);
} }
} }
@@ -579,6 +575,14 @@ namespace gaseous_server.Classes
} }
} }
public string LibraryFirmwareDirectory
{
get
{
return Path.Combine(LibraryRootDirectory, "Firmware");
}
}
public string LibraryUploadDirectory public string LibraryUploadDirectory
{ {
get get
@@ -660,7 +664,8 @@ namespace gaseous_server.Classes
{ {
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); } if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
if (!Directory.Exists(LibraryImportDirectory)) { Directory.CreateDirectory(LibraryImportDirectory); } if (!Directory.Exists(LibraryImportDirectory)) { Directory.CreateDirectory(LibraryImportDirectory); }
if (!Directory.Exists(LibraryBIOSDirectory)) { Directory.CreateDirectory(LibraryBIOSDirectory); } // if (!Directory.Exists(LibraryBIOSDirectory)) { Directory.CreateDirectory(LibraryBIOSDirectory); }
if (!Directory.Exists(LibraryFirmwareDirectory)) { Directory.CreateDirectory(LibraryFirmwareDirectory); }
if (!Directory.Exists(LibraryUploadDirectory)) { Directory.CreateDirectory(LibraryUploadDirectory); } if (!Directory.Exists(LibraryUploadDirectory)) { Directory.CreateDirectory(LibraryUploadDirectory); }
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); } if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); } if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }

View File

@@ -149,9 +149,6 @@ namespace gaseous_server.Classes
db.ExecuteNonQuery(sql, dbDict); db.ExecuteNonQuery(sql, dbDict);
} while (reader.EndOfStream == false); } while (reader.EndOfStream == false);
} }
// this is a safe background task
BackgroundUpgradeTargetSchemaVersions.Add(1023);
break; break;
case 1024: case 1024:
@@ -181,6 +178,73 @@ namespace gaseous_server.Classes
}; };
db.ExecuteNonQuery(sql, dbDict); 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 = (bool)row["DefaultLibrary"];
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);
}
}
// migrating metadata is a safe background task
BackgroundUpgradeTargetSchemaVersions.Add(1024);
break; break;
} }
break; break;
@@ -197,8 +261,8 @@ namespace gaseous_server.Classes
MySql_1002_MigrateMetadataVersion(); MySql_1002_MigrateMetadataVersion();
break; break;
case 1023: case 1024:
MySql_1023_MigrateMetadataVersion(); MySql_1024_MigrateMetadataVersion();
break; break;
} }
} }
@@ -301,12 +365,12 @@ namespace gaseous_server.Classes
} }
} }
public static void MySql_1023_MigrateMetadataVersion() public static void MySql_1024_MigrateMetadataVersion()
{ {
FileSignature fileSignature = new FileSignature(); FileSignature fileSignature = new FileSignature();
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT * FROM Games_Roms WHERE RomDataVersion = 1;"; string sql = "SELECT * FROM view_Games_Roms WHERE RomDataVersion = 1;";
DataTable data = db.ExecuteCMD(sql); DataTable data = db.ExecuteCMD(sql);
long count = 1; long count = 1;
foreach (DataRow row in data.Rows) foreach (DataRow row in data.Rows)

View File

@@ -24,7 +24,7 @@ namespace gaseous_server.Classes
ageRestriction_Generic += " OR view_Games.AgeGroupId IS NULL"; 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`;"; 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 GROUP BY Platform.`Name`;";
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300)); DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
@@ -82,7 +82,7 @@ namespace gaseous_server.Classes
// age groups // age groups
List<FilterItem> agegroupings = new List<FilterItem>(); List<FilterItem> agegroupings = new List<FilterItem>();
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id HAVING RomCount > 0) Game GROUP BY Game.AgeGroupId ORDER BY Game.AgeGroupId DESC"; sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(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)); dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
foreach (DataRow dr in dbResponse.Rows) foreach (DataRow dr in dbResponse.Rows)
@@ -112,7 +112,7 @@ 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 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 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 JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
sql = sql.Replace("<ITEMNAME>", Name); sql = sql.Replace("<ITEMNAME>", Name);
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300)); DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));

View File

@@ -60,6 +60,18 @@ 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 public static List<LibraryItem> GetLibraries
{ {
get get

View File

@@ -73,7 +73,7 @@ namespace gaseous_server.Classes
RetVal.Add("type", "rom"); RetVal.Add("type", "rom");
// check to make sure we don't already have this file imported // check to make sure we don't already have this file imported
sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1"; sql = "SELECT COUNT(Id) AS count FROM view_Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
dbDict.Add("md5", hash.md5hash); dbDict.Add("md5", hash.md5hash);
dbDict.Add("sha1", hash.sha1hash); dbDict.Add("sha1", hash.sha1hash);
DataTable importDB = db.ExecuteCMD(sql, dbDict); DataTable importDB = db.ExecuteCMD(sql, dbDict);
@@ -129,7 +129,7 @@ namespace gaseous_server.Classes
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true); IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
// add to database // add to database
long RomId = StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath); long RomId = StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath, 0, true);
// build return value // build return value
RetVal.Add("romid", RomId); RetVal.Add("romid", RomId);
@@ -151,11 +151,8 @@ namespace gaseous_server.Classes
{ {
if (biosItem.hash == hash.md5hash) if (biosItem.hash == hash.md5hash)
{ {
string biosPath = biosItem.biosPath.Replace(biosItem.filename, ""); string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, biosItem.hash + ".bios");
if (!Directory.Exists(biosPath)) Logging.Log(Logging.LogType.Information, "Import Game", " " + GameFileImportPath + " is a BIOS file - moving to " + biosPath);
{
Directory.CreateDirectory(biosPath);
}
File.Move(GameFileImportPath, biosItem.biosPath, true); File.Move(GameFileImportPath, biosItem.biosPath, true);
@@ -329,7 +326,7 @@ namespace gaseous_server.Classes
return SearchCandidates; return SearchCandidates;
} }
public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, gaseous_server.Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0) public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, gaseous_server.Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0, bool SourceIsExternal = false)
{ {
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
@@ -339,7 +336,7 @@ namespace gaseous_server.Classes
if (UpdateId == 0) 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, RomDataVersion) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid, @romdataversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);"; sql = "INSERT INTO Games_Roms (PlatformId, GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, RelativePath, MetadataSource, MetadataGameName, MetadataVersion, LibraryId, RomDataVersion) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid, @romdataversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
} }
else else
{ {
@@ -378,7 +375,13 @@ namespace gaseous_server.Classes
dbDict.Add("romtype", (int)discoveredSignature.Rom.RomType); dbDict.Add("romtype", (int)discoveredSignature.Rom.RomType);
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(discoveredSignature.Rom.RomTypeMedia, "")); dbDict.Add("romtypemedia", Common.ReturnValueIfNull(discoveredSignature.Rom.RomTypeMedia, ""));
dbDict.Add("medialabel", Common.ReturnValueIfNull(discoveredSignature.Rom.MediaLabel, "")); dbDict.Add("medialabel", Common.ReturnValueIfNull(discoveredSignature.Rom.MediaLabel, ""));
dbDict.Add("path", GameFileImportPath);
string libraryRootPath = library.Path;
if (libraryRootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false)
{
libraryRootPath += Path.DirectorySeparatorChar;
}
dbDict.Add("path", GameFileImportPath.Replace(libraryRootPath, ""));
DataTable romInsert = db.ExecuteCMD(sql, dbDict); DataTable romInsert = db.ExecuteCMD(sql, dbDict);
long romId = 0; long romId = 0;
@@ -394,7 +397,7 @@ namespace gaseous_server.Classes
// move to destination // move to destination
if (library.IsDefaultLibrary == true) if (library.IsDefaultLibrary == true)
{ {
MoveGameFile(romId); MoveGameFile(romId, SourceIsExternal);
} }
return romId; return romId;
@@ -430,10 +433,14 @@ namespace gaseous_server.Classes
return DestinationPathName; return DestinationPathName;
} }
public static bool MoveGameFile(long RomId) public static bool MoveGameFile(long RomId, bool SourceIsExternal)
{ {
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId); Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
string romPath = rom.Path; string romPath = rom.Path;
if (SourceIsExternal == true)
{
romPath = rom.RelativePath;
}
if (File.Exists(romPath)) if (File.Exists(romPath))
{ {
@@ -458,10 +465,16 @@ namespace gaseous_server.Classes
// update the db // update the db
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); 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>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("id", RomId); 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); db.ExecuteCMD(sql, dbDict);
return true; return true;
@@ -483,7 +496,7 @@ namespace gaseous_server.Classes
// move rom files to their new location // move rom files to their new location
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT * FROM Games_Roms WHERE LibraryId = @libraryid"; string sql = "SELECT * FROM view_Games_Roms WHERE LibraryId = @libraryid";
Dictionary<string, object> dbDict = new Dictionary<string, object>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("libraryid", library.Id); dbDict.Add("libraryid", library.Id);
DataTable romDT = db.ExecuteCMD(sql, dbDict); DataTable romDT = db.ExecuteCMD(sql, dbDict);
@@ -495,7 +508,7 @@ namespace gaseous_server.Classes
SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]); 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"]); Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
long RomId = (long)romDT.Rows[i]["id"]; long RomId = (long)romDT.Rows[i]["id"];
MoveGameFile(RomId); MoveGameFile(RomId, false);
} }
} }
ClearStatus(); ClearStatus();
@@ -639,7 +652,7 @@ namespace gaseous_server.Classes
dupDict.Add("libraryid", library.Id); dupDict.Add("libraryid", library.Id);
db.ExecuteCMD(duplicateSql, dupDict); 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>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("libraryid", library.Id); dbDict.Add("libraryid", library.Id);
DataTable dtRoms = db.ExecuteCMD(sql, dbDict); DataTable dtRoms = db.ExecuteCMD(sql, dbDict);
@@ -664,7 +677,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); dtRoms = db.ExecuteCMD(sql, dbDict);
// search for files in the library that aren't in the database // search for files in the library that aren't in the database
@@ -736,7 +749,7 @@ namespace gaseous_server.Classes
} }
ClearStatus(); 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); dtRoms = db.ExecuteCMD(sql, dbDict);
// check all roms to see if their local file still exists // check all roms to see if their local file still exists
@@ -760,7 +773,7 @@ namespace gaseous_server.Classes
if (romPath != ComputeROMPath(romId)) if (romPath != ComputeROMPath(romId))
{ {
Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found, but needs to be moved"); Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found, but needs to be moved");
MoveGameFile(romId); MoveGameFile(romId, false);
} }
else else
{ {
@@ -801,11 +814,11 @@ namespace gaseous_server.Classes
string sql = ""; string sql = "";
if (ForceExecute == false) 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;"; sql = "SELECT * FROM view_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 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;"; sql = "SELECT * FROM view_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>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7)); dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7));

View File

@@ -510,8 +510,8 @@ namespace gaseous_server.Classes.Metadata
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = @" string sql = @"
SELECT DISTINCT SELECT DISTINCT
Games_Roms.GameId, view_Games_Roms.GameId,
Games_Roms.PlatformId, view_Games_Roms.PlatformId,
Platform.`Name`, Platform.`Name`,
User_RecentPlayedRoms.UserId AS MostRecentUserId, User_RecentPlayedRoms.UserId AS MostRecentUserId,
User_RecentPlayedRoms.RomId AS MostRecentRomId, User_RecentPlayedRoms.RomId AS MostRecentRomId,
@@ -530,23 +530,23 @@ SELECT DISTINCT
END AS `FavouriteRomName`, END AS `FavouriteRomName`,
User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup
FROM FROM
Games_Roms view_Games_Roms
LEFT JOIN LEFT JOIN
Platform ON Games_Roms.PlatformId = Platform.Id Platform ON view_Games_Roms.PlatformId = Platform.Id
LEFT JOIN LEFT JOIN
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId AND User_RecentPlayedRoms.GameId = view_Games_Roms.GameId
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId AND User_RecentPlayedRoms.PlatformId = view_Games_Roms.PlatformId
LEFT JOIN LEFT JOIN
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId AND User_GameFavouriteRoms.GameId = view_Games_Roms.GameId
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId AND User_GameFavouriteRoms.PlatformId = view_Games_Roms.PlatformId
LEFT JOIN LEFT JOIN
Games_Roms AS GMR ON GMR.Id = User_RecentPlayedRoms.RomId view_Games_Roms AS GMR ON GMR.Id = User_RecentPlayedRoms.RomId
LEFT JOIN LEFT JOIN
Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId view_Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId
WHERE WHERE
Games_Roms.GameId = @gameid view_Games_Roms.GameId = @gameid
ORDER BY Platform.`Name`;"; ORDER BY Platform.`Name`;";
Dictionary<string, object> dbDict = new Dictionary<string, object> Dictionary<string, object> dbDict = new Dictionary<string, object>
{ {
@@ -583,7 +583,10 @@ ORDER BY Platform.`Name`;";
{ {
LastPlayedRomId = (long?)row["MostRecentRomId"]; LastPlayedRomId = (long?)row["MostRecentRomId"];
LastPlayedIsMediagroup = (bool)row["MostRecentRomIsMediaGroup"]; LastPlayedIsMediagroup = (bool)row["MostRecentRomIsMediaGroup"];
LastPlayedRomName = (string)row["MostRecentRomName"]; if (row["MostRecentRomName"] != System.DBNull.Value)
{
LastPlayedRomName = string.IsNullOrEmpty((string?)row["MostRecentRomName"]) ? "" : (string)row["MostRecentRomName"];
}
} }
long? FavouriteRomId = null; long? FavouriteRomId = null;
@@ -593,7 +596,10 @@ ORDER BY Platform.`Name`;";
{ {
FavouriteRomId = (long?)row["FavouriteRomId"]; FavouriteRomId = (long?)row["FavouriteRomId"];
FavouriteRomIsMediagroup = (bool)row["FavouriteRomIsMediaGroup"]; FavouriteRomIsMediagroup = (bool)row["FavouriteRomIsMediaGroup"];
FavouriteRomName = (string)row["FavouriteRomName"]; if (row["MostRecentRomName"] != System.DBNull.Value)
{
FavouriteRomName = string.IsNullOrEmpty((string?)row["MostRecentRomName"]) ? "" : (string)row["MostRecentRomName"];
}
} }
AvailablePlatformItem valuePair = new AvailablePlatformItem AvailablePlatformItem valuePair = new AvailablePlatformItem

View File

@@ -39,7 +39,7 @@ namespace gaseous_server.Classes
string NameSearchWhere = ""; string NameSearchWhere = "";
if (NameSearch.Length > 0) if (NameSearch.Length > 0)
{ {
NameSearchWhere = " AND Games_Roms.`Name` LIKE @namesearch"; NameSearchWhere = " AND view_Games_Roms.`Name` LIKE @namesearch";
dbDict.Add("namesearch", '%' + NameSearch + '%'); dbDict.Add("namesearch", '%' + NameSearch + '%');
} }
@@ -51,37 +51,37 @@ namespace gaseous_server.Classes
UserJoin = @" UserJoin = @"
LEFT JOIN LEFT JOIN
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId AND User_RecentPlayedRoms.GameId = view_Games_Roms.GameId
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId AND User_RecentPlayedRoms.PlatformId = view_Games_Roms.PlatformId
AND User_RecentPlayedRoms.RomId = Games_Roms.Id AND User_RecentPlayedRoms.RomId = view_Games_Roms.Id
AND User_RecentPlayedRoms.IsMediaGroup = 0 AND User_RecentPlayedRoms.IsMediaGroup = 0
LEFT JOIN LEFT JOIN
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId AND User_GameFavouriteRoms.GameId = view_Games_Roms.GameId
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId AND User_GameFavouriteRoms.PlatformId = view_Games_Roms.PlatformId
AND User_GameFavouriteRoms.RomId = Games_Roms.Id AND User_GameFavouriteRoms.RomId = view_Games_Roms.Id
AND User_GameFavouriteRoms.IsMediaGroup = 0 AND User_GameFavouriteRoms.IsMediaGroup = 0
"; ";
} }
// platform query // platform query
sqlPlatform = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;"; sqlPlatform = "SELECT DISTINCT view_Games_Roms.PlatformId, Platform.`Name` FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;";
if (PlatformId == -1) if (PlatformId == -1)
{ {
// data query // data query
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;"; 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.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, view_Games_Roms.`Name` LIMIT 1000;";
// count query // count query
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";"; sqlCount = "SELECT COUNT(view_Games_Roms.Id) AS RomCount FROM view_Games_Roms WHERE view_Games_Roms.GameId = @id" + NameSearchWhere + ";";
} }
else else
{ {
// data query // data query
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;"; 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.GameId = @id AND view_Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, view_Games_Roms.`Name` LIMIT 1000;";
// count query // count query
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";"; sqlCount = "SELECT COUNT(view_Games_Roms.Id) AS RomCount FROM view_Games_Roms WHERE view_Games_Roms.GameId = @id AND view_Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
dbDict.Add("platformid", PlatformId); dbDict.Add("platformid", PlatformId);
} }
@@ -114,7 +114,7 @@ namespace gaseous_server.Classes
public static GameRomItem GetRom(long RomId) public static GameRomItem GetRom(long RomId)
{ {
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id WHERE Games_Roms.Id = @id"; string sql = "SELECT view_Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON view_Games_Roms.GameId = Game.Id WHERE view_Games_Roms.Id = @id";
Dictionary<string, object> dbDict = new Dictionary<string, object>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("id", RomId); dbDict.Add("id", RomId);
DataTable romDT = db.ExecuteCMD(sql, dbDict); DataTable romDT = db.ExecuteCMD(sql, dbDict);
@@ -134,7 +134,7 @@ namespace gaseous_server.Classes
public static GameRomItem GetRom(string MD5) public static GameRomItem GetRom(string MD5)
{ {
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id WHERE Games_Roms.MD5 = @id"; string sql = "SELECT view_Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM view_Games_Roms LEFT JOIN Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON view_Games_Roms.GameId = Game.Id WHERE view_Games_Roms.MD5 = @id";
Dictionary<string, object> dbDict = new Dictionary<string, object>(); Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("id", MD5); dbDict.Add("id", MD5);
DataTable romDT = db.ExecuteCMD(sql, dbDict); DataTable romDT = db.ExecuteCMD(sql, dbDict);
@@ -282,6 +282,7 @@ namespace gaseous_server.Classes
RomTypeMedia = (string)romDR["romtypemedia"], RomTypeMedia = (string)romDR["romtypemedia"],
MediaLabel = (string)romDR["medialabel"], MediaLabel = (string)romDR["medialabel"],
Path = (string)romDR["path"], Path = (string)romDR["path"],
RelativePath = (string)romDR["relativepath"],
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"], SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""), SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
HasSaveStates = hasSaveStates, HasSaveStates = hasSaveStates,
@@ -322,6 +323,7 @@ namespace gaseous_server.Classes
public long GameId { get; set; } public long GameId { get; set; }
public string Game { get; set; } public string Game { get; set; }
public string? Path { get; set; } public string? Path { get; set; }
public string? RelativePath { get; set; }
public string? SignatureSourceGameTitle { get; set; } public string? SignatureSourceGameTitle { get; set; }
public bool HasSaveStates { get; set; } = false; public bool HasSaveStates { get; set; } = false;
public GameLibrary.LibraryItem Library { get; set; } public GameLibrary.LibraryItem Library { get; set; }

View File

@@ -1,4 +1,6 @@
using System.Data; using System.Data;
using gaseous_server.Classes.Metadata;
using IGDB.Models;
namespace gaseous_server.Classes namespace gaseous_server.Classes
{ {
@@ -15,8 +17,9 @@ namespace gaseous_server.Classes
public Models.UserProfile? GetUserProfile(string UserId) public Models.UserProfile? GetUserProfile(string UserId)
{ {
// build the user profile object
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT Id, DisplayName, Quip, AvatarExtension, ProfileBackgroundExtension, UnstructuredData FROM UserProfiles WHERE Id = @userid;"; string sql = "SELECT Id, UserId, DisplayName, Quip, AvatarExtension, ProfileBackgroundExtension, UnstructuredData FROM UserProfiles WHERE Id = @userid;";
Dictionary<string, object> dbDict = new Dictionary<string, object>{ Dictionary<string, object> dbDict = new Dictionary<string, object>{
{ "userid", UserId } { "userid", UserId }
}; };
@@ -48,6 +51,24 @@ namespace gaseous_server.Classes
}; };
} }
// 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)
{
NowPlaying = new Models.UserProfile.NowPlayingItem
{
Game = Games.GetGame((long)nowPlayingData.Rows[0]["GameId"], false, false, false),
Platform = Platforms.GetPlatform((long)nowPlayingData.Rows[0]["PlatformId"], false, false),
Duration = Convert.ToInt64(nowPlayingData.Rows[0]["SessionLength"])
};
}
// return the user profile object
return new Models.UserProfile return new Models.UserProfile
{ {
UserId = Guid.Parse(data.Rows[0]["Id"].ToString()), UserId = Guid.Parse(data.Rows[0]["Id"].ToString()),
@@ -55,6 +76,7 @@ namespace gaseous_server.Classes
Quip = data.Rows[0]["Quip"].ToString(), Quip = data.Rows[0]["Quip"].ToString(),
Avatar = Avatar, Avatar = Avatar,
ProfileBackground = ProfileBackground, ProfileBackground = ProfileBackground,
NowPlaying = NowPlaying,
Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(data.Rows[0]["UnstructuredData"].ToString()) Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(data.Rows[0]["UnstructuredData"].ToString())
}; };
} }

View File

@@ -10,6 +10,8 @@ using Asp.Versioning;
using Authentication; using Authentication;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using gaseous_server.Models; using gaseous_server.Models;
using IGDB.Models;
using gaseous_server.Classes.Metadata;
namespace gaseous_server.Controllers namespace gaseous_server.Controllers
{ {
@@ -62,25 +64,15 @@ namespace gaseous_server.Controllers
{ {
try try
{ {
Platform platform = Platforms.GetPlatform(PlatformId);
PlatformMapping.PlatformMapItem platformMap = PlatformMapping.GetPlatformMap(PlatformId);
List<string> biosHashes = new List<string>();
if (GameId == -1 || filtered == false) if (GameId == -1 || filtered == false)
{ {
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId); // get all bios files for selected platform
biosHashes.AddRange(platformMap.EnabledBIOSHashes);
string biosPath = Path.Combine(Config.LibraryConfiguration.LibraryBIOSDirectory, platform.Slug);
string tempFile = Path.GetTempFileName();
using (FileStream zipFile = System.IO.File.Create(tempFile))
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
{
foreach (string file in Directory.GetFiles(biosPath))
{
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
}
}
var stream = new FileStream(tempFile, FileMode.Open);
return File(stream, "application/zip", platform.Slug + ".zip");
} }
else else
{ {
@@ -90,24 +82,31 @@ namespace gaseous_server.Controllers
PlatformMapping platformMapping = new PlatformMapping(); PlatformMapping platformMapping = new PlatformMapping();
PlatformMapping.PlatformMapItem userPlatformMap = platformMapping.GetUserPlatformMap(user.Id, PlatformId, GameId); PlatformMapping.PlatformMapItem userPlatformMap = platformMapping.GetUserPlatformMap(user.Id, PlatformId, GameId);
// build zip file biosHashes.AddRange(userPlatformMap.EnabledBIOSHashes);
string tempFile = Path.GetTempFileName(); }
using (FileStream zipFile = System.IO.File.Create(tempFile)) // build zip file
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create)) string tempFile = Path.GetTempFileName();
using (FileStream zipFile = System.IO.File.Create(tempFile))
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
{
foreach (string hash in biosHashes)
{ {
foreach (Bios.BiosItem bios in GetBios(PlatformId, true)) // get the bios data for the hash
foreach (PlatformMapping.PlatformMapItem.EmulatorBiosItem bios in platformMap.Bios)
{ {
if (userPlatformMap.EnabledBIOSHashes.Contains(bios.hash)) if (bios.hash == hash)
{ {
zipArchive.CreateEntryFromFile(bios.biosPath, bios.filename); // add the bios file to the zip
zipArchive.CreateEntryFromFile(Path.Combine(Config.LibraryConfiguration.LibraryFirmwareDirectory, hash + ".bios"), bios.filename);
} }
} }
} }
var stream = new FileStream(tempFile, FileMode.Open);
return File(stream, "application/zip", userPlatformMap.IGDBSlug + ".zip");
} }
var stream = new FileStream(tempFile, FileMode.Open);
return File(stream, "application/zip", platform.Slug + ".zip");
} }
catch catch
{ {

View File

@@ -105,7 +105,7 @@ namespace gaseous_server.Controllers
if (platform.Length > 0) if (platform.Length > 0)
{ {
tempVal = "Games_Roms.PlatformId IN ("; tempVal = "view_Games_Roms.PlatformId IN (";
string[] platformClauseItems = platform.Split(","); string[] platformClauseItems = platform.Split(",");
for (int i = 0; i < platformClauseItems.Length; i++) for (int i = 0; i < platformClauseItems.Length; i++)
{ {
@@ -281,9 +281,7 @@ namespace gaseous_server.Controllers
} }
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
//string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.* FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause; string sql = "SELECT DISTINCT view_Games_Roms.GameId AS ROMGameId, Game.*, case when Game.`Name` like 'The %' then CONCAT(trim(substr(Game.`Name` from 4)), ', The') else Game.`Name` end as NameThe FROM view_Games_Roms LEFT JOIN Game ON Game.Id = view_Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId LEFT JOIN (SELECT Relation_Game_AgeRatings.GameId, AgeRating.* FROM Relation_Game_AgeRatings JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id) view_AgeRatings ON Game.Id = view_AgeRatings.GameId " + whereClause + " " + havingClause + " " + orderByClause;
string sql = "SELECT DISTINCT Games_Roms.GameId AS ROMGameId, Game.*, case when Game.`Name` like 'The %' then CONCAT(trim(substr(Game.`Name` from 4)), ', The') else Game.`Name` end as NameThe FROM Games_Roms LEFT JOIN Game ON Game.Id = Games_Roms.GameId LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId LEFT JOIN (SELECT Relation_Game_AgeRatings.GameId, AgeRating.* FROM Relation_Game_AgeRatings JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id) view_AgeRatings ON Game.Id = view_AgeRatings.GameId " + whereClause + " " + havingClause + " " + orderByClause;
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>(); List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();

View File

@@ -37,7 +37,7 @@ namespace gaseous_server.Controllers
{ {
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); 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>(); List<Platform> RetVal = new List<Platform>();

View File

@@ -51,7 +51,7 @@ namespace gaseous_server.Controllers
ReturnValue.DatabaseSize = (long)(System.Decimal)dbResponse.Rows[0][1]; ReturnValue.DatabaseSize = (long)(System.Decimal)dbResponse.Rows[0][1];
// platform statistics // 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 Platform.`name`, grc.Count, grs.Size FROM Platform INNER JOIN (SELECT Platform.`name` AS `Name`, SUM(grs.Size) AS Size FROM Platform JOIN view_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 view_Games_Roms AS grc ON (grc.PlatformId = Platform.Id) GROUP BY Platform.`name`) grc ON (grc.`Name` = Platform.`name`) ORDER BY Platform.`name`;";
dbResponse = db.ExecuteCMD(sql); dbResponse = db.ExecuteCMD(sql);
ReturnValue.PlatformStatistics = new List<SystemInfo.PlatformStatisticsItem>(); ReturnValue.PlatformStatistics = new List<SystemInfo.PlatformStatisticsItem>();
foreach (DataRow dr in dbResponse.Rows) foreach (DataRow dr in dbResponse.Rows)

View File

@@ -303,7 +303,7 @@ namespace gaseous_server.Controllers.v1_1
string platformWhereClause = ""; string platformWhereClause = "";
if (model.Platform.Count > 0) 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++) for (int i = 0; i < model.Platform.Count; i++)
{ {
if (i > 0) if (i > 0)
@@ -511,26 +511,26 @@ FROM
WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The') WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The')
ELSE Game.`Name` ELSE Game.`Name`
END AS NameThe, END AS NameThe,
Games_Roms.PlatformId, view_Games_Roms.PlatformId,
AgeGroup.AgeGroupId, AgeGroup.AgeGroupId,
COUNT(Games_Roms.Id) AS RomCount COUNT(view_Games_Roms.Id) AS RomCount
FROM FROM
Game Game
LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId 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 + @" LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + @"
GROUP BY Game.Id GROUP BY Game.Id
HAVING RomCount > 0) Game HAVING RomCount > 0) Game
LEFT JOIN LEFT JOIN
(SELECT (SELECT
Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount view_Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount
FROM FROM
GameState GameState
JOIN Games_Roms ON GameState.RomId = Games_Roms.Id JOIN view_Games_Roms ON GameState.RomId = view_Games_Roms.Id
WHERE WHERE
GameState.IsMediaGroup = 0 GameState.IsMediaGroup = 0
AND GameState.UserId = @userid 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 LEFT JOIN
(SELECT (SELECT
RomMediaGroup.GameId, RomMediaGroup.GameId,

View File

@@ -31,7 +31,7 @@ namespace gaseous_server.Controllers
[Route("{UserId}")] [Route("{UserId}")]
[ProducesResponseType(typeof(Models.UserProfile), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Models.UserProfile), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ResponseCache(CacheProfileName = "5Minute")] [ResponseCache(CacheProfileName = "Default30")]
public ActionResult GetUserProfile(string UserId) public ActionResult GetUserProfile(string UserId)
{ {
Classes.UserProfile profile = new Classes.UserProfile(); Classes.UserProfile profile = new Classes.UserProfile();

View File

@@ -1,3 +1,5 @@
using IGDB.Models;
namespace gaseous_server.Models namespace gaseous_server.Models
{ {
public class UserProfile public class UserProfile
@@ -5,6 +7,13 @@ namespace gaseous_server.Models
public Guid UserId { get; set; } public Guid UserId { get; set; }
public string DisplayName { get; set; } public string DisplayName { get; set; }
public string Quip { get; set; } public string Quip { get; set; }
public NowPlayingItem? NowPlaying { get; set; }
public class NowPlayingItem
{
public Game Game { get; set; }
public Platform Platform { get; set; }
public long Duration { get; set; }
}
public ProfileImageItem? Avatar { get; set; } public ProfileImageItem? Avatar { get; set; }
public ProfileImageItem? ProfileBackground { get; set; } public ProfileImageItem? ProfileBackground { get; set; }
public Dictionary<string, object> Data { get; set; } public Dictionary<string, object> Data { get; set; }

View File

@@ -48,6 +48,9 @@ Config.InitSettings();
// write updated settings back to the config file // write updated settings back to the config file
Config.UpdateConfig(); Config.UpdateConfig();
// update default library path
GameLibrary.UpdateDefaultLibraryPath();
// set api metadata source from config // set api metadata source from config
Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource; Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource;
@@ -335,6 +338,9 @@ gaseous_server.Classes.Metadata.Platforms.AssignAllPlatformsToGameIdZero();
// extract platform map if not present // extract platform map if not present
PlatformMapping.ExtractPlatformMap(); PlatformMapping.ExtractPlatformMap();
// migrate old firmware directory structure to new style
Bios.MigrateToNewFolderStructure();
// add background tasks // add background tasks
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem( ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.SignatureIngestor) ProcessQueue.QueueItemType.SignatureIngestor)

View File

@@ -76,4 +76,24 @@ CREATE TABLE `User_GameFavouriteRoms` (
`PlatformId` `PlatformId`
), ),
CONSTRAINT `GameFavouriteRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE CONSTRAINT `GameFavouriteRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
); );
ALTER TABLE `Games_Roms`
CHANGE `Path` `RelativePath` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
ALTER TABLE `Games_Roms`
ADD CONSTRAINT Games_Roms_LibraryId FOREIGN KEY (`LibraryId`) REFERENCES `GameLibraries` (`Id`) ON DELETE CASCADE;
CREATE VIEW view_Games_Roms AS
SELECT `Games_Roms`.*, CONCAT(
`GameLibraries`.`Path`, '/', `Games_Roms`.`RelativePath`
) AS `Path`, `GameLibraries`.`Name` AS `LibraryName`
FROM
`Games_Roms`
JOIN `GameLibraries` ON `Games_Roms`.`LibraryId` = `GameLibraries`.`Id`;
CREATE VIEW view_UserTimeTracking AS
SELECT *, DATE_ADD(
SessionTime, INTERVAL SessionLength MINUTE
) AS SessionEnd
FROM UserTimeTracking;

View File

@@ -21,7 +21,7 @@
<PackageReference Include="gaseous-signature-parser" Version="2.2.1" /> <PackageReference Include="gaseous-signature-parser" Version="2.2.1" />
<PackageReference Include="gaseous.IGDB" Version="1.0.2" /> <PackageReference Include="gaseous.IGDB" Version="1.0.2" />
<PackageReference Include="hasheous-client" Version="1.0.2" /> <PackageReference Include="hasheous-client" Version="1.0.2" />
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.0.0" /> <PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.8.0" />
<PackageReference Include="sharpcompress" Version="0.37.2" /> <PackageReference Include="sharpcompress" Version="0.37.2" />
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" /> <PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" />

View File

@@ -26,41 +26,63 @@
"/scripts/jquery.lazy.plugins.min.js", "/scripts/jquery.lazy.plugins.min.js",
"/scripts/moment-with-locales.min.js", "/scripts/moment-with-locales.min.js",
"/scripts/select2.min.js", "/scripts/select2.min.js",
"/scripts/filterformating.js",
"/scripts/gamesformating.js",
"/scripts/main.js",
"/scripts/modals.js", "/scripts/modals.js",
"/scripts/preferences.js", "/scripts/preferences.js",
"/scripts/account.js", "/scripts/account.js",
"/scripts/libraries.js", "/scripts/libraries.js",
"/scripts/notifications.js", "/scripts/notifications.js",
"/scripts/rominfo.js", "/scripts/rominfo.js",
"/scripts/uploadrom.js", "/scripts/uploadrom.js"
"/scripts/filterformating.js",
"/scripts/gamesformating.js",
"/scripts/main.js"
]; ];
let head = document.getElementsByTagName('head')[0]; let head = document.getElementsByTagName('head')[0];
// placeholder for global userProfile variable // placeholder for global userProfile variable
var userProfile; var userProfile;
</script>
</head>
// update script links <body>
for (let i = 0; i < scriptLinks.length; i++) { <!-- Background Images -->
let newScript = document.createElement('script'); <div id="bgImages"></div>
newScript.src = scriptLinks[i] + '?v=' + AppVersion; <div id="bgImage_Opacity"></div>
newScript.type = "text/javascript";
newScript.async = false;
head.appendChild(newScript); <!-- Notifications -->
} <div id="notifications_target"></div>
// update stylesheet links <!-- Page Banner -->
for (let i = 0; i < styleSheets.length; i++) { <div id="banner_target"></div>
let newLink = document.createElement('link');
newLink.rel = "stylesheet";
newLink.href = styleSheets[i] + '?v=' + AppVersion;
newLink.type = "text/css";
head.appendChild(newLink); <!-- Page Content -->
<div id="content"></div>
<script type="text/javascript">
// start the application
let backgroundImageHandler = undefined;
async function loadScriptsAndStyles() {
// update script links
for (let i = 0; i < scriptLinks.length; i++) {
let newScript = document.createElement('script');
newScript.src = scriptLinks[i] + '?v=' + AppVersion;
newScript.type = "text/javascript";
newScript.async = false;
head.appendChild(newScript);
}
// update stylesheet links
for (let i = 0; i < styleSheets.length; i++) {
let newLink = document.createElement('link');
newLink.rel = "stylesheet";
newLink.href = styleSheets[i] + '?v=' + AppVersion;
newLink.type = "text/css";
head.appendChild(newLink);
}
} }
async function LoadPageContent(page, targetDiv) { async function LoadPageContent(page, targetDiv) {
@@ -83,66 +105,53 @@
backgroundImageHandler = new BackgroundImageRotator(); backgroundImageHandler = new BackgroundImageRotator();
} }
</script>
</head>
<body> async function startApp() {
<!-- Background Images --> await loadScriptsAndStyles();
<div id="bgImages"></div>
<div id="bgImage_Opacity"></div>
<!-- Notifications --> console.log("Starting Gaseous Games");
<div id="notifications_target"></div> console.log("App Version: " + AppVersion);
console.log("First Run Status: " + FirstRunStatus);
switch (FirstRunStatus) {
case 0:
case "0":
// first run - load first run wizard
await LoadPageContent('first', 'content');
break;
<!-- Page Banner --> default:
<div id="banner_target"></div> // first run - load login page or redirect if user already logged in
<!-- Page Content --> await fetch('/api/v1.1/Account/Profile/Basic')
<div id="content"></div> .then(async response => {
if (response.ok) {
// user is signed in - start setting up the application
console.log("User is logged in");
userProfile = await response.json();
<script type="text/javascript"> // load page banner
// start the application await LoadPageContent('banner', 'banner_target');
let backgroundImageHandler = undefined;
console.log("Starting Gaseous Games");
console.log("App Version: " + AppVersion);
console.log("First Run Status: " + FirstRunStatus);
switch (FirstRunStatus) {
case 0:
case "0":
// first run - load first run wizard
LoadPageContent('first', 'content');
break;
default: // load page content
// first run - load login page or redirect if user already logged in let pageSelection = getQueryString('page', 'string');
fetch('/api/v1.1/Account/Profile/Basic') if (!pageSelection) {
.then(async response => { pageSelection = GetPreference("DefaultHomePage", 'home');
if (response.ok) { }
// user is signed in - start setting up the application await LoadPageContent(pageSelection, 'content');
console.log("User is logged in"); } else {
userProfile = await response.json(); // user is not signed in - load login page
await LoadPageContent('login');
// load page banner
LoadPageContent('banner', 'banner_target');
// load page content
let pageSelection = getQueryString('page', 'string');
if (!pageSelection) {
pageSelection = GetPreference("DefaultHomePage", 'home');
} }
LoadPageContent(pageSelection, 'content'); })
} else { .catch(async (error) => {
// user is not signed in - load login page console.log(error);
LoadPageContent('login'); await LoadPageContent('login');
} });
}) break;
.catch((error) => { }
console.log(error);
LoadPageContent('login');
});
break;
} }
window.document.addEventListener('DOMContentLoaded', startApp);
</script> </script>
</body> </body>

View File

@@ -44,7 +44,7 @@
</div> </div>
</div> </div>
<div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous Games</div> <div id="banner_header_label" onclick="window.location.href = '/index.html';">Gaseous</div>
</div> </div>
<!-- page code --> <!-- page code -->

View File

@@ -8,7 +8,7 @@
<!-- <img src="/images/logo.png" style="display: block; margin: 20px auto; width: 100px;" /> --> <!-- <img src="/images/logo.png" style="display: block; margin: 20px auto; width: 100px;" /> -->
<div class="loginwindow-logospace-logo">&nbsp;</div> <div class="loginwindow-logospace-logo">&nbsp;</div>
<div id="loginwindow_header_label" class="loginwindow-logospace-label">Gaseous Games</div> <div id="loginwindow_header_label" class="loginwindow-logospace-label">Gaseous</div>
<div style="height: 20px;">&nbsp;</div> <div style="height: 20px;">&nbsp;</div>
@@ -29,7 +29,7 @@
<div class="loginwindow-logospace-logo">&nbsp;</div> <div class="loginwindow-logospace-logo">&nbsp;</div>
<div class="loginwindow-logospace-label"> <div class="loginwindow-logospace-label">
<div> <div>
Gaseous Games Gaseous
</div> </div>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@
<div class="loginwindow-logospace-logo">&nbsp;</div> <div class="loginwindow-logospace-logo">&nbsp;</div>
<div class="loginwindow-logospace-label"> <div class="loginwindow-logospace-label">
<div> <div>
Gaseous Games Gaseous
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@
<div class="section" style="flex-grow:1;"> <div class="section" style="flex-grow:1;">
<div class="section-header">General</div> <div class="section-header">General</div>
<div class="section-body"> <div class="section-body">
<table class="romtable"> <table class="romtable" cellspacing="0">
<tr class="romrow"> <tr class="romrow">
<th class="romcell">User Id</th> <th class="romcell">User Id</th>
<td id="user-id" class="romcell"></td> <td id="user-id" class="romcell"></td>

View File

@@ -366,6 +366,18 @@ class ProfileCard {
this.Quip.classList.add('profile-card-quip'); this.Quip.classList.add('profile-card-quip');
this.ProfileBody = document.createElement('div'); this.ProfileBody = document.createElement('div');
this.ProfileBody.classList.add('profile-card-body'); this.ProfileBody.classList.add('profile-card-body');
this.ProfileNowPlaying = document.createElement('div');
this.ProfileNowPlaying.classList.add('profile-card-now-playing-body');
this.ProfileNowPlayingLabel = document.createElement('div');
this.ProfileNowPlayingLabel.classList.add('profile-card-now-playing-label');
this.ProfileNowPlayingCover = document.createElement('div');
this.ProfileNowPlayingCover.classList.add('profile-card-now-playing-cover');
this.ProfileNowPlayingTitle = document.createElement('div');
this.ProfileNowPlayingTitle.classList.add('profile-card-now-playing-title');
this.ProfileNowPlayingPlatform = document.createElement('div');
this.ProfileNowPlayingPlatform.classList.add('profile-card-now-playing-platform');
this.ProfileNowPlayingDuration = document.createElement('div');
this.ProfileNowPlayingDuration.classList.add('profile-card-now-playing-duration');
this.Avatar = document.createElement('div'); this.Avatar = document.createElement('div');
this.Avatar.classList.add('profile-card-avatar'); this.Avatar.classList.add('profile-card-avatar');
@@ -375,12 +387,28 @@ class ProfileCard {
this.ProfileBody.appendChild(this.DisplayName); this.ProfileBody.appendChild(this.DisplayName);
this.ProfileBody.appendChild(this.Quip); this.ProfileBody.appendChild(this.Quip);
// now playing
this.ProfileNowPlaying.appendChild(this.ProfileNowPlayingLabel);
this.ProfileNowPlaying.appendChild(this.ProfileNowPlayingCover);
this.ProfileNowPlaying.appendChild(this.ProfileNowPlayingTitle);
this.ProfileNowPlaying.appendChild(this.ProfileNowPlayingPlatform);
this.ProfileNowPlaying.appendChild(this.ProfileNowPlayingDuration);
// assemble card // assemble card
this.Card.appendChild(this.BackgroundImage); this.Card.appendChild(this.BackgroundImage);
this.Card.appendChild(this.ProfileBody); this.Card.appendChild(this.ProfileBody);
this.Card.appendChild(this.ProfileNowPlaying);
this.Card.appendChild(this.Avatar); this.Card.appendChild(this.Avatar);
this.ProfileData = null;
const response = this.#FetchProfile(this); const response = this.#FetchProfile(this);
// set timeout to refresh the profile card every 30 seconds
let callingObject = this;
setInterval(function () {
callingObject.#FetchProfile(callingObject);
}, 30000);
return this.Card; return this.Card;
} }
@@ -392,12 +420,57 @@ class ProfileCard {
} else { } else {
const profile = await response.json(); const profile = await response.json();
if (profile) { if (profile) {
this.Avatar.appendChild(new Avatar(callingObject.ProfileId, 50, 50)); let stillUpdateAnyway = false;
if (profile.profileBackground) { if (callingObject.ProfileData === null) {
this.BackgroundImage.style = "background-image: url('/api/v1.1/UserProfile/" + callingObject.ProfileId + "/Background');"; callingObject.ProfileData = profile;
stillUpdateAnyway = true;
} }
this.DisplayName.innerHTML = profile.displayName;
this.Quip.innerHTML = profile.quip; // update avatar if different
if (callingObject.ProfileData.avatar !== profile.avatar || stillUpdateAnyway === true) {
callingObject.Avatar.innerHTML = "";
callingObject.Avatar.appendChild(new Avatar(callingObject.ProfileId, 50, 50));
}
// update profile background if different
if (callingObject.ProfileData.profileBackground !== profile.profileBackground || stillUpdateAnyway === true) {
if (profile.profileBackground) {
callingObject.BackgroundImage.style = "background-image: url('/api/v1.1/UserProfile/" + callingObject.ProfileId + "/Background');";
} else {
callingObject.BackgroundImage.style = "";
}
}
// update display name if different
if (callingObject.ProfileData.displayName !== profile.displayName || stillUpdateAnyway === true) {
callingObject.DisplayName.innerHTML = profile.displayName;
}
// update quip if different
if (callingObject.ProfileData.quip !== profile.quip || stillUpdateAnyway === true) {
callingObject.Quip.innerHTML = profile.quip;
}
if (profile.nowPlaying) {
callingObject.ProfileNowPlayingLabel.innerHTML = "Now Playing";
if (profile.nowPlaying.game.cover) {
callingObject.ProfileNowPlayingCover.style = "background-image: url('/api/v1.1/Games/" + profile.nowPlaying.game.id + "/cover/" + profile.nowPlaying.game.cover.id + "/image/cover_big/" + profile.nowPlaying.game.cover.id + ".jpg');";
} else {
callingObject.ProfileNowPlayingCover.style = "background-image: url('/images/unknowngame.png');";
}
callingObject.ProfileNowPlayingTitle.innerHTML = profile.nowPlaying.game.name;
callingObject.ProfileNowPlayingPlatform.innerHTML = profile.nowPlaying.platform.name;
if (profile.nowPlaying.duration === 1) {
callingObject.ProfileNowPlayingDuration.innerHTML = profile.nowPlaying.duration + " minute";
} else {
callingObject.ProfileNowPlayingDuration.innerHTML = profile.nowPlaying.duration + " minutes";
}
callingObject.ProfileNowPlaying.style.display = "";
} else {
callingObject.ProfileNowPlaying.style.display = "none";
}
callingObject.ProfileData = profile;
} }
} }
}); });

View File

@@ -134,7 +134,8 @@ h3 {
top: 50%; top: 50%;
left: 50%; left: 50%;
margin-right: -50%; margin-right: -50%;
transform: translate(-50%, -50%); /* transform: translate(-50%, -50%); */
transform: translateX(-50%) translateY(calc(-50% - .5px));
min-width: 700px; min-width: 700px;
max-width: 1000px; max-width: 1000px;
width: 60%; width: 60%;
@@ -185,8 +186,8 @@ h3 {
.modal-window-tabs { .modal-window-tabs {
background-color: var(--modal-tabs-background-color); background-color: var(--modal-tabs-background-color);
backdrop-filter: blur(16px); /* backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); */
display: block; display: block;
flex-grow: 0; flex-grow: 0;
flex-shrink: 1; flex-shrink: 1;
@@ -237,8 +238,8 @@ h3 {
text-align: top; text-align: top;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
backdrop-filter: blur(16px); /* backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); */
} }
.modal-window-header { .modal-window-header {
@@ -313,7 +314,7 @@ h3 {
#banner_icon { #banner_icon {
/* background-color: white; */ /* background-color: white; */
background-color: rgba(0, 22, 56, 0.8); background-color: rgba(0, 22, 56, 0.2);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
position: fixed; position: fixed;
@@ -336,7 +337,7 @@ h3 {
#banner_icon_image { #banner_icon_image {
width: 30px; width: 30px;
height: 30px; height: 30px;
filter: drop-shadow(1px 1px 0 rgb(90, 90, 90)) drop-shadow(-1px 1px 0 rgb(90, 90, 90)) drop-shadow(1px -1px 0 rgb(90, 90, 90)) drop-shadow(-1px -1px 0 rgb(90, 90, 90)); filter: drop-shadow(1px 1px 0 rgb(180, 180, 180)) drop-shadow(-1px 1px 0 rgb(180, 180, 180)) drop-shadow(1px -1px 0 rgb(180, 180, 180)) drop-shadow(-1px -1px 0 rgb(180, 180, 180));
} }
.banner_button { .banner_button {
@@ -416,7 +417,7 @@ h3 {
#banner_header { #banner_header {
background: rgba(0, 22, 56, 0.8); background: rgba(0, 22, 56, 0.8);
background: linear-gradient(90deg, rgba(0, 22, 56, 0.8) 0%, rgba(0, 0, 0, 0.8) 100%); background: linear-gradient(90deg, rgba(0, 22, 56, 0.2) 0%, rgba(0, 0, 0, 0.5) 100%);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
position: fixed; position: fixed;
@@ -435,7 +436,7 @@ h3 {
font-size: 16pt; font-size: 16pt;
vertical-align: top; vertical-align: top;
/*color: #edeffa;*/ /*color: #edeffa;*/
color: #7c70da; color: #FFFFFF;
} }
#banner_header_label { #banner_header_label {
@@ -1191,8 +1192,8 @@ input[name='filter_panel_range_max'] {
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
background-color: white; background-color: white;
filter: blur(32px); filter: blur(64px);
-webkit-filter: blur(32px); -webkit-filter: blur(64px);
} }
.bgImage_LessBlur { .bgImage_LessBlur {
@@ -2365,18 +2366,17 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 1px; gap: 1px;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
} }
.loginwindow-logospace { .loginwindow-logospace {
background-color: var(--modal-tabs-background-color); background-color: var(--login-logospace-background);
width: 315px; width: 315px;
position: relative; position: relative;
} }
.loginwindow_loginspace { .loginwindow_loginspace {
background-color: var(--modal-window-background-color); background-color: var(--login-loginspace-background);
padding: 20px; padding: 20px;
flex-grow: 1; flex-grow: 1;
} }
@@ -2425,7 +2425,7 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
font-size: 18pt; font-size: 18pt;
vertical-align: top; vertical-align: top;
/*color: #edeffa;*/ /*color: #edeffa;*/
color: white; color: var(--login-logospace-label);
margin-top: 8px; margin-top: 8px;
} }
@@ -2451,9 +2451,9 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
.dropdown-content { .dropdown-content {
display: none; display: none;
position: absolute; position: absolute;
background-color: var(--modal-background-color); background-color: var(--dropdown-background);
border-radius: var(--standard-radius); border-radius: var(--standard-radius);
border-color: var(--modal-border-color); border-color: var(--dropdown-border);
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
overflow: hidden; overflow: hidden;
@@ -2465,15 +2465,13 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
filter: drop-shadow(5px 5px 10px #000); filter: drop-shadow(5px 5px 10px #000);
-webkit-filter: drop-shadow(5px 5px 10px #000); -webkit-filter: drop-shadow(5px 5px 10px #000);
padding: 3px; padding: 3px;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
cursor: default; cursor: default;
} }
/* Links inside the dropdown */ /* Links inside the dropdown */
.dropdown-content a, .dropdown-content a,
.dropdown-content span { .dropdown-content span {
color: white; color: var(--dropdown-menu-text-color);
padding: 12px 16px; padding: 12px 16px;
text-decoration: none; text-decoration: none;
display: block; display: block;
@@ -2488,7 +2486,7 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
/* Change color of dropdown links on hover */ /* Change color of dropdown links on hover */
.dropdown-content a:hover { .dropdown-content a:hover {
background-color: var(--modal-border-color); background-color: var(--dropdown-border);
} }
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */ /* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
@@ -2658,7 +2656,7 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
border-radius: var(--standard-radius); border-radius: var(--standard-radius);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-color: rgba(173, 216, 230, 0.3); border-color: var(--profile-card-border);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }
@@ -2681,7 +2679,7 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
aspect-ratio: 4.17/1; aspect-ratio: 4.17/1;
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-color: rgb(0, 0, 130); background-color: var(--profile-card-background-image);
} }
.profile-card-body { .profile-card-body {
@@ -2690,15 +2688,13 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
padding-bottom: 20px; padding-bottom: 20px;
background-color: rgba(173, 216, 230, 0.3); background-color: var(--profile-card-body-background);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
} }
.profile-card-display-name { .profile-card-display-name {
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
color: white; color: var(--profile-card-display-name-text-color);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -2707,7 +2703,47 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
.profile-card-quip { .profile-card-quip {
margin-top: 3px; margin-top: 3px;
font-style: italic; font-style: italic;
color: white; color: var(--profile-card-quip-text-color);
}
.profile-card-now-playing-body {
position: relative;
min-height: 70px;
background-color: var(--profile-card-body-background);
padding-top: 0px;
padding-left: 10px;
padding-right: 10px;
padding-bottom: 10px;
}
.profile-card-now-playing-label {
font-style: italic;
margin-bottom: 5px;
}
.profile-card-now-playing-cover {
position: absolute;
left: 10px;
top: 25px;
width: 40px;
height: 40px;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
}
.profile-card-now-playing-title {
margin-left: 50px;
font-weight: bold;
}
.profile-card-now-playing-platform {
margin-left: 50px;
}
.profile-card-now-playing-duration {
margin-top: 10px;
margin-left: 50px;
} }
.password-rules { .password-rules {
@@ -2806,8 +2842,6 @@ button:not(.select2-selection__choice__remove):not(.select2-selection__clear):no
display: block; display: block;
background: var(--section-body-background); background: var(--section-body-background);
background: linear-gradient(0deg, var(--section-body-background-solid) 25%, rgba(255, 255, 255, 0) 100%); background: linear-gradient(0deg, var(--section-body-background-solid) 25%, rgba(255, 255, 255, 0) 100%);
backdrop-filter: blur(8px);
--webkit-backdrop-filter: blur(8px);
padding: 5px; padding: 5px;
vertical-align: bottom; vertical-align: bottom;
content: ""; content: "";

View File

@@ -71,7 +71,7 @@
--button-blue-font-colour-disabled: var(--button-blue-font-colour); --button-blue-font-colour-disabled: var(--button-blue-font-colour);
/* select2 */ /* select2 */
--select2-background: var(--input-background); --select2-background: rgb(43, 43, 43);
--select2-background-disabled: var(--input-background-disabled); --select2-background-disabled: var(--input-background-disabled);
--select2-border: var(--input-border); --select2-border: var(--input-border);
--select2-border-hover: var(--input-border-hover); --select2-border-hover: var(--input-border-hover);
@@ -106,8 +106,28 @@
/* ------------------------------------------- */ /* ------------------------------------------- */
--modal-background-color: rgba(0, 0, 0, 0.4); --modal-background-color: rgba(0, 0, 0, 0.4);
--modal-border-color: rgba(255, 255, 255, 0.414); --modal-border-color: rgba(255, 255, 255, 0.414);
--modal-tabs-background-color: rgba(255, 255, 255, 0.2); --modal-tabs-background-color: rgb(100, 100, 100);
--modal-window-background-color: rgba(70, 70, 70, 0.6); --modal-window-background-color: rgb(79, 79, 79);
--modal-window-header-text-color: rgb(255, 255, 255); --modal-window-header-text-color: rgb(255, 255, 255);
--modal-window-header-background-color: rgb(56, 56, 56); --modal-window-header-background-color: rgb(56, 56, 56);
/* dropdown */
/* ------------------------------------------- */
--dropdown-background: rgb(0, 0, 0);
--dropdown-border: var(--modal-border-color);
--dropdown-menu-text-color: rgb(255, 255, 255);
/* profile card */
/* ------------------------------------------- */
--profile-card-border: rgba(173, 216, 230, 0.3);
--profile-card-background-image: rgb(0, 0, 130);
--profile-card-body-background: rgb(133, 156, 163);
--profile-card-display-name-text-color: rgb(255, 255, 255);
--profile-card-quip-text-color: var(--profile-card-display-name-text-color);
/* login */
/* ------------------------------------------- */
--login-logospace-background: rgba(100, 100, 100, 0.7);
--login-loginspace-background: rgba(79, 79, 79, 0.7);
--login-logospace-label: rgb(255, 255, 255);
} }