From 92ffab98e1b7971db1fdd5f2f979b44fad274880 Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Sun, 13 Feb 2022 10:24:58 +0000 Subject: [PATCH 01/19] Small fixes --- Damselfly.Core/ScopedServices/SearchService.cs | 3 +++ Damselfly.Core/Services/ExifService.cs | 11 +++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Damselfly.Core/ScopedServices/SearchService.cs b/Damselfly.Core/ScopedServices/SearchService.cs index 66aa7de5..2da5108b 100644 --- a/Damselfly.Core/ScopedServices/SearchService.cs +++ b/Damselfly.Core/ScopedServices/SearchService.cs @@ -395,6 +395,9 @@ public string SearchBreadcrumbs if (Person != null) hints.Add($"Person: {Person.Name}"); + if (MinRating != null) + hints.Add($"Rating: at least {MinRating} stars"); + if (SimilarTo != null) hints.Add($"Looks Like: {SimilarTo.FileName}"); diff --git a/Damselfly.Core/Services/ExifService.cs b/Damselfly.Core/Services/ExifService.cs index a8f661c0..ead7d355 100644 --- a/Damselfly.Core/Services/ExifService.cs +++ b/Damselfly.Core/Services/ExifService.cs @@ -112,7 +112,11 @@ public async Task UpdateTagsAsync(Image image, List addTags, List public async Task UpdateFaceDataAsync(Image[] images, List faces, AppIdentityUser user = null) { - // TODO: Split tags with commas here? +#if ! DEBUG + // Not supported yet.... + return; +# endif + var timestamp = DateTime.UtcNow; var changeDesc = string.Empty; @@ -359,7 +363,6 @@ private async Task ProcessExifOperations(int imageId, List } else if (op.Type == ExifOperation.ExifType.Face) { -#if DEBUG var imageObject = JsonSerializer.Deserialize(op.Text); // Face tags using MGW standard @@ -383,10 +386,6 @@ private async Task ProcessExifOperations(int imageId, List processedOps.Add(op); needExecuteExifTool = true; -#else - op.State = ExifOperation.FileWriteState.Failed; - Logging.Log("Writing Face EXIF data is not supported at this time."); -#endif } } From 214807290176bc05a4dbd044edfea472f855ea63 Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Sun, 13 Feb 2022 14:05:05 +0000 Subject: [PATCH 02/19] Fix endless writing metadata --- Damselfly.Core/Services/ExifService.cs | 78 ++++++++++++-------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/Damselfly.Core/Services/ExifService.cs b/Damselfly.Core/Services/ExifService.cs index ead7d355..53a805c0 100644 --- a/Damselfly.Core/Services/ExifService.cs +++ b/Damselfly.Core/Services/ExifService.cs @@ -296,8 +296,7 @@ private async Task ProcessExifOperations(int imageId, List Logging.LogVerbose("Updating tags for file {0}", image.FullPath); string args = string.Empty; - List processedOps = new List(); - bool needExecuteExifTool = false; + List opsToProcess = new List(); foreach (var op in exifOperations) { @@ -325,41 +324,35 @@ private async Task ProcessExifOperations(int imageId, List if (op.Operation == ExifOperation.OperationType.Remove) { Logging.LogVerbose($" Removing keyword {operationText} from {op.Image.FileName}"); - processedOps.Add(op); + opsToProcess.Add(op); } else if (op.Operation == ExifOperation.OperationType.Add) { Logging.LogVerbose($" Adding keyword '{operationText}' to {op.Image.FileName}"); args += $" -keywords+=\"{operationText}\" "; - processedOps.Add(op); + opsToProcess.Add(op); } - - needExecuteExifTool = true; } else if( op.Type == ExifOperation.ExifType.Caption ) { args += $" -iptc:Caption-Abstract=\"{op.Text}\""; - processedOps.Add(op); - needExecuteExifTool = true; + opsToProcess.Add(op); } else if (op.Type == ExifOperation.ExifType.Description) { args += $" -Exif:ImageDescription=\"{op.Text}\""; - processedOps.Add(op); - needExecuteExifTool = true; + opsToProcess.Add(op); } else if (op.Type == ExifOperation.ExifType.Copyright) { args += $" -Copyright=\"{op.Text}\""; args += $" -iptc:CopyrightNotice=\"{op.Text}\""; - processedOps.Add(op); - needExecuteExifTool = true; + opsToProcess.Add(op); } else if (op.Type == ExifOperation.ExifType.Rating) { args += $" -exif:Rating=\"{op.Text}\""; - processedOps.Add(op); - needExecuteExifTool = true; + opsToProcess.Add(op); } else if (op.Type == ExifOperation.ExifType.Face) { @@ -370,28 +363,31 @@ private async Task ProcessExifOperations(int imageId, List // -xmp-mwg-rs:RegionAreaX=0.319270833 -xmp-mwg-rs:RegionAreaY=0.21015625 -xmp-mwg-rs:RegionAreaW=0.165104167 -xmp-mwg-rs:RegionAreaH=0.30390625 // -xmp-mwg-rs:RegionName=John -xmp-mwg-rs:RegionRotation=0 -xmp-mwg-rs:RegionType="Face" myfile.xmp - // TODO: How to add multiple faces? - args += $" -xmp-mwg-rs:RegionType=\"Face\""; - args += $" -xmp-mwg-rs:RegionAppliedToDimensionsUnit=\"pixel\""; - args += $" -xmp-mwg-rs:RegionAppliedToDimensionsH=4000"; - args += $" -xmp-mwg-rs:RegionAppliedToDimensionsW=6000"; - args += $" -xmp-mwg-rs:RegionAreaX=0.319270833 -xmp-mwg-rs:RegionAreaY=0.21015625"; - args += $" -xmp-mwg-rs:RegionAreaW=0.165104167 -xmp-mwg-rs:RegionAreaH=0.30390625"; - args += $" -xmp-mwg-rs:RegionRotation=0"; - - if (imageObject.Person != null) + if (System.Diagnostics.Debugger.IsAttached) { - args += $" -xmp-mwg-rs:RegionName={imageObject.Person.Name}"; - } + // TODO: How to add multiple faces? + args += $" -xmp-mwg-rs:RegionType=\"Face\""; + args += $" -xmp-mwg-rs:RegionAppliedToDimensionsUnit=\"pixel\""; + args += $" -xmp-mwg-rs:RegionAppliedToDimensionsH=4000"; + args += $" -xmp-mwg-rs:RegionAppliedToDimensionsW=6000"; + args += $" -xmp-mwg-rs:RegionAreaX=0.319270833 -xmp-mwg-rs:RegionAreaY=0.21015625"; + args += $" -xmp-mwg-rs:RegionAreaW=0.165104167 -xmp-mwg-rs:RegionAreaH=0.30390625"; + args += $" -xmp-mwg-rs:RegionRotation=0"; + + if (imageObject.Person != null) + { + args += $" -xmp-mwg-rs:RegionName={imageObject.Person.Name}"; + } - processedOps.Add(op); - needExecuteExifTool = true; + opsToProcess.Add(op); + } } } - var db = new ImageContext(); + // Assume they've all failed unless we succeed below. + exifOperations.ForEach(x => x.State = ExifOperation.FileWriteState.Failed); - if (needExecuteExifTool) + if (opsToProcess.Any() ) { // Note: we could do this to preserve the last-mod-time: // args += " -P -overwrite_original_in_place"; @@ -418,7 +414,7 @@ private async Task ProcessExifOperations(int imageId, List if (success) { - processedOps.ForEach(x => x.State = ExifOperation.FileWriteState.Written); + opsToProcess.ForEach(x => x.State = ExifOperation.FileWriteState.Written); // Updating the timestamp on the image to newer than its metadata will // trigger its metadata and tags to be refreshed during the next scan @@ -426,25 +422,23 @@ private async Task ProcessExifOperations(int imageId, List } else { - processedOps.ForEach(x => x.State = ExifOperation.FileWriteState.Failed); Logging.LogError("ExifTool Tag update failed for image: {0}", image.FullPath); - RestoreTempExifImage(image.FullPath); } } + var db = new ImageContext(); + // Now write the updates - await db.BulkUpdate(db.KeywordOperations, processedOps); + await db.BulkUpdate(db.KeywordOperations, exifOperations); - if( needExecuteExifTool ) - { - var totals = string.Join(", ", exifOperations.GroupBy(x => x.State) - .Select(x => $"{x.Key}: {x.Count()}") - .ToList()); + // Now write a summary of how many succeeded and failed. + var totals = string.Join(", ", exifOperations.GroupBy(x => x.State) + .Select(x => $"{x.Key}: {x.Count()}") + .ToList()); - _statusService.StatusText = $"EXIF data written for {image.FileName}. {totals}"; - } - + _statusService.StatusText = $"EXIF data written for {image.FileName}. {totals}"; + return success; } From 1ae64a96774a2d2181d55271473469ee93ed71e5 Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Mon, 14 Feb 2022 23:37:47 +0000 Subject: [PATCH 03/19] Export config workflow. --- Damselfly.Web/Damselfly.Web.csproj | 2 + .../Shared/{ => Dialogs}/BasketDialog.razor | 0 .../{ => Dialogs}/BasketMoveDialog.razor | 0 .../Shared/Dialogs/ExportConfigDialog.razor | 146 ++++++++++++++++++ .../Shared/{ => Dialogs}/RescanDialog.razor | 0 .../Shared/{ => Dialogs}/UserDialog.razor | 0 .../Shared/ExportConfigManager.razor | 68 +++----- Damselfly.Web/Shared/ExportSettings.razor | 27 +--- Damselfly.Web/_Imports.razor | 3 +- 9 files changed, 177 insertions(+), 69 deletions(-) rename Damselfly.Web/Shared/{ => Dialogs}/BasketDialog.razor (100%) rename Damselfly.Web/Shared/{ => Dialogs}/BasketMoveDialog.razor (100%) create mode 100644 Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor rename Damselfly.Web/Shared/{ => Dialogs}/RescanDialog.razor (100%) rename Damselfly.Web/Shared/{ => Dialogs}/UserDialog.razor (100%) diff --git a/Damselfly.Web/Damselfly.Web.csproj b/Damselfly.Web/Damselfly.Web.csproj index 05d5cc16..1f75f6d6 100644 --- a/Damselfly.Web/Damselfly.Web.csproj +++ b/Damselfly.Web/Damselfly.Web.csproj @@ -52,6 +52,7 @@ + @@ -63,6 +64,7 @@ + diff --git a/Damselfly.Web/Shared/BasketDialog.razor b/Damselfly.Web/Shared/Dialogs/BasketDialog.razor similarity index 100% rename from Damselfly.Web/Shared/BasketDialog.razor rename to Damselfly.Web/Shared/Dialogs/BasketDialog.razor diff --git a/Damselfly.Web/Shared/BasketMoveDialog.razor b/Damselfly.Web/Shared/Dialogs/BasketMoveDialog.razor similarity index 100% rename from Damselfly.Web/Shared/BasketMoveDialog.razor rename to Damselfly.Web/Shared/Dialogs/BasketMoveDialog.razor diff --git a/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor b/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor new file mode 100644 index 00000000..79205bc7 --- /dev/null +++ b/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor @@ -0,0 +1,146 @@ + +@using System.ComponentModel.DataAnnotations +@using Damselfly.Core.Interfaces + +@inject BasketService basketService +@inject UserService userService +@inject UserStatusService statusService +@inject ConfigService configService + + + + @(Mode == "Edit" ? $"Edit Config '{Config.Name}'" : "Create New Export Config") + + + + + + @if (!string.IsNullOrEmpty(errorMsg)) + { +

@errorMsg

+ } + + @foreach (var choice in exportSizes) + { + + @choice.ToString() + + } + + + @foreach (var choice in exportTypes) + { + + @choice.ToString() + + } + + + +
+
+ + @if (Mode == "Edit") + { + + + Delete Config + Cancel + Save + + + } + else + { + Cancel + Add Config + } + +
+ +@code { + [CascadingParameter] + MudDialogInstance MudDialog { get; set; } + + [Parameter] + public ExportConfig Config { get; set; } = new ExportConfig(); + + [Parameter] + public string Mode { get; set; } + + public ExportType[] exportTypes { get; private set; } = new ExportType[0]; + public ExportSize[] exportSizes { get; private set; } = new ExportSize[0]; + + private async Task OnValidSubmit(EditContext context) + { + await Save(); + } + + async Task DeleteConfig() + { + var db = new ImageContext(); + + var existingConfig = db.DownloadConfigs.Where(x => x.ExportConfigId == Config.ExportConfigId); + + await db.BatchDelete(existingConfig); + + statusService.StatusText = $"Config '{Config.Name}' was deleted."; + + MudDialog.Close(DialogResult.Ok(true)); + } + + async Task Save() + { + using var db = new ImageContext(); + + try + { + if (Mode == "Add") + { + if (db.DownloadConfigs.Any(x => x.Name.Equals(Config.Name) )) + { + DisplayError($"Config '{Config.Name}' already exists. Please choose another name."); + return; + } + else + { + db.DownloadConfigs.Add(Config); + await db.SaveChangesAsync("SaveExportConfig"); + + statusService.StatusText = $"New download config '{Config.Name}' was created."; + } + } + else if (Mode == "Edit") + { + db.DownloadConfigs.Update(Config); + await db.SaveChangesAsync("SaveExportConfig"); + + + statusService.StatusText = $"Config '{Config.Name}' saved."; + } + + MudDialog.Close(DialogResult.Ok(true)); + } + catch (Exception ex) + { + Logging.LogError($"Unexpected error saving export config: {ex}"); + DisplayError($"Unexpected error saving export config {ex.Message}"); + } + } + + private string errorMsg; + + private void DisplayError(string errorText) + { + errorMsg = errorText; + StateHasChanged(); + } + + void Cancel() => MudDialog.Cancel(); + + protected override void OnInitialized() + { + exportTypes = (ExportType[])Enum.GetValues(typeof(ExportType)); + exportSizes = (ExportSize[])Enum.GetValues(typeof(ExportSize)); + } +} \ No newline at end of file diff --git a/Damselfly.Web/Shared/RescanDialog.razor b/Damselfly.Web/Shared/Dialogs/RescanDialog.razor similarity index 100% rename from Damselfly.Web/Shared/RescanDialog.razor rename to Damselfly.Web/Shared/Dialogs/RescanDialog.razor diff --git a/Damselfly.Web/Shared/UserDialog.razor b/Damselfly.Web/Shared/Dialogs/UserDialog.razor similarity index 100% rename from Damselfly.Web/Shared/UserDialog.razor rename to Damselfly.Web/Shared/Dialogs/UserDialog.razor diff --git a/Damselfly.Web/Shared/ExportConfigManager.razor b/Damselfly.Web/Shared/ExportConfigManager.razor index d99dfdd1..4ee225e8 100644 --- a/Damselfly.Web/Shared/ExportConfigManager.razor +++ b/Damselfly.Web/Shared/ExportConfigManager.razor @@ -1,67 +1,47 @@ @inject ThumbnailService thumbService @inject NavigationManager NavigationManager @inject WordpressService wpService; +@inject IDialogService DialogService -
- @if (!AddingConfig) - { - - - } - else - { - - - - } + -@code { + +@code +{ readonly List configs = new List(); - bool AddingConfig { get; set; } - string NewConfigName { get; set; } [Parameter] public ExportConfig CurrentConfig { get; set; } - private void SaveConfig() + private async Task OpenAddBasketDialog() { - AddingConfig = false; + var newConfig = new ExportConfig { Name = "New Config" }; - using var db = new ImageContext(); + var parameters = new DialogParameters { { "Config", newConfig }, { "mode", "Add" } }; + var dialog = DialogService.Show("Add New Config", parameters); + var result = await dialog.Result; - if( CurrentConfig.ExportConfigId == -1 ) - db.DownloadConfigs.Add(CurrentConfig); - else - db.DownloadConfigs.Update(CurrentConfig); - db.SaveChanges("AddExportConfig"); - - StateHasChanged(); + await LoadData(); } - private void CancelAdding() + private async Task OpenEditBasketDialog() { - AddingConfig = false; - StateHasChanged(); - } + var parameters = new DialogParameters { { "Config", CurrentConfig }, { "mode", "Edit" } }; + var dialog = DialogService.Show("Edit Config", parameters); + var result = await dialog.Result; - private void AddBasket() - { - AddingConfig = true; - StateHasChanged(); + await LoadData(); } - private void ConfigChanged(ChangeEventArgs e) - { - StateHasChanged(); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) diff --git a/Damselfly.Web/Shared/ExportSettings.razor b/Damselfly.Web/Shared/ExportSettings.razor index 1462dc08..267d9e4f 100644 --- a/Damselfly.Web/Shared/ExportSettings.razor +++ b/Damselfly.Web/Shared/ExportSettings.razor @@ -15,34 +15,13 @@

Export Settings

- - +
- - +
- - -
-
- - +
@if (FileExporter != null && FileExporter.IsDesktopHosted) diff --git a/Damselfly.Web/_Imports.razor b/Damselfly.Web/_Imports.razor index 5dab716e..7a7837f5 100644 --- a/Damselfly.Web/_Imports.razor +++ b/Damselfly.Web/_Imports.razor @@ -22,9 +22,10 @@ @using Damselfly.Web @using Damselfly.Web.Data @using Damselfly.Web.Extensions -@using Damselfly.Web.Shared @using Damselfly.Web.Components +@using Damselfly.Web.Shared @using Damselfly.Web.Shared.Images +@using Damselfly.Web.Shared.Dialogs @using Radzen @using Radzen.Blazor @using MudBlazor From 569eb05e33d5460144437d8d69934b79dda4f82a Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Tue, 15 Feb 2022 13:34:50 +0000 Subject: [PATCH 04/19] DbContext usings. --- Damselfly.Core/Services/ExifService.cs | 6 +-- Damselfly.Core/Services/ImageCache.cs | 2 +- .../Services/ImageRecognitionService.cs | 23 ++++---- Damselfly.Core/Services/IndexingService.cs | 54 +++++++++---------- Damselfly.Core/Services/MetaDataService.cs | 23 ++++---- Damselfly.Core/Services/ThumbnailService.cs | 6 +-- .../Shared/Dialogs/BasketDialog.razor | 4 +- .../Shared/Dialogs/ExportConfigDialog.razor | 2 +- .../Shared/Images/ImageProperties.razor | 2 +- Damselfly.Web/Shared/Stats.razor | 51 +++++++++--------- Damselfly.Web/Startup.cs | 7 ++- 11 files changed, 87 insertions(+), 93 deletions(-) diff --git a/Damselfly.Core/Services/ExifService.cs b/Damselfly.Core/Services/ExifService.cs index 53a805c0..da45aef9 100644 --- a/Damselfly.Core/Services/ExifService.cs +++ b/Damselfly.Core/Services/ExifService.cs @@ -427,7 +427,7 @@ private async Task ProcessExifOperations(int imageId, List } } - var db = new ImageContext(); + using var db = new ImageContext(); // Now write the updates await db.BulkUpdate(db.KeywordOperations, exifOperations); @@ -581,7 +581,7 @@ private async Task>> ConflateOperations(Lis if (discardedOps.Any()) { - var db = new ImageContext(); + using var db = new ImageContext(); // Mark the ops as discarded, and save them. discardedOps.ForEach(x => x.State = ExifOperation.FileWriteState.Discarded); @@ -683,7 +683,7 @@ public async Task Process() public async Task> GetPendingJobs(int maxCount) { - var db = new ImageContext(); + using var db = new ImageContext(); // We skip any operations where the timestamp is more recent than 30s var timeThreshold = DateTime.UtcNow.AddSeconds(-1 * s_exifWriteDelay); diff --git a/Damselfly.Core/Services/ImageCache.cs b/Damselfly.Core/Services/ImageCache.cs index 39aca7ae..4acae0c6 100644 --- a/Damselfly.Core/Services/ImageCache.cs +++ b/Damselfly.Core/Services/ImageCache.cs @@ -55,7 +55,7 @@ public async Task WarmUp() Logging.Log($"Warming up image cache with up to {warmupCount} most recent images."); - var db = new ImageContext(); + using var db = new ImageContext(); var warmupIds = await db.Images.OrderByDescending(x => x.SortDate) .Take(warmupCount) diff --git a/Damselfly.Core/Services/ImageRecognitionService.cs b/Damselfly.Core/Services/ImageRecognitionService.cs index 48a433b4..d59d3e5b 100644 --- a/Damselfly.Core/Services/ImageRecognitionService.cs +++ b/Damselfly.Core/Services/ImageRecognitionService.cs @@ -82,16 +82,15 @@ private void LoadPersonCache(bool force = false) { var watch = new Stopwatch("LoadPersonCache"); - using (var db = new ImageContext()) - { - // Pre-cache tags from DB. - _peopleCache = new ConcurrentDictionary(db.People - .Where(x => !string.IsNullOrEmpty(x.AzurePersonId)) - .AsNoTracking() - .ToDictionary(k => k.AzurePersonId, v => v)); - if (_peopleCache.Any()) - Logging.LogTrace("Pre-loaded cach with {0} people.", _peopleCache.Count()); - } + using var db = new ImageContext(); + + // Pre-cache tags from DB. + _peopleCache = new ConcurrentDictionary(db.People + .Where(x => !string.IsNullOrEmpty(x.AzurePersonId)) + .AsNoTracking() + .ToDictionary(k => k.AzurePersonId, v => v)); + if (_peopleCache.Any()) + Logging.LogTrace("Pre-loaded cach with {0} people.", _peopleCache.Count()); watch.Stop(); } @@ -602,7 +601,7 @@ public void StartService() /// private async Task DetectObjects(int imageId) { - var db = new ImageContext(); + using var db = new ImageContext(); var image = await _imageCache.GetCachedImage(imageId); db.Attach(image); @@ -672,7 +671,7 @@ public async Task Process() public async Task> GetPendingJobs( int maxJobs ) { - var db = new ImageContext(); + using var db = new ImageContext(); var images = await db.ImageMetaData.Where(x => x.AILastUpdated == null && x.ThumbLastUpdated != null) .OrderByDescending(x => x.LastUpdated) diff --git a/Damselfly.Core/Services/IndexingService.cs b/Damselfly.Core/Services/IndexingService.cs index 438a4b39..cf9a7c78 100644 --- a/Damselfly.Core/Services/IndexingService.cs +++ b/Damselfly.Core/Services/IndexingService.cs @@ -77,39 +77,37 @@ public async Task IndexFolder(DirectoryInfo folder, Folder parent ) try { - using (var db = new ImageContext()) - { - // Load the existing folder and its images from the DB - folderToScan = await db.Folders - .Where(x => x.Path.Equals(folder.FullName)) - .Include(x => x.Images) - .FirstOrDefaultAsync(); - - if (folderToScan == null) - { - Logging.LogVerbose("Scanning new folder: {0}\\{1}", folder.Parent.Name, folder.Name); - folderToScan = new Folder { Path = folder.FullName }; - } - else - Logging.LogVerbose("Scanning existing folder: {0}\\{1} ({2} images in DB)", folder.Parent.Name, folder.Name, folderToScan.Images.Count()); + using var db = new ImageContext(); + // Load the existing folder and its images from the DB + folderToScan = await db.Folders + .Where(x => x.Path.Equals(folder.FullName)) + .Include(x => x.Images) + .FirstOrDefaultAsync(); - if (folderToScan.FolderId == 0) - { - Logging.Log($"Adding new folder: {folderToScan.Path}"); + if (folderToScan == null) + { + Logging.LogVerbose("Scanning new folder: {0}\\{1}", folder.Parent.Name, folder.Name); + folderToScan = new Folder { Path = folder.FullName }; + } + else + Logging.LogVerbose("Scanning existing folder: {0}\\{1} ({2} images in DB)", folder.Parent.Name, folder.Name, folderToScan.Images.Count()); - if (parent != null) - folderToScan.ParentFolderId = parent.FolderId; + if (folderToScan.FolderId == 0) + { + Logging.Log($"Adding new folder: {folderToScan.Path}"); - // New folder, add it. - db.Folders.Add(folderToScan); - await db.SaveChangesAsync("AddFolders"); - foldersChanged = true; - } + if (parent != null) + folderToScan.ParentFolderId = parent.FolderId; - // Now, check for missing folders, and clean up if appropriate. - foldersChanged = await RemoveMissingChildDirs(db, folderToScan) || foldersChanged; + // New folder, add it. + db.Folders.Add(folderToScan); + await db.SaveChangesAsync("AddFolders"); + foldersChanged = true; } + // Now, check for missing folders, and clean up if appropriate. + foldersChanged = await RemoveMissingChildDirs(db, folderToScan) || foldersChanged; + _watcherService.CreateFileWatcher(folder); // Now scan the images. If there's changes it could mean the folder @@ -482,7 +480,7 @@ public async Task> GetPendingJobs( int maxCount ) { if (_fullIndexComplete) { - var db = new ImageContext(); + using var db = new ImageContext(); // Now, see if there's any folders that have a null scan date. var folders = await db.Folders.Where(x => x.FolderScanDate == null) diff --git a/Damselfly.Core/Services/MetaDataService.cs b/Damselfly.Core/Services/MetaDataService.cs index a606e49b..d14678a5 100644 --- a/Damselfly.Core/Services/MetaDataService.cs +++ b/Damselfly.Core/Services/MetaDataService.cs @@ -372,7 +372,7 @@ public async Task ScanMetaData( int imageId ) Stopwatch watch = new Stopwatch("ScanMetadata"); var writeSideCarTagsToImages = _configService.GetBool(ConfigSettings.ImportSidecarKeywords); - var db = new ImageContext(); + using var db = new ImageContext(); var updateTimeStamp = DateTime.UtcNow; var imageKeywords = new List(); List sideCarTags = new List(); @@ -479,7 +479,7 @@ private async Task WriteXMPFaces(Image image, List xmpFaces) var names = xmpFaces.Select(x => x.Person.Name) .ToList(); - var db = new ImageContext(); + using var db = new ImageContext(); var peopleLookup = db.People.Where(x => names.Contains(x.Name)) .ToDictionary(x => x.Name, y => y.PersonId); @@ -804,15 +804,14 @@ private void LoadTagCache(bool force = false) { var watch = new Stopwatch("LoadTagCache"); - using (var db = new ImageContext()) - { - // Pre-cache tags from DB. - _tagCache = new ConcurrentDictionary(db.Tags - .AsNoTracking() - .ToDictionary(k => k.Keyword, v => v)); - if (_tagCache.Any()) - Logging.LogTrace("Pre-loaded cach with {0} tags.", _tagCache.Count()); - } + using var db = new ImageContext(); + + // Pre-cache tags from DB. + _tagCache = new ConcurrentDictionary(db.Tags + .AsNoTracking() + .ToDictionary(k => k.Keyword, v => v)); + if (_tagCache.Any()) + Logging.LogTrace("Pre-loaded cach with {0} tags.", _tagCache.Count()); watch.Stop(); } @@ -955,7 +954,7 @@ public async Task Process() public async Task> GetPendingJobs(int maxJobs) { - var db = new ImageContext(); + using var db = new ImageContext(); // Find all images where there's either no metadata, or where the image or sidecar file // was updated more recently than the image metadata diff --git a/Damselfly.Core/Services/ThumbnailService.cs b/Damselfly.Core/Services/ThumbnailService.cs index a6baf8c6..07588594 100644 --- a/Damselfly.Core/Services/ThumbnailService.cs +++ b/Damselfly.Core/Services/ThumbnailService.cs @@ -344,7 +344,7 @@ public async Task CreateThumbs(ImageMetaData sourceImage, bo /// public async Task CreateThumb(int imageId) { - var db = new ImageContext(); + using var db = new ImageContext(); var image = await _imageCache.GetCachedImage(imageId); @@ -371,7 +371,7 @@ public async Task AddHashToImage( Image image, ImageProcessResult processResult { try { - var db = new ImageContext(); + using var db = new ImageContext(); Hash hash = image.Hash; if (hash == null) @@ -650,7 +650,7 @@ public async Task> GetPendingJobs( int maxJobs ) if (!EnableThumbnailGeneration) return new ThumbProcess[0]; - var db = new ImageContext(); + using var db = new ImageContext(); var images = await db.ImageMetaData.Where(x => x.ThumbLastUpdated == null) .OrderByDescending(x => x.LastUpdated) diff --git a/Damselfly.Web/Shared/Dialogs/BasketDialog.razor b/Damselfly.Web/Shared/Dialogs/BasketDialog.razor index 15fe987b..d84a26db 100644 --- a/Damselfly.Web/Shared/Dialogs/BasketDialog.razor +++ b/Damselfly.Web/Shared/Dialogs/BasketDialog.razor @@ -73,7 +73,7 @@ async Task DeleteBasket() { IStatusService statusAudience = model.IsPublic ? statusService : userStatusService; - var db = new ImageContext(); + using var db = new ImageContext(); var existingBasket = db.Baskets.Where(x => x.BasketId == Basket.BasketId); @@ -89,7 +89,7 @@ async Task Save() { - var db = new ImageContext(); + using var db = new ImageContext(); IStatusService statusAudience = model.IsPublic ? statusService : userStatusService; try diff --git a/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor b/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor index 79205bc7..7c9318f4 100644 --- a/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor +++ b/Damselfly.Web/Shared/Dialogs/ExportConfigDialog.razor @@ -78,7 +78,7 @@ async Task DeleteConfig() { - var db = new ImageContext(); + using var db = new ImageContext(); var existingConfig = db.DownloadConfigs.Where(x => x.ExportConfigId == Config.ExportConfigId); diff --git a/Damselfly.Web/Shared/Images/ImageProperties.razor b/Damselfly.Web/Shared/Images/ImageProperties.razor index 6d84a638..5df81204 100644 --- a/Damselfly.Web/Shared/Images/ImageProperties.razor +++ b/Damselfly.Web/Shared/Images/ImageProperties.razor @@ -137,7 +137,7 @@ else private async Task SaveProperty( Action propertyUpdate ) { - var db = new ImageContext(); + using var db = new ImageContext(); var metadata = CurrentImage.MetaData; db.Attach(metadata); propertyUpdate.Invoke(CurrentImage.MetaData); diff --git a/Damselfly.Web/Shared/Stats.razor b/Damselfly.Web/Shared/Stats.razor index 55505535..a7017806 100644 --- a/Damselfly.Web/Shared/Stats.razor +++ b/Damselfly.Web/Shared/Stats.razor @@ -67,34 +67,33 @@ protected async Task GetStatsSync() { - using (var db = new ImageContext()) - { - TotalImages = await db.Images.CountAsync(); - TotalTags = await db.Tags.CountAsync(); - TotalFolders = await db.Folders.CountAsync(); - TotalImagesSizeBytes = await db.Images.SumAsync( x => (long)x.FileSizeBytes ); - PeopleFound = await db.People.CountAsync(); - PeopleIdentified = await db.People.Where( x => x.Name != "Unknown" ).CountAsync(); - ObjectsRecognised = await db.ImageObjects.CountAsync(); - PendingAIScans = await db.ImageMetaData.Where(x => !x.AILastUpdated.HasValue).CountAsync(); - PendingThumbs = await db.ImageMetaData.Where(x => !x.ThumbLastUpdated.HasValue).CountAsync(); - PendingImages = await db.Images.Where(x => x.MetaData == null || x.LastUpdated > x.MetaData.LastUpdated ).Include( x => x.MetaData ).CountAsync(); - PendingKeywordOps = await db.KeywordOperations.Where(x => x.State == ExifOperation.FileWriteState.Pending).CountAsync(); - PendingKeywordImages = await db.KeywordOperations.Where(x => x.State == ExifOperation.FileWriteState.Pending) - .Select(x => x.ImageId ) - .Distinct().CountAsync(); + using var db = new ImageContext(); + + TotalImages = await db.Images.CountAsync(); + TotalTags = await db.Tags.CountAsync(); + TotalFolders = await db.Folders.CountAsync(); + TotalImagesSizeBytes = await db.Images.SumAsync( x => (long)x.FileSizeBytes ); + PeopleFound = await db.People.CountAsync(); + PeopleIdentified = await db.People.Where( x => x.Name != "Unknown" ).CountAsync(); + ObjectsRecognised = await db.ImageObjects.CountAsync(); + PendingAIScans = await db.ImageMetaData.Where(x => !x.AILastUpdated.HasValue).CountAsync(); + PendingThumbs = await db.ImageMetaData.Where(x => !x.ThumbLastUpdated.HasValue).CountAsync(); + PendingImages = await db.Images.Where(x => x.MetaData == null || x.LastUpdated > x.MetaData.LastUpdated ).Include( x => x.MetaData ).CountAsync(); + PendingKeywordOps = await db.KeywordOperations.Where(x => x.State == ExifOperation.FileWriteState.Pending).CountAsync(); + PendingKeywordImages = await db.KeywordOperations.Where(x => x.State == ExifOperation.FileWriteState.Pending) + .Select(x => x.ImageId ) + .Distinct().CountAsync(); - // TODO: Should pull this out of the TransThrottle instance. - var now = DateTime.UtcNow; - var monthStart = new DateTime( now.Year, now.Month, 1, 0, 0, 1 ); - var monthEnd = monthStart.AddMonths(1).AddSeconds( -1 ); - var totalTrans = await db.CloudTransactions.Where(x => x.Date >= monthStart && x.Date <= monthEnd).SumAsync(x => x.TransCount); + // TODO: Should pull this out of the TransThrottle instance. + var now = DateTime.UtcNow; + var monthStart = new DateTime( now.Year, now.Month, 1, 0, 0, 1 ); + var monthEnd = monthStart.AddMonths(1).AddSeconds( -1 ); + var totalTrans = await db.CloudTransactions.Where(x => x.Date >= monthStart && x.Date <= monthEnd).SumAsync(x => x.TransCount); - if( totalTrans > 0 ) - AzureMonthlyTransactions = $"{totalTrans} (during {monthStart:MMM})"; + if( totalTrans > 0 ) + AzureMonthlyTransactions = $"{totalTrans} (during {monthStart:MMM})"; - StatsReady = true; - await InvokeAsync( StateHasChanged ); - }; + StatsReady = true; + await InvokeAsync( StateHasChanged ); } } \ No newline at end of file diff --git a/Damselfly.Web/Startup.cs b/Damselfly.Web/Startup.cs index 11e9d03f..86f69c59 100644 --- a/Damselfly.Web/Startup.cs +++ b/Damselfly.Web/Startup.cs @@ -322,10 +322,9 @@ private static void StartTaskScheduler(TaskService taskScheduler, DownloadServic ExecutionFrequency = new TimeSpan(2, 0, 0), WorkMethod = () => { - using (var db = new ImageContext()) - { - db.FlushDBWriteCache(); - } + using var db = new ImageContext(); + + db.FlushDBWriteCache(); } }); */ From 929524d6868c23f7b0af4649239b60e27d166e02 Mon Sep 17 00:00:00 2001 From: Mark Otway Date: Mon, 21 Feb 2022 10:27:51 +0000 Subject: [PATCH 05/19] Crash commit --- .DS_Store | Bin 8196 -> 8196 bytes Accord/Accord.Imaging/Accord.Imaging.csproj | 2 +- .../Damselfly.Core.DbModels.csproj | 2 +- .../Damselfly.Core.Utils.csproj | 2 +- Damselfly.Core/Damselfly.Core.csproj | 10 +++++----- .../Damselfly.ML.AccordFace.csproj | 2 +- .../Damselfly.ML.AzureFace.csproj | 2 +- .../Damselfly.ML.ObjectDetection.csproj | 4 ++-- .../Damselfly.Migrations.Postgres.csproj | 2 +- Damselfly.Web/Damselfly.Web.csproj | 6 +++--- .../Shared/ExportConfigManager.razor | 4 ++-- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.DS_Store b/.DS_Store index cd8b372ce7101e4bad9235929867ee9b79f08bd0..12a692b055bd057ac54e3ec924854ea9c6f4583a 100644 GIT binary patch delta 78 zcmZp1XmQxUCN|kku#DftP)EVY!mw6Hq1w>Uz-aPmL5s-`M5Q-B5L0K|%qqdiMnIJs FBLIC}7Uuu} delta 30 gcmZp1XmQxUCN}x9$o|cT#he&7vrGJEh4Snf0l%0GH~;_u diff --git a/Accord/Accord.Imaging/Accord.Imaging.csproj b/Accord/Accord.Imaging/Accord.Imaging.csproj index f906b353..1a2593e0 100644 --- a/Accord/Accord.Imaging/Accord.Imaging.csproj +++ b/Accord/Accord.Imaging/Accord.Imaging.csproj @@ -30,7 +30,7 @@ - + diff --git a/Damselfly.Core.DbModels/Damselfly.Core.DbModels.csproj b/Damselfly.Core.DbModels/Damselfly.Core.DbModels.csproj index 25df6ef9..6797c751 100644 --- a/Damselfly.Core.DbModels/Damselfly.Core.DbModels.csproj +++ b/Damselfly.Core.DbModels/Damselfly.Core.DbModels.csproj @@ -12,7 +12,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Damselfly.Core.Utils/Damselfly.Core.Utils.csproj b/Damselfly.Core.Utils/Damselfly.Core.Utils.csproj index 75dd8604..798e435e 100644 --- a/Damselfly.Core.Utils/Damselfly.Core.Utils.csproj +++ b/Damselfly.Core.Utils/Damselfly.Core.Utils.csproj @@ -1,6 +1,6 @@ - + diff --git a/Damselfly.Core/Damselfly.Core.csproj b/Damselfly.Core/Damselfly.Core.csproj index acef1469..1e977d83 100644 --- a/Damselfly.Core/Damselfly.Core.csproj +++ b/Damselfly.Core/Damselfly.Core.csproj @@ -23,18 +23,18 @@ - - + + - - + + - + diff --git a/Damselfly.ML.AccordFace/Damselfly.ML.AccordFace.csproj b/Damselfly.ML.AccordFace/Damselfly.ML.AccordFace.csproj index e82541be..54ae46a9 100644 --- a/Damselfly.ML.AccordFace/Damselfly.ML.AccordFace.csproj +++ b/Damselfly.ML.AccordFace/Damselfly.ML.AccordFace.csproj @@ -6,7 +6,7 @@ - + diff --git a/Damselfly.ML.AzureFace/Damselfly.ML.AzureFace.csproj b/Damselfly.ML.AzureFace/Damselfly.ML.AzureFace.csproj index c3fa53bb..55777739 100644 --- a/Damselfly.ML.AzureFace/Damselfly.ML.AzureFace.csproj +++ b/Damselfly.ML.AzureFace/Damselfly.ML.AzureFace.csproj @@ -12,6 +12,6 @@ - + diff --git a/Damselfly.ML.ObjectDetection.ML/Damselfly.ML.ObjectDetection.csproj b/Damselfly.ML.ObjectDetection.ML/Damselfly.ML.ObjectDetection.csproj index b5b596e0..86c3c55f 100644 --- a/Damselfly.ML.ObjectDetection.ML/Damselfly.ML.ObjectDetection.csproj +++ b/Damselfly.ML.ObjectDetection.ML/Damselfly.ML.ObjectDetection.csproj @@ -6,11 +6,11 @@ - + - + diff --git a/Damselfly.Migrations.Postgres/Damselfly.Migrations.Postgres.csproj b/Damselfly.Migrations.Postgres/Damselfly.Migrations.Postgres.csproj index 15035620..11c97646 100644 --- a/Damselfly.Migrations.Postgres/Damselfly.Migrations.Postgres.csproj +++ b/Damselfly.Migrations.Postgres/Damselfly.Migrations.Postgres.csproj @@ -1,7 +1,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Damselfly.Web/Damselfly.Web.csproj b/Damselfly.Web/Damselfly.Web.csproj index 1f75f6d6..f738969a 100644 --- a/Damselfly.Web/Damselfly.Web.csproj +++ b/Damselfly.Web/Damselfly.Web.csproj @@ -79,9 +79,9 @@ - + - + @@ -100,6 +100,6 @@ - + \ No newline at end of file diff --git a/Damselfly.Web/Shared/ExportConfigManager.razor b/Damselfly.Web/Shared/ExportConfigManager.razor index 4ee225e8..9abb1d25 100644 --- a/Damselfly.Web/Shared/ExportConfigManager.razor +++ b/Damselfly.Web/Shared/ExportConfigManager.razor @@ -4,10 +4,10 @@ @inject IDialogService DialogService