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..248677b 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/archived-tag/ +Accept: application/json + +### diff --git a/src/ImmichToSlideshow/Controllers/AssetsController.cs b/src/ImmichToSlideshow/Controllers/AssetsController.cs index cc65bcb..c158e08 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("archived-tag")] + public IActionResult GetArchivedTag() => + Content(_AssetService.GetArchivedTag(), _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/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..f83ef9f 100644 --- a/src/ImmichToSlideshow/Services/AssetService.cs +++ b/src/ImmichToSlideshow/Services/AssetService.cs @@ -15,104 +15,7 @@ public class AssetService(ILogger logger, AppSettings appSettings) private readonly ILogger _Logger = logger; private readonly AppSettings _AppSettings = appSettings; - 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 +25,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 +47,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 +59,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 +71,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 +83,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 +94,25 @@ public class AssetService(ILogger logger, AppSettings appSettings) return results?.AsReadOnly(); } + public Tag[]? GetArchivedTag(AppSettings appSettings) + { + Tag[] results; + NpgsqlParameter[] npgsqlParameters = []; + string commandText = CommandText.GetArchivedTag(appSettings.ArchivedTag); + StringBuilder stringBuilder = GetForJsonPath(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); + string json = stringBuilder.ToString(); + results = JsonSerializer.Deserialize(json, TagCollectionSourceGenerationContext.Default.TagArray); + return results; + } + + public string? GetArchivedTag() + { + string result; + Tag[]? tags = GetArchivedTag(_AppSettings); + result = tags is null || tags.Length != 1 ? null : tags[0].Id; + return result; + } + public string? SaveRandomPaths(Guid ownerId) { string? results; @@ -252,9 +174,12 @@ public class AssetService(ILogger logger, AppSettings appSettings) return results.AsReadOnly(); } + private static string GetDeviceAssetIds(ReadOnlyCollection identifiers, ReadOnlyCollection assets) => + $"'{string.Join($"',{Environment.NewLine}'", (from l in identifiers where !assets.Contains($"{l.PaddedId}{l.Extension}") select $"{l.PaddedId}{l.Extension}").ToArray())}'"; + 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 +196,47 @@ 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); + if (tags is null || tags.Length != 1) results = null; else - results = [result.Value]; + results = SetArchiveImmich(_AppSettings, ownerId, identifiers, tags); } } } return results?.AsReadOnly(); } + private static ReadOnlyCollection SetArchiveImmich(AppSettings appSettings, Guid ownerId, Identifier[] identifiers, Tag[] tags) + { + ReadOnlyCollection? results; + NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; + string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(appSettings.FilterTags); + StringBuilder stringBuilder = GetForJsonPath(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly()); + string json = stringBuilder.ToString(); + Asset[]? assets = JsonSerializer.Deserialize(json, AssetCollectionSourceGenerationContext.Default.AssetArray); + if (assets is null || assets.Length == 0) + results = null; + else + results = SetArchiveImmich(appSettings, ownerId, identifiers, tags, assets); + return results?.AsReadOnly(); + } + + private static ReadOnlyCollection SetArchiveImmich(AppSettings appSettings, Guid ownerId, Identifier[]? identifiers, Tag[]? tags, Asset[]? assets) + { + ReadOnlyCollection? results; + string tagsId = tags[0].Id; + NpgsqlParameter[] npgsqlParameters = + [ + new NpgsqlParameter(nameof(tagsId), tagsId), + new NpgsqlParameter(nameof(ownerId), ownerId), + ]; + string[] assetDeviceAssetIds = (from l in assets select l.DeviceAssetId).ToArray(); + string deviceAssetIds = GetDeviceAssetIds(identifiers.AsReadOnly(), assetDeviceAssetIds.AsReadOnly()); + string commandText = CommandText.SetAssetArchived(deviceAssetIds); + 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..d7e1dac --- /dev/null +++ b/src/ImmichToSlideshow/Services/CommandText.cs @@ -0,0 +1,118 @@ +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(" ) "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + + internal static string GetArchivedTag(string archivedTag) + { // cSpell:disable + List results = new(); + results.Add(" SELECT json_agg(t) "); + results.Add(" FROM tags t "); + results.Add($" WHERE value = '{archivedTag}' "); + return string.Join(Environment.NewLine, results); + } // cSpell:enable + +} \ No newline at end of file