Insert into asset tag instead of updating is archived field

Convert to Podman
This commit is contained in:
2025-06-15 18:10:52 -07:00
parent ac4e4c277d
commit ab90adee42
10 changed files with 330 additions and 135 deletions

89
.vscode/tasks.json vendored
View File

@ -88,6 +88,84 @@
], ],
"problemMatcher": "$msCompile" "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", "label": "Publish AOT",
"command": "dotnet", "command": "dotnet",
@ -104,17 +182,6 @@
"/consoleloggerparameters:NoSummary" "/consoleloggerparameters:NoSummary"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
},
{
"label": "docker compose up --build",
"command": "docker",
"type": "process",
"args": [
"compose",
"up",
"--build"
],
"problemMatcher": "$msCompile"
} }
] ]
} }

View File

@ -23,8 +23,3 @@ EXPOSE 5001
WORKDIR /app WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
ENTRYPOINT [ "dotnet", "ImmichToSlideshow.dll" ] 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

View File

@ -30,3 +30,10 @@ Accept: application/json
GET {{host}}/api/v1/assets/{{ownerId}}/set-archive-immich/ GET {{host}}/api/v1/assets/{{ownerId}}/set-archive-immich/
Accept: application/json Accept: application/json
###
GET {{host}}/api/v1/assets/{{ownerId}}/archived-tag/
Accept: application/json
###

View File

@ -27,6 +27,10 @@ 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("{ownerId:guid}/archived-tag")]
public IActionResult GetArchivedTag(Guid ownerId) =>
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) =>
Content(_AssetService.SaveRandomPaths(ownerId), _ContentType); Content(_AssetService.SaveRandomPaths(ownerId), _ContentType);

View File

@ -4,10 +4,12 @@ using System.Text.Json.Serialization;
namespace ImmichToSlideshow.Models; namespace ImmichToSlideshow.Models;
public record AppSettings(int AddDays, public record AppSettings(int AddDays,
string ArchivedTag,
string Company, string Company,
string ConnectionString, string ConnectionString,
string CurrentCommit, string CurrentCommit,
string CurrentResultsDirectory, string CurrentResultsDirectory,
string[] FilterTags,
string ImmichUploadDirectory, string ImmichUploadDirectory,
string RandomResultsDirectory, string RandomResultsDirectory,
string SyncDirectory, string SyncDirectory,

View File

@ -7,10 +7,12 @@ public class AppSettings
{ {
public int? AddDays { get; set; } public int? AddDays { get; set; }
public string? ArchivedTag { get; set; }
public string? Company { get; set; } public string? Company { get; set; }
public string? ConnectionString { get; set; } public string? ConnectionString { get; set; }
public string? CurrentCommit { get; set; } public string? CurrentCommit { get; set; }
public string? CurrentResultsDirectory { get; set; } public string? CurrentResultsDirectory { get; set; }
public string[]? FilterTags { get; set; }
public string? ImmichUploadDirectory { get; set; } public string? ImmichUploadDirectory { get; set; }
public string? RandomResultsDirectory { get; set; } public string? RandomResultsDirectory { get; set; }
public string? SyncDirectory { get; set; } public string? SyncDirectory { get; set; }
@ -45,10 +47,12 @@ public class AppSettings
{ {
Models.AppSettings result; Models.AppSettings result;
if (appSettings?.AddDays is null) throw new NullReferenceException(nameof(appSettings.AddDays)); 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?.Company is null) throw new NullReferenceException(nameof(appSettings.Company));
if (appSettings?.ConnectionString is null) throw new NullReferenceException(nameof(appSettings.ConnectionString)); if (appSettings?.ConnectionString is null) throw new NullReferenceException(nameof(appSettings.ConnectionString));
if (appSettings?.CurrentCommit is null) throw new NullReferenceException(nameof(appSettings.CurrentCommit)); if (appSettings?.CurrentCommit is null) throw new NullReferenceException(nameof(appSettings.CurrentCommit));
if (appSettings?.CurrentResultsDirectory is null) throw new NullReferenceException(nameof(appSettings.CurrentResultsDirectory)); 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?.ImmichUploadDirectory is null) throw new NullReferenceException(nameof(appSettings.ImmichUploadDirectory));
if (appSettings?.RandomResultsDirectory is null) throw new NullReferenceException(nameof(appSettings.RandomResultsDirectory)); if (appSettings?.RandomResultsDirectory is null) throw new NullReferenceException(nameof(appSettings.RandomResultsDirectory));
if (appSettings?.SyncDirectory is null) throw new NullReferenceException(nameof(appSettings.SyncDirectory)); 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?.WithOrigins is null) throw new NullReferenceException(nameof(appSettings.WithOrigins));
if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName)); if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName));
result = new(appSettings.AddDays.Value, result = new(appSettings.AddDays.Value,
appSettings.ArchivedTag,
appSettings.Company, appSettings.Company,
appSettings.ConnectionString, appSettings.ConnectionString,
appSettings.CurrentCommit, appSettings.CurrentCommit,
appSettings.CurrentResultsDirectory, appSettings.CurrentResultsDirectory,
appSettings.FilterTags,
appSettings.ImmichUploadDirectory, appSettings.ImmichUploadDirectory,
appSettings.RandomResultsDirectory, appSettings.RandomResultsDirectory,
appSettings.SyncDirectory, appSettings.SyncDirectory,

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

@ -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
{
}

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,107 +11,12 @@ 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 string GetColumnsCommandText() private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters)
{ // cSpell:disable
List<string> 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<string> 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<string> 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<string> 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; int? result;
if (string.IsNullOrEmpty(connectionString)) if (string.IsNullOrEmpty(connectionString))
@ -122,19 +26,19 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
using NpgsqlConnection npgsqlConnection = new(connectionString); using NpgsqlConnection npgsqlConnection = new(connectionString);
npgsqlConnection.Open(); npgsqlConnection.Open();
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection); using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
npgsqlCommand.Parameters.AddRange(npgsqlParameters); npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray());
result = npgsqlCommand.ExecuteNonQuery(); result = npgsqlCommand.ExecuteNonQuery();
} }
return result; return result;
} }
private static StringBuilder GetForJsonPath(string connectionString, string commandText, NpgsqlParameter[] npgsqlParameters) private static StringBuilder GetForJsonPath(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters)
{ {
StringBuilder result = new(); StringBuilder result = new();
using NpgsqlConnection npgsqlConnection = new(connectionString); using NpgsqlConnection npgsqlConnection = new(connectionString);
npgsqlConnection.Open(); npgsqlConnection.Open();
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection); using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
npgsqlCommand.Parameters.AddRange(npgsqlParameters); npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray());
NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.SequentialAccess); NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.SequentialAccess);
while (npgsqlDataReader.Read()) while (npgsqlDataReader.Read())
_ = result.Append(npgsqlDataReader.GetString(0)); _ = result.Append(npgsqlDataReader.GetString(0));
@ -144,9 +48,9 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
public string? GetColumns() public string? GetColumns()
{ {
string result; string result;
string commandText = GetColumnsCommandText();
NpgsqlParameter[] npgsqlParameters = []; NpgsqlParameter[] npgsqlParameters = [];
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); string commandText = CommandText.GetColumns();
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
result = stringBuilder.ToString(); result = stringBuilder.ToString();
if (result.Length == 1) if (result.Length == 1)
File.WriteAllText(".vscode/jsonl/.jsonl", result); File.WriteAllText(".vscode/jsonl/.jsonl", result);
@ -156,9 +60,9 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
public string? GetOwnerIds() public string? GetOwnerIds()
{ {
string result; string result;
string commandText = GetOwnerIdActiveImageCommandText();
NpgsqlParameter[] npgsqlParameters = []; NpgsqlParameter[] npgsqlParameters = [];
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters); string commandText = CommandText.GetOwnerIdActiveImage();
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
result = stringBuilder.ToString(); result = stringBuilder.ToString();
if (result.Length == 1) if (result.Length == 1)
File.WriteAllText(".vscode/jsonl/.jsonl", result); File.WriteAllText(".vscode/jsonl/.jsonl", result);
@ -168,9 +72,9 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
public string? GetAssets(Guid ownerId) public string? GetAssets(Guid ownerId)
{ {
string result; string result;
string commandText = GetAssetActiveImagePreviewNotDuplicateCommandText();
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; 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(); result = stringBuilder.ToString();
if (result.Length == 1) if (result.Length == 1)
File.WriteAllText(".vscode/jsonl/assets.jsonl", result); File.WriteAllText(".vscode/jsonl/assets.jsonl", result);
@ -180,9 +84,9 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId) public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId)
{ {
string[]? results; string[]? results;
string commandText = GetAssetActiveImagePreviewNotDuplicateCommandText();
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)]; 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(); string json = stringBuilder.ToString();
Random random = new(); Random random = new();
string ownerIdValue = ownerId.ToString(); string ownerIdValue = ownerId.ToString();
@ -191,6 +95,31 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
return results?.AsReadOnly(); 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) public string? SaveRandomPaths(Guid ownerId)
{ {
string? results; string? results;
@ -254,7 +183,7 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
public ReadOnlyCollection<int> SetArchiveImmich(Guid ownerId) public ReadOnlyCollection<int> SetArchiveImmich(Guid ownerId)
{ {
List<int> results; ReadOnlyCollection<int>? results;
string checkDirectory = Path.Combine(_AppSettings.CurrentResultsDirectory, "B)Metadata", _AppSettings.CurrentCommit, "[]"); string checkDirectory = Path.Combine(_AppSettings.CurrentResultsDirectory, "B)Metadata", _AppSettings.CurrentCommit, "[]");
if (!Directory.Exists(checkDirectory)) if (!Directory.Exists(checkDirectory))
results = null; results = null;
@ -271,18 +200,32 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
results = null; results = null;
else else
{ {
string deviceAssetIds = $"'{string.Join($"',{Environment.NewLine}'", identifiers.Select(l => $"{l.PaddedId}{l.Extension}").ToArray())}'"; Tag[]? tags = GetArchivedTag(_AppSettings, ownerId);
string commandText = SetAssetArchivedCommandText(deviceAssetIds); if (tags is null || tags.Length != 1)
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
int? result = ExecuteNonQuery(_AppSettings.ConnectionString, commandText, npgsqlParameters);
if (result is null)
results = null; results = null;
else else
results = [result.Value]; results = SetArchiveImmich(logger, appSettings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
} }
} }
} }
return results?.AsReadOnly(); return results?.AsReadOnly();
} }
private static ReadOnlyCollection<int> SetArchiveImmich(ILogger<Program> logger, AppSettings appSettings, Guid ownerId, ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<Tag> tags)
{
ReadOnlyCollection<int>? 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();
}
} }

View File

@ -0,0 +1,130 @@
namespace ImmichToSlideshow.Services;
internal static class CommandText
{
internal static string GetColumns()
{ // cSpell:disable
List<string> 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<string> 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<string> 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<string> 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<string> 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
}