Multiple Updates (#251)
* Added more error logging to zip expansion * Added more logging * More logging, and archive contents can now be seen in rom info * Bug fixes and caching enhancements * Import path now cleaned after import
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using HasheousClient.Models;
|
using HasheousClient.Models;
|
||||||
|
using SevenZip;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Rar;
|
using SharpCompress.Archives.Rar;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
@@ -10,6 +12,7 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
public static gaseous_server.Models.Signatures_Games GetFileSignature(Common.hashObject hash, FileInfo fi, string GameFileImportPath)
|
public static gaseous_server.Models.Signatures_Games GetFileSignature(Common.hashObject hash, FileInfo fi, string GameFileImportPath)
|
||||||
{
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Getting signature for file: " + GameFileImportPath);
|
||||||
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
||||||
discoveredSignature = _GetFileSignature(hash, fi, GameFileImportPath, false);
|
discoveredSignature = _GetFileSignature(hash, fi, GameFileImportPath, false);
|
||||||
|
|
||||||
@@ -20,81 +23,152 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
// file is a zip and less than 1 GiB
|
// file is a zip and less than 1 GiB
|
||||||
// extract the zip file and search the contents
|
// extract the zip file and search the contents
|
||||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing " + GameFileImportPath + " to examine contents");
|
|
||||||
|
|
||||||
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, Path.GetRandomFileName());
|
string ExtractPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, Path.GetRandomFileName());
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing " + GameFileImportPath + " to " + ExtractPath + " examine contents");
|
||||||
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch(ImportedFileExtension)
|
switch(ImportedFileExtension)
|
||||||
{
|
{
|
||||||
case ".zip":
|
case ".zip":
|
||||||
ZipFile.ExtractToDirectory(GameFileImportPath, ExtractPath);
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using zip");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(GameFileImportPath))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Unzip error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ".rar":
|
case ".rar":
|
||||||
using (var archive = RarArchive.Open(GameFileImportPath))
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using rar");
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
using (var archive = RarArchive.Open(GameFileImportPath))
|
||||||
{
|
{
|
||||||
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
{
|
{
|
||||||
ExtractFullPath = true,
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
Overwrite = true
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
});
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Unrar error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ".7z":
|
case ".7z":
|
||||||
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(GameFileImportPath))
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using 7z");
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(GameFileImportPath))
|
||||||
{
|
{
|
||||||
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
{
|
{
|
||||||
ExtractFullPath = true,
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Extracting file: " + entry.Key);
|
||||||
Overwrite = true
|
entry.WriteToDirectory(ExtractPath, new ExtractionOptions()
|
||||||
});
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "7z error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Processing decompressed files for signature matches");
|
||||||
// loop through contents until we find the first signature match
|
// loop through contents until we find the first signature match
|
||||||
|
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||||
|
bool signatureFound = false;
|
||||||
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
FileInfo zfi = new FileInfo(file);
|
if (File.Exists(file))
|
||||||
Common.hashObject zhash = new Common.hashObject(file);
|
|
||||||
|
|
||||||
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi, file, true);
|
|
||||||
zDiscoveredSignature.Rom.Name = Path.ChangeExtension(zDiscoveredSignature.Rom.Name, ImportedFileExtension);
|
|
||||||
|
|
||||||
if (zDiscoveredSignature.Score > discoveredSignature.Score)
|
|
||||||
{
|
{
|
||||||
if (
|
FileInfo zfi = new FileInfo(file);
|
||||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEArcade ||
|
Common.hashObject zhash = new Common.hashObject(file);
|
||||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEMess
|
|
||||||
)
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking signature of decompressed file " + file);
|
||||||
{
|
|
||||||
zDiscoveredSignature.Rom.Name = zDiscoveredSignature.Game.Description + ImportedFileExtension;
|
|
||||||
}
|
|
||||||
zDiscoveredSignature.Rom.Crc = discoveredSignature.Rom.Crc;
|
|
||||||
zDiscoveredSignature.Rom.Md5 = discoveredSignature.Rom.Md5;
|
|
||||||
zDiscoveredSignature.Rom.Sha1 = discoveredSignature.Rom.Sha1;
|
|
||||||
zDiscoveredSignature.Rom.Size = discoveredSignature.Rom.Size;
|
|
||||||
discoveredSignature = zDiscoveredSignature;
|
|
||||||
|
|
||||||
break;
|
if (zfi != null)
|
||||||
|
{
|
||||||
|
ArchiveData archiveData = new ArchiveData{
|
||||||
|
FileName = Path.GetFileName(file),
|
||||||
|
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||||
|
Size = zfi.Length,
|
||||||
|
MD5 = hash.md5hash,
|
||||||
|
SHA1 = hash.sha1hash
|
||||||
|
};
|
||||||
|
archiveFiles.Add(archiveData);
|
||||||
|
|
||||||
|
if (signatureFound == false)
|
||||||
|
{
|
||||||
|
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi, file, true);
|
||||||
|
zDiscoveredSignature.Rom.Name = Path.ChangeExtension(zDiscoveredSignature.Rom.Name, ImportedFileExtension);
|
||||||
|
|
||||||
|
if (zDiscoveredSignature.Score > discoveredSignature.Score)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEArcade ||
|
||||||
|
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEMess
|
||||||
|
)
|
||||||
|
{
|
||||||
|
zDiscoveredSignature.Rom.Name = zDiscoveredSignature.Game.Description + ImportedFileExtension;
|
||||||
|
}
|
||||||
|
zDiscoveredSignature.Rom.Crc = discoveredSignature.Rom.Crc;
|
||||||
|
zDiscoveredSignature.Rom.Md5 = discoveredSignature.Rom.Md5;
|
||||||
|
zDiscoveredSignature.Rom.Sha1 = discoveredSignature.Rom.Sha1;
|
||||||
|
zDiscoveredSignature.Rom.Size = discoveredSignature.Rom.Size;
|
||||||
|
discoveredSignature = zDiscoveredSignature;
|
||||||
|
|
||||||
|
signatureFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
discoveredSignature.Rom.Attributes.Add(new KeyValuePair<string, object>(
|
||||||
|
"ZipContents", Newtonsoft.Json.JsonConvert.SerializeObject(archiveFiles)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Get Signature", "Error processing zip file: " + GameFileImportPath, ex);
|
Logging.Log(Logging.LogType.Critical, "Get Signature", "Error processing compressed file: " + GameFileImportPath, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(ExtractPath)) { Directory.Delete(ExtractPath, true); }
|
if (Directory.Exists(ExtractPath))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Deleting temporary decompress folder: " + ExtractPath);
|
||||||
|
|
||||||
|
Directory.Delete(ExtractPath, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return discoveredSignature;
|
return discoveredSignature;
|
||||||
@@ -110,6 +184,7 @@ namespace gaseous_server.Classes
|
|||||||
if (dbSignature != null)
|
if (dbSignature != null)
|
||||||
{
|
{
|
||||||
// local signature found
|
// local signature found
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
||||||
discoveredSignature = dbSignature;
|
discoveredSignature = dbSignature;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -120,12 +195,16 @@ namespace gaseous_server.Classes
|
|||||||
if (dbSignature != null)
|
if (dbSignature != null)
|
||||||
{
|
{
|
||||||
// signature retrieved from Hasheous
|
// signature retrieved from Hasheous
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
||||||
|
|
||||||
discoveredSignature = dbSignature;
|
discoveredSignature = dbSignature;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// construct a signature from file data
|
// construct a signature from file data
|
||||||
dbSignature = _GetFileSignatureFromFileData(hash, fi, GameFileImportPath);
|
dbSignature = _GetFileSignatureFromFileData(hash, fi, GameFileImportPath);
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
||||||
|
|
||||||
discoveredSignature = dbSignature;
|
discoveredSignature = dbSignature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,5 +361,14 @@ namespace gaseous_server.Classes
|
|||||||
return discoveredSignature;
|
return discoveredSignature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ArchiveData
|
||||||
|
{
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
public long Size { get; set; }
|
||||||
|
public string MD5 { get; set; }
|
||||||
|
public string SHA1 { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -16,44 +16,37 @@ using HasheousClient.Models;
|
|||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class ImportGames : QueueItemStatus
|
public class ImportGame : QueueItemStatus
|
||||||
{
|
{
|
||||||
public ImportGames(string ImportPath)
|
public void ProcessDirectory(string ImportPath)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(ImportPath))
|
if (Directory.Exists(ImportPath))
|
||||||
{
|
{
|
||||||
string[] importContents_Files = Directory.GetFiles(ImportPath);
|
string[] importContents = Directory.GetFiles(ImportPath, "*.*", SearchOption.AllDirectories);
|
||||||
string[] importContents_Directories = Directory.GetDirectories(ImportPath);
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Import Games", "Found " + importContents.Length + " files to process in import directory: " + ImportPath);
|
||||||
|
|
||||||
// import files first
|
// import files first
|
||||||
int importCount = 1;
|
int importCount = 1;
|
||||||
foreach (string importContent in importContents_Files) {
|
foreach (string importContent in importContents) {
|
||||||
SetStatus(importCount, importContents_Files.Length, "Importing file: " + importContent);
|
SetStatus(importCount, importContents.Length, "Importing file: " + importContent);
|
||||||
|
|
||||||
ImportGame.ImportGameFile(importContent, null);
|
ImportGameFile(importContent, null);
|
||||||
|
|
||||||
importCount += 1;
|
importCount += 1;
|
||||||
}
|
}
|
||||||
ClearStatus();
|
ClearStatus();
|
||||||
|
|
||||||
// import sub directories
|
DeleteOrphanedDirectories(ImportPath);
|
||||||
foreach (string importDir in importContents_Directories) {
|
|
||||||
Classes.ImportGames importGames = new Classes.ImportGames(importDir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
||||||
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||||
}
|
|
||||||
|
|
||||||
public class ImportGame : QueueItemStatus
|
|
||||||
{
|
|
||||||
public static void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
@@ -443,7 +436,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OrganiseLibrary()
|
public void OrganiseLibrary()
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Organise Library", "Starting default library organisation");
|
Logging.Log(Logging.LogType.Information, "Organise Library", "Starting default library organisation");
|
||||||
|
|
||||||
@@ -477,8 +470,12 @@ namespace gaseous_server.Classes
|
|||||||
foreach (var directory in Directory.GetDirectories(startLocation))
|
foreach (var directory in Directory.GetDirectories(startLocation))
|
||||||
{
|
{
|
||||||
DeleteOrphanedDirectories(directory);
|
DeleteOrphanedDirectories(directory);
|
||||||
if (Directory.GetFiles(directory).Length == 0 &&
|
|
||||||
Directory.GetDirectories(directory).Length == 0)
|
string[] files = Directory.GetFiles(directory);
|
||||||
|
string[] directories = Directory.GetDirectories(directory);
|
||||||
|
|
||||||
|
if (files.Length == 0 &&
|
||||||
|
directories.Length == 0)
|
||||||
{
|
{
|
||||||
Directory.Delete(directory, false);
|
Directory.Delete(directory, false);
|
||||||
}
|
}
|
||||||
@@ -621,16 +618,16 @@ namespace gaseous_server.Classes
|
|||||||
if (romFound == false)
|
if (romFound == false)
|
||||||
{
|
{
|
||||||
// file is not in database - process it
|
// file is not in database - process it
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Orphaned file found in library: " + LibraryFile);
|
||||||
|
|
||||||
Common.hashObject hash = new Common.hashObject(LibraryFile);
|
Common.hashObject hash = new Common.hashObject(LibraryFile);
|
||||||
FileInfo fi = new FileInfo(LibraryFile);
|
FileInfo fi = new FileInfo(LibraryFile);
|
||||||
|
|
||||||
gaseous_server.Models.Signatures_Games sig = GetFileSignature(hash, fi, LibraryFile);
|
gaseous_server.Models.Signatures_Games sig = GetFileSignature(hash, fi, LibraryFile);
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Orphaned file found in library: " + LibraryFile);
|
|
||||||
|
|
||||||
// get discovered platform
|
// get discovered platform
|
||||||
IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(sig.Flags.IGDBPlatformId);
|
IGDB.Models.Platform determinedPlatform = Metadata.Platforms.GetPlatform(sig.Flags.IGDBPlatformId);
|
||||||
|
|
||||||
IGDB.Models.Game determinedGame = new Game();
|
IGDB.Models.Game determinedGame = new Game();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -687,8 +684,13 @@ 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");
|
||||||
MoveGameFile(romId);
|
MoveGameFile(romId);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Library Scan", "ROM at path " + romPath + " found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
@@ -422,6 +423,56 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
return returnPath;
|
return returnPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T? GetSearchCache<T>(string SearchFields, string SearchString)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM SearchCache WHERE SearchFields = @searchfields AND SearchString = @searchstring;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "searchfields", SearchFields },
|
||||||
|
{ "searchstring", SearchString }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
if (data.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
// cache hit
|
||||||
|
string rawString = data.Rows[0]["Content"].ToString();
|
||||||
|
T ReturnValue = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(rawString);
|
||||||
|
if (ReturnValue != null)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Found search result in cache. Search string: " + SearchString);
|
||||||
|
return ReturnValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Search result not found in cache.");
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Search result not found in cache.");
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetSearchCache<T>(string SearchFields, string SearchString, T SearchResult)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Search Cache", "Storing search results in cache. Search string: " + SearchString);
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "INSERT INTO SearchCache (SearchFields, SearchString, Content, LastSearch) VALUES (@searchfields, @searchstring, @content, @lastsearch);";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "searchfields", SearchFields },
|
||||||
|
{ "searchstring", SearchString },
|
||||||
|
{ "content", Newtonsoft.Json.JsonConvert.SerializeObject(SearchResult) },
|
||||||
|
{ "lastsearch", DateTime.UtcNow }
|
||||||
|
};
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See https://api-docs.igdb.com/?javascript#images for more information about the image url structure
|
/// See https://api-docs.igdb.com/?javascript#images for more information about the image url structure
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -477,16 +477,26 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check search cache
|
||||||
|
List<Game>? games = Communications.GetSearchCache<List<Game>>(searchFields, searchBody);
|
||||||
|
|
||||||
// get Game metadata
|
if (games == null)
|
||||||
Communications comms = new Communications();
|
{
|
||||||
Game[]? results = new Game[0];
|
// cache miss
|
||||||
if (allowSearch == true)
|
// get Game metadata
|
||||||
{
|
Communications comms = new Communications();
|
||||||
results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
Game[]? results = new Game[0];
|
||||||
|
if (allowSearch == true)
|
||||||
|
{
|
||||||
|
results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return games.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SearchType
|
public enum SearchType
|
||||||
|
@@ -77,7 +77,8 @@ namespace gaseous_server.Controllers
|
|||||||
// Process uploaded files
|
// Process uploaded files
|
||||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
||||||
{
|
{
|
||||||
Classes.ImportGame.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
Classes.ImportGame uploadImport = new ImportGame();
|
||||||
|
uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(workPath))
|
if (Directory.Exists(workPath))
|
||||||
|
@@ -1,13 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NuGet.Common;
|
||||||
using static gaseous_server.Classes.Metadata.Games;
|
using static gaseous_server.Classes.Metadata.Games;
|
||||||
|
|
||||||
|
|
||||||
@@ -37,36 +40,88 @@ namespace gaseous_server.Controllers
|
|||||||
string searchFields = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
|
string searchFields = "fields abbreviation,alternative_name,category,checksum,created_at,generation,name,platform_family,platform_logo,slug,summary,updated_at,url,versions,websites; ";
|
||||||
searchBody += "where name ~ *\"" + SearchString + "\"*;";
|
searchBody += "where name ~ *\"" + SearchString + "\"*;";
|
||||||
|
|
||||||
// get Platform metadata
|
List<Platform>? searchCache = Communications.GetSearchCache<List<Platform>>(searchFields, searchBody);
|
||||||
Communications comms = new Communications();
|
|
||||||
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, searchFields, searchBody);
|
|
||||||
|
|
||||||
return results.ToList();
|
if (searchCache == null)
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
// get Platform metadata from data source
|
||||||
|
Communications comms = new Communications();
|
||||||
|
var results = await comms.APIComm<Platform>(IGDBClient.Endpoints.Platforms, searchFields, searchBody);
|
||||||
|
|
||||||
|
Communications.SetSearchCache<List<Platform>>(searchFields, searchBody, results.ToList());
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return searchCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Game")]
|
[Route("Game")]
|
||||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<GaseousGame>), StatusCodes.Status200OK)]
|
||||||
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
|
public async Task<ActionResult> SearchGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
List<Game> RetVal = await _SearchForGame(PlatformId, SearchString);
|
List<GaseousGame> RetVal = await _SearchForGame(PlatformId, SearchString);
|
||||||
return Ok(RetVal);
|
return Ok(RetVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<List<Game>> _SearchForGame(long PlatformId, string SearchString)
|
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
string searchBody = "";
|
string searchBody = "";
|
||||||
string searchFields = "fields cover.*,first_release_date,name,platforms,slug; ";
|
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||||
searchBody += "search \"" + SearchString + "\";";
|
searchBody += "search \"" + SearchString + "\";";
|
||||||
searchBody += "where platforms = (" + PlatformId + ");";
|
searchBody += "where platforms = (" + PlatformId + ");";
|
||||||
|
|
||||||
// get Platform metadata
|
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
||||||
Communications comms = new Communications();
|
|
||||||
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
|
||||||
|
|
||||||
return results.ToList();
|
if (searchCache == null)
|
||||||
|
{
|
||||||
|
// cache miss
|
||||||
|
// get Game metadata from data source
|
||||||
|
Communications comms = new Communications();
|
||||||
|
var results = await comms.APIComm<Game>(IGDBClient.Endpoints.Games, searchFields, searchBody);
|
||||||
|
|
||||||
|
List<GaseousGame> games = new List<GaseousGame>();
|
||||||
|
foreach (Game game in results.ToList())
|
||||||
|
{
|
||||||
|
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
||||||
|
switch(cacheStatus)
|
||||||
|
{
|
||||||
|
case Storage.CacheStatus.NotPresent:
|
||||||
|
Storage.NewCacheValue(game, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Storage.CacheStatus.Expired:
|
||||||
|
Storage.NewCacheValue(game, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
games.Add(new GaseousGame(game));
|
||||||
|
}
|
||||||
|
|
||||||
|
Communications.SetSearchCache<List<GaseousGame>>(searchFields, searchBody, games);
|
||||||
|
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get full version of results from database
|
||||||
|
// this is a hacky workaround due to the readonly nature of IGDB.Model.Game IdentityOrValue fields
|
||||||
|
List<GaseousGame> gamesToReturn = new List<GaseousGame>();
|
||||||
|
foreach (GaseousGame game in searchCache)
|
||||||
|
{
|
||||||
|
Game tempGame = Games.GetGame((long)game.Id, false, false, false);
|
||||||
|
gamesToReturn.Add(new GaseousGame(tempGame));
|
||||||
|
}
|
||||||
|
|
||||||
|
return gamesToReturn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using IGDB;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
namespace gaseous_server.Models
|
namespace gaseous_server.Models
|
||||||
{
|
{
|
||||||
|
@@ -144,10 +144,11 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.TitleIngestor:
|
case QueueItemType.TitleIngestor:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Title Ingestor");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Title Ingestor");
|
||||||
Classes.ImportGames importGames = new Classes.ImportGames(Config.LibraryConfiguration.LibraryImportDirectory)
|
Classes.ImportGame import = new ImportGame
|
||||||
{
|
{
|
||||||
CallingQueueItem = this
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
|
import.ProcessDirectory(Config.LibraryConfiguration.LibraryImportDirectory);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
Classes.ImportGame.DeleteOrphanedDirectories(Config.LibraryConfiguration.LibraryImportDirectory);
|
Classes.ImportGame.DeleteOrphanedDirectories(Config.LibraryConfiguration.LibraryImportDirectory);
|
||||||
@@ -170,7 +171,11 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.OrganiseLibrary:
|
case QueueItemType.OrganiseLibrary:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Organiser");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Organiser");
|
||||||
Classes.ImportGame.OrganiseLibrary();
|
Classes.ImportGame importLibraryOrg = new ImportGame
|
||||||
|
{
|
||||||
|
CallingQueueItem = this
|
||||||
|
};
|
||||||
|
importLibraryOrg.OrganiseLibrary();
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
@@ -178,11 +183,11 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.LibraryScan:
|
case QueueItemType.LibraryScan:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Scanners");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Library Scanners");
|
||||||
Classes.ImportGame import = new ImportGame
|
Classes.ImportGame libScan = new ImportGame
|
||||||
{
|
{
|
||||||
CallingQueueItem = this
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
import.LibraryScan();
|
libScan.LibraryScan();
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
|
5
gaseous-server/Support/Database/MySQL/gaseous-1012.sql
Normal file
5
gaseous-server/Support/Database/MySQL/gaseous-1012.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE `Games_Roms`
|
||||||
|
ADD INDEX `id_IdAndLibraryId` (`Id` ASC, `LibraryId` ASC) VISIBLE;
|
||||||
|
|
||||||
|
ALTER TABLE `ServerLogs`
|
||||||
|
ADD INDEX `idx_EventDate` (`EventTime` ASC) VISIBLE;
|
9
gaseous-server/Support/Database/MySQL/gaseous-1013.sql
Normal file
9
gaseous-server/Support/Database/MySQL/gaseous-1013.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE `SearchCache` (
|
||||||
|
`SearchFields` varchar(384) NOT NULL,
|
||||||
|
`SearchString` varchar(128) NOT NULL,
|
||||||
|
`Content` longtext DEFAULT NULL,
|
||||||
|
`LastSearch` datetime DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`SearchFields`,`SearchString`),
|
||||||
|
KEY `idx_SearchString` (`SearchFields`,`SearchString`),
|
||||||
|
KEY `idx_LastSearch` (`LastSearch`)
|
||||||
|
);
|
@@ -56,6 +56,8 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1009.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1009.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1010.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1010.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1011.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1011.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1012.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1013.sql" />
|
||||||
<None Remove="Classes\Metadata\" />
|
<None Remove="Classes\Metadata\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -89,5 +91,7 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1009.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1009.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1010.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1010.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1011.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1011.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1012.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1013.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<div id="properties_toc">
|
<div id="properties_toc">
|
||||||
<div id="properties_toc_general" name="properties_toc_item" onclick="SelectTab('general');">General</div>
|
<div id="properties_toc_general" name="properties_toc_item" onclick="SelectTab('general');">General</div>
|
||||||
<div id="properties_toc_attributes" name="properties_toc_item" onclick="SelectTab('attributes');">Attributes</div>
|
<div id="properties_toc_archive" name="properties_toc_item" onclick="SelectTab('archive');" style="display: none;">Archive Contents</div>
|
||||||
|
<div id="properties_toc_attributes" name="properties_toc_item" onclick="SelectTab('attributes');" style="display: none;">Attributes</div>
|
||||||
<div id="properties_toc_match" name="properties_toc_item" onclick="SelectTab('match');">Title Match</div>
|
<div id="properties_toc_match" name="properties_toc_item" onclick="SelectTab('match');">Title Match</div>
|
||||||
<!--<div id="properties_toc_manage" name="properties_toc_item" onclick="SelectTab('manage');">Manage</div>-->
|
<!--<div id="properties_toc_manage" name="properties_toc_item" onclick="SelectTab('manage');">Manage</div>-->
|
||||||
</div>
|
</div>
|
||||||
@@ -53,6 +54,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="properties_bodypanel_archive" name="properties_tab" style="display: none;">
|
||||||
|
<div id="properties_bodypanel_archive_content" style="height: 315px; overflow-x: scroll;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="properties_bodypanel_attributes" name="properties_tab" style="display: none;">
|
<div id="properties_bodypanel_attributes" name="properties_tab" style="display: none;">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -120,7 +125,6 @@
|
|||||||
|
|
||||||
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables, 'GET', function (result) {
|
ajaxCall('/api/v1.1/Games/' + gameId + '/roms/' + modalVariables, 'GET', function (result) {
|
||||||
romData = result;
|
romData = result;
|
||||||
console.log(romData);
|
|
||||||
document.getElementById('modal-heading').innerHTML = result.name;
|
document.getElementById('modal-heading').innerHTML = result.name;
|
||||||
document.getElementById('rominfo_library').innerHTML = result.library.name;
|
document.getElementById('rominfo_library').innerHTML = result.library.name;
|
||||||
document.getElementById('rominfo_platform').innerHTML = result.platform;
|
document.getElementById('rominfo_platform').innerHTML = result.platform;
|
||||||
@@ -142,8 +146,7 @@
|
|||||||
|
|
||||||
if (result.attributes.length > 0) {
|
if (result.attributes.length > 0) {
|
||||||
document.getElementById('properties_bodypanel_attributes').appendChild(BuildAttributesTable(result.attributes, result.source));
|
document.getElementById('properties_bodypanel_attributes').appendChild(BuildAttributesTable(result.attributes, result.source));
|
||||||
} else {
|
document.getElementById('properties_bodypanel_archive_content').appendChild(BuildArchiveTable(result.attributes, result.source));
|
||||||
document.getElementById('properties_toc_attributes').style.display = 'none';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -199,12 +202,9 @@
|
|||||||
|
|
||||||
$('#properties_fixplatform').on('select2:select', function (e) {
|
$('#properties_fixplatform').on('select2:select', function (e) {
|
||||||
var platformData = e.params.data;
|
var platformData = e.params.data;
|
||||||
console.log(platformData);
|
|
||||||
|
|
||||||
var gameValue = $('#properties_fixgame').select2('data');
|
var gameValue = $('#properties_fixgame').select2('data');
|
||||||
if (gameValue) {
|
if (gameValue) {
|
||||||
console.log(gameValue[0]);
|
|
||||||
|
|
||||||
setFixGameDropDown();
|
setFixGameDropDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -264,23 +264,75 @@
|
|||||||
aTable.style.width = '100%';
|
aTable.style.width = '100%';
|
||||||
|
|
||||||
for (var i = 0; i < attributes.length; i++) {
|
for (var i = 0; i < attributes.length; i++) {
|
||||||
var aRow = document.createElement('tr');
|
if (attributes[i].key != "ZipContents") {
|
||||||
|
// show attributes button
|
||||||
|
document.getElementById('properties_toc_attributes').style.display = '';
|
||||||
|
var aRow = document.createElement('tr');
|
||||||
|
|
||||||
var aTitleCell = document.createElement('th');
|
var aTitleCell = document.createElement('th');
|
||||||
aTitleCell.width = "25%";
|
aTitleCell.width = "25%";
|
||||||
if (sourceName == "TOSEC") {
|
if (sourceName == "TOSEC") {
|
||||||
aTitleCell.innerHTML = ConvertTOSECAttributeName(attributes[i].key);
|
aTitleCell.innerHTML = ConvertTOSECAttributeName(attributes[i].key);
|
||||||
} else {
|
} else {
|
||||||
aTitleCell.innerHTML = attributes[i].key;
|
aTitleCell.innerHTML = attributes[i].key;
|
||||||
|
}
|
||||||
|
aRow.appendChild(aTitleCell);
|
||||||
|
|
||||||
|
var aValueCell = document.createElement('td');
|
||||||
|
aValueCell.width = "75%";
|
||||||
|
aValueCell.innerHTML = attributes[i].value;
|
||||||
|
aRow.appendChild(aValueCell);
|
||||||
|
|
||||||
|
aTable.appendChild(aRow);
|
||||||
}
|
}
|
||||||
aRow.appendChild(aTitleCell);
|
}
|
||||||
|
|
||||||
var aValueCell = document.createElement('td');
|
return aTable;
|
||||||
aValueCell.width = "75%";
|
}
|
||||||
aValueCell.innerHTML = attributes[i].value;
|
|
||||||
aRow.appendChild(aValueCell);
|
|
||||||
|
|
||||||
aTable.appendChild(aRow);
|
function BuildArchiveTable(attributes, sourceName) {
|
||||||
|
for (var i = 0; i < attributes.length; i++) {
|
||||||
|
if (attributes[i].key == "ZipContents") {
|
||||||
|
var archiveContent = JSON.parse(attributes[i].value);
|
||||||
|
|
||||||
|
// show archive button
|
||||||
|
document.getElementById('properties_toc_archive').style.display = '';
|
||||||
|
|
||||||
|
var aTable = document.createElement('table');
|
||||||
|
aTable.className = 'romtable';
|
||||||
|
aTable.setAttribute('cellspacing', 0);
|
||||||
|
aTable.style.width = '100%';
|
||||||
|
|
||||||
|
for (var r = 0; r < archiveContent.length; r++) {
|
||||||
|
var aBody = document.createElement('tbody');
|
||||||
|
aBody.className = 'romrow';
|
||||||
|
|
||||||
|
var aRow = document.createElement('tr');
|
||||||
|
|
||||||
|
var aNameCell = document.createElement('th');
|
||||||
|
aNameCell.className = 'romcell';
|
||||||
|
aNameCell.innerHTML = archiveContent[r].FilePath + '/' + archiveContent[r].FileName;
|
||||||
|
aRow.appendChild(aNameCell);
|
||||||
|
|
||||||
|
var aSizeCell = document.createElement('td');
|
||||||
|
aSizeCell.className = 'romcell';
|
||||||
|
aSizeCell.innerHTML = formatBytes(archiveContent[r].Size);
|
||||||
|
aRow.appendChild(aSizeCell);
|
||||||
|
|
||||||
|
aBody.appendChild(aRow);
|
||||||
|
|
||||||
|
var hRow = document.createElement('tr');
|
||||||
|
|
||||||
|
var aHashCell = document.createElement('td');
|
||||||
|
aHashCell.setAttribute('colspan', 2);
|
||||||
|
aHashCell.style.paddingLeft = '20px';
|
||||||
|
aHashCell.innerHTML = "MD5: " + archiveContent[r].MD5 + "<br />SHA1: " + archiveContent[r].SHA1;
|
||||||
|
hRow.appendChild(aHashCell);
|
||||||
|
aBody.appendChild(hRow);
|
||||||
|
|
||||||
|
aTable.appendChild(aBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return aTable;
|
return aTable;
|
||||||
|
@@ -245,8 +245,6 @@ function intToRGB(i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DropDownRenderGameOption(state) {
|
function DropDownRenderGameOption(state) {
|
||||||
console.log(state);
|
|
||||||
|
|
||||||
if (state.loading) {
|
if (state.loading) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -260,7 +258,7 @@ function DropDownRenderGameOption(state) {
|
|||||||
|
|
||||||
if (state.cover) {
|
if (state.cover) {
|
||||||
response = $(
|
response = $(
|
||||||
'<table class="dropdown-div"><tr><td class="dropdown-cover"><img src="/api/v1.1/Games/' + state.id + '/cover/image/cover_small/' + state.cover.value.imageId + '.jpg" /></td><td class="dropdown-label"><span class="dropdown-title">' + state.text + '</span><span class="dropdown-releasedate">' + releaseDate + '</span></td></tr></table>'
|
'<table class="dropdown-div"><tr><td class="dropdown-cover"><img src="/api/v1.1/Games/' + state.id + '/cover/image/cover_small/' + state.cover.imageId + '.jpg" /></td><td class="dropdown-label"><span class="dropdown-title">' + state.text + '</span><span class="dropdown-releasedate">' + releaseDate + '</span></td></tr></table>'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
response = $(
|
response = $(
|
||||||
|
Reference in New Issue
Block a user