From 070589f718304521e3ae8e8605148020cb1ab1c1 Mon Sep 17 00:00:00 2001 From: Michael Green <84688932+michael-j-green@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:32:18 -0700 Subject: [PATCH] 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. --- build/embeddeddb/entrypoint.sh | 3 + build/standard/entrypoint.sh | 3 + gaseous-server/Classes/Config.cs | 6 +- gaseous-server/Classes/DatabaseMigration.cs | 78 +++++++++++++++++-- gaseous-server/Classes/Filters.cs | 6 +- gaseous-server/Classes/GameLibrary.cs | 12 +++ gaseous-server/Classes/ImportGames.cs | 50 ++++++++---- gaseous-server/Classes/Metadata/Games.cs | 32 ++++---- gaseous-server/Classes/Roms.cs | 30 +++---- .../Controllers/V1.0/GamesController.cs | 6 +- .../Controllers/V1.0/PlatformsController.cs | 2 +- .../Controllers/V1.0/SystemController.cs | 2 +- .../Controllers/V1.1/GamesController.cs | 14 ++-- gaseous-server/Program.cs | 3 + .../Support/Database/MySQL/gaseous-1024.sql | 16 +++- 15 files changed, 190 insertions(+), 73 deletions(-) diff --git a/build/embeddeddb/entrypoint.sh b/build/embeddeddb/entrypoint.sh index 89cb777..508f93c 100644 --- a/build/embeddeddb/entrypoint.sh +++ b/build/embeddeddb/entrypoint.sh @@ -5,6 +5,9 @@ echo "Creating user gaseous with UID ${PUID} and GID ${PGID}" groupadd -g ${PGID} gaseous useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo usermod -p "*" gaseous +mkdir -p /home/gaseous/.aspnet +chown -R ${PUID} /App /home/gaseous/.aspnet +chgrp -R ${PGID} /App /home/gaseous/.aspnet mkdir -p /home/gaseous/.gaseous-server chown -R ${PUID} /App /home/gaseous/.gaseous-server chgrp -R ${PGID} /App /home/gaseous/.gaseous-server diff --git a/build/standard/entrypoint.sh b/build/standard/entrypoint.sh index 8256268..d4e9e49 100644 --- a/build/standard/entrypoint.sh +++ b/build/standard/entrypoint.sh @@ -5,6 +5,9 @@ echo "Creating user gaseous with UID ${PUID} and GID ${PGID}" groupadd -g ${PGID} gaseous useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo usermod -p "*" gaseous +mkdir -p /home/gaseous/.aspnet +chown -R ${PUID} /App /home/gaseous/.aspnet +chgrp -R ${PGID} /App /home/gaseous/.aspnet mkdir -p /home/gaseous/.gaseous-server chown -R ${PUID} /App /home/gaseous/.gaseous-server chgrp -R ${PGID} /App /home/gaseous/.gaseous-server diff --git a/gaseous-server/Classes/Config.cs b/gaseous-server/Classes/Config.cs index f7b88e9..c82dadb 100644 --- a/gaseous-server/Classes/Config.cs +++ b/gaseous-server/Classes/Config.cs @@ -531,11 +531,7 @@ namespace gaseous_server.Classes { get { - return ReadSetting("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data")); - } - set - { - SetSetting("LibraryRootDirectory", value); + return Path.Combine(Config.ConfigurationPath, "Data"); } } diff --git a/gaseous-server/Classes/DatabaseMigration.cs b/gaseous-server/Classes/DatabaseMigration.cs index ba6a67d..0bb712c 100644 --- a/gaseous-server/Classes/DatabaseMigration.cs +++ b/gaseous-server/Classes/DatabaseMigration.cs @@ -149,9 +149,6 @@ namespace gaseous_server.Classes db.ExecuteNonQuery(sql, dbDict); } while (reader.EndOfStream == false); } - - // this is a safe background task - BackgroundUpgradeTargetSchemaVersions.Add(1023); break; case 1024: @@ -181,6 +178,73 @@ namespace gaseous_server.Classes }; 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 + { + { "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 + { + { "newpath", newPath }, + { "id", romRow["Id"] } + }; + db.ExecuteNonQuery(sql, dbDict); + } + } + + // migrating metadata is a safe background task + BackgroundUpgradeTargetSchemaVersions.Add(1024); break; } break; @@ -197,8 +261,8 @@ namespace gaseous_server.Classes MySql_1002_MigrateMetadataVersion(); break; - case 1023: - MySql_1023_MigrateMetadataVersion(); + case 1024: + MySql_1024_MigrateMetadataVersion(); 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(); 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); long count = 1; foreach (DataRow row in data.Rows) diff --git a/gaseous-server/Classes/Filters.cs b/gaseous-server/Classes/Filters.cs index f58291a..570a69b 100644 --- a/gaseous-server/Classes/Filters.cs +++ b/gaseous-server/Classes/Filters.cs @@ -24,7 +24,7 @@ namespace gaseous_server.Classes ageRestriction_Generic += " OR view_Games.AgeGroupId IS NULL"; } - string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, Games_Roms.PlatformId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id GROUP BY Platform.`Name`;"; + 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)); @@ -82,7 +82,7 @@ namespace gaseous_server.Classes // age groups List agegroupings = new List(); - 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)); foreach (DataRow dr in dbResponse.Rows) @@ -112,7 +112,7 @@ namespace gaseous_server.Classes { //string sql = "SELECT DISTINCT .Id, .`Name`, COUNT(view_Games.Id) AS GameCount FROM LEFT JOIN Relation_Game_s ON Relation_Game_s.sId = .Id LEFT JOIN view_Games ON view_Games.Id = Relation_Game_s.GameId WHERE (" + AgeRestriction_Generic + ") GROUP BY .Id HAVING GameCount > 0 ORDER BY .`Name`;"; - string sql = "SELECT .Id, .`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_s ON Game.Id = Relation_Game_s.GameId JOIN ON Relation_Game_s.sId = .Id GROUP BY .`Name` ORDER BY .`Name`;"; + string sql = "SELECT .Id, .`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_s ON Game.Id = Relation_Game_s.GameId JOIN ON Relation_Game_s.sId = .Id GROUP BY .`Name` ORDER BY .`Name`;"; sql = sql.Replace("", Name); DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300)); diff --git a/gaseous-server/Classes/GameLibrary.cs b/gaseous-server/Classes/GameLibrary.cs index b30ea46..bc8f890 100644 --- a/gaseous-server/Classes/GameLibrary.cs +++ b/gaseous-server/Classes/GameLibrary.cs @@ -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 dbDict = new Dictionary + { + { "path", Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "Library") } + }; + db.ExecuteCMD(sql, dbDict); + } + public static List GetLibraries { get diff --git a/gaseous-server/Classes/ImportGames.cs b/gaseous-server/Classes/ImportGames.cs index d0fa5a3..155c392 100644 --- a/gaseous-server/Classes/ImportGames.cs +++ b/gaseous-server/Classes/ImportGames.cs @@ -73,7 +73,7 @@ namespace gaseous_server.Classes RetVal.Add("type", "rom"); // check to make sure we don't already have this file imported - sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1"; + sql = "SELECT COUNT(Id) AS count FROM view_Games_Roms WHERE MD5=@md5 AND SHA1=@sha1"; dbDict.Add("md5", hash.md5hash); dbDict.Add("sha1", hash.sha1hash); DataTable importDB = db.ExecuteCMD(sql, dbDict); @@ -129,7 +129,7 @@ namespace gaseous_server.Classes IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true); // 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 RetVal.Add("romid", RomId); @@ -329,7 +329,7 @@ namespace gaseous_server.Classes return SearchCandidates; } - public static long StoreROM(GameLibrary.LibraryItem library, Common.hashObject hash, IGDB.Models.Game determinedGame, IGDB.Models.Platform determinedPlatform, gaseous_server.Models.Signatures_Games discoveredSignature, string GameFileImportPath, long UpdateId = 0) + 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); @@ -339,7 +339,7 @@ namespace gaseous_server.Classes 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 { @@ -378,7 +378,13 @@ namespace gaseous_server.Classes dbDict.Add("romtype", (int)discoveredSignature.Rom.RomType); dbDict.Add("romtypemedia", Common.ReturnValueIfNull(discoveredSignature.Rom.RomTypeMedia, "")); dbDict.Add("medialabel", Common.ReturnValueIfNull(discoveredSignature.Rom.MediaLabel, "")); - dbDict.Add("path", GameFileImportPath); + + 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); long romId = 0; @@ -394,7 +400,7 @@ namespace gaseous_server.Classes // move to destination if (library.IsDefaultLibrary == true) { - MoveGameFile(romId); + MoveGameFile(romId, SourceIsExternal); } return romId; @@ -430,10 +436,14 @@ namespace gaseous_server.Classes return DestinationPathName; } - public static bool MoveGameFile(long RomId) + public static bool MoveGameFile(long RomId, bool SourceIsExternal) { Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId); string romPath = rom.Path; + if (SourceIsExternal == true) + { + romPath = rom.RelativePath; + } if (File.Exists(romPath)) { @@ -458,10 +468,16 @@ namespace gaseous_server.Classes // update the db Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "UPDATE Games_Roms SET Path=@path WHERE Id=@id"; + string sql = "UPDATE Games_Roms SET RelativePath=@path WHERE Id=@id"; Dictionary dbDict = new Dictionary(); dbDict.Add("id", RomId); - dbDict.Add("path", DestinationPath); + + string libraryRootPath = rom.Library.Path; + if (libraryRootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false) + { + libraryRootPath += Path.DirectorySeparatorChar; + } + dbDict.Add("path", DestinationPath.Replace(libraryRootPath, "")); db.ExecuteCMD(sql, dbDict); return true; @@ -483,7 +499,7 @@ namespace gaseous_server.Classes // move rom files to their new location Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "SELECT * FROM Games_Roms WHERE LibraryId = @libraryid"; + string sql = "SELECT * FROM view_Games_Roms WHERE LibraryId = @libraryid"; Dictionary dbDict = new Dictionary(); dbDict.Add("libraryid", library.Id); DataTable romDT = db.ExecuteCMD(sql, dbDict); @@ -495,7 +511,7 @@ namespace gaseous_server.Classes SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]); Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]); long RomId = (long)romDT.Rows[i]["id"]; - MoveGameFile(RomId); + MoveGameFile(RomId, false); } } ClearStatus(); @@ -639,7 +655,7 @@ namespace gaseous_server.Classes dupDict.Add("libraryid", library.Id); db.ExecuteCMD(duplicateSql, dupDict); - string sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; + string sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; Dictionary dbDict = new Dictionary(); dbDict.Add("libraryid", library.Id); DataTable dtRoms = db.ExecuteCMD(sql, dbDict); @@ -664,7 +680,7 @@ namespace gaseous_server.Classes } } - sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; + sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; dtRoms = db.ExecuteCMD(sql, dbDict); // search for files in the library that aren't in the database @@ -736,7 +752,7 @@ namespace gaseous_server.Classes } ClearStatus(); - sql = "SELECT * FROM Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; + sql = "SELECT * FROM view_Games_Roms WHERE LibraryId=@libraryid ORDER BY `name`"; dtRoms = db.ExecuteCMD(sql, dbDict); // check all roms to see if their local file still exists @@ -760,7 +776,7 @@ namespace gaseous_server.Classes if (romPath != ComputeROMPath(romId)) { Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found, but needs to be moved"); - MoveGameFile(romId); + MoveGameFile(romId, false); } else { @@ -801,11 +817,11 @@ namespace gaseous_server.Classes string sql = ""; if (ForceExecute == false) { - sql = "SELECT * FROM Games_Roms WHERE (PlatformId = 0 AND GameId <> 0) OR (((PlatformId = 0 OR GameId = 0) AND MetadataSource = 0) OR (PlatformId = 0 AND GameId = 0)) AND (LastMatchAttemptDate IS NULL OR LastMatchAttemptDate < @lastmatchattemptdate) AND LibraryId = @libraryid LIMIT 100;"; + 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 { - 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 dbDict = new Dictionary(); dbDict.Add("lastmatchattemptdate", DateTime.UtcNow.AddDays(-7)); diff --git a/gaseous-server/Classes/Metadata/Games.cs b/gaseous-server/Classes/Metadata/Games.cs index e659755..79904dd 100644 --- a/gaseous-server/Classes/Metadata/Games.cs +++ b/gaseous-server/Classes/Metadata/Games.cs @@ -510,8 +510,8 @@ namespace gaseous_server.Classes.Metadata Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); string sql = @" SELECT DISTINCT - Games_Roms.GameId, - Games_Roms.PlatformId, + view_Games_Roms.GameId, + view_Games_Roms.PlatformId, Platform.`Name`, User_RecentPlayedRoms.UserId AS MostRecentUserId, User_RecentPlayedRoms.RomId AS MostRecentRomId, @@ -530,23 +530,23 @@ SELECT DISTINCT END AS `FavouriteRomName`, User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup FROM - Games_Roms + view_Games_Roms LEFT JOIN - Platform ON Games_Roms.PlatformId = Platform.Id + Platform ON view_Games_Roms.PlatformId = Platform.Id LEFT JOIN User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid - AND User_RecentPlayedRoms.GameId = Games_Roms.GameId - AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId + AND User_RecentPlayedRoms.GameId = view_Games_Roms.GameId + AND User_RecentPlayedRoms.PlatformId = view_Games_Roms.PlatformId LEFT JOIN User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid - AND User_GameFavouriteRoms.GameId = Games_Roms.GameId - AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId + AND User_GameFavouriteRoms.GameId = view_Games_Roms.GameId + AND User_GameFavouriteRoms.PlatformId = view_Games_Roms.PlatformId 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 - Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId + view_Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId WHERE - Games_Roms.GameId = @gameid + view_Games_Roms.GameId = @gameid ORDER BY Platform.`Name`;"; Dictionary dbDict = new Dictionary { @@ -583,7 +583,10 @@ ORDER BY Platform.`Name`;"; { LastPlayedRomId = (long?)row["MostRecentRomId"]; 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; @@ -593,7 +596,10 @@ ORDER BY Platform.`Name`;"; { FavouriteRomId = (long?)row["FavouriteRomId"]; 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 diff --git a/gaseous-server/Classes/Roms.cs b/gaseous-server/Classes/Roms.cs index 4721977..a8b27bf 100644 --- a/gaseous-server/Classes/Roms.cs +++ b/gaseous-server/Classes/Roms.cs @@ -39,7 +39,7 @@ namespace gaseous_server.Classes string NameSearchWhere = ""; if (NameSearch.Length > 0) { - NameSearchWhere = " AND Games_Roms.`Name` LIKE @namesearch"; + NameSearchWhere = " AND view_Games_Roms.`Name` LIKE @namesearch"; dbDict.Add("namesearch", '%' + NameSearch + '%'); } @@ -51,37 +51,37 @@ namespace gaseous_server.Classes UserJoin = @" LEFT JOIN User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid - AND User_RecentPlayedRoms.GameId = Games_Roms.GameId - AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId - AND User_RecentPlayedRoms.RomId = Games_Roms.Id + AND User_RecentPlayedRoms.GameId = view_Games_Roms.GameId + AND User_RecentPlayedRoms.PlatformId = view_Games_Roms.PlatformId + AND User_RecentPlayedRoms.RomId = view_Games_Roms.Id AND User_RecentPlayedRoms.IsMediaGroup = 0 LEFT JOIN User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid - AND User_GameFavouriteRoms.GameId = Games_Roms.GameId - AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId - AND User_GameFavouriteRoms.RomId = Games_Roms.Id + AND User_GameFavouriteRoms.GameId = view_Games_Roms.GameId + AND User_GameFavouriteRoms.PlatformId = view_Games_Roms.PlatformId + AND User_GameFavouriteRoms.RomId = view_Games_Roms.Id AND User_GameFavouriteRoms.IsMediaGroup = 0 "; } // platform query - sqlPlatform = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;"; + 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) { // 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 - 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 { // 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 - 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); } @@ -114,7 +114,7 @@ namespace gaseous_server.Classes public static GameRomItem GetRom(long RomId) { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, 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 dbDict = new Dictionary(); dbDict.Add("id", RomId); DataTable romDT = db.ExecuteCMD(sql, dbDict); @@ -134,7 +134,7 @@ namespace gaseous_server.Classes public static GameRomItem GetRom(string MD5) { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, 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 dbDict = new Dictionary(); dbDict.Add("id", MD5); DataTable romDT = db.ExecuteCMD(sql, dbDict); @@ -282,6 +282,7 @@ namespace gaseous_server.Classes RomTypeMedia = (string)romDR["romtypemedia"], MediaLabel = (string)romDR["medialabel"], Path = (string)romDR["path"], + RelativePath = (string)romDR["relativepath"], SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"], SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""), HasSaveStates = hasSaveStates, @@ -322,6 +323,7 @@ namespace gaseous_server.Classes public long GameId { get; set; } public string Game { get; set; } public string? Path { get; set; } + public string? RelativePath { get; set; } public string? SignatureSourceGameTitle { get; set; } public bool HasSaveStates { get; set; } = false; public GameLibrary.LibraryItem Library { get; set; } diff --git a/gaseous-server/Controllers/V1.0/GamesController.cs b/gaseous-server/Controllers/V1.0/GamesController.cs index 2b4c08f..b7b0a60 100644 --- a/gaseous-server/Controllers/V1.0/GamesController.cs +++ b/gaseous-server/Controllers/V1.0/GamesController.cs @@ -105,7 +105,7 @@ namespace gaseous_server.Controllers if (platform.Length > 0) { - tempVal = "Games_Roms.PlatformId IN ("; + tempVal = "view_Games_Roms.PlatformId IN ("; string[] platformClauseItems = platform.Split(","); 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); - //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 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; + 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; List RetVal = new List(); diff --git a/gaseous-server/Controllers/V1.0/PlatformsController.cs b/gaseous-server/Controllers/V1.0/PlatformsController.cs index bebb965..6ddda49 100644 --- a/gaseous-server/Controllers/V1.0/PlatformsController.cs +++ b/gaseous-server/Controllers/V1.0/PlatformsController.cs @@ -37,7 +37,7 @@ namespace gaseous_server.Controllers { Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString); - string sql = "SELECT * FROM Platform WHERE Id IN (SELECT DISTINCT PlatformId FROM Games_Roms) ORDER BY `Name` ASC;"; + string sql = "SELECT * FROM Platform WHERE Id IN (SELECT DISTINCT PlatformId FROM view_Games_Roms) ORDER BY `Name` ASC;"; List RetVal = new List(); diff --git a/gaseous-server/Controllers/V1.0/SystemController.cs b/gaseous-server/Controllers/V1.0/SystemController.cs index ea7995d..b3bd011 100644 --- a/gaseous-server/Controllers/V1.0/SystemController.cs +++ b/gaseous-server/Controllers/V1.0/SystemController.cs @@ -51,7 +51,7 @@ namespace gaseous_server.Controllers ReturnValue.DatabaseSize = (long)(System.Decimal)dbResponse.Rows[0][1]; // platform statistics - sql = "SELECT Platform.`name`, grc.Count, grs.Size FROM Platform INNER JOIN (SELECT Platform.`name` AS `Name`, SUM(grs.Size) AS Size FROM Platform JOIN Games_Roms AS grs ON (grs.PlatformId = Platform.Id) GROUP BY Platform.`name`) grs ON (grs.`Name` = Platform.`name`) INNER JOIN (SELECT Platform.`name` AS `Name`, COUNT(grc.Size) AS Count FROM Platform JOIN Games_Roms AS grc ON (grc.PlatformId = Platform.Id) GROUP BY Platform.`name`) grc ON (grc.`Name` = Platform.`name`) ORDER BY Platform.`name`;"; + sql = "SELECT 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); ReturnValue.PlatformStatistics = new List(); foreach (DataRow dr in dbResponse.Rows) diff --git a/gaseous-server/Controllers/V1.1/GamesController.cs b/gaseous-server/Controllers/V1.1/GamesController.cs index 5e675ad..f1e9f8b 100644 --- a/gaseous-server/Controllers/V1.1/GamesController.cs +++ b/gaseous-server/Controllers/V1.1/GamesController.cs @@ -303,7 +303,7 @@ namespace gaseous_server.Controllers.v1_1 string platformWhereClause = ""; if (model.Platform.Count > 0) { - tempVal = " AND Games_Roms.PlatformId IN ("; + tempVal = " AND view_Games_Roms.PlatformId IN ("; for (int i = 0; i < model.Platform.Count; i++) { if (i > 0) @@ -511,26 +511,26 @@ FROM WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The') ELSE Game.`Name` END AS NameThe, - Games_Roms.PlatformId, + view_Games_Roms.PlatformId, AgeGroup.AgeGroupId, - COUNT(Games_Roms.Id) AS RomCount + COUNT(view_Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId - LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId" + platformWhereClause + @" + LEFT JOIN view_Games_Roms ON Game.Id = view_Games_Roms.GameId" + platformWhereClause + @" LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + @" GROUP BY Game.Id HAVING RomCount > 0) Game LEFT JOIN (SELECT - Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount + view_Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount FROM GameState - JOIN Games_Roms ON GameState.RomId = Games_Roms.Id + JOIN view_Games_Roms ON GameState.RomId = view_Games_Roms.Id WHERE GameState.IsMediaGroup = 0 AND GameState.UserId = @userid - GROUP BY Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId + GROUP BY view_Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId LEFT JOIN (SELECT RomMediaGroup.GameId, diff --git a/gaseous-server/Program.cs b/gaseous-server/Program.cs index ff86a81..23b63b1 100644 --- a/gaseous-server/Program.cs +++ b/gaseous-server/Program.cs @@ -48,6 +48,9 @@ Config.InitSettings(); // write updated settings back to the config file Config.UpdateConfig(); +// update default library path +GameLibrary.UpdateDefaultLibraryPath(); + // set api metadata source from config Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource; diff --git a/gaseous-server/Support/Database/MySQL/gaseous-1024.sql b/gaseous-server/Support/Database/MySQL/gaseous-1024.sql index e0e421d..a2ea403 100644 --- a/gaseous-server/Support/Database/MySQL/gaseous-1024.sql +++ b/gaseous-server/Support/Database/MySQL/gaseous-1024.sql @@ -76,4 +76,18 @@ CREATE TABLE `User_GameFavouriteRoms` ( `PlatformId` ), CONSTRAINT `GameFavouriteRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE -); \ No newline at end of file +); + +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`; \ No newline at end of file