private void Extract(IExtractable item, ExtractCounter counter) { try { switch (item.GetContentType()) { case 0: if (SaveImage(item)) { counter.Extracted++; } break; case 1: if (writeModelFileFunc != null && SaveModel(item)) { counter.Extracted++; } break; case 2: if (writeSoundFileFunc != null && SaveSound(item)) { counter.Extracted++; } break; } } catch (Exception e) { LogError($"Error extracting {item.DisplayName}", e); counter.Errors++; } }
private async Task ProcessQueueAsync() { isBusy = true; try { var nextWorkerId = 0; var locker = new KeyedSemaphore(); var counter = new ExtractCounter(); var start = DateTime.Now; //note that multiple workers can result in the working status (status bar text) //being inaccurate - each tag will only set the status once so if a slow tag //sets the status and a fast tag replaces it then the status will not update //back to the slow tag after the fast one finishes. Func <Task> process = async() => { var prefix = Settings.BatchWorkerCount > 1 ? $"[Worker {nextWorkerId++}] " : string.Empty; while (extractionQueue.Count > 0) { if (tokenSource.IsCancellationRequested) { break; } IExtractable item; if (!extractionQueue.TryDequeue(out item)) { break; } using (await locker.WaitAsync(item.ItemKey)) { SetWorkingStatus($"{prefix}Extracting {item.DisplayName}"); Extract(item, counter); } } }; var processors = Enumerable.Range(0, Settings.BatchWorkerCount).Select(i => Task.Run(process)).ToList(); await Task.WhenAll(processors); var span = DateTime.Now - start; LogOutput($"Extracted {counter.Extracted} tags in {Math.Round(span.TotalSeconds)} seconds with {counter.Errors} errors."); } catch (Exception ex) { Substrate.LogError("Error during batch extraction", ex); } finally { tokenSource.Dispose(); tokenSource = null; } isBusy = false; ClearWorkingStatus(); }