Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Webreaper committed Nov 8, 2021
2 parents b55db51 + 1283812 commit fbb9b14
Show file tree
Hide file tree
Showing 30 changed files with 553 additions and 194 deletions.
Binary file modified .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .github/workflows/damselfly-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: Setup Dotnet Environment
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.100-rc.2.21505.57'
dotnet-version: '6.0.100'

- name: Run Dotnet Server Build
run: sh scripts/makeserver.sh ${{ matrix.target }}
Expand Down
4 changes: 4 additions & 0 deletions Damselfly.Core.DbModels/DBAbstractions/BaseModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ protected override void OnConfiguring(DbContextOptionsBuilder options)
if (lazyLoad)
options.UseLazyLoadingProxies();

// Default to no tracking for performance. We can use Attach or
// AsTracking explicitly for when we need to do write operations.
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTrackingWithIdentityResolution);

// See efmigrations.md
//var obj = Activator.CreateInstance("Damselfly.Migrations.Sqlite", "Damselfly.Migrations.Sqlite.Models.SqlLiteModel");
//var obj = Activator.CreateInstance("Damselfly.Migrations.Postgres", "Damselfly.Migrations.Postgres.Models.PostgresModel");
Expand Down
6 changes: 4 additions & 2 deletions Damselfly.Core.ImageProcessing/SkiaSharpProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Task<ImageProcessResult> CreateThumbs(FileInfo source, IDictionary<FileIn
using var sourceBitmap = LoadOrientedBitmap(source, desiredWidth);
load.Stop();

hashThumb = new Stopwatch("HashHumb");
hashThumb = new Stopwatch("HashThumb");
result.ImageHash = GetHash(sourceBitmap);
hashThumb.Stop();

Expand Down Expand Up @@ -154,7 +154,9 @@ public Task GetCroppedFile(FileInfo source, int x, int y, int width, int height,
{
try
{
using var sourceBitmap = LoadOrientedBitmap(source, width);
SKCodec codec = SKCodec.Create(source.FullName);
SKImageInfo info = codec.Info;
using SKBitmap sourceBitmap = SKBitmap.Decode(codec);

// setup crop rect
var cropRect = new SKRectI(x, y, x + width, y + height);
Expand Down
3 changes: 2 additions & 1 deletion Damselfly.Core/Models/ImageContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ public enum OrientationType
public Image SimilarTo { get; set; } = null;
public Folder Folder { get; set; } = null;
public Tag Tag { get; set; } = null;
public Person Person { get; set; } = null;
public DateTime? MaxDate { get; set; } = null;
public DateTime? MinDate { get; set; } = null;
public FaceSearchType? FaceSearch { get; set; } = null;
Expand All @@ -649,7 +650,7 @@ public enum OrientationType

public override string ToString()
{
return $"Filter: T={SearchText}, F={Folder?.FolderId}, Max={MaxDate}, Min={MinDate}, Max={MaxSizeKB}KB, Min={MinSizeKB}KB, Tags={TagsOnly}, Grouping={Grouping}, Sort={SortOrder}, Face={FaceSearch}, SimilarTo={SimilarTo?.ImageId}";
return $"Filter: T={SearchText}, F={Folder?.FolderId}, Max={MaxDate}, Min={MinDate}, Max={MaxSizeKB}KB, Min={MinSizeKB}KB, Tags={TagsOnly}, Grouping={Grouping}, Sort={SortOrder}, Face={FaceSearch}, Person={Person?.Name}, SimilarTo={SimilarTo?.ImageId}";
}
}

Expand Down
14 changes: 12 additions & 2 deletions Damselfly.Core/ScopedServices/SearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ public void NotifyStateChanged()
{
Logging.LogVerbose($"Filter changed: {query}");

OnChange?.Invoke();
OnSearchChanged?.Invoke();
}

public event Action OnChange;
public event Action OnSearchChanged;

public string SearchText { get { return query.SearchText; } set { if (query.SearchText != value.Trim() ) { query.SearchText = value.Trim(); QueryChanged(); } } }
public DateTime? MaxDate { get { return query.MaxDate; } set { if (query.MaxDate != value) { query.MaxDate = value; QueryChanged(); } } }
Expand All @@ -66,6 +66,7 @@ public void NotifyStateChanged()
public Tag Tag { get { return query.Tag; } set { if (query.Tag != value) { query.Tag = value; QueryChanged(); } } }
public int? LensId { get { return query.LensId; } set { if (query.LensId != value) { query.LensId = value; QueryChanged(); } } }
public Image SimilarTo { get { return query.SimilarTo; } set { if (query.SimilarTo != value) { query.SimilarTo = value; QueryChanged(); } } }
public Person Person { get { return query.Person; } set { if (query.Person != value) { query.Person = value; QueryChanged(); } } }
public GroupingType Grouping { get { return query.Grouping; } set { if (query.Grouping != value) { query.Grouping = value; QueryChanged(); } } }
public SortOrderType SortOrder { get { return query.SortOrder; } set { if (query.SortOrder != value) { query.SortOrder = value; QueryChanged(); } } }
public FaceSearchType? FaceSearch { get { return query.FaceSearch; } set { if (query.FaceSearch != value) { query.FaceSearch = value; QueryChanged(); } } }
Expand Down Expand Up @@ -214,6 +215,12 @@ private async Task<bool> LoadMoreData(int first, int count)
images = images.Union(fileImages);
}

if (query.Person?.PersonId >= 0)
{
// Filter by folderID
images = images.Where(x => x.ImageObjects.Any( p => p.PersonId == query.Person.PersonId ) );
}

if (query.Folder?.FolderId >= 0)
{
// Filter by folderID
Expand Down Expand Up @@ -371,6 +378,9 @@ public string SearchBreadcrumbs
if (Folder != null)
hints.Add($"Folder: {Folder.Name}");

if (Person != null)
hints.Add($"Person: {Person.Name}");

if (SimilarTo != null)
hints.Add($"Looks Like: {SimilarTo.FileName}");

Expand Down
45 changes: 28 additions & 17 deletions Damselfly.Core/Services/ExifService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public async Task UpdateTagsAsync(Image[] images, List<string> addTags, List<str
new ExifOperation
{
ImageId = image.ImageId,
Text = keyword.RemoveSmartQuotes(),
Text = keyword.Sanitise(),
Type = ExifOperation.ExifType.Keyword,
Operation = ExifOperation.OperationType.Remove,
TimeStamp = timestamp
Expand Down Expand Up @@ -243,7 +243,9 @@ private async Task<bool> ProcessExifOperations(int imageId, List<ExifOperation>
env["LANG"] = "en_US.UTF-8";
env["LC_ALL"] = "en_US.UTF-8";

Stopwatch watch = new Stopwatch("RunExifTool");
success = process.StartProcess("exiftool", args, env);
watch.Stop();

var db = new ImageContext();

Expand Down Expand Up @@ -343,13 +345,15 @@ public async Task CleanUpKeywordOperations(TimeSpan cleanupFreq)
/// </summary>
/// <param name="tagsToProcess"></param>
/// <returns></returns>
private IDictionary<Image, List<ExifOperation>> ConflateOperations(List<ExifOperation> opsToProcess )
private async Task<IDictionary<int, List<ExifOperation>>> ConflateOperations(List<ExifOperation> opsToProcess )
{
var result = new Dictionary<Image, List<ExifOperation>>();
// The result is the image ID, and a list of conflated ops.
var result = new Dictionary<int, List<ExifOperation>>();
var discardedOps = new List<ExifOperation>();

// First, conflate the keywords.
var imageKeywords = opsToProcess.Where( x => x.Type == ExifOperation.ExifType.Keyword )
.GroupBy(x => x.Image);
.GroupBy(x => x.Image.ImageId);

foreach( var imageOpList in imageKeywords )
{
Expand All @@ -368,14 +372,14 @@ private IDictionary<Image, List<ExifOperation>> ConflateOperations(List<ExifOper

foreach( var imageKeywordOp in orderedOps )
{
// Store the most recent op for each operation,
// over-writing the previous
if( exifOpDict.TryGetValue( imageKeywordOp.Text, out var existing ) )
{
// Update the state before it's replaced in the dict.
existing.State = ExifOperation.FileWriteState.Discarded;
discardedOps.Add( existing );
}

// Store the most recent op for each operation,
// over-writing the previous
exifOpDict[imageKeywordOp.Text] = imageKeywordOp;
}
}
Expand All @@ -400,14 +404,23 @@ private IDictionary<Image, List<ExifOperation>> ConflateOperations(List<ExifOper
foreach( var pair in imageCaptions )
{
// Add the most recent to the result
result[pair.Image] = pair.Newest;
pair.Discarded.ForEach(x => x.State = ExifOperation.FileWriteState.Discarded);
result[pair.Image.ImageId] = pair.Newest;
discardedOps.AddRange(pair.Discarded);
}

var db = new ImageContext();

// Write the discarded states back to the DB
db.SaveChanges("ConflateExifOps");
if (discardedOps.Any())
{
var db = new ImageContext();

// Mark the ops as discarded, and save them.
discardedOps.ForEach(x => x.State = ExifOperation.FileWriteState.Discarded);

Logging.Log($"Discarding {discardedOps.Count} duplicate EXIF operations.");
Stopwatch watch = new Stopwatch("WriteDiscardedExifOps");
await db.BulkUpdate(db.KeywordOperations, discardedOps);
watch.Stop();
}

return result;
}
Expand Down Expand Up @@ -475,21 +488,19 @@ public async Task<ICollection<IProcessJob>> GetPendingJobs(int maxCount)
// We skip any operations where the timestamp is more recent than 30s
var timeThreshold = DateTime.UtcNow.AddSeconds(-1 * s_exifWriteDelay);

// Find all images where there's either no metadata, or where the image
// was updated more recently than the image metadata
// Find all the operations that are pending, and the timestamp is older than the threshold.
var opsToProcess = await db.KeywordOperations.AsQueryable()
.Where(x => x.State == ExifOperation.FileWriteState.Pending && x.TimeStamp < timeThreshold)
.OrderByDescending(x => x.TimeStamp)
.Take(maxCount)
.Include(x => x.Image)
.Include(x => x.Image.Folder)
.ToListAsync();

var conflatedOps = ConflateOperations(opsToProcess);
var conflatedOps = await ConflateOperations(opsToProcess);

var jobs = conflatedOps.Select(x => new ExifProcess
{
ImageId = x.Key.ImageId,
ImageId = x.Key,
ExifOps = x.Value,
Service = this
}).ToArray();
Expand Down
17 changes: 17 additions & 0 deletions Damselfly.Core/Services/ImageRecognitionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,22 @@ public async Task UpdateName( ImageObject faceObject, string name )

// Add/update the cache
_peopleCache[faceObject.Person.AzurePersonId] = faceObject.Person;

}

public async Task UpdateName( Person person, string name )
{
using var db = new ImageContext();

// TODO: If this is an existing person/name, we might need to merge in Azure
person.Name = name;
person.State = Person.PersonState.Identified;
db.People.Update(person);

await db.SaveChangesAsync("SetName");

// Add/update the cache
_peopleCache[person.AzurePersonId] = person;
}

/// <summary>
Expand Down Expand Up @@ -519,6 +535,7 @@ public void StartService()
}

LoadPersonCache();

_workService.AddJobSource(this);
}

Expand Down
6 changes: 6 additions & 0 deletions Damselfly.Core/Services/IndexingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ private async Task<bool> ScanFolderImages(int folderIdToScan)
if (imagesWereAddedOrRemoved)
NotifyFolderChanged();

if (imagesWereAddedOrRemoved || updatedImages > 0)
{
// Should flag the metadata service here...
}


return imagesWereAddedOrRemoved;
}

Expand Down
Loading

0 comments on commit fbb9b14

Please sign in to comment.