diff --git a/gaseous-server/Classes/GameLibrary.cs b/gaseous-server/Classes/GameLibrary.cs index 0b57b85..b30ea46 100644 --- a/gaseous-server/Classes/GameLibrary.cs +++ b/gaseous-server/Classes/GameLibrary.cs @@ -175,6 +175,24 @@ namespace gaseous_server } } + public static LibraryItem ScanLibrary(int LibraryId) + { + // add the library to scan to the queue + LibraryItem library = GetLibrary(LibraryId); + ImportGame.LibrariesToScan.Add(library); + + // start the library scan if it's not already running + foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems) + { + if (item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState != ProcessQueue.QueueItemState.Running) + { + item.ForceExecute(); + } + } + + return library; + } + public class LibraryItem { public LibraryItem(int Id, string Name, string Path, long DefaultPlatformId, bool IsDefaultLibrary) diff --git a/gaseous-server/Classes/ImportGames.cs b/gaseous-server/Classes/ImportGames.cs index dd0dcfc..d0fa5a3 100644 --- a/gaseous-server/Classes/ImportGames.cs +++ b/gaseous-server/Classes/ImportGames.cs @@ -523,61 +523,82 @@ namespace gaseous_server.Classes } } - public void LibraryScan(GameLibrary.LibraryItem? singleLibrary = null) + public static List LibrariesToScan = new List(); + public void LibraryScan() { int maxWorkers = Config.MetadataConfiguration.MaxLibraryScanWorkers; - List libraries = new List(); - if (singleLibrary == null) + if (LibrariesToScan.Count == 0) { - libraries.AddRange(GameLibrary.GetLibraries); - } - else - { - libraries.Add(singleLibrary); + LibrariesToScan.AddRange(GameLibrary.GetLibraries); } // setup background tasks for each library - foreach (GameLibrary.LibraryItem library in libraries) + do { - Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name); - ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem( - ProcessQueue.QueueItemType.LibraryScanWorker, - 1, - new List - { - ProcessQueue.QueueItemType.OrganiseLibrary, - ProcessQueue.QueueItemType.Rematcher - }, - false, - true); - queue.Options = library; - queue.ForceExecute(); + Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan queue size: " + LibrariesToScan.Count); - ProcessQueue.QueueItems.Add(queue); + GameLibrary.LibraryItem library = LibrariesToScan[0]; + LibrariesToScan.RemoveAt(0); - // check number of running tasks is less than maxWorkers - bool allowContinue; - do + // check if library is already being scanned + bool libraryAlreadyScanning = false; + List ProcessQueueItems = new List(); + ProcessQueueItems.AddRange(ProcessQueue.QueueItems); + foreach (ProcessQueue.QueueItem item in ProcessQueueItems) { - allowContinue = true; - int currentWorkerCount = 0; - List queueItems = new List(); - queueItems.AddRange(ProcessQueue.QueueItems); - foreach (ProcessQueue.QueueItem item in queueItems) + if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker) { - if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker) + if (((GameLibrary.LibraryItem)item.Options).Id == library.Id) { - currentWorkerCount += 1; + libraryAlreadyScanning = true; } } - if (currentWorkerCount >= maxWorkers) + } + + if (libraryAlreadyScanning == false) + { + Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name); + ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem( + ProcessQueue.QueueItemType.LibraryScanWorker, + 1, + new List + { + ProcessQueue.QueueItemType.OrganiseLibrary, + ProcessQueue.QueueItemType.Rematcher + }, + false, + true) { - allowContinue = false; - Thread.Sleep(60000); - } - } while (allowContinue == false); - } + Options = library + }; + queue.ForceExecute(); + + ProcessQueue.QueueItems.Add(queue); + + // check number of running tasks is less than maxWorkers + bool allowContinue; + do + { + allowContinue = true; + int currentWorkerCount = 0; + List LibraryScan_QueueItems = new List(); + LibraryScan_QueueItems.AddRange(ProcessQueue.QueueItems); + foreach (ProcessQueue.QueueItem item in LibraryScan_QueueItems) + { + if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker) + { + currentWorkerCount += 1; + } + } + if (currentWorkerCount >= maxWorkers) + { + allowContinue = false; + Thread.Sleep(60000); + } + } while (allowContinue == false); + } + } while (LibrariesToScan.Count > 0); bool WorkersStillWorking; do @@ -597,6 +618,12 @@ namespace gaseous_server.Classes } while (WorkersStillWorking == true); Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan complete. All workers stopped"); + + if (LibrariesToScan.Count > 0) + { + Logging.Log(Logging.LogType.Information, "Library Scan", "There are still libraries to scan. Restarting scan process"); + LibraryScan(); + } } public void LibrarySpecificScan(GameLibrary.LibraryItem library) diff --git a/gaseous-server/Controllers/V1.0/LibraryController.cs b/gaseous-server/Controllers/V1.0/LibraryController.cs index 59211f1..a0ece29 100644 --- a/gaseous-server/Controllers/V1.0/LibraryController.cs +++ b/gaseous-server/Controllers/V1.0/LibraryController.cs @@ -86,5 +86,24 @@ namespace gaseous_server.Controllers return NotFound(exLNF.ToString()); } } + + [MapToApiVersion("1.0")] + [MapToApiVersion("1.1")] + [HttpPost("{LibraryId}/Scan")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult ScanLibrary(int LibraryId) + { + try + { + GameLibrary.ScanLibrary(LibraryId); + return Ok(); + } + catch (GameLibrary.LibraryNotFound exLNF) + { + return NotFound(exLNF.ToString()); + } + } } } \ No newline at end of file diff --git a/gaseous-server/Support/PlatformMap.json b/gaseous-server/Support/PlatformMap.json index 9e8e4d0..d26a78b 100644 --- a/gaseous-server/Support/PlatformMap.json +++ b/gaseous-server/Support/PlatformMap.json @@ -335,7 +335,14 @@ "Extensions": { "SupportedFileExtensions": [ ".CPC", - ".DSK" + ".DSK", + ".SNA", + ".TAP", + ".CDT", + ".VOC", + ".M3U", + ".CPR", + ".ZIP" ], "UniqueFileExtensions": [ ".CPC" @@ -343,9 +350,25 @@ }, "RetroPieDirectoryName": "amstradcpc", "WebEmulator": { - "Type": "", - "Core": "", - "AvailableWebEmulators": [] + "Type": "EmulatorJS", + "Core": "crocods", + "AvailableWebEmulators": [ + { + "EmulatorType": "EmulatorJS", + "AvailableWebEmulatorCores": [ + { + "Core": "crocods", + "AlternateCoreName": "", + "Default": true + }, + { + "Core": "cap32", + "AlternateCoreName": "", + "Default": false + } + ] + } + ] }, "Bios": [] }, @@ -3442,14 +3465,35 @@ "SFC" ], "Extensions": { - "SupportedFileExtensions": [], + "SupportedFileExtensions": [ + ".7Z", + ".BIN", + ".BS", + ".FIG", + ".MGD", + ".SFC", + ".SMC", + ".SWC", + ".ZIP" + ], "UniqueFileExtensions": [] }, - "RetroPieDirectoryName": "", + "RetroPieDirectoryName": "snes", "WebEmulator": { - "Type": "", - "Core": "", - "AvailableWebEmulators": null + "Type": "EmulatorJS", + "Core": "snes", + "AvailableWebEmulators": [ + { + "EmulatorType": "EmulatorJS", + "AvailableWebEmulatorCores": [ + { + "Core": "snes", + "AlternateCoreName": "snes9x", + "Default": true + } + ] + } + ] }, "Bios": [] }, diff --git a/gaseous-server/wwwroot/pages/settings/libraries.js b/gaseous-server/wwwroot/pages/settings/libraries.js index f71d868..4c950f9 100644 --- a/gaseous-server/wwwroot/pages/settings/libraries.js +++ b/gaseous-server/wwwroot/pages/settings/libraries.js @@ -12,7 +12,7 @@ function drawLibrary() { function (result) { let newTable = document.getElementById('settings_libraries'); newTable.innerHTML = ''; - newTable.appendChild(createTableRow(true, ['Name', 'Path', 'Default Platform', 'Default Library', ''])); + newTable.appendChild(createTableRow(true, ['Name', 'Path', 'Default Platform', 'Default Library', '', ''])); for (let i = 0; i < result.length; i++) { let platformName = ''; @@ -36,6 +36,35 @@ function drawLibrary() { let controls = document.createElement('div'); controls.style.textAlign = 'right'; + let scanButton = document.createElement('img'); + scanButton.id = 'startProcess'; + scanButton.className = 'taskstart'; + scanButton.src = '/images/start-task.svg'; + scanButton.title = 'Start Scan'; + scanButton.addEventListener('click', function () { + let scanLibrary = new MessageBox('Scan Library', 'Are you sure you want to scan this library?'); + scanLibrary.addButton(new ModalButton('OK', 2, scanLibrary, function (callingObject) { + ajaxCall( + '/api/v1.1/Library/' + result[i].id + '/Scan', + 'POST', + function () { + callingObject.msgDialog.close(); + drawLibrary(); + }, + function () { + callingObject.msgDialog.close(); + drawLibrary(); + } + ); + })); + + scanLibrary.addButton(new ModalButton('Cancel', 0, scanLibrary, function (callingObject) { + callingObject.msgDialog.close(); + })); + + scanLibrary.open(); + }); + let deleteButton = ''; if (result[i].isDefaultLibrary == false) { deleteButton = document.createElement('a'); @@ -80,6 +109,7 @@ function drawLibrary() { result[i].path, platformName, defaultLibrary, + scanButton, controls ], 'romrow',