Files
immich-to-slideshow/src/ImmichToSlideshow/Services/AssetService.cs
mikep@0027C8334BC77C8 8034f79753 Birthday
hurl file over http file

AddControllers

Formatting
2025-09-20 14:18:46 -07:00

283 lines
13 KiB
C#

using ImmichToSlideshow.Domain;
using ImmichToSlideshow.Models;
using ImmichToSlideshow.Models.Immich;
using Npgsql;
using System.Collections.ObjectModel;
using System.Data;
using System.Text;
using System.Text.Json;
namespace ImmichToSlideshow.Services;
public class AssetService(ILogger<Program> logger, AppSettings appSettings) {
#pragma warning disable CS9124
private readonly ILogger<Program> _Logger = logger;
private readonly Settings _Settings = appSettings.Settings;
#pragma warning restore CS9124
private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection<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.ToArray());
result = npgsqlCommand.ExecuteNonQuery();
}
return result;
}
private static StringBuilder GetForJsonPath(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters) {
StringBuilder result = new();
using NpgsqlConnection npgsqlConnection = new(connectionString);
npgsqlConnection.Open();
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray());
NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.SequentialAccess);
while (npgsqlDataReader.Read()) {
_ = result.Append(npgsqlDataReader.GetString(0));
}
return result;
}
public string? GetColumns() {
string result;
NpgsqlParameter[] npgsqlParameters = [];
string commandText = CommandText.GetColumns();
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
result = stringBuilder.ToString();
if (result.Length == 1) {
File.WriteAllText(".vscode/jsonl/.jsonl", result);
}
return result;
}
public string? GetOwnerIds() {
string result;
NpgsqlParameter[] npgsqlParameters = [];
string commandText = CommandText.GetOwnerIdActiveImage(_Settings.LowestVersionHistory);
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
result = stringBuilder.ToString();
if (result.Length == 1) {
File.WriteAllText(".vscode/jsonl/.jsonl", result);
}
return result;
}
public string? GetAssets(Guid ownerId) {
string result;
ReadOnlyCollection<string> people = Array.Empty<string>().AsReadOnly();
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people);
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
result = stringBuilder.ToString();
if (result.Length == 1) {
File.WriteAllText(".vscode/jsonl/assets.jsonl", result);
}
return result;
}
public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId, string? monthDay) {
string[]? results;
string commandText;
Random random = new();
List<string> people = [];
StringBuilder stringBuilder;
if (!string.IsNullOrEmpty(monthDay)) {
foreach (KeyValuePair<string, string> keyValuePair in _Settings.People) {
if (!keyValuePair.Key.Contains(monthDay)) {
continue;
}
people.Add($"People/{keyValuePair.Value.Trim('/')}");
}
}
try {
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people.AsReadOnly());
stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
} catch (Exception) {
people.Clear();
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people.AsReadOnly());
stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
}
string json = stringBuilder.ToString();
string ownerIdValue = ownerId.ToString();
Asset[]? assets = JsonSerializer.Deserialize(json, AssetCollectionSourceGenerationContext.Default.AssetArray);
results = assets is null ? null : (from l in assets orderby random.NextSingle() select l.Path.Split(ownerIdValue)[1]).ToArray();
return results?.AsReadOnly();
}
public Tag[]? GetArchivedTag(Settings settings, Guid ownerId) {
Tag[]? results;
Guid userId = ownerId;
string value = settings.ArchivedTag;
NpgsqlParameter[] npgsqlParameters = [
new NpgsqlParameter(nameof(value), value),
new NpgsqlParameter(nameof(userId), userId),
];
string commandText = CommandText.GetArchivedTag(_Settings.LowestVersionHistory);
StringBuilder stringBuilder = GetForJsonPath(settings.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(_Settings, ownerId);
result = tags is null || tags.Length != 1 ? null : tags[0].Id;
return result;
}
public string? SaveRandomPaths(Guid ownerId, string? monthDay) {
string? results = null;
FileInfo fileInfo;
DateTime dateTime = DateTime.Now;
ReadOnlyCollection<string>? paths;
bool? check = monthDay is null ? null : monthDay == "00-00";
if (Directory.Exists(_Settings.RandomResultsDirectory)) {
_ = Directory.CreateDirectory(_Settings.RandomResultsDirectory);
}
for (int i = 0; i < 366; i++) {
if (check is null || check.Value) {
monthDay = i == 0 && check is not null && check.Value ? "02-29" : dateTime.AddDays(i).ToString("MM-dd");
}
fileInfo = new(Path.Combine(_Settings.RandomResultsDirectory, $"{monthDay}.json"));
if (fileInfo.Exists && fileInfo.CreationTime > dateTime.AddDays(_Settings.AddDays)) {
results = null;
} else {
_Logger.LogDebug("Writing <{FullName}>", fileInfo.FullName);
paths = GetRandomPaths(ownerId, monthDay);
if (paths is null) {
results = null;
} else {
_Logger.LogInformation("{count} path(s)", paths.Count.ToString());
results = JsonSerializer.Serialize(paths);
File.WriteAllText(fileInfo.FullName, results);
}
}
if (check is null || !check.Value) {
break;
}
}
return results;
}
private record Record(string Source, string Destination);
public ReadOnlyCollection<string> SyncImmich(Guid ownerId) {
List<string> results = [];
Record record;
List<Record> records = [];
if (Directory.Exists(_Settings.SyncDirectory)) {
_ = Directory.CreateDirectory(_Settings.SyncDirectory);
}
int syncLength = _Settings.SyncDirectory.Length;
string[] syncFiles = Directory.GetFiles(_Settings.SyncDirectory, "*", SearchOption.AllDirectories);
string[] syncCheck = syncFiles.Select(l => l[syncLength..]).ToArray();
if (Directory.Exists(_Settings.ImmichUploadDirectory)) {
_ = Directory.CreateDirectory(_Settings.ImmichUploadDirectory);
}
int immichUploadLength = _Settings.ImmichUploadDirectory.Length;
string[] immichUploadFiles = Directory.GetFiles(_Settings.ImmichUploadDirectory, "*", SearchOption.AllDirectories);
string[] immichUploadCheck = immichUploadFiles.Select(l => l[immichUploadLength..]).ToArray();
for (int i = 0; i < immichUploadFiles.Length; i++) {
if (syncCheck.Contains(immichUploadCheck[i])) {
continue;
}
results.Add(immichUploadCheck[i]);
record = new(immichUploadFiles[i], string.Concat(_Settings.SyncDirectory, immichUploadCheck[i]));
records.Add(record);
}
_Logger.LogInformation("{count} file(s)", results.Count.ToString());
for (int i = 0; i < records.Count; i++) {
record = records[i];
_Logger.LogDebug("Copying <{source}>", record.Source);
File.Copy(record.Source, record.Destination);
}
return results.AsReadOnly();
}
public ReadOnlyCollection<int>? SetArchiveImmich(Guid ownerId) {
ReadOnlyCollection<int>? results;
if (!File.Exists(_Settings.NotNinePath)) {
results = null;
} else {
string json = File.ReadAllText(_Settings.NotNinePath);
Identifier[]? identifiers = JsonSerializer.Deserialize<Identifier[]>(json);
if (identifiers is null || identifiers.Length == 0) {
results = null;
} else {
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
if (tags is null || tags.Length != 1) {
results = null;
} else {
results = SetArchiveImmich(logger, _Settings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
}
}
}
return results?.AsReadOnly();
}
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, string tagsId, string deviceAssetIds) {
ReadOnlyCollection<int>? results;
NpgsqlParameter[] npgsqlParameters = [
new NpgsqlParameter(nameof(tagsId), tagsId),
new NpgsqlParameter(nameof(ownerId), ownerId),
];
string commandText = CommandText.SetAssetArchived(settings.LowestVersionHistory, deviceAssetIds);
logger.LogDebug(commandText.Replace($"@{nameof(tagsId)}", $"'{tagsId}'").Replace($"@{nameof(ownerId)}", $"'{ownerId}'".ToString()));
int? result = ExecuteNonQuery(settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
results = result is null ? null : new([result.Value]);
return results?.AsReadOnly();
}
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<Tag> tags) {
ReadOnlyCollection<int>? results;
string tagsId = tags[0].Id;
string deviceAssetIds = Identifier.GetDeviceAssetIds(identifiers);
results = SetArchiveImmich(logger, settings, ownerId, tagsId, deviceAssetIds);
return results?.AsReadOnly();
}
public ReadOnlyCollection<int>? SetDigiKam4ArchiveImmich(Guid ownerId) {
ReadOnlyCollection<int>? results;
ReadOnlyCollection<ImageTag>? imageTags = ImageTag.Get(tag: _Settings.ArchivedTag,
tagsPath: _Settings.DigiKam4?.Tags,
imageTagsPath: _Settings.DigiKam4?.ImageTags,
imagesPath: _Settings.DigiKam4?.Images);
if (imageTags is null || imageTags.Count == 0) {
results = null;
} else {
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
if (tags is null || tags.Length != 1) {
results = null;
} else {
results = SetArchiveImmich(logger, _Settings, ownerId, imageTags, tags.AsReadOnly());
}
}
return results?.AsReadOnly();
}
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, ReadOnlyCollection<ImageTag> imageTags, ReadOnlyCollection<Tag> tags) {
ReadOnlyCollection<int>? results;
string tagsId = tags[0].Id;
string deviceAssetIds = Identifier.GetDeviceAssetIds(imageTags);
results = SetArchiveImmich(logger, settings, ownerId, tagsId, deviceAssetIds);
return results?.AsReadOnly();
}
public ReadOnlyCollection<int>? UpdateAssetsSetLocalDateTimeForThreeAndSeven() {
ReadOnlyCollection<int>? results;
NpgsqlParameter[] npgsqlParameters = [];
string commandText = CommandText.UpdateAssetsSetLocalDateTimeForThreeAndSeven(_Settings.LowestVersionHistory);
int? result = ExecuteNonQuery(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
results = result is null ? null : new([result.Value]);
return results?.AsReadOnly();
}
}