From ab90adee421f84ee402dc2edabf75ecbdb55ea63 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 15 Jun 2025 18:10:52 -0700 Subject: [PATCH] Insert into asset tag instead of updating is archived field Convert to Podman --- .vscode/tasks.json | 89 +++++++-- Dockerfile | 7 +- requests/ImmichToSlideshow.http | 9 +- .../Controllers/AssetsController.cs | 4 + src/ImmichToSlideshow/Models/AppSettings.cs | 2 + .../Models/Binder/AppSettings.cs | 6 + src/ImmichToSlideshow/Models/Identifier.cs | 7 + src/ImmichToSlideshow/Models/Immich/Tag.cs | 34 ++++ .../Services/AssetService.cs | 177 ++++++------------ src/ImmichToSlideshow/Services/CommandText.cs | 130 +++++++++++++ 10 files changed, 330 insertions(+), 135 deletions(-) create mode 100644 src/ImmichToSlideshow/Models/Immich/Tag.cs create mode 100644 src/ImmichToSlideshow/Services/CommandText.cs diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4052324..f335709 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -88,6 +88,84 @@ ], "problemMatcher": "$msCompile" }, + { + "label": "podman-login", + "command": "podman", + "type": "process", + "args": [ + "login", + "gitea.phares.duckdns.org:443" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-compose-up-build", + "command": "podman", + "type": "process", + "args": [ + "compose", + "up", + "--build" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-build", + "command": "podman", + "type": "process", + "args": [ + "build", + "-t", + "immich-to-slideshow", + "." + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-image-list", + "command": "podman", + "type": "process", + "args": [ + "image", + "ls" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-run", + "command": "podman", + "type": "process", + "args": [ + "run", + "-p", + "5001:5001", + "--name", + "immich-to-slideshow_webapp", + "a3de856b5731" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-tag", + "command": "podman", + "type": "process", + "args": [ + "tag", + "asdf", + "gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "podman-push", + "command": "podman", + "type": "process", + "args": [ + "push", + "gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest" + ], + "problemMatcher": "$msCompile" + }, { "label": "Publish AOT", "command": "dotnet", @@ -104,17 +182,6 @@ "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" - }, - { - "label": "docker compose up --build", - "command": "docker", - "type": "process", - "args": [ - "compose", - "up", - "--build" - ], - "problemMatcher": "$msCompile" } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 975ad84..8f99424 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,9 +22,4 @@ ENV ASPNETCORE_HTTP_PORTS=5001 EXPOSE 5001 WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT [ "dotnet", "ImmichToSlideshow.dll" ] - -# docker build -t sprint-console-001 . -# docker images ls | grep -i 001 -# docker run -p 5001:5001 --name sprint-console-api-001 sprint-console-001 -# docker run -p 5001:5001 --name sprint-console-api-001 sprint-console-001 \ No newline at end of file +ENTRYPOINT [ "dotnet", "ImmichToSlideshow.dll" ] \ No newline at end of file diff --git a/requests/ImmichToSlideshow.http b/requests/ImmichToSlideshow.http index b32050e..2116a99 100644 --- a/requests/ImmichToSlideshow.http +++ b/requests/ImmichToSlideshow.http @@ -29,4 +29,11 @@ Accept: application/json ### GET {{host}}/api/v1/assets/{{ownerId}}/set-archive-immich/ -Accept: application/json \ No newline at end of file +Accept: application/json + +### + +GET {{host}}/api/v1/assets/{{ownerId}}/archived-tag/ +Accept: application/json + +### diff --git a/src/ImmichToSlideshow/Controllers/AssetsController.cs b/src/ImmichToSlideshow/Controllers/AssetsController.cs index cc65bcb..55d4899 100644 --- a/src/ImmichToSlideshow/Controllers/AssetsController.cs +++ b/src/ImmichToSlideshow/Controllers/AssetsController.cs @@ -27,6 +27,10 @@ public class AssetsController(AssetService assetService) : ControllerBase public IActionResult GetRandomPaths(Guid ownerId) => Ok(_AssetService.GetRandomPaths(ownerId)); + [HttpGet("{ownerId:guid}/archived-tag")] + public IActionResult GetArchivedTag(Guid ownerId) => + Content(_AssetService.GetArchivedTag(ownerId), _ContentType); + [HttpGet("{ownerId:guid}/save-random-paths")] public IActionResult SaveRandomPaths(Guid ownerId) => Content(_AssetService.SaveRandomPaths(ownerId), _ContentType); diff --git a/src/ImmichToSlideshow/Models/AppSettings.cs b/src/ImmichToSlideshow/Models/AppSettings.cs index 064ccca..0845815 100644 --- a/src/ImmichToSlideshow/Models/AppSettings.cs +++ b/src/ImmichToSlideshow/Models/AppSettings.cs @@ -4,10 +4,12 @@ using System.Text.Json.Serialization; namespace ImmichToSlideshow.Models; public record AppSettings(int AddDays, + string ArchivedTag, string Company, string ConnectionString, string CurrentCommit, string CurrentResultsDirectory, + string[] FilterTags, string ImmichUploadDirectory, string RandomResultsDirectory, string SyncDirectory, diff --git a/src/ImmichToSlideshow/Models/Binder/AppSettings.cs b/src/ImmichToSlideshow/Models/Binder/AppSettings.cs index 453b2aa..d1bc484 100644 --- a/src/ImmichToSlideshow/Models/Binder/AppSettings.cs +++ b/src/ImmichToSlideshow/Models/Binder/AppSettings.cs @@ -7,10 +7,12 @@ public class AppSettings { public int? AddDays { get; set; } + public string? ArchivedTag { get; set; } public string? Company { get; set; } public string? ConnectionString { get; set; } public string? CurrentCommit { get; set; } public string? CurrentResultsDirectory { get; set; } + public string[]? FilterTags { get; set; } public string? ImmichUploadDirectory { get; set; } public string? RandomResultsDirectory { get; set; } public string? SyncDirectory { get; set; } @@ -45,10 +47,12 @@ public class AppSettings { Models.AppSettings result; if (appSettings?.AddDays is null) throw new NullReferenceException(nameof(appSettings.AddDays)); + if (appSettings?.ArchivedTag is null) throw new NullReferenceException(nameof(appSettings.ArchivedTag)); 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?.FilterTags is null) throw new NullReferenceException(nameof(appSettings.FilterTags)); 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)); @@ -56,10 +60,12 @@ public class AppSettings if (appSettings?.WithOrigins is null) throw new NullReferenceException(nameof(appSettings.WithOrigins)); if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName)); result = new(appSettings.AddDays.Value, + appSettings.ArchivedTag, appSettings.Company, appSettings.ConnectionString, appSettings.CurrentCommit, appSettings.CurrentResultsDirectory, + appSettings.FilterTags, appSettings.ImmichUploadDirectory, appSettings.RandomResultsDirectory, appSettings.SyncDirectory, diff --git a/src/ImmichToSlideshow/Models/Identifier.cs b/src/ImmichToSlideshow/Models/Identifier.cs index 2bfe45e..9b671e3 100644 --- a/src/ImmichToSlideshow/Models/Identifier.cs +++ b/src/ImmichToSlideshow/Models/Identifier.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Text.Json; using System.Text.Json.Serialization; @@ -18,6 +19,12 @@ public sealed record Identifier(string[] DirectoryNames, return result; } + internal static string GetDeviceAssetIds(ReadOnlyCollection identifiers) => + $"'{string.Join($"',{Environment.NewLine}'", (from l in identifiers select GetDeviceAssetId(l)).ToArray())}'"; + + internal static string GetDeviceAssetId(Identifier identifier) => + $"{identifier.PaddedId}{identifier.Extension}"; + } [JsonSourceGenerationOptions(WriteIndented = true)] diff --git a/src/ImmichToSlideshow/Models/Immich/Tag.cs b/src/ImmichToSlideshow/Models/Immich/Tag.cs new file mode 100644 index 0000000..86d7651 --- /dev/null +++ b/src/ImmichToSlideshow/Models/Immich/Tag.cs @@ -0,0 +1,34 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ImmichToSlideshow.Models.Immich; + +public record Tag([property: JsonPropertyName("id")] string Id, + [property: JsonPropertyName("userId")] string UserId, + [property: JsonPropertyName("value")] string OwnerId, + // [property: JsonPropertyName("createdAt")] DateTime CreatedAt, + // [property: JsonPropertyName("updatedAt")] DateTime UpdatedAt, + // [property: JsonPropertyName("color")] char Color, + // [property: JsonPropertyName("parentId")] string ParentId, + [property: JsonPropertyName("updateId")] string UpdateId) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, TagSourceGenerationContext.Default.Tag); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Tag))] +internal partial class TagSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Tag[]))] +internal partial class TagCollectionSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/src/ImmichToSlideshow/Services/AssetService.cs b/src/ImmichToSlideshow/Services/AssetService.cs index 66c140f..fb1c6b2 100644 --- a/src/ImmichToSlideshow/Services/AssetService.cs +++ b/src/ImmichToSlideshow/Services/AssetService.cs @@ -1,6 +1,5 @@ using ImmichToSlideshow.Models; using ImmichToSlideshow.Models.Immich; -using Microsoft.AspNetCore.Mvc; using Npgsql; using System.Collections.ObjectModel; using System.Data; @@ -12,107 +11,12 @@ namespace ImmichToSlideshow.Services; public class AssetService(ILogger logger, AppSettings appSettings) { +#pragma warning disable CS9124 private readonly ILogger _Logger = logger; private readonly AppSettings _AppSettings = appSettings; +#pragma warning restore CS9124 - private static string GetColumnsCommandText() - { // cSpell:disable - List results = new(); - // results.Add(" SELECT COALESCE(SUM(checksum_failures), 0) "); - // results.Add(" FROM pg_stat_database "); - // results.Add(" SELECT json_agg(t) "); - // results.Add(" FROM information_schema.tables t "); - // results.Add(" WHERE table_schema='public' "); - // results.Add(" AND table_type='BASE TABLE' "); - results.Add(" SELECT json_agg(c) "); - results.Add(" FROM information_schema.columns c "); - // results.Add(" WHERE table_name ='assets' "); - // results.Add(" WHERE table_name ='libraries' "); - results.Add(" WHERE table_name ='asset_files' "); - return string.Join(Environment.NewLine, results); - } // cSpell:enable - - private static string GetOwnerIdActiveImageCommandText() - { // cSpell:disable - List results = new(); - results.Add(" SELECT json_agg(j) "); - results.Add(" FROM ( "); - results.Add(" SELECT a.\"ownerId\" "); - results.Add(" FROM assets a "); - results.Add(" WHERE a.\"status\" = 'active' "); - results.Add(" AND a.\"type\" = 'IMAGE' "); - results.Add(" GROUP"); - results.Add(" BY a.\"ownerId\" "); - results.Add(" ) j "); - return string.Join(Environment.NewLine, results); - } // cSpell:enable - - private static string GetAssetActiveImagePreviewNotDuplicateCommandText() - { // cSpell:disable - List results = new(); - results.Add(" SELECT json_agg(j) "); - results.Add(" FROM ( "); - results.Add(" SELECT a.\"id\" "); - results.Add(" , a.\"deviceAssetId\" "); - // results.Add(" , a.\"ownerId\" "); - // results.Add(" , a.\"deviceId\" "); - // results.Add(" , a.\"type\" "); - results.Add(" , a.\"originalPath\" "); - // results.Add(" , a.\"fileCreatedAt\" "); - // results.Add(" , a.\"fileModifiedAt\" "); - // results.Add(" , a.\"isFavorite\" "); - // results.Add(" , a.\"duration\" "); - // results.Add(" , a.\"encodedVideoPath\" "); - // results.Add(" , a.\"checksum\" "); - // results.Add(" , a.\"isVisible\" "); - // results.Add(" , a.\"livePhotoVideoId\" "); - // results.Add(" , a.\"updatedAt\" "); - // results.Add(" , a.\"createdAt\" "); - // results.Add(" , a.\"isArchived\" "); - results.Add(" , a.\"originalFileName\" "); - // results.Add(" , a.\"sidecarPath\" "); - // results.Add(" , a.\"thumbhash\" "); - // results.Add(" , a.\"isOffline\" "); - // results.Add(" , a.\"libraryId\" "); - // results.Add(" , a.\"isExternal\" "); - // results.Add(" , a.\"deletedAt\" "); - // results.Add(" , a.\"localDateTime\" "); - // results.Add(" , a.\"stackId\" "); - results.Add(" , a.\"duplicateId\" "); - // results.Add(" , a.\"status\" "); - results.Add(" , f.\"path\" "); - results.Add(" FROM assets a "); - results.Add(" INNER "); - results.Add(" JOIN asset_files f "); - results.Add(" ON a.\"id\" = f.\"assetId\" "); - results.Add(" WHERE a.\"status\" = 'active' "); - 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 "); - results.Add(" AND a.\"ownerId\" = @ownerId "); - results.Add(" ) j "); - 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) + private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection npgsqlParameters) { int? result; if (string.IsNullOrEmpty(connectionString)) @@ -122,19 +26,19 @@ public class AssetService(ILogger logger, AppSettings appSettings) using NpgsqlConnection npgsqlConnection = new(connectionString); npgsqlConnection.Open(); using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection); - npgsqlCommand.Parameters.AddRange(npgsqlParameters); + npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray()); result = npgsqlCommand.ExecuteNonQuery(); } return result; } - private static StringBuilder GetForJsonPath(string connectionString, string commandText, NpgsqlParameter[] npgsqlParameters) + private static StringBuilder GetForJsonPath(string connectionString, string commandText, ReadOnlyCollection npgsqlParameters) { StringBuilder result = new(); using NpgsqlConnection npgsqlConnection = new(connectionString); npgsqlConnection.Open(); using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection); - npgsqlCommand.Parameters.AddRange(npgsqlParameters); + npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray()); NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.SequentialAccess); while (npgsqlDataReader.Read()) _ = result.Append(npgsqlDataReader.GetString(0)); @@ -144,9 +48,9 @@ public class AssetService(ILogger logger, AppSettings appSettings) public string? GetColumns() { string result; - string commandText = GetColumnsCommandText(); NpgsqlParameter[] npgsqlParameters = []; - StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); + string commandText = CommandText.GetColumns(); + StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); result = stringBuilder.ToString(); if (result.Length == 1) File.WriteAllText(".vscode/jsonl/.jsonl", result); @@ -156,9 +60,9 @@ public class AssetService(ILogger logger, AppSettings appSettings) public string? GetOwnerIds() { string result; - string commandText = GetOwnerIdActiveImageCommandText(); NpgsqlParameter[] npgsqlParameters = []; - StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); + string commandText = CommandText.GetOwnerIdActiveImage(); + StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); result = stringBuilder.ToString(); if (result.Length == 1) File.WriteAllText(".vscode/jsonl/.jsonl", result); @@ -168,9 +72,9 @@ public class AssetService(ILogger logger, AppSettings appSettings) public string? GetAssets(Guid ownerId) { string result; - string commandText = GetAssetActiveImagePreviewNotDuplicateCommandText(); NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; - StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); + string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_AppSettings.FilterTags); + StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); result = stringBuilder.ToString(); if (result.Length == 1) File.WriteAllText(".vscode/jsonl/assets.jsonl", result); @@ -180,9 +84,9 @@ public class AssetService(ILogger logger, AppSettings appSettings) public ReadOnlyCollection? GetRandomPaths(Guid ownerId) { string[]? results; - string commandText = GetAssetActiveImagePreviewNotDuplicateCommandText(); NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; - StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); + string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_AppSettings.FilterTags); + StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); string json = stringBuilder.ToString(); Random random = new(); string ownerIdValue = ownerId.ToString(); @@ -191,6 +95,31 @@ public class AssetService(ILogger logger, AppSettings appSettings) return results?.AsReadOnly(); } + public Tag[]? GetArchivedTag(AppSettings appSettings, Guid ownerId) + { + Tag[] results; + Guid userId = ownerId; + string value = appSettings.ArchivedTag; + NpgsqlParameter[] npgsqlParameters = + [ + new NpgsqlParameter(nameof(value), value), + new NpgsqlParameter(nameof(userId), userId), + ]; + string commandText = CommandText.GetArchivedTag(); + StringBuilder stringBuilder = GetForJsonPath(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); + string json = stringBuilder.ToString(); + results = JsonSerializer.Deserialize(json, TagCollectionSourceGenerationContext.Default.TagArray); + return results; + } + + public string? GetArchivedTag(Guid ownerId) + { + string result; + Tag[]? tags = GetArchivedTag(_AppSettings, ownerId); + result = tags is null || tags.Length != 1 ? null : tags[0].Id; + return result; + } + public string? SaveRandomPaths(Guid ownerId) { string? results; @@ -254,7 +183,7 @@ public class AssetService(ILogger logger, AppSettings appSettings) public ReadOnlyCollection SetArchiveImmich(Guid ownerId) { - List results; + ReadOnlyCollection? results; string checkDirectory = Path.Combine(_AppSettings.CurrentResultsDirectory, "B)Metadata", _AppSettings.CurrentCommit, "[]"); if (!Directory.Exists(checkDirectory)) results = null; @@ -271,18 +200,32 @@ public class AssetService(ILogger logger, AppSettings appSettings) 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) + Tag[]? tags = GetArchivedTag(_AppSettings, ownerId); + if (tags is null || tags.Length != 1) results = null; else - results = [result.Value]; + results = SetArchiveImmich(logger, appSettings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly()); } } } return results?.AsReadOnly(); } + private static ReadOnlyCollection SetArchiveImmich(ILogger logger, AppSettings appSettings, Guid ownerId, ReadOnlyCollection identifiers, ReadOnlyCollection tags) + { + ReadOnlyCollection? results; + string tagsId = tags[0].Id; + NpgsqlParameter[] npgsqlParameters = + [ + new NpgsqlParameter(nameof(tagsId), tagsId), + new NpgsqlParameter(nameof(ownerId), ownerId), + ]; + string deviceAssetIds = Identifier.GetDeviceAssetIds(identifiers); + string commandText = CommandText.SetAssetArchived(deviceAssetIds); + logger.LogDebug(commandText.Replace($"@{nameof(tagsId)}", $"'{tagsId}'").Replace($"@{nameof(ownerId)}", $"'{ownerId}'".ToString())); + int? result = ExecuteNonQuery(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); + results = result is null ? null : new([result.Value]); + return results?.AsReadOnly(); + } + } \ No newline at end of file diff --git a/src/ImmichToSlideshow/Services/CommandText.cs b/src/ImmichToSlideshow/Services/CommandText.cs new file mode 100644 index 0000000..01d223a --- /dev/null +++ b/src/ImmichToSlideshow/Services/CommandText.cs @@ -0,0 +1,130 @@ +namespace ImmichToSlideshow.Services; + +internal static class CommandText +{ + + internal static string GetColumns() + { // cSpell:disable + List results = new(); + // results.Add(" SELECT COALESCE(SUM(checksum_failures), 0) "); + // results.Add(" FROM pg_stat_database "); + // results.Add(" SELECT json_agg(t) "); + // results.Add(" FROM information_schema.tables t "); + // results.Add(" WHERE table_schema= 'public' "); + // results.Add(" AND table_type= 'BASE TABLE' "); + results.Add(" SELECT json_agg(c) "); + results.Add(" FROM information_schema.columns c "); + // results.Add(" WHERE table_name = 'assets' "); + // results.Add(" WHERE table_name = 'libraries' "); + results.Add(" WHERE table_name = 'asset_files' "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + internal static string GetOwnerIdActiveImage() + { // cSpell:disable + List results = new(); + results.Add(" SELECT json_agg(j) "); + results.Add(" FROM ( "); + results.Add(" SELECT a.\"ownerId\" "); + results.Add(" FROM assets a "); + results.Add(" WHERE a.\"status\" = 'active' "); + results.Add(" AND a.\"type\" = 'IMAGE' "); + results.Add(" GROUP"); + results.Add(" BY a.\"ownerId\" "); + results.Add(" ) j "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + internal static string GetAssetActiveImagePreviewNotDuplicate(string[] filterTags) + { // cSpell:disable + List results = new(); + results.Add(" SELECT json_agg(j) "); + results.Add(" FROM ( "); + results.Add(" SELECT a.\"id\" "); + results.Add(" , a.\"deviceAssetId\" "); + // results.Add(" , a.\"ownerId\" "); + // results.Add(" , a.\"deviceId\" "); + // results.Add(" , a.\"type\" "); + results.Add(" , a.\"originalPath\" "); + // results.Add(" , a.\"fileCreatedAt\" "); + // results.Add(" , a.\"fileModifiedAt\" "); + // results.Add(" , a.\"isFavorite\" "); + // results.Add(" , a.\"duration\" "); + // results.Add(" , a.\"encodedVideoPath\" "); + // results.Add(" , a.\"checksum\" "); + // results.Add(" , a.\"isVisible\" "); + // results.Add(" , a.\"livePhotoVideoId\" "); + // results.Add(" , a.\"updatedAt\" "); + // results.Add(" , a.\"createdAt\" "); + // results.Add(" , a.\"isArchived\" "); + results.Add(" , a.\"originalFileName\" "); + // results.Add(" , a.\"sidecarPath\" "); + // results.Add(" , a.\"thumbhash\" "); + // results.Add(" , a.\"isOffline\" "); + // results.Add(" , a.\"libraryId\" "); + // results.Add(" , a.\"isExternal\" "); + // results.Add(" , a.\"deletedAt\" "); + // results.Add(" , a.\"localDateTime\" "); + // results.Add(" , a.\"stackId\" "); + results.Add(" , a.\"duplicateId\" "); + // results.Add(" , a.\"status\" "); + results.Add(" , f.\"path\" "); + results.Add(" FROM assets a "); + results.Add(" INNER "); + results.Add(" JOIN asset_files f "); + results.Add(" ON a.\"id\" = f.\"assetId\" "); + results.Add(" WHERE a.\"status\" = 'active' "); + results.Add(" AND a.\"type\" = 'IMAGE' "); + results.Add(" AND f.\"type\" = 'preview' "); + results.Add(" AND a.\"duplicateId\" is null "); + results.Add(" AND a.\"id\" not in ( "); + results.Add(" SELECT \"assetsId\" "); + results.Add(" FROM tag_asset g "); + results.Add(" JOIN tags t "); + results.Add(" ON g.\"tagsId\" = t.\"id\" "); + results.Add($" WHERE t.\"value\" in ('{string.Join("','", filterTags)}') "); + results.Add(" ) "); + results.Add(" AND a.\"isExternal\" = true "); + results.Add(" AND a.\"isOffline\" = false "); + results.Add(" AND a.\"ownerId\" = @ownerId "); + results.Add(" ) j "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + internal static string SetAssetArchived(string deviceAssetIds) + { // cSpell:disable + List results = new(); + results.Add(" INSERT INTO tag_asset "); + results.Add(" (\"assetsId\", \"tagsId\") "); + results.Add(" SELECT a.\"id\", @tagsId::uuid "); + results.Add(" FROM assets a "); + results.Add(" WHERE a.\"type\" = 'IMAGE' "); + results.Add(" AND a.\"ownerId\" = @ownerId "); + results.Add(" AND a.\"deviceAssetId\" in ( "); + results.Add(deviceAssetIds); + results.Add(" ) "); + results.Add(" AND a.\"id\" not in ( "); + results.Add(" SELECT \"id\" "); + results.Add(" FROM assets b "); + results.Add(" INNER "); + results.Add(" JOIN tag_asset t "); + results.Add(" ON b.\"id\" = t.\"assetsId\" "); + results.Add(" WHERE t.\"tagsId\" = @tagsId::uuid "); + results.Add(" AND b.\"deviceAssetId\" in ( "); + results.Add(deviceAssetIds); + results.Add(" ) "); + results.Add(" ) "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + internal static string GetArchivedTag() + { // cSpell:disable + List results = new(); + results.Add(" SELECT json_agg(t) "); + results.Add(" FROM tags t "); + results.Add($" WHERE t.\"value\" = @value "); + results.Add(" AND t.\"userId\" = @userId "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + +} \ No newline at end of file