Compare commits

..

1 Commits

Author SHA1 Message Date
ab90adee42 Insert into asset tag instead of updating is archived field
Convert to Podman
2025-06-15 18:10:52 -07:00
5 changed files with 47 additions and 39 deletions

View File

@ -33,7 +33,7 @@ Accept: application/json
### ###
GET {{host}}/api/v1/assets/archived-tag/ GET {{host}}/api/v1/assets/{{ownerId}}/archived-tag/
Accept: application/json Accept: application/json
### ###

View File

@ -27,9 +27,9 @@ public class AssetsController(AssetService assetService) : ControllerBase
public IActionResult GetRandomPaths(Guid ownerId) => public IActionResult GetRandomPaths(Guid ownerId) =>
Ok(_AssetService.GetRandomPaths(ownerId)); Ok(_AssetService.GetRandomPaths(ownerId));
[HttpGet("archived-tag")] [HttpGet("{ownerId:guid}/archived-tag")]
public IActionResult GetArchivedTag() => public IActionResult GetArchivedTag(Guid ownerId) =>
Content(_AssetService.GetArchivedTag(), _ContentType); Content(_AssetService.GetArchivedTag(ownerId), _ContentType);
[HttpGet("{ownerId:guid}/save-random-paths")] [HttpGet("{ownerId:guid}/save-random-paths")]
public IActionResult SaveRandomPaths(Guid ownerId) => public IActionResult SaveRandomPaths(Guid ownerId) =>

View File

@ -1,3 +1,4 @@
using System.Collections.ObjectModel;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@ -18,6 +19,12 @@ public sealed record Identifier(string[] DirectoryNames,
return result; return result;
} }
internal static string GetDeviceAssetIds(ReadOnlyCollection<Identifier> 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)] [JsonSourceGenerationOptions(WriteIndented = true)]

View File

@ -1,6 +1,5 @@
using ImmichToSlideshow.Models; using ImmichToSlideshow.Models;
using ImmichToSlideshow.Models.Immich; using ImmichToSlideshow.Models.Immich;
using Microsoft.AspNetCore.Mvc;
using Npgsql; using Npgsql;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Data; using System.Data;
@ -12,8 +11,10 @@ namespace ImmichToSlideshow.Services;
public class AssetService(ILogger<Program> logger, AppSettings appSettings) public class AssetService(ILogger<Program> logger, AppSettings appSettings)
{ {
#pragma warning disable CS9124
private readonly ILogger<Program> _Logger = logger; private readonly ILogger<Program> _Logger = logger;
private readonly AppSettings _AppSettings = appSettings; private readonly AppSettings _AppSettings = appSettings;
#pragma warning restore CS9124
private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters) private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters)
{ {
@ -94,21 +95,27 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
return results?.AsReadOnly(); return results?.AsReadOnly();
} }
public Tag[]? GetArchivedTag(AppSettings appSettings) public Tag[]? GetArchivedTag(AppSettings appSettings, Guid ownerId)
{ {
Tag[] results; Tag[] results;
NpgsqlParameter[] npgsqlParameters = []; Guid userId = ownerId;
string commandText = CommandText.GetArchivedTag(appSettings.ArchivedTag); 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()); StringBuilder stringBuilder = GetForJsonPath(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
string json = stringBuilder.ToString(); string json = stringBuilder.ToString();
results = JsonSerializer.Deserialize(json, TagCollectionSourceGenerationContext.Default.TagArray); results = JsonSerializer.Deserialize(json, TagCollectionSourceGenerationContext.Default.TagArray);
return results; return results;
} }
public string? GetArchivedTag() public string? GetArchivedTag(Guid ownerId)
{ {
string result; string result;
Tag[]? tags = GetArchivedTag(_AppSettings); Tag[]? tags = GetArchivedTag(_AppSettings, ownerId);
result = tags is null || tags.Length != 1 ? null : tags[0].Id; result = tags is null || tags.Length != 1 ? null : tags[0].Id;
return result; return result;
} }
@ -174,9 +181,6 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static string GetDeviceAssetIds(ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<string> assets) =>
$"'{string.Join($"',{Environment.NewLine}'", (from l in identifiers where !assets.Contains($"{l.PaddedId}{l.Extension}") select $"{l.PaddedId}{l.Extension}").ToArray())}'";
public ReadOnlyCollection<int> SetArchiveImmich(Guid ownerId) public ReadOnlyCollection<int> SetArchiveImmich(Guid ownerId)
{ {
ReadOnlyCollection<int>? results; ReadOnlyCollection<int>? results;
@ -196,33 +200,18 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
results = null; results = null;
else else
{ {
Tag[]? tags = GetArchivedTag(_AppSettings); Tag[]? tags = GetArchivedTag(_AppSettings, ownerId);
if (tags is null || tags.Length != 1) if (tags is null || tags.Length != 1)
results = null; results = null;
else else
results = SetArchiveImmich(_AppSettings, ownerId, identifiers, tags); results = SetArchiveImmich(logger, appSettings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
} }
} }
} }
return results?.AsReadOnly(); return results?.AsReadOnly();
} }
private static ReadOnlyCollection<int> SetArchiveImmich(AppSettings appSettings, Guid ownerId, Identifier[] identifiers, Tag[] tags) private static ReadOnlyCollection<int> SetArchiveImmich(ILogger<Program> logger, AppSettings appSettings, Guid ownerId, ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<Tag> tags)
{
ReadOnlyCollection<int>? 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<int> SetArchiveImmich(AppSettings appSettings, Guid ownerId, Identifier[]? identifiers, Tag[]? tags, Asset[]? assets)
{ {
ReadOnlyCollection<int>? results; ReadOnlyCollection<int>? results;
string tagsId = tags[0].Id; string tagsId = tags[0].Id;
@ -231,9 +220,9 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
new NpgsqlParameter(nameof(tagsId), tagsId), new NpgsqlParameter(nameof(tagsId), tagsId),
new NpgsqlParameter(nameof(ownerId), ownerId), new NpgsqlParameter(nameof(ownerId), ownerId),
]; ];
string[] assetDeviceAssetIds = (from l in assets select l.DeviceAssetId).ToArray(); string deviceAssetIds = Identifier.GetDeviceAssetIds(identifiers);
string deviceAssetIds = GetDeviceAssetIds(identifiers.AsReadOnly(), assetDeviceAssetIds.AsReadOnly());
string commandText = CommandText.SetAssetArchived(deviceAssetIds); 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()); int? result = ExecuteNonQuery(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
results = result is null ? null : new([result.Value]); results = result is null ? null : new([result.Value]);
return results?.AsReadOnly(); return results?.AsReadOnly();

View File

@ -98,20 +98,32 @@ internal static class CommandText
results.Add(" (\"assetsId\", \"tagsId\") "); results.Add(" (\"assetsId\", \"tagsId\") ");
results.Add(" SELECT a.\"id\", @tagsId::uuid "); results.Add(" SELECT a.\"id\", @tagsId::uuid ");
results.Add(" FROM assets a "); results.Add(" FROM assets a ");
results.Add(" WHERE a.\"type\" = 'IMAGE' "); results.Add(" WHERE a.\"type\" = 'IMAGE' ");
results.Add(" AND a.\"ownerId\" = @ownerId "); results.Add(" AND a.\"ownerId\" = @ownerId ");
results.Add(" AND a.\"deviceAssetId\" in ( "); results.Add(" AND a.\"deviceAssetId\" in ( ");
results.Add(deviceAssetIds); results.Add(deviceAssetIds);
results.Add(" ) "); 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); return string.Join(Environment.NewLine, results);
} // cSpell:enable } // cSpell:enable
internal static string GetArchivedTag(string archivedTag) internal static string GetArchivedTag()
{ // cSpell:disable { // cSpell:disable
List<string> results = new(); List<string> results = new();
results.Add(" SELECT json_agg(t) "); results.Add(" SELECT json_agg(t) ");
results.Add(" FROM tags t "); results.Add(" FROM tags t ");
results.Add($" WHERE value = '{archivedTag}' "); results.Add($" WHERE t.\"value\" = @value ");
results.Add(" AND t.\"userId\" = @userId ");
return string.Join(Environment.NewLine, results); return string.Join(Environment.NewLine, results);
} // cSpell:enable } // cSpell:enable