Compare commits

..

16 Commits

Author SHA1 Message Date
Michael Green
59173d8ae5 Merge branch 'main' into branch-v1.7.0 2024-04-16 11:51:21 +10:00
Michael Green
178f70cb98 Performance improvements to infinite scrolling (#347) 2024-04-16 11:39:58 +10:00
Michael Green
080a823cda Merge 1.7.3 into main (#331) 2024-04-15 14:38:17 +10:00
Michael Green
60dbaf85a4 Merge branch 'main' into branch-v1.7.0 2024-04-15 14:35:32 +10:00
Michael Green
8a80274030 Integrate EJS 4.0.12 - Adds a new Master System core, and a new DS core (#344)
Closes #340
2024-04-15 14:23:11 +10:00
Michael Green
7e8679151b Integrate EJS 4.0.12 - Adds a new Master System core, and a new DS core (#343)
Closes #340
2024-04-15 13:05:18 +10:00
Michael Green
123239cf58 Merge branch 'main' into branch-v1.7.0 2024-03-12 00:48:56 +11:00
Michael Green
04419383aa When fixing matches, search doesn't return the correct values (#330)
Issue was due to the search result limit being too low. Increased the search result size to 100 returned objects.
2024-03-12 00:42:59 +11:00
Michael Green
0bef298abf SQL error when loading the library with the MySQL database server (#327)
Fixes #305
2024-03-10 13:58:42 +11:00
Michael Green
a4d581b369 Infinite Scrolling breaks clicking the Gaseous Games logo to return to library (#326)
Closes #316

Overhauled how infinite scrolling works. Should be more reliable now.
2024-03-10 01:47:51 +11:00
Michael Green
16cb0c89dc Hide unneeded buttons from the emulator (#324)
Closes #317

Removes the save and load file buttons - leaving the save and load state buttons
2024-03-06 22:38:32 +11:00
Michael Green
95b52c47dd New library dialog content overruns the edges of the dialog (#323)
Closes #303

This fix is a clean up fix - will review functionality for 1.8.0
2024-03-06 20:48:42 +11:00
Michael Green
b1056299b8 Ensure ROMs are decompressed before loading them into a media group (#321)
All compressed archives (zip, rar, and 7z) are decompressed when a media group is created.

Only files with an extension defined in the platform mapping are added to the M3U file.

Closes #307
2024-03-01 13:39:27 +11:00
Michael Green
14c5761959 Error on startup when reading value LastRun_BackgroundDatabaseUpgrade (#319)
Fixes #300
2024-02-26 16:17:26 +11:00
Michael Green
d7b3711be6 Update for PlatformMap.json to add missing core support (#318)
Adds cores to PlatformMap.json for platforms (closes #315):
* Family Computer = fceumm
* Super Famicom = snes9x
* TurboGrafx-16/PC Engine + Turbografx-16/PC Engine CD = mednafen_pce
* Neo Geo Pocket + Neo Geo Pocket Color = mednafen_ngp
* Wonderswan + Wonderswan Color = mednafen_wswan
* Nec PC-FX = mednafen_pcfx
2024-02-25 13:22:41 +11:00
Michael Green
111c501911 Fix for broken first run on fresh installs
* Fix for broken first run on fresh installs
2024-02-11 00:47:41 +11:00
19 changed files with 610 additions and 294 deletions

View File

@@ -17,8 +17,8 @@ RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime
# download and unzip EmulatorJS from CDN
RUN apt-get update && apt-get install -y p7zip-full
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
RUN wget https://cdn.emulatorjs.org/releases/4.0.11.7z
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.11.7z
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0

View File

@@ -196,6 +196,11 @@ namespace gaseous_server.Classes
{
string SettingName = (string)dataRow["Setting"];
if (SettingName.StartsWith("LastRun_"))
{
Console.WriteLine("Break");
}
if (AppSettings.ContainsKey(SettingName))
{
AppSettings.Remove(SettingName);

View File

@@ -9,7 +9,20 @@ namespace gaseous_server.Classes
{
public class Database
{
public static int schema_version = 0;
private static int _schema_version { get; set; } = 0;
public static int schema_version
{
get
{
//Logging.Log(Logging.LogType.Information, "Database Schema", "Schema version is " + _schema_version);
return _schema_version;
}
set
{
//Logging.Log(Logging.LogType.Information, "Database Schema", "Setting schema version " + _schema_version);
_schema_version = value;
}
}
public Database()
{
@@ -80,7 +93,16 @@ namespace gaseous_server.Classes
ExecuteCMD(sql, dbDict);
}
for (int i = 1000; i < 10000; i++)
sql = "SELECT schema_version FROM schema_version;";
dbDict = new Dictionary<string, object>();
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
if (OuterSchemaVer == 0)
{
OuterSchemaVer = 1000;
}
for (int i = OuterSchemaVer; i < 10000; i++)
{
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
string dbScript = "";
@@ -96,7 +118,7 @@ namespace gaseous_server.Classes
// apply script
sql = "SELECT schema_version FROM schema_version;";
dbDict = new Dictionary<string, object>();
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
SchemaVersion = ExecuteCMD(sql, dbDict);
if (SchemaVersion.Rows.Count == 0)
{
// something is broken here... where's the table?
@@ -107,6 +129,8 @@ namespace gaseous_server.Classes
{
int SchemaVer = (int)SchemaVersion.Rows[0][0];
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
// update schema version variable
Database.schema_version = SchemaVer;
if (SchemaVer < i)
{
try

View File

@@ -561,6 +561,7 @@ namespace gaseous_server.Classes.Metadata
}
public long? Id { get; set; }
public long Index { get; set; }
public string Name { get; set; }
public string Slug { get; set; }
public double? TotalRating { get; set; }

View File

@@ -5,6 +5,9 @@ using Microsoft.VisualBasic;
using IGDB.Models;
using gaseous_server.Classes.Metadata;
using System.IO.Compression;
using SharpCompress.Archives;
using SharpCompress.Common;
using gaseous_server.Models;
namespace gaseous_server.Classes
{
@@ -259,6 +262,7 @@ namespace gaseous_server.Classes
{
Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false);
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false);
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(mediaGroupItem.PlatformId);
Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name);
@@ -293,10 +297,124 @@ namespace gaseous_server.Classes
foreach (long RomId in mediaGroupItem.RomIds)
{
Roms.GameRomItem rom = Roms.GetRom(RomId);
bool fileNameFound = false;
if (File.Exists(rom.Path))
{
string romExt = Path.GetExtension(rom.Path);
if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt))
{
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
// is compressed
switch (romExt)
{
case ".zip":
try
{
using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(rom.Path))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
if (fileNameFound == false)
{
//check if extension is in valid extensions
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
{
// update rom file name
rom.Name = entry.Key;
fileNameFound = true;
}
}
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
catch (Exception zipEx)
{
Logging.Log(Logging.LogType.Warning, "Media Group", "Unzip error", zipEx);
throw;
}
break;
case ".rar":
try
{
using (var archive = SharpCompress.Archives.Rar.RarArchive.Open(rom.Path))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
if (fileNameFound == false)
{
//check if extension is in valid extensions
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
{
// update rom file name
rom.Name = entry.Key;
fileNameFound = true;
}
}
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
catch (Exception zipEx)
{
Logging.Log(Logging.LogType.Warning, "Media Group", "Unrar error", zipEx);
throw;
}
break;
case ".7z":
try
{
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(rom.Path))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
if (fileNameFound == false)
{
//check if extension is in valid extensions
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
{
// update rom file name
rom.Name = entry.Key;
fileNameFound = true;
}
}
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
catch (Exception zipEx)
{
Logging.Log(Logging.LogType.Warning, "Media Group", "7z error", zipEx);
throw;
}
break;
}
}
else
{
// is uncompressed
Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name);
File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path)));
}
romItems.Add(rom);
}

View File

@@ -43,7 +43,7 @@ namespace gaseous_server.Controllers
[MapToApiVersion("1.0")]
[HttpGet]
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
public ActionResult Game(
public async Task<ActionResult> Game(
string name = "",
string platform = "",
string genre = "",
@@ -303,7 +303,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "5Minute")]
public ActionResult Game(long GameId)
public async Task<ActionResult> Game(long GameId)
{
try
{
@@ -331,7 +331,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<AlternativeName>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameAlternativeNames(long GameId)
public async Task<ActionResult> GameAlternativeNames(long GameId)
{
try
{
@@ -364,7 +364,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<AgeRatings.GameAgeRating>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameAgeClassification(long GameId)
public async Task<ActionResult> GameAgeClassification(long GameId)
{
try
{
@@ -397,7 +397,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<Artwork>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameArtwork(long GameId)
public async Task<ActionResult> GameArtwork(long GameId)
{
try
{
@@ -428,7 +428,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Artwork), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameArtwork(long GameId, long ArtworkId)
public async Task<ActionResult> GameArtwork(long GameId, long ArtworkId)
{
try
{
@@ -464,7 +464,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
public async Task<ActionResult> GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
{
try
{
@@ -531,7 +531,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Cover), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameCover(long GameId)
public async Task<ActionResult> GameCover(long GameId)
{
try
{
@@ -566,7 +566,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/cover/image/{size}/{imagename}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
public async Task<ActionResult> GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
{
try
{
@@ -693,7 +693,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<Genre>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameGenre(long GameId)
public async Task<ActionResult> GameGenre(long GameId)
{
try
{
@@ -731,7 +731,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<Dictionary<string, object>>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameInvolvedCompanies(long GameId)
public async Task<ActionResult> GameInvolvedCompanies(long GameId)
{
try
{
@@ -776,7 +776,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameInvolvedCompanies(long GameId, long CompanyId)
public async Task<ActionResult> GameInvolvedCompanies(long GameId, long CompanyId)
{
try
{
@@ -818,7 +818,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/companies/{CompanyId}/image")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameCompanyImage(long GameId, long CompanyId)
public async Task<ActionResult> GameCompanyImage(long GameId, long CompanyId)
{
try
{
@@ -863,7 +863,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/platforms")]
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GamePlatforms(long GameId)
public async Task<ActionResult> GamePlatforms(long GameId)
{
try
{
@@ -882,7 +882,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<ReleaseDate>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameReleaseDates(long GameId)
public async Task<ActionResult> GameReleaseDates(long GameId)
{
try
{
@@ -943,7 +943,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
//[ResponseCache(CacheProfileName = "5Minute")]
public ActionResult GameRom(long GameId, long RomId)
public async Task<ActionResult> GameRom(long GameId, long RomId)
{
try
{
@@ -972,7 +972,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/roms/{RomId}")]
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
public async Task<ActionResult> GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
{
try
{
@@ -1002,7 +1002,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/roms/{RomId}")]
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomDelete(long GameId, long RomId)
public async Task<ActionResult> GameRomDelete(long GameId, long RomId)
{
try
{
@@ -1034,7 +1034,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/roms/{RomId}/file")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomFile(long GameId, long RomId)
public async Task<ActionResult> GameRomFile(long GameId, long RomId)
{
try
{
@@ -1073,7 +1073,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/roms/{RomId}/{FileName}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomFile(long GameId, long RomId, string FileName)
public async Task<ActionResult> GameRomFile(long GameId, long RomId, string FileName)
{
try
{
@@ -1172,7 +1172,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/romgroup")]
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
public async Task<ActionResult> NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
{
try
{
@@ -1233,7 +1233,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/romgroup/{RomGroupId}")]
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomGroupDelete(long GameId, long RomGroupId)
public async Task<ActionResult> GameRomGroupDelete(long GameId, long RomGroupId)
{
try
{
@@ -1266,7 +1266,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/romgroup/{RomGroupId}/{filename}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
public async Task<ActionResult> GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
{
try
{
@@ -1311,7 +1311,7 @@ namespace gaseous_server.Controllers
[Route("search")]
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameSearch(long RomId = 0, string SearchString = "")
public async Task<ActionResult> GameSearch(long RomId = 0, string SearchString = "")
{
try
{
@@ -1352,7 +1352,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<Screenshot>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameScreenshot(long GameId)
public async Task<ActionResult> GameScreenshot(long GameId)
{
try
{
@@ -1383,7 +1383,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(Screenshot), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameScreenshot(long GameId, long ScreenshotId)
public async Task<ActionResult> GameScreenshot(long GameId, long ScreenshotId)
{
try
{
@@ -1417,7 +1417,7 @@ namespace gaseous_server.Controllers
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
{
try
{
@@ -1468,7 +1468,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(typeof(List<GameVideo>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ResponseCache(CacheProfileName = "7Days")]
public ActionResult GameVideo(long GameId)
public async Task<ActionResult> GameVideo(long GameId)
{
try
{

View File

@@ -76,6 +76,7 @@ namespace gaseous_server.Controllers
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
searchBody += "search \"" + SearchString + "\";";
searchBody += "where platforms = (" + PlatformId + ");";
searchBody += "limit 100;";
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);

View File

@@ -479,6 +479,7 @@ namespace gaseous_server.Controllers.v1_1
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = @"
SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
SELECT DISTINCT
Game.Id,
Game.`Name`,
@@ -569,6 +570,7 @@ FROM
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
retMinGame.Index = i;
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
{
retMinGame.HasSavedGame = true;
@@ -591,25 +593,31 @@ FROM
// build alpha list
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
int CurrentPage = 0;
int NextPageIndex = 0;
int CurrentPage = 1;
int NextPageIndex = pageSize;
for (int i = 0; i < dbResponse.Rows.Count; i++)
{
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
{
firstChar = "#";
if (!AlphaList.ContainsKey("#"))
{
AlphaList.Add("#", 1);
}
}
else
{
if (!AlphaList.ContainsKey(firstChar))
{
AlphaList.Add(firstChar, CurrentPage);
}
if (NextPageIndex == i)
if (NextPageIndex == i + 1)
{
NextPageIndex += pageSize;
CurrentPage += 1;
}
}
}
GameReturnPackage gameReturn = new GameReturnPackage
{

View File

@@ -1232,6 +1232,9 @@
"alternateCoreName": "melonds",
"default": true
},
{
"core": "desmume"
},
{
"core": "desmume2015"
}
@@ -1590,18 +1593,21 @@
"retroPieDirectoryName": "mastersystem",
"webEmulator": {
"type": "EmulatorJS",
"core": "picodrive",
"core": "smsplus",
"availableWebEmulators": [
{
"emulatorType": "EmulatorJS",
"availableWebEmulatorCores": [
{
"core": "picodrive",
"core": "segaMS",
"alternateCoreName": "smsplus",
"default": true
},
{
"core": "segaMS",
"alternateCoreName": "genesis_plus_gx"
"core": "picodrive"
},
{
"core": "genesis_plus_gx"
}
]
}

View File

@@ -40,6 +40,11 @@
EJS_threads = false;
EJS_Buttons = {
saveSavFiles: false,
loadSavFiles: false
}
EJS_onSaveState = function(e) {
var returnValue = {
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),

View File

@@ -1,12 +1,7 @@
<div style="padding-top: 5px;">
<strong>New Library</strong>
</div>
<div style="width: 300px;">
<table style="width: 98%; margin-top: 15px; margin-bottom: 15px;">
<tr>
<th>Name</th>
<td><input type="text" id="newlibrary_name" style="width: 95%;" /></td>
<th style="width: 20%;">Name</th>
<td style="width: 80%;"><input type="text" id="newlibrary_name" style="width: 98%;" /></td>
</tr>
<tr>
<th>Default Platform</th>
@@ -14,21 +9,22 @@
</tr>
<tr>
<th>Path</th>
<td><input type="text" id="newlibrary_path" style="width: 95%;" /></td>
<td><input type="text" id="newlibrary_path" style="width: 98%;" /></td>
</tr>
</table>
<div style="width: 100%; text-align: right;">
<div style="width: 100%; text-align: right; margin-top: 160px;">
<div style="display: inline-block; margin-right: 20px;">
<button value="OK" onclick="newLibrary();">OK</button>
</div>
<div style="display: inline-block;">
<button value="Cancel" onclick="closeSubDialog();">Cancel</button>
</div>
<button value="Cancel" onclick="closeDialog();">Cancel</button>
</div>
</div>
<script type="text/javascript">
document.getElementById('modal-heading').innerHTML = "New Library";
$('#newlibrary_defaultplatform').select2({
minimumInputLength: 3,
ajax: {

View File

@@ -78,7 +78,7 @@
<td style="width: 75%;"><select id="properties_fixgame" style="width: 100%;"></select></td>
</tr>
<tr>
<td colspan="2" style="text-align: right;"><button id="properties_fixsave" value="Save Match" onclick="SaveFixedGame();">Save Match</button></td>
<td colspan="2" style="text-align: right;"><button id="properties_fixclear" value="Clear Match" onclick="ClearFixedGame();">Clear Match</button><button id="properties_fixsave" value="Save Match" onclick="SaveFixedGame();">Save Match</button></td>
</tr>
</table>
</div>
@@ -252,6 +252,7 @@
var fixplatform = $('#properties_fixplatform').select2('data');
var fixgame = $('#properties_fixgame').select2('data');
document.getElementById('properties_fixclear').setAttribute("disabled", "disabled");
document.getElementById('properties_fixsave').setAttribute("disabled", "disabled");
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform[0].id + '&NewGameId=' + fixgame[0].id, 'PATCH', function (result) {
@@ -259,6 +260,18 @@
});
}
function ClearFixedGame() {
var fixplatform = 0;
var fixgame = 0;
document.getElementById('properties_fixclear').setAttribute("disabled", "disabled");
document.getElementById('properties_fixsave').setAttribute("disabled", "disabled");
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables + '?NewPlatformId=' + fixplatform + '&NewGameId=' + fixgame, 'PATCH', function (result) {
window.location.reload();
});
}
function BuildAttributesTable(attributes, sourceName) {
var aTable = document.createElement('table');
aTable.style.width = '100%';

View File

@@ -72,6 +72,11 @@
</table>
</td>
</tr>
<tr>
<td>
<strong>Note</strong>: The page will need to be reloaded for changes to take effect.
</td>
</tr>
<tr>
<td style="text-align: right;">
<button id="profile_pref_ok" value="OK" onclick="SavePrefs();">OK</button>
@@ -220,7 +225,8 @@
SetPreference_Batch(model);
if (getQueryString('page', 'string') == 'home' || getQueryString('page', 'string') == undefined) {
executeFilter1_1(1);
setCookie('games_library_last_page', 1);
//location.reload();
}
closeDialog();

View File

@@ -23,6 +23,8 @@
var emuBios = '';
var emuBackground = '';
console.log("Loading rom url: " + decodeURIComponent(getQueryString('rompath', 'string')));
ajaxCall('/api/v1.1/Games/' + gameId, 'GET', function (result) {
gameData = result;
@@ -51,10 +53,14 @@
emuBios = '';
} else {
emuBios = '/api/v1.1/Bios/zip/' + platformId;
console.log("Using BIOS link: " + emuBios);
}
switch (getQueryString('engine', 'string')) {
case 'EmulatorJS':
console.log("Emulator: " + getQueryString('engine', 'string'));
console.log("Core: " + getQueryString('core', 'string'));
$('#emulator').load('/emulators/EmulatorJS.html?v=' + AppVersion);
break;
}

View File

@@ -545,7 +545,7 @@
var saveStatesButton = '';
if (mediaGroup.emulator) {
if (mediaGroup.emulator.type.length > 0) {
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '(' + mediaGroup.id + ')' + '.zip');
var romPath = encodeURIComponent('/api/v1.1/Games/' + gameId + '/romgroup/' + mediaGroup.id + '/' + gameData.name + '.zip');
if (mediaGroup.hasSaveStates == true) {
var modalVariables = {

View File

@@ -6,7 +6,7 @@
<table id="settings_libraries" class="romtable" style="width: 100%;" cellspacing="0">
</table>
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showSubDialog('librarynew');">New Library</button></div>
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showDialog('librarynew');">New Library</button></div>
<h2>Advanced Settings</h2>
<p><strong>Warning</strong> Do not modify the below settings unless you know what you're doing.</p>

View File

@@ -27,7 +27,7 @@ function formatFilterPanel(containerElement, result) {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
executeFilter1_1();
applyFilters();
}
});
containerPanelSearch.appendChild(containerPanelSearchField);
@@ -99,7 +99,7 @@ function formatFilterPanel(containerElement, result) {
// add filter button
var searchButton = document.createElement('div');
searchButton.id = 'games_library_searchbutton';
searchButton.setAttribute('onclick', 'executeFilter1_1();');
searchButton.setAttribute('onclick', 'applyFilters();');
searchButton.innerHTML = 'Apply';
buttonsDiv.appendChild(searchButton);
@@ -365,6 +365,12 @@ function filter_panel_range_value(name) {
}
}
function applyFilters() {
document.getElementById('games_library').innerHTML = '';
executeFilter1_1();
}
function resetFilters() {
// clear name
document.getElementById('filter_panel_search').value = '';
@@ -381,6 +387,7 @@ function resetFilters() {
filter_panel_range_enabled_check(rangeCheckboxes[i].getAttribute('data-name'));
}
document.getElementById('games_library').innerHTML = '';
executeFilter1_1();
}
@@ -393,8 +400,18 @@ function executeFilter1_1(pageNumber, pageSize) {
existingSearchModel = undefined;
}
let pageMode = GetPreference('LibraryPagination', 'paged');
if (!pageSize) {
switch (pageMode) {
case "infinite":
pageSize = 30;
break;
case "paged":
default:
pageSize = 30;
break;
}
}
var model;

View File

@@ -56,30 +56,77 @@ var ClassificationRatings = {
};
var pageReloadInterval;
var firstLoad = true;
function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScrollTop) {
console.log("Displaying page: " + pageNumber);
console.log("Page size: " + pageSize);
var pageMode = GetPreference('LibraryPagination', 'paged');
if (pageNumber == 1 || pageMode == 'paged') {
targetElement.innerHTML = '';
if (pageNumber == 1) {
localStorage.setItem("gaseous-library-scrollpos", 0);
}
if (pageMode == 'paged') {
targetElement.innerHTML = '';
}
switch (pageMode) {
case 'paged':
if (forceScrollTop == true) {
window.scrollTo(0, 0);
}
break;
case 'infinite':
var gamePlaceholders = document.getElementsByName('GamePlaceholder');
let currentPage = 1;
let totalPages = Math.ceil(result.count / pageSize);
let startIndex = 0;
let endIndex = pageSize;
for (let p = currentPage; p < totalPages + 1; p++) {
//console.log("Page: " + p + " - StartIndex: " + startIndex + " - EndIndex: " + endIndex);
let newPageAnchor = document.getElementById('pageAnchor' + p);
if (!newPageAnchor) {
newPageAnchor = document.createElement('span');
newPageAnchor.id = 'pageAnchor' + p;
newPageAnchor.setAttribute('name', 'pageAnchor' + p);
newPageAnchor.className = 'pageAnchor';
newPageAnchor.setAttribute('data-page', p);
newPageAnchor.setAttribute('data-loaded', "0");
targetElement.appendChild(newPageAnchor);
}
var pagerCheck = document.getElementById('games_library_pagerstore');
if (pageNumber == 1) {
pagerCheck.innerHTML = "0";
if (endIndex > result.count) {
endIndex = result.count;
}
if (pageNumber > Number(pagerCheck.innerHTML) || pageMode == 'paged') {
pagerCheck.innerHTML = pageNumber;
for (let i = startIndex; i < endIndex; i++) {
var placeHolderpresent = false;
for (var x = 0; x < gamePlaceholders.length; x++) {
if (gamePlaceholders[x].getAttribute('data-index') == i) {
placeHolderpresent = true;
}
}
if (placeHolderpresent == false) {
var gamePlaceholder = document.createElement('div');
gamePlaceholder.setAttribute('name', 'GamePlaceholder');
gamePlaceholder.id = 'GamePlaceholder' + i;
gamePlaceholder.setAttribute('data-index', i);
gamePlaceholder.className = 'game_tile';
newPageAnchor.appendChild(gamePlaceholder);
}
}
startIndex = endIndex;
endIndex = startIndex + pageSize;
if (startIndex > result.count) {
break;
}
}
break;
}
document.getElementById('games_library_recordcount').innerHTML = result.count + ' games';
@@ -100,14 +147,24 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
for (var i = 0; i < result.games.length; i++) {
var game = renderGameIcon(result.games[i], showTitle, showRatings, showClassification, classificationDisplayOrder, false);
switch (pageMode) {
case "paged":
targetElement.appendChild(game);
break;
case "infinite":
var placeholderElement = document.getElementById('GamePlaceholder' + result.games[i].index);
if (placeholderElement.className != 'game_tile_wrapper') {
placeholderElement.className = 'game_tile_wrapper';
placeholderElement.innerHTML = '';
placeholderElement.appendChild(game);
}
break;
}
$('.lazy').Lazy({
scrollDirection: 'vertical',
effect: 'fadeIn',
visibleOnly: true
});
$(game).fadeIn(500);
}
var pager = document.getElementById('games_pager');
pager.style.display = 'none';
@@ -117,15 +174,23 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
switch(pageMode) {
case 'infinite':
if (result.games.length == pageSize) {
var loadPageButton = document.createElement("div");
loadPageButton.id = 'games_library_loadmore';
loadPageButton.innerHTML = 'Load More';
loadPageButton.setAttribute('onclick', 'executeFilter1_1(' + (pageNumber + 1) + ', ' + pageSize + ');');
loadPageButton.setAttribute('data-pagenumber', Number(pageNumber + 1));
loadPageButton.setAttribute('data-pagesize', pageSize);
targetElement.appendChild(loadPageButton);
for (const [key, value] of Object.entries(result.alphaList)) {
var letterPager = document.createElement('span');
letterPager.className = 'games_library_alpha_pager_letter';
letterPager.setAttribute('onclick', 'document.location.hash = "#pageAnchor' + (value) + '"; executeFilter1_1(' + (value) + ');');
letterPager.innerHTML = key;
alphaPager.appendChild(letterPager);
}
if (firstLoad == true) {
if (localStorage.getItem("gaseous-library-scrollpos") != null) {
$(window).scrollTop(localStorage.getItem("gaseous-library-scrollpos"));
}
firstLoad = false;
}
IsInView();
break;
case 'paged':
@@ -138,11 +203,6 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
}
if (result.count > pageSize) {
// add some padding to the bottom of the games list
var loadPageButton = document.createElement("div");
loadPageButton.id = 'games_library_padding';
targetElement.appendChild(loadPageButton);
var pageCount = Math.ceil(result.count / pageSize);
// add first page button
@@ -167,7 +227,8 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
// add page numbers
var pageEitherSide = 4;
var currentPage = Number(pagerCheck.innerHTML);
// var currentPage = Number(pagerCheck.innerHTML);
var currentPage = pageNumber;
var pageNumbers = document.createElement('span');
for (var i = 1; i <= pageCount; i++) {
if (
@@ -187,7 +248,7 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
)
) {
var pageNum = document.createElement('span');
if (Number(pagerCheck.innerHTML) == i) {
if (pageNumber == i) {
pageNum.className = 'games_pager_number_disabled';
} else {
pageNum.className = 'games_pager_number';
@@ -229,19 +290,17 @@ function formatGamesPanel(targetElement, result, pageNumber, pageSize, forceScro
}
break;
}
$('.lazy').Lazy({
effect: 'show',
effectTime: 500,
visibleOnly: true,
defaultImage: '/images/unknowngame.png',
delay: 250,
afterLoad: function(element) {
//console.log(element[0].getAttribute('data-id'));
}
// var pageReloadFunction = function() {
// formatGamesPanel(targetElement, result, pageNumber, pageSize, false);
// ajaxCall('/api/v1.1/Filter', 'GET', function (result) {
// var scrollerElement = document.getElementById('games_filter_scroller');
// formatFilterPanel(scrollerElement, result);
// })
// };
// window.clearTimeout(pageReloadInterval);
// pageReloadInterval = setTimeout(pageReloadFunction, 10000);
});
}
function isScrolledIntoView(elem) {
@@ -256,15 +315,49 @@ function isScrolledIntoView(elem) {
}
}
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect();
const { innerHeight, innerWidth } = window;
return partiallyVisible
? ((top > 0 && top < innerHeight) ||
(bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};
function IsInView() {
var pageMode = GetPreference('LibraryPagination', 'paged');
switch (pageMode) {
case "paged":
var loadElement = document.getElementById('games_library_loadmore');
if (loadElement) {
if (isScrolledIntoView(loadElement)) {
//if (isScrolledIntoView(loadElement)) {
if (elementIsVisibleInViewport(loadElement, true)) {
var pageNumber = Number(document.getElementById('games_library_loadmore').getAttribute('data-pagenumber'));
var pageSize = document.getElementById('games_library_loadmore').getAttribute('data-pagesize');
executeFilter1_1(pageNumber, pageSize);
executeFilter1_1(pageNumber);
}
}
break;
case "infinite":
// store scroll location
localStorage.setItem("gaseous-library-scrollpos", $(window).scrollTop());
// load page
let anchors = document.getElementsByClassName('pageAnchor');
for (let i = 0; i < anchors.length; i++) {
//if (isScrolledIntoView(anchors[i])) {
if (elementIsVisibleInViewport(anchors[i], true)) {
if (anchors[i].getAttribute('data-loaded') == "0") {
console.log("Loading page: " + anchors[i].getAttribute('data-page'));
document.getElementById(anchors[i].id).setAttribute('data-loaded', "1");
executeFilter1_1(Number(anchors[i].getAttribute('data-page')));
}
}
}
break;
}
}
$(window).scroll(IsInView);
@@ -279,26 +372,30 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
var gameBox = document.createElement('div');
gameBox.id = "game_tile_" + gameObject.id;
if (useSmallCover == true) {
gameBox.className = classes['game_tile game_tile_small'];
gameBox.classList.add(...classes['game_tile game_tile_small']);
} else {
gameBox.className = classes['game_tile'];
gameBox.classList.add(...classes['game_tile']);
}
gameBox.setAttribute('onclick', 'window.location.href = "/index.html?page=game&id=' + gameObject.id + '";');
gameBox.style.display = 'none';
var gameImageBox = document.createElement('div');
gameImageBox.className = classes['game_tile_box'];
gameImageBox.classList.add(...classes['game_tile_box']);
var gameImage = document.createElement('img');
gameImage.id = 'game_tile_cover_' + gameObject.id;
gameImage.setAttribute('data-id', gameObject.id);
if (useSmallCover == true) {
gameImage.className = classes['game_tile_image game_tile_image_small lazy'];
gameImage.classList.add(...classes['game_tile_image game_tile_image_small lazy']);
} else {
gameImage.className = classes['game_tile_image lazy'];
gameImage.classList.add(...classes['game_tile_image lazy']);
}
gameImage.src = '/images/unknowngame.png';
// gameImage.src = '/images/unknowngame.png';
if (gameObject.cover) {
gameImage.setAttribute('data-src', '/api/v1.1/Games/' + gameObject.id + '/cover/image/cover_big/' + gameObject.cover.imageId + '.jpg');
} else {
gameImage.className = classes['game_tile_image unknown'];
gameImage.classList.add(...classes['game_tile_image unknown']);
gameImage.setAttribute('data-src', '/images/unknowngame.png');
}
gameImageBox.appendChild(gameImage);
@@ -312,7 +409,6 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
if (gameObject.ageRatings[c].category == classificationDisplayOrder[b]) {
shownClassificationBoard = classificationDisplayOrder[b];
displayClassification = true;
//classificationPath = '/api/v1.1/Ratings/Images/' + classificationDisplayOrder[b] + '/' + getKeyByValue(AgeRatingStrings, gameObject.ageRatings[c].rating) + '/image.svg';
classificationPath = '/images/Ratings/' + classificationDisplayOrder[b] + '/' + gameObject.ageRatings[c].rating + '.svg';
}
}
@@ -326,7 +422,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
if (gameObject.hasSavedGame == true) {
var gameSaveIcon = document.createElement('img');
gameSaveIcon.src = '/images/SaveStates.png';
gameSaveIcon.className = classes['game_tile_box_savedgame savedstateicon'];
gameSaveIcon.classList.add(...classes['game_tile_box_savedgame savedstateicon']);
gameImageBox.appendChild(gameSaveIcon);
}
@@ -334,13 +430,13 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
if (gameObject.isFavourite == true) {
var gameFavIcon = document.createElement('img');
gameFavIcon.src = '/images/favourite-filled.svg';
gameFavIcon.className = classes['game_tile_box_favouritegame favouriteicon'];
gameFavIcon.classList.add(...classes['game_tile_box_favouritegame favouriteicon']);
gameImageBox.appendChild(gameFavIcon);
}
if (gameObject.totalRating || displayClassification == true) {
var gameImageRatingBanner = document.createElement('div');
gameImageRatingBanner.className = classes['game_tile_box_ratingbanner'];
gameImageRatingBanner.classList.add(...classes['game_tile_box_ratingbanner']);
if (showRatings == true || displayClassification == true) {
if (showRatings == true) {
@@ -361,7 +457,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
if (displayClassification == true) {
var gameImageClassificationLogo = document.createElement('img');
gameImageClassificationLogo.src = classificationPath;
gameImageClassificationLogo.className = classes['rating_image_overlay'];
gameImageClassificationLogo.classList.add(...classes['rating_image_overlay']);
gameImageBox.appendChild(gameImageClassificationLogo);
}
}
@@ -370,7 +466,7 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
if (showTitle == true) {
var gameBoxTitle = document.createElement('div');
gameBoxTitle.className = classes['game_tile_label'];
gameBoxTitle.classList.add(...classes['game_tile_label']);
gameBoxTitle.innerHTML = gameObject.name;
gameBox.appendChild(gameBoxTitle);
}
@@ -381,31 +477,31 @@ function renderGameIcon(gameObject, showTitle, showRatings, showClassification,
function getViewModeClasses(listView) {
if (listView == false) {
return {
"game_tile game_tile_small": "game_tile game_tile_small",
"game_tile": "game_tile",
"game_tile_box": "game_tile_box",
"game_tile_image game_tile_image_small lazy": "game_tile_image game_tile_image_small lazy",
"game_tile_image lazy": "game_tile_image lazy",
"game_tile_image unknown": "game_tile_image unknown",
"game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame savedstateicon",
"game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame favouriteicon",
"game_tile_box_ratingbanner": "game_tile_box_ratingbanner",
"rating_image_overlay": "rating_image_overlay",
"game_tile_label": "game_tile_label"
"game_tile game_tile_small": [ "game_tile", "game_tile_small" ],
"game_tile": [ "game_tile" ],
"game_tile_box": [ "game_tile_box" ],
"game_tile_image game_tile_image_small lazy": [ "game_tile_image", "game_tile_image_small", "lazy" ],
"game_tile_image lazy": [ "game_tile_image", "lazy" ],
"game_tile_image unknown": [ "game_tile_image", "unknown" ],
"game_tile_box_savedgame savedstateicon": [ "game_tile_box_savedgame", "savedstateicon" ],
"game_tile_box_favouritegame favouriteicon": [ "game_tile_box_favouritegame", "favouriteicon" ],
"game_tile_box_ratingbanner": [ "game_tile_box_ratingbanner" ],
"rating_image_overlay": [ "rating_image_overlay" ],
"game_tile_label": [ "game_tile_label" ]
};
} else {
return {
"game_tile game_tile_small": "game_tile_row game_tile_small",
"game_tile": "game_tile_row",
"game_tile_box": "game_tile_box_row",
"game_tile_image game_tile_image_small lazy": "game_tile_image_row game_tile_image_small lazy",
"game_tile_image lazy": "game_tile_image_row lazy",
"game_tile_image unknown": "game_tile_image_row unknown",
"game_tile_box_savedgame savedstateicon": "game_tile_box_savedgame_row savedstateicon",
"game_tile_box_favouritegame favouriteicon": "game_tile_box_favouritegame_row favouriteicon",
"game_tile_box_ratingbanner": "game_tile_box_ratingbanner_row",
"rating_image_overlay": "rating_image_overlay_row",
"game_tile_label": "game_tile_label_row"
"game_tile game_tile_small": [ "game_tile_row", "game_tile_small" ],
"game_tile": [ "game_tile_row" ],
"game_tile_box": [ "game_tile_box_row" ],
"game_tile_image game_tile_image_small lazy": [ "game_tile_image_row", "game_tile_image_small", "lazy" ],
"game_tile_image lazy": [ "game_tile_image_row", "lazy" ],
"game_tile_image unknown": [ "game_tile_image_row", "unknown" ],
"game_tile_box_savedgame savedstateicon": [ "game_tile_box_savedgame_row", "savedstateicon" ],
"game_tile_box_favouritegame favouriteicon": [ "game_tile_box_favouritegame_row", "favouriteicon" ],
"game_tile_box_ratingbanner": [ "game_tile_box_ratingbanner_row" ],
"rating_image_overlay": [ "rating_image_overlay_row" ],
"game_tile_label": [ "game_tile_label_row" ]
};
}
}

View File

@@ -548,11 +548,25 @@ input[name='filter_panel_range_max'] {
background-color: blue;
}
.game_tile_wrapper {
display: inline-block;
}
.game_tile_placeholder {
display: inline-block;
min-height: 243px;
width: 232px;
margin-bottom: 10px;
}
.game_tile {
padding: 5px;
padding-top: 10px;
padding-bottom: 5px;
padding-left: 5px;
padding-right: 5px;
display: inline-block;
width: 220px;
min-height: 200px;
min-height: 243px;
align-items: center;
justify-content: center;
text-align: center;
@@ -689,6 +703,9 @@ input[name='filter_panel_range_max'] {
max-height: 200px;
min-height: 200px;
background-color: transparent;
}
.game_tile_image_shadow {
box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
@@ -701,9 +718,6 @@ input[name='filter_panel_range_max'] {
min-height: 75px;
margin-left: 10px;
background-color: transparent;
box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
-moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44);
}
.game_tile_image, .unknown {