Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter photos by face #26

Merged
merged 3 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ImmichFrame/Exceptions/ImmichFrameExceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ public AlbumNotFoundException(string message) : base(message) { }
public AlbumNotFoundException(string message, Exception innerException) : base(message, innerException) { }
public AlbumNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}

public class PersonNotFoundException : ImmichFrameException
{
public PersonNotFoundException() : base() { }
public PersonNotFoundException(string message) : base(message) { }
public PersonNotFoundException(string message, Exception innerException) : base(message, innerException) { }
public PersonNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class MemoryNotFoundException : ImmichFrameException
{
public MemoryNotFoundException() : base() { }
Expand Down
63 changes: 58 additions & 5 deletions ImmichFrame/Helpers/AssetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{
public class AssetHelper
{
private Task<Dictionary<Guid, AssetResponseDto>> _memoryAssetInfos;

Check warning on line 14 in ImmichFrame/Helpers/AssetHelper.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field '_memoryAssetInfos' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private DateTime lastMemoryAssetRefesh;
public Task<Dictionary<Guid, AssetResponseDto>> MemoryAssetInfos
{
Expand All @@ -27,7 +27,7 @@
}
}

private Task<Dictionary<Guid, AssetResponseDto>> _albumAssetInfos;

Check warning on line 30 in ImmichFrame/Helpers/AssetHelper.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field '_albumAssetInfos' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private DateTime lastAlbumAssetRefesh;
public Task<Dictionary<Guid, AssetResponseDto>> AlbumAssetInfos
{
Expand All @@ -44,6 +44,23 @@
return _albumAssetInfos;
}
}
private Task<Dictionary<Guid, AssetResponseDto>> _peopleAssetInfos;

Check warning on line 47 in ImmichFrame/Helpers/AssetHelper.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field '_peopleAssetInfos' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private DateTime lastPeopleAssetRefresh;
public Task<Dictionary<Guid, AssetResponseDto>> PeopleAssetInfos
{
get
{
// Refresh if no assets loaded or lastPeopleAssetRefresh is older than one day
// TODO: Put refresh duration in config
if (_peopleAssetInfos == null || lastPeopleAssetRefresh.AddDays(1) < DateTime.Now)
{
lastPeopleAssetRefresh = DateTime.Now;
_peopleAssetInfos = GetPeopleAssetIds();
}

return _peopleAssetInfos;
}
}

public async Task<AssetResponseDto?> GetNextAsset()
{
Expand All @@ -52,7 +69,7 @@
return await GetRandomMemoryAsset();
}

return Settings.CurrentSettings.Albums.Any() ? await GetRandomAlbumAsset() : await GetRandomAsset();
return Settings.CurrentSettings.Albums.Any() ? await GetRandomAlbumAsset() : Settings.CurrentSettings.People.Any() ? await GetRandomPeopleAsset() : await GetRandomAsset();
}

private async Task<Dictionary<Guid, AssetResponseDto>> GetMemoryAssetIds()
Expand Down Expand Up @@ -89,16 +106,14 @@
var allAssets = new List<AssetResponseDto>();
var settings = Settings.CurrentSettings;


var x = new ImmichApi(settings.ImmichServerUrl, client);

var immichApi = new ImmichApi(settings.ImmichServerUrl, client);

client.UseApiKey(settings.ApiKey);
foreach (var albumId in settings.Albums!)
{
try
{
var albumInfo = await x.GetAlbumInfoAsync(albumId, null, null);
var albumInfo = await immichApi.GetAlbumInfoAsync(albumId, null, null);

allAssets.AddRange(albumInfo.Assets);
}
Expand All @@ -111,6 +126,34 @@
return allAssets.ToDictionary(x => Guid.Parse(x.Id));
}
}
private async Task<Dictionary<Guid, AssetResponseDto>> GetPeopleAssetIds()
{
using (var client = new HttpClient())
{
var allAssets = new List<AssetResponseDto>();
var settings = Settings.CurrentSettings;

var immichApi = new ImmichApi(settings.ImmichServerUrl, client);

client.UseApiKey(settings.ApiKey);
foreach (var personId in settings.People!)
{
try
JW-CH marked this conversation as resolved.
Show resolved Hide resolved
{
var personInfo = await immichApi.GetPersonAssetsAsync(personId);

allAssets.AddRange(personInfo);
}
catch (ApiException ex)
{
throw new PersonNotFoundException($"Person '{personId}' was not found, check your settings file", ex);
}
}
// Remove duplicates
var uniqueAssets = allAssets.GroupBy(x => x.Id).Select(group => group.First());
return uniqueAssets.ToDictionary(x => Guid.Parse(x.Id));
}
}

private Random _random = new Random();
private async Task<AssetResponseDto?> GetRandomAlbumAsset()
Expand All @@ -123,6 +166,16 @@

return albumAssetInfos.ElementAt(rnd).Value;
}
private async Task<AssetResponseDto?> GetRandomPeopleAsset()
{
var peopleAssetInfos = await PeopleAssetInfos;
if (!peopleAssetInfos.Any())
throw new AssetNotFoundException();

var rnd = _random.Next(peopleAssetInfos.Count);

return peopleAssetInfos.ElementAt(rnd).Value;
}

private async Task<AssetResponseDto?> GetRandomMemoryAsset()
{
Expand Down
2 changes: 2 additions & 0 deletions ImmichFrame/Models/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

public class Settings
{
public string ImmichServerUrl { get; set; }

Check warning on line 12 in ImmichFrame/Models/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'ImmichServerUrl' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public string ApiKey { get; set; }

Check warning on line 13 in ImmichFrame/Models/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'ApiKey' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public int Interval { get; set; }
public bool DownloadImages { get; set; }
public bool OnlyMemories { get; set; }
public int RenewImagesDuration { get; set; }
public List<Guid> Albums { get; set; }

Check warning on line 18 in ImmichFrame/Models/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Albums' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public List<Guid> People { get; set; }

Check warning on line 19 in ImmichFrame/Models/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'People' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public bool ShowClock { get; set; }
public int ClockFontSize { get; set; }
public string? ClockFormat { get; set; }
Expand All @@ -29,7 +30,7 @@
public string? WeatherUnits { get; set; }
public string? WeatherLatLong { get; set; }

private static Settings _settings;

Check warning on line 33 in ImmichFrame/Models/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field '_settings' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
public static Settings CurrentSettings
{
get
Expand All @@ -53,6 +54,7 @@
ImmichServerUrl = doc.Element("ImmichServerUrl")!.Value,
ApiKey = doc.Element("ApiKey")?.Value ?? string.Empty,
Albums = doc.Element("Albums")?.DescendantNodes().OfType<XElement>().Select(x => Guid.Parse(x.Value)).Distinct().ToList() ?? new(),
People = doc.Element("People")?.DescendantNodes().OfType<XElement>().Select(x => Guid.Parse(x.Value)).Distinct().ToList() ?? new(),
Interval = int.Parse(doc.Element("Interval")!.Value),
DownloadImages = Convert.ToBoolean(doc.Element("DownloadImages")?.Value),
OnlyMemories = Convert.ToBoolean(doc.Element("OnlyMemories")?.Value),
Expand Down
7 changes: 7 additions & 0 deletions ImmichFrame/Settings.example.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
<Album>First Album UID</Album>
<Album>Second Album UID</Album>
</Albums>

<!--OPTIONAL: Choose one or multiple People to have in the rotation-->
<!--Remove this section if you want to show random images-->
<People>
<Person>First Person UID</Person>
<Person>Second Person UID</Person>
</People>

<!--Interval for photo cycling in seconds-->
<Interval>8</Interval>
Expand Down
Loading