diff --git a/requests/ImmichToSlideshow.http b/requests/ImmichToSlideshow.http index 3df20d8..b32050e 100644 --- a/requests/ImmichToSlideshow.http +++ b/requests/ImmichToSlideshow.http @@ -24,4 +24,9 @@ Accept: application/json ### GET {{host}}/api/v1/assets/{{ownerId}}/sync-immich/ +Accept: application/json + +### + +GET {{host}}/api/v1/assets/{{ownerId}}/set-archive-immich/ Accept: application/json \ No newline at end of file diff --git a/src/ImmichToSlideshow/Controllers/AssetsController.cs b/src/ImmichToSlideshow/Controllers/AssetsController.cs index 1db6a44..cc65bcb 100644 --- a/src/ImmichToSlideshow/Controllers/AssetsController.cs +++ b/src/ImmichToSlideshow/Controllers/AssetsController.cs @@ -35,4 +35,8 @@ public class AssetsController(AssetService assetService) : ControllerBase public IActionResult SyncImmich(Guid ownerId) => Ok(_AssetService.SyncImmich(ownerId)); + [HttpGet("{ownerId:guid}/set-archive-immich")] + public IActionResult SetArchiveImmich(Guid ownerId) => + Ok(_AssetService.SetArchiveImmich(ownerId)); + } \ No newline at end of file diff --git a/src/ImmichToSlideshow/Models/AppSettings.cs b/src/ImmichToSlideshow/Models/AppSettings.cs index 29d5d13..064ccca 100644 --- a/src/ImmichToSlideshow/Models/AppSettings.cs +++ b/src/ImmichToSlideshow/Models/AppSettings.cs @@ -6,6 +6,8 @@ namespace ImmichToSlideshow.Models; public record AppSettings(int AddDays, string Company, string ConnectionString, + string CurrentCommit, + string CurrentResultsDirectory, string ImmichUploadDirectory, string RandomResultsDirectory, string SyncDirectory, diff --git a/src/ImmichToSlideshow/Models/Binder/AppSettings.cs b/src/ImmichToSlideshow/Models/Binder/AppSettings.cs index 0a65937..453b2aa 100644 --- a/src/ImmichToSlideshow/Models/Binder/AppSettings.cs +++ b/src/ImmichToSlideshow/Models/Binder/AppSettings.cs @@ -9,6 +9,8 @@ public class AppSettings public int? AddDays { get; set; } public string? Company { get; set; } public string? ConnectionString { get; set; } + public string? CurrentCommit { get; set; } + public string? CurrentResultsDirectory { get; set; } public string? ImmichUploadDirectory { get; set; } public string? RandomResultsDirectory { get; set; } public string? SyncDirectory { get; set; } @@ -45,6 +47,8 @@ public class AppSettings if (appSettings?.AddDays is null) throw new NullReferenceException(nameof(appSettings.AddDays)); if (appSettings?.Company is null) throw new NullReferenceException(nameof(appSettings.Company)); if (appSettings?.ConnectionString is null) throw new NullReferenceException(nameof(appSettings.ConnectionString)); + if (appSettings?.CurrentCommit is null) throw new NullReferenceException(nameof(appSettings.CurrentCommit)); + if (appSettings?.CurrentResultsDirectory is null) throw new NullReferenceException(nameof(appSettings.CurrentResultsDirectory)); if (appSettings?.ImmichUploadDirectory is null) throw new NullReferenceException(nameof(appSettings.ImmichUploadDirectory)); if (appSettings?.RandomResultsDirectory is null) throw new NullReferenceException(nameof(appSettings.RandomResultsDirectory)); if (appSettings?.SyncDirectory is null) throw new NullReferenceException(nameof(appSettings.SyncDirectory)); @@ -54,6 +58,8 @@ public class AppSettings result = new(appSettings.AddDays.Value, appSettings.Company, appSettings.ConnectionString, + appSettings.CurrentCommit, + appSettings.CurrentResultsDirectory, appSettings.ImmichUploadDirectory, appSettings.RandomResultsDirectory, appSettings.SyncDirectory, diff --git a/src/ImmichToSlideshow/Models/Identifier.cs b/src/ImmichToSlideshow/Models/Identifier.cs new file mode 100644 index 0000000..2bfe45e --- /dev/null +++ b/src/ImmichToSlideshow/Models/Identifier.cs @@ -0,0 +1,33 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ImmichToSlideshow.Models; + +public sealed record Identifier(string[] DirectoryNames, + string Extension, + bool? HasDateTimeOriginal, + int Id, + long Length, + string PaddedId, + long Ticks) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, IdentifierSourceGenerationContext.Default.Identifier); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Identifier))] +public partial class IdentifierSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Identifier[]))] +public partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/src/ImmichToSlideshow/Services/AssetService.cs b/src/ImmichToSlideshow/Services/AssetService.cs index 7ca5a19..66c140f 100644 --- a/src/ImmichToSlideshow/Services/AssetService.cs +++ b/src/ImmichToSlideshow/Services/AssetService.cs @@ -89,6 +89,7 @@ public class AssetService(ILogger logger, AppSettings appSettings) results.Add(" AND a.\"type\" = 'IMAGE' "); results.Add(" AND f.\"type\" = 'preview' "); results.Add(" AND a.\"duplicateId\" is null "); + results.Add(" AND a.\"isArchived\" = false "); results.Add(" AND a.\"isExternal\" = true "); results.Add(" AND a.\"isOffline\" = false "); results.Add(" AND a.\"isVisible\" = true "); @@ -97,6 +98,36 @@ public class AssetService(ILogger logger, AppSettings appSettings) return string.Join(Environment.NewLine, results); } // cSpell:enable + private static string SetAssetArchivedCommandText(string deviceAssetIds) + { // cSpell:disable + List results = new(); + results.Add(" UPDATE assets "); + results.Add(" SET \"isArchived\" = true "); + results.Add(" WHERE \"isArchived\" = false "); + results.Add(" AND \"type\" = 'IMAGE' "); + results.Add(" AND \"ownerId\" = @ownerId "); + results.Add(" AND \"deviceAssetId\" in ( "); + results.Add(deviceAssetIds); + results.Add(" ) "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + private static int? ExecuteNonQuery(string connectionString, string commandText, NpgsqlParameter[] npgsqlParameters) + { + int? result; + if (string.IsNullOrEmpty(connectionString)) + result = null; + else + { + using NpgsqlConnection npgsqlConnection = new(connectionString); + npgsqlConnection.Open(); + using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection); + npgsqlCommand.Parameters.AddRange(npgsqlParameters); + result = npgsqlCommand.ExecuteNonQuery(); + } + return result; + } + private static StringBuilder GetForJsonPath(string connectionString, string commandText, NpgsqlParameter[] npgsqlParameters) { StringBuilder result = new(); @@ -221,4 +252,37 @@ public class AssetService(ILogger logger, AppSettings appSettings) return results.AsReadOnly(); } + public ReadOnlyCollection SetArchiveImmich(Guid ownerId) + { + List results; + string checkDirectory = Path.Combine(_AppSettings.CurrentResultsDirectory, "B)Metadata", _AppSettings.CurrentCommit, "[]"); + if (!Directory.Exists(checkDirectory)) + results = null; + else + { + string checkFile = Path.Combine(checkDirectory, "!9.json"); + if (!File.Exists(checkFile)) + results = null; + else + { + string json = File.ReadAllText(checkFile); + Identifier[]? identifiers = JsonSerializer.Deserialize(json); + if (identifiers is null || identifiers.Length == 0) + results = null; + else + { + string deviceAssetIds = $"'{string.Join($"',{Environment.NewLine}'", identifiers.Select(l => $"{l.PaddedId}{l.Extension}").ToArray())}'"; + string commandText = SetAssetArchivedCommandText(deviceAssetIds); + NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; + int? result = ExecuteNonQuery(_AppSettings.ConnectionString, commandText, npgsqlParameters); + if (result is null) + results = null; + else + results = [result.Value]; + } + } + } + return results?.AsReadOnly(); + } + } \ No newline at end of file