DigiKam4 Archive
Change to only need the one json file and changed AppSettings to not need a binder file Editorconfig for no new line before open braces Nuget package bumps Database lowest-version-history
This commit is contained in:
@ -1,27 +1,27 @@
|
||||
using ImmichToSlideshow.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ImmichToSlideshow.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/v1/[controller]")]
|
||||
public class AssetsController(AssetService assetService) : ControllerBase
|
||||
{
|
||||
public class AssetsController(AssetService assetService) : ControllerBase {
|
||||
|
||||
private readonly string _ContentType = "application/json";
|
||||
private readonly AssetService _AssetService = assetService;
|
||||
|
||||
[HttpGet("columns")]
|
||||
public IActionResult GetColumns() =>
|
||||
Content(_AssetService.GetColumns(), _ContentType);
|
||||
Content(_AssetService.GetColumns() ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("owner-ids")]
|
||||
public IActionResult GetOwnerIds() =>
|
||||
Content(_AssetService.GetOwnerIds(), _ContentType);
|
||||
Content(_AssetService.GetOwnerIds() ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("{ownerId:guid}")]
|
||||
public IActionResult Get(Guid ownerId) =>
|
||||
Content(_AssetService.GetAssets(ownerId), _ContentType);
|
||||
Content(_AssetService.GetAssets(ownerId) ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("{ownerId:guid}/random-paths")]
|
||||
public IActionResult GetRandomPaths(Guid ownerId) =>
|
||||
@ -29,11 +29,11 @@ public class AssetsController(AssetService assetService) : ControllerBase
|
||||
|
||||
[HttpGet("{ownerId:guid}/archived-tag")]
|
||||
public IActionResult GetArchivedTag(Guid ownerId) =>
|
||||
Content(_AssetService.GetArchivedTag(ownerId), _ContentType);
|
||||
Content(_AssetService.GetArchivedTag(ownerId) ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("{ownerId:guid}/save-random-paths")]
|
||||
public IActionResult SaveRandomPaths(Guid ownerId) =>
|
||||
Content(_AssetService.SaveRandomPaths(ownerId), _ContentType);
|
||||
Content(_AssetService.SaveRandomPaths(ownerId) ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("{ownerId:guid}/sync-immich")]
|
||||
public IActionResult SyncImmich(Guid ownerId) =>
|
||||
@ -43,4 +43,8 @@ public class AssetsController(AssetService assetService) : ControllerBase
|
||||
public IActionResult SetArchiveImmich(Guid ownerId) =>
|
||||
Ok(_AssetService.SetArchiveImmich(ownerId));
|
||||
|
||||
[HttpGet("{ownerId:guid}/set-digi-kam-4-archive-immich")]
|
||||
public IActionResult SetDigiKam4ArchiveImmich(Guid ownerId) =>
|
||||
Ok(_AssetService.SetDigiKam4ArchiveImmich(ownerId));
|
||||
|
||||
}
|
@ -3,11 +3,9 @@ using ImmichToSlideshow.Services;
|
||||
|
||||
namespace ImmichToSlideshow.DependencyInjection;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
public static IServiceCollection AddServices(this IServiceCollection services, AppSettings appSettings)
|
||||
{
|
||||
public static IServiceCollection AddServices(this IServiceCollection services, AppSettings appSettings) {
|
||||
_ = services.AddScoped<AssetService>();
|
||||
_ = services.AddSingleton(_ => appSettings);
|
||||
return services;
|
||||
|
74
src/ImmichToSlideshow/Domain/ImageTag.cs
Normal file
74
src/ImmichToSlideshow/Domain/ImageTag.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using ImmichToSlideshow.Models.DigiKam;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
// Business concerns
|
||||
|
||||
public record ImageTag(long Id,
|
||||
string Name,
|
||||
string Tag) {
|
||||
|
||||
internal static ReadOnlyCollection<ImageTag>? Get(string tag, string? tagsPath, string? imageTagsPath, string? imagesPath) {
|
||||
List<ImageTag>? results;
|
||||
ReadOnlyCollection<Tags>? tags = Tags.GetTags(tagsPath);
|
||||
if (tags is null || tags.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<int> tagIds = GetTagIds(tag, tags);
|
||||
if (tagIds.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<ImageTags>? imageTags = ImageTags.GetImageTags(imageTagsPath);
|
||||
if (imageTags is null || imageTags.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<int> imageIds = GetImageIds(imageTags, tagIds);
|
||||
if (imageIds.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
results = [];
|
||||
long id;
|
||||
ImageTag imageTag;
|
||||
ReadOnlyCollection<Images>? images = Images.GetImages(imagesPath);
|
||||
if (images is null || images.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
foreach (Images i in images) {
|
||||
if (!imageIds.Contains(i.Id) || !long.TryParse(i.Name.Split('.')[0], out id)) {
|
||||
continue;
|
||||
}
|
||||
imageTag = new(Id: id, Name: i.Name, Tag: tag);
|
||||
results.Add(imageTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetTagIds(string tag, ReadOnlyCollection<Tags> tags) {
|
||||
List<int> results = [];
|
||||
foreach (Tags t in tags) {
|
||||
if (t.Name != tag) {
|
||||
continue;
|
||||
}
|
||||
results.Add(t.Id);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetImageIds(ReadOnlyCollection<ImageTags> imageTags, ReadOnlyCollection<int> tagIds) {
|
||||
List<int> results = [];
|
||||
foreach (ImageTags i in imageTags) {
|
||||
if (!tagIds.Contains(i.TagId)) {
|
||||
continue;
|
||||
}
|
||||
results.Add(i.ImageId);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,8 @@
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
public class Product
|
||||
{
|
||||
// Business concerns
|
||||
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
public required string Name { get; init; }
|
||||
public required string Category { get; init; }
|
||||
public required string SubCategory { get; init; }
|
||||
|
||||
// Business concerns
|
||||
|
||||
}
|
||||
public record Product(Guid Id,
|
||||
string Name,
|
||||
string Category,
|
||||
string SubCategory);
|
@ -1,14 +1,11 @@
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
public class User
|
||||
{
|
||||
// Business concerns
|
||||
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
public List<Product> Products { get; init; } = [];
|
||||
public record User(Guid Id,
|
||||
List<Product> Products) {
|
||||
|
||||
internal void AddProduct(Product product) =>
|
||||
Products.Add(product);
|
||||
|
||||
// Business concerns
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
@ -7,6 +7,7 @@
|
||||
<UserSecretsId>cc24ad7a-1d95-4c47-a3ea-0d8475ab06da</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql" Version="9.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -3,31 +3,68 @@ 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,
|
||||
string URLs,
|
||||
string[] WithOrigins,
|
||||
string WorkingDirectoryName)
|
||||
{
|
||||
public record AppSettings(string Company, Settings Settings, string URLs, string[] WithOrigins) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void Verify(AppSettings appSettings) {
|
||||
if (appSettings?.Company is null)
|
||||
throw new NullReferenceException(nameof(Company));
|
||||
if (appSettings?.URLs is null)
|
||||
throw new NullReferenceException(nameof(URLs));
|
||||
if (appSettings?.WithOrigins is null)
|
||||
throw new NullReferenceException(nameof(WithOrigins));
|
||||
if (appSettings?.Settings?.AddDays is null)
|
||||
throw new NullReferenceException(nameof(Settings.AddDays));
|
||||
if (appSettings?.Settings?.ArchivedTag is null)
|
||||
throw new NullReferenceException(nameof(Settings.ArchivedTag));
|
||||
if (appSettings?.Settings?.ConnectionString is null)
|
||||
throw new NullReferenceException(nameof(Settings.ConnectionString));
|
||||
if (appSettings?.Settings?.DigiKam4 is null)
|
||||
throw new NullReferenceException(nameof(Settings.DigiKam4));
|
||||
if (appSettings?.Settings?.FilterTags is null)
|
||||
throw new NullReferenceException(nameof(Settings.FilterTags));
|
||||
if (appSettings?.Settings?.ImmichUploadDirectory is null)
|
||||
throw new NullReferenceException(nameof(Settings.ImmichUploadDirectory));
|
||||
if (appSettings?.Settings?.RandomResultsDirectory is null)
|
||||
throw new NullReferenceException(nameof(Settings.RandomResultsDirectory));
|
||||
if (appSettings?.Settings?.SyncDirectory is null)
|
||||
throw new NullReferenceException(nameof(Settings.SyncDirectory));
|
||||
}
|
||||
|
||||
public static AppSettings Get(IConfigurationRoot configurationRoot) {
|
||||
AppSettings result;
|
||||
#pragma warning disable IL3050, IL2026
|
||||
string? urls = configurationRoot.GetSection(nameof(URLs)).Get<string>();
|
||||
string? company = configurationRoot.GetSection(nameof(Company)).Get<string>();
|
||||
Settings? settings = configurationRoot.GetSection(nameof(Settings)).Get<Settings>();
|
||||
string[]? withOrigins = configurationRoot.GetSection(nameof(WithOrigins)).Get<string[]>();
|
||||
#pragma warning restore IL3050, IL2026
|
||||
if (company is null || settings is null || urls is null || withOrigins is null) {
|
||||
List<string> paths = [];
|
||||
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers) {
|
||||
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
|
||||
continue;
|
||||
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
|
||||
continue;
|
||||
paths.Add(physicalFileProvider.Root);
|
||||
}
|
||||
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
|
||||
}
|
||||
result = new(Company: company,
|
||||
Settings: settings,
|
||||
URLs: urls,
|
||||
WithOrigins: withOrigins);
|
||||
Verify(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(AppSettings))]
|
||||
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
[*.cs]
|
||||
csharp_preserve_single_line_statements = true
|
@ -1,95 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.Binder;
|
||||
|
||||
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; }
|
||||
public string? URLs { get; set; }
|
||||
public string[]? WithOrigins { get; set; }
|
||||
public string? WorkingDirectoryName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, BinderAppSettingsSourceGenerationContext.Default.AppSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
|
||||
{
|
||||
if (appSettings?.Company is null)
|
||||
{
|
||||
List<string> paths = [];
|
||||
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
|
||||
{
|
||||
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
|
||||
continue;
|
||||
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
|
||||
continue;
|
||||
paths.Add(physicalFileProvider.Root);
|
||||
}
|
||||
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.AppSettings Get(AppSettings? 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));
|
||||
if (appSettings?.URLs is null) throw new NullReferenceException(nameof(appSettings.URLs));
|
||||
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,
|
||||
appSettings.URLs,
|
||||
appSettings.WithOrigins,
|
||||
appSettings.WorkingDirectoryName);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
|
||||
{
|
||||
Models.AppSettings result;
|
||||
#pragma warning disable IL3050, IL2026
|
||||
AppSettings? appSettings = configurationRoot.Get<AppSettings>();
|
||||
#pragma warning restore IL3050, IL2026
|
||||
PreVerify(configurationRoot, appSettings);
|
||||
result = Get(appSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(AppSettings))]
|
||||
internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
11
src/ImmichToSlideshow/Models/DigiKam/AlbumRoots.cs
Normal file
11
src/ImmichToSlideshow/Models/DigiKam/AlbumRoots.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record AlbumRoots([property: JsonPropertyName("caseSensitivity")] int CaseSensitivity,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("identifier")] string Identifier,
|
||||
[property: JsonPropertyName("label")] string Label,
|
||||
[property: JsonPropertyName("specificPath")] string SpecificPath,
|
||||
[property: JsonPropertyName("status")] int Status,
|
||||
[property: JsonPropertyName("type")] int Type);
|
12
src/ImmichToSlideshow/Models/DigiKam/Albums.cs
Normal file
12
src/ImmichToSlideshow/Models/DigiKam/Albums.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Albums([property: JsonPropertyName("albumRoot")] int AlbumRoot,
|
||||
[property: JsonPropertyName("caption")] object Caption,
|
||||
[property: JsonPropertyName("collection")] object Collection,
|
||||
[property: JsonPropertyName("date")] string Date,
|
||||
[property: JsonPropertyName("icon")] object Icon,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("modificationDate")] DateTime ModificationDate,
|
||||
[property: JsonPropertyName("relativePath")] string RelativePath);
|
11
src/ImmichToSlideshow/Models/DigiKam/ImageComments.cs
Normal file
11
src/ImmichToSlideshow/Models/DigiKam/ImageComments.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageComments([property: JsonPropertyName("author")] object Author,
|
||||
[property: JsonPropertyName("comment")] string Comment,
|
||||
[property: JsonPropertyName("date")] object Date,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("language")] string Language,
|
||||
[property: JsonPropertyName("type")] int Type);
|
15
src/ImmichToSlideshow/Models/DigiKam/ImagePositions.cs
Normal file
15
src/ImmichToSlideshow/Models/DigiKam/ImagePositions.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImagePositions([property: JsonPropertyName("accuracy")] object Accuracy,
|
||||
[property: JsonPropertyName("altitude")] double? Altitude,
|
||||
[property: JsonPropertyName("description")] object Description,
|
||||
[property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("latitude")] string Latitude,
|
||||
[property: JsonPropertyName("latitudeNumber")] double? LatitudeNumber,
|
||||
[property: JsonPropertyName("longitude")] string Longitude,
|
||||
[property: JsonPropertyName("longitudeNumber")] double? LongitudeNumber,
|
||||
[property: JsonPropertyName("orientation")] object Orientation,
|
||||
[property: JsonPropertyName("roll")] object Roll,
|
||||
[property: JsonPropertyName("tilt")] object Tilt);
|
@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageTagProperties([property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("property")] string Property,
|
||||
[property: JsonPropertyName("tagid")] int TagId,
|
||||
[property: JsonPropertyName("value")] string Value);
|
21
src/ImmichToSlideshow/Models/DigiKam/ImageTags.cs
Normal file
21
src/ImmichToSlideshow/Models/DigiKam/ImageTags.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageTags([property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("tagid")] int TagId) {
|
||||
|
||||
internal static ReadOnlyCollection<ImageTags>? GetImageTags(string? path) {
|
||||
ImageTags[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<ImageTags[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
28
src/ImmichToSlideshow/Models/DigiKam/Images.cs
Normal file
28
src/ImmichToSlideshow/Models/DigiKam/Images.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Images([property: JsonPropertyName("album")] int? Album,
|
||||
[property: JsonPropertyName("category")] int Category,
|
||||
[property: JsonPropertyName("fileSize")] object FileSize,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("manualOrder")] object ManualOrder,
|
||||
[property: JsonPropertyName("modificationDate")] DateTime ModificationDate,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("status")] int Status,
|
||||
[property: JsonPropertyName("uniqueHash")] string UniqueHash) {
|
||||
|
||||
internal static ReadOnlyCollection<Images>? GetImages(string? path) {
|
||||
Images[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<Images[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
7
src/ImmichToSlideshow/Models/DigiKam/TagProperties.cs
Normal file
7
src/ImmichToSlideshow/Models/DigiKam/TagProperties.cs
Normal file
@ -0,0 +1,7 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record TagProperties([property: JsonPropertyName("property")] string Property,
|
||||
[property: JsonPropertyName("tagid")] int TagId,
|
||||
[property: JsonPropertyName("value")] object Value);
|
24
src/ImmichToSlideshow/Models/DigiKam/Tags.cs
Normal file
24
src/ImmichToSlideshow/Models/DigiKam/Tags.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Tags([property: JsonPropertyName("icon")] object Icon,
|
||||
[property: JsonPropertyName("iconkde")] object IconKDE,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("pid")] int PId) {
|
||||
|
||||
internal static ReadOnlyCollection<Tags>? GetTags(string? path) {
|
||||
Tags[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<Tags[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
22
src/ImmichToSlideshow/Models/DigiKam4.cs
Normal file
22
src/ImmichToSlideshow/Models/DigiKam4.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public record DigiKam4(string Images,
|
||||
string ImageTagProperties,
|
||||
string ImageTags,
|
||||
string TagProperties,
|
||||
string Tags) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, DigiKam4SourceGenerationContext.Default.DigiKam4);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(DigiKam4))]
|
||||
public partial class DigiKam4SourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using ImmichToSlideshow.Domain;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
@ -10,11 +11,9 @@ public sealed record Identifier(string[] DirectoryNames,
|
||||
int Id,
|
||||
long Length,
|
||||
string PaddedId,
|
||||
long Ticks)
|
||||
{
|
||||
long Ticks) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, IdentifierSourceGenerationContext.Default.Identifier);
|
||||
return result;
|
||||
}
|
||||
@ -22,6 +21,9 @@ public sealed record Identifier(string[] DirectoryNames,
|
||||
internal static string GetDeviceAssetIds(ReadOnlyCollection<Identifier> identifiers) =>
|
||||
$"'{string.Join($"',{Environment.NewLine}'", (from l in identifiers select GetDeviceAssetId(l)).ToArray())}'";
|
||||
|
||||
internal static string GetDeviceAssetIds(ReadOnlyCollection<ImageTag> imageTags) =>
|
||||
$"'{string.Join($"',{Environment.NewLine}'", (from l in imageTags select l.Name).ToArray())}'";
|
||||
|
||||
internal static string GetDeviceAssetId(Identifier identifier) =>
|
||||
$"{identifier.PaddedId}{identifier.Extension}";
|
||||
|
||||
@ -29,12 +31,10 @@ public sealed record Identifier(string[] DirectoryNames,
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier))]
|
||||
public partial class IdentifierSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
public partial class IdentifierSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier[]))]
|
||||
public partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
public partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -31,11 +31,9 @@ public record Asset([property: JsonPropertyName("id")] string Id,
|
||||
// [property: JsonPropertyName("stackId")]? object? StackId,
|
||||
[property: JsonPropertyName("duplicateId")] string? DuplicateId,
|
||||
// [property: JsonPropertyName("status")] string Status,
|
||||
[property: JsonPropertyName("path")] string Path)
|
||||
{
|
||||
[property: JsonPropertyName("path")] string Path) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, AssetSourceGenerationContext.Default.Asset);
|
||||
return result;
|
||||
}
|
||||
@ -44,12 +42,10 @@ public record Asset([property: JsonPropertyName("id")] string Id,
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Asset))]
|
||||
internal partial class AssetSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AssetSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Asset[]))]
|
||||
internal partial class AssetCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AssetCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -10,11 +10,9 @@ public record Tag([property: JsonPropertyName("id")] string Id,
|
||||
// [property: JsonPropertyName("updatedAt")] DateTime UpdatedAt,
|
||||
// [property: JsonPropertyName("color")] char Color,
|
||||
// [property: JsonPropertyName("parentId")] string ParentId,
|
||||
[property: JsonPropertyName("updateId")] string UpdateId)
|
||||
{
|
||||
[property: JsonPropertyName("updateId")] string UpdateId) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, TagSourceGenerationContext.Default.Tag);
|
||||
return result;
|
||||
}
|
||||
@ -23,12 +21,10 @@ public record Tag([property: JsonPropertyName("id")] string Id,
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Tag))]
|
||||
internal partial class TagSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class TagSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Tag[]))]
|
||||
internal partial class TagCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class TagCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
27
src/ImmichToSlideshow/Models/Settings.cs
Normal file
27
src/ImmichToSlideshow/Models/Settings.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public record Settings(int AddDays,
|
||||
string ArchivedTag,
|
||||
string ConnectionString,
|
||||
DigiKam4? DigiKam4,
|
||||
string[] FilterTags,
|
||||
string ImmichUploadDirectory,
|
||||
float LowestVersionHistory,
|
||||
string NotNinePath,
|
||||
string RandomResultsDirectory,
|
||||
string SyncDirectory) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, SettingsSourceGenerationContext.Default.Settings);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Settings))]
|
||||
public partial class SettingsSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
namespace ImmichToSlideshow.Persistence.Database;
|
||||
|
||||
public static class DbConstants
|
||||
{
|
||||
public static class DbConstants {
|
||||
|
||||
public const string DefaultConnectionStringPath = "Database:ConnectionStrings:DefaultConnection";
|
||||
|
||||
|
@ -4,14 +4,12 @@ using ImmichToSlideshow.RequestPipeline;
|
||||
|
||||
namespace ImmichToSlideshow;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public class Program {
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
public static void Main(string[] args) {
|
||||
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(args);
|
||||
_ = webApplicationBuilder.Configuration.AddUserSecrets<Program>();
|
||||
AppSettings appSettings = Models.Binder.AppSettings.Get(webApplicationBuilder.Configuration);
|
||||
AppSettings appSettings = AppSettings.Get(webApplicationBuilder.Configuration);
|
||||
_ = webApplicationBuilder.Services.AddControllers();
|
||||
_ = webApplicationBuilder.Services.AddServices(appSettings);
|
||||
WebApplication webApplication = webApplicationBuilder.Build();
|
||||
|
@ -2,19 +2,16 @@ using ImmichToSlideshow.Models;
|
||||
|
||||
namespace ImmichToSlideshow.RequestPipeline;
|
||||
|
||||
public static class WebApplicationExtensions
|
||||
{
|
||||
public static class WebApplicationExtensions {
|
||||
|
||||
public static WebApplication InitializeDatabase(this WebApplication webApplication) =>
|
||||
// DBInitializer.Initialize(application.Configuration[DbConstants.DefaultConnectionStringPath]!);
|
||||
webApplication;
|
||||
|
||||
public static WebApplication InitializeCorsAndHttps(this WebApplication webApplication, AppSettings appSettings)
|
||||
{
|
||||
public static WebApplication InitializeCorsAndHttps(this WebApplication webApplication, AppSettings appSettings) {
|
||||
_ = webApplication.UseCors(corsPolicyBuilder =>
|
||||
corsPolicyBuilder.WithOrigins(appSettings.WithOrigins).AllowAnyHeader().AllowAnyMethod());
|
||||
if (appSettings.URLs.Contains("https", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (appSettings.URLs.Contains("https", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
_ = webApplication.UseHttpsRedirection();
|
||||
_ = webApplication.UseHsts();
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
using ImmichToSlideshow.Domain;
|
||||
using ImmichToSlideshow.Models;
|
||||
using ImmichToSlideshow.Models.Immich;
|
||||
using Npgsql;
|
||||
@ -8,21 +9,18 @@ using System.Text.Json;
|
||||
|
||||
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 AppSettings _AppSettings = appSettings;
|
||||
private readonly Settings _Settings = appSettings.Settings;
|
||||
#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) {
|
||||
int? result;
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
if (string.IsNullOrEmpty(connectionString)) {
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
using NpgsqlConnection npgsqlConnection = new(connectionString);
|
||||
npgsqlConnection.Open();
|
||||
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
|
||||
@ -32,61 +30,60 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
|
||||
return result;
|
||||
}
|
||||
|
||||
private static StringBuilder GetForJsonPath(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters)
|
||||
{
|
||||
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())
|
||||
while (npgsqlDataReader.Read()) {
|
||||
_ = result.Append(npgsqlDataReader.GetString(0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetColumns()
|
||||
{
|
||||
public string? GetColumns() {
|
||||
string result;
|
||||
NpgsqlParameter[] npgsqlParameters = [];
|
||||
string commandText = CommandText.GetColumns();
|
||||
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1)
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetOwnerIds()
|
||||
{
|
||||
public string? GetOwnerIds() {
|
||||
string result;
|
||||
NpgsqlParameter[] npgsqlParameters = [];
|
||||
string commandText = CommandText.GetOwnerIdActiveImage();
|
||||
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
string commandText = CommandText.GetOwnerIdActiveImage(_Settings.LowestVersionHistory);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1)
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetAssets(Guid ownerId)
|
||||
{
|
||||
public string? GetAssets(Guid ownerId) {
|
||||
string result;
|
||||
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
|
||||
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_AppSettings.FilterTags);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1)
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/assets.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId)
|
||||
{
|
||||
public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId) {
|
||||
string[]? results;
|
||||
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
|
||||
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_AppSettings.FilterTags);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
string json = stringBuilder.ToString();
|
||||
Random random = new();
|
||||
string ownerIdValue = ownerId.ToString();
|
||||
@ -95,49 +92,44 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
public Tag[]? GetArchivedTag(AppSettings appSettings, Guid ownerId)
|
||||
{
|
||||
Tag[] results;
|
||||
public Tag[]? GetArchivedTag(Settings settings, Guid ownerId) {
|
||||
Tag[]? results;
|
||||
Guid userId = ownerId;
|
||||
string value = appSettings.ArchivedTag;
|
||||
NpgsqlParameter[] npgsqlParameters =
|
||||
[
|
||||
string value = settings.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 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(_AppSettings, ownerId);
|
||||
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)
|
||||
{
|
||||
public string? SaveRandomPaths(Guid ownerId) {
|
||||
string? results;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
string tomorrow = dateTime.AddDays(1).ToString("MM-dd");
|
||||
if (Directory.Exists(_AppSettings.RandomResultsDirectory))
|
||||
_ = Directory.CreateDirectory(_AppSettings.RandomResultsDirectory);
|
||||
FileInfo fileInfo = new(Path.Combine(_AppSettings.RandomResultsDirectory, $"{tomorrow}.json"));
|
||||
if (fileInfo.Exists && fileInfo.CreationTime > dateTime.AddDays(_AppSettings.AddDays))
|
||||
if (Directory.Exists(_Settings.RandomResultsDirectory)) {
|
||||
_ = Directory.CreateDirectory(_Settings.RandomResultsDirectory);
|
||||
}
|
||||
FileInfo fileInfo = new(Path.Combine(_Settings.RandomResultsDirectory, $"{tomorrow}.json"));
|
||||
if (fileInfo.Exists && fileInfo.CreationTime > dateTime.AddDays(_Settings.AddDays)) {
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_Logger.LogDebug("Writing <{FullName}>", fileInfo.FullName);
|
||||
ReadOnlyCollection<string>? paths = GetRandomPaths(ownerId);
|
||||
if (paths is null)
|
||||
if (paths is null) {
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_Logger.LogInformation("{count} path(s)", paths.Count.ToString());
|
||||
results = JsonSerializer.Serialize(paths);
|
||||
File.WriteAllText(fileInfo.FullName, results);
|
||||
@ -148,32 +140,32 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
|
||||
|
||||
private record Record(string Source, string Destination);
|
||||
|
||||
public ReadOnlyCollection<string> SyncImmich(Guid ownerId)
|
||||
{
|
||||
public ReadOnlyCollection<string> SyncImmich(Guid ownerId) {
|
||||
List<string> results = [];
|
||||
Record record;
|
||||
List<Record> records = [];
|
||||
if (Directory.Exists(_AppSettings.SyncDirectory))
|
||||
_ = Directory.CreateDirectory(_AppSettings.SyncDirectory);
|
||||
int syncLength = _AppSettings.SyncDirectory.Length;
|
||||
string[] syncFiles = Directory.GetFiles(_AppSettings.SyncDirectory, "*", SearchOption.AllDirectories);
|
||||
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(_AppSettings.ImmichUploadDirectory))
|
||||
_ = Directory.CreateDirectory(_AppSettings.ImmichUploadDirectory);
|
||||
int immichUploadLength = _AppSettings.ImmichUploadDirectory.Length;
|
||||
string[] immichUploadFiles = Directory.GetFiles(_AppSettings.ImmichUploadDirectory, "*", SearchOption.AllDirectories);
|
||||
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]))
|
||||
for (int i = 0; i < immichUploadFiles.Length; i++) {
|
||||
if (syncCheck.Contains(immichUploadCheck[i])) {
|
||||
continue;
|
||||
}
|
||||
results.Add(immichUploadCheck[i]);
|
||||
record = new(immichUploadFiles[i], string.Concat(_AppSettings.SyncDirectory, 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++)
|
||||
{
|
||||
for (int i = 0; i < records.Count; i++) {
|
||||
record = records[i];
|
||||
_Logger.LogDebug("Copying <{source}>", record.Source);
|
||||
File.Copy(record.Source, record.Destination);
|
||||
@ -181,51 +173,73 @@ public class AssetService(ILogger<Program> logger, AppSettings appSettings)
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<int> SetArchiveImmich(Guid ownerId)
|
||||
{
|
||||
public ReadOnlyCollection<int>? SetArchiveImmich(Guid ownerId) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
string checkDirectory = Path.Combine(_AppSettings.CurrentResultsDirectory, "B)Metadata", _AppSettings.CurrentCommit, "[]");
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
if (!File.Exists(_Settings.NotNinePath)) {
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, "!9.json");
|
||||
if (!File.Exists(checkFile))
|
||||
} else {
|
||||
string json = File.ReadAllText(_Settings.NotNinePath);
|
||||
Identifier[]? identifiers = JsonSerializer.Deserialize<Identifier[]>(json);
|
||||
if (identifiers is null || identifiers.Length == 0) {
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(checkFile);
|
||||
Identifier[]? identifiers = JsonSerializer.Deserialize<Identifier[]>(json);
|
||||
if (identifiers is null || identifiers.Length == 0)
|
||||
} else {
|
||||
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
|
||||
if (tags is null || tags.Length != 1) {
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
Tag[]? tags = GetArchivedTag(_AppSettings, ownerId);
|
||||
if (tags is null || tags.Length != 1)
|
||||
results = null;
|
||||
else
|
||||
results = SetArchiveImmich(logger, appSettings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
|
||||
} else {
|
||||
results = SetArchiveImmich(logger, _Settings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
|
||||
}
|
||||
}
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> SetArchiveImmich(ILogger<Program> logger, AppSettings appSettings, Guid ownerId, ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<Tag> tags)
|
||||
{
|
||||
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, string tagsId, string deviceAssetIds) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
string tagsId = tags[0].Id;
|
||||
NpgsqlParameter[] npgsqlParameters =
|
||||
[
|
||||
NpgsqlParameter[] npgsqlParameters = [
|
||||
new NpgsqlParameter(nameof(tagsId), tagsId),
|
||||
new NpgsqlParameter(nameof(ownerId), ownerId),
|
||||
];
|
||||
string deviceAssetIds = Identifier.GetDeviceAssetIds(identifiers);
|
||||
string commandText = CommandText.SetAssetArchived(deviceAssetIds);
|
||||
string commandText = CommandText.SetAssetArchived(settings.LowestVersionHistory, deviceAssetIds);
|
||||
logger.LogDebug(commandText.Replace($"@{nameof(tagsId)}", $"'{tagsId}'").Replace($"@{nameof(ownerId)}", $"'{ownerId}'".ToString()));
|
||||
int? result = ExecuteNonQuery(appSettings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
@ -1,129 +1,176 @@
|
||||
namespace ImmichToSlideshow.Services;
|
||||
|
||||
internal static class CommandText
|
||||
{
|
||||
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' ");
|
||||
internal static string GetColumns() { // cSpell:disable
|
||||
List<string> results = [
|
||||
// " SELECT COALESCE(SUM(checksum_failures), 0) ",
|
||||
// " FROM pg_stat_database ",
|
||||
// " SELECT json_agg(t) ",
|
||||
// " FROM information_schema.tables t ",
|
||||
// " WHERE table_schema= 'public' ",
|
||||
// " AND table_type= 'BASE TABLE' ",
|
||||
" SELECT json_agg(c) ",
|
||||
" FROM information_schema.columns c ",
|
||||
// " WHERE table_name = 'assets' ",
|
||||
// " WHERE table_name = 'libraries' ",
|
||||
" 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 ");
|
||||
internal static string GetOwnerIdActiveImage(float lowestVersionHistory) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(j) ",
|
||||
" FROM ( ",
|
||||
" SELECT a.\"ownerId\" "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE a.\"status\" = 'active' ",
|
||||
" AND a.\"type\" = 'IMAGE' ",
|
||||
" GROUP",
|
||||
" BY a.\"ownerId\" ",
|
||||
" ) 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 ");
|
||||
internal static string GetAssetActiveImagePreviewNotDuplicate(float lowestVersionHistory, string[] filterTags) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(j) ",
|
||||
" FROM ( ",
|
||||
" SELECT a.\"id\" ",
|
||||
" , a.\"deviceAssetId\" ",
|
||||
// " , a.\"ownerId\" ",
|
||||
// " , a.\"deviceId\" ",
|
||||
// " , a.\"type\" ",
|
||||
" , a.\"originalPath\" ",
|
||||
// " , a.\"fileCreatedAt\" ",
|
||||
// " , a.\"fileModifiedAt\" ",
|
||||
// " , a.\"isFavorite\" ",
|
||||
// " , a.\"duration\" ",
|
||||
// " , a.\"encodedVideoPath\" ",
|
||||
// " , a.\"checksum\" ",
|
||||
// " , a.\"isVisible\" ",
|
||||
// " , a.\"livePhotoVideoId\" ",
|
||||
// " , a.\"updatedAt\" ",
|
||||
// " , a.\"createdAt\" ",
|
||||
// " , a.\"isArchived\" ",
|
||||
" , a.\"originalFileName\" ",
|
||||
// " , a.\"sidecarPath\" ",
|
||||
// " , a.\"thumbhash\" ",
|
||||
// " , a.\"isOffline\" ",
|
||||
// " , a.\"libraryId\" ",
|
||||
// " , a.\"isExternal\" ",
|
||||
// " , a.\"deletedAt\" ",
|
||||
// " , a.\"localDateTime\" ",
|
||||
// " , a.\"stackId\" ",
|
||||
" , a.\"duplicateId\" ",
|
||||
// " , a.\"status\" ",
|
||||
" , f.\"path\" "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.AddRange(" INNER ");
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN asset_files f ");
|
||||
} else {
|
||||
results.Add(" JOIN public.asset_file f ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON a.\"id\" = f.\"assetId\" ",
|
||||
" WHERE a.\"status\" = 'active' ",
|
||||
" AND a.\"type\" = 'IMAGE' ",
|
||||
" AND f.\"type\" = 'preview' ",
|
||||
" AND a.\"duplicateId\" is null ",
|
||||
" AND a.\"id\" not in ( ",
|
||||
" SELECT \"assetsId\" "
|
||||
]);
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM tag_asset g ");
|
||||
} else {
|
||||
results.Add(" FROM public.tag_asset g ");
|
||||
}
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN tags t ");
|
||||
} else {
|
||||
results.Add(" JOIN public.tag t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON g.\"tagsId\" = t.\"id\" ",
|
||||
$" WHERE t.\"value\" in ('{string.Join("','", filterTags)}') ",
|
||||
" ) ",
|
||||
" AND a.\"isExternal\" = true ",
|
||||
" AND a.\"isOffline\" = false ",
|
||||
" AND a.\"ownerId\" = @ownerId ",
|
||||
" ) 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 ");
|
||||
internal static string SetAssetArchived(float lowestVersionHistory, string deviceAssetIds) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" INSERT INTO tag_asset ",
|
||||
" (\"assetsId\", \"tagsId\") ",
|
||||
" SELECT a.\"id\", @tagsId::uuid "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE a.\"type\" = 'IMAGE' ",
|
||||
" AND a.\"ownerId\" = @ownerId ",
|
||||
" AND a.\"deviceAssetId\" in ( ",
|
||||
deviceAssetIds,
|
||||
" ) ",
|
||||
" AND a.\"id\" not in ( ",
|
||||
" SELECT \"id\" "
|
||||
]);
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets b ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset 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(" ) ");
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN tag_asset t ");
|
||||
} else {
|
||||
results.Add(" JOIN public.tag_asset t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON b.\"id\" = t.\"assetsId\" ",
|
||||
" WHERE t.\"tagsId\" = @tagsId::uuid ",
|
||||
" AND b.\"deviceAssetId\" in ( ",
|
||||
deviceAssetIds,
|
||||
" ) ",
|
||||
" ); "
|
||||
]);
|
||||
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 ");
|
||||
internal static string GetArchivedTag(float lowestVersionHistory) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(t) "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM tags t ");
|
||||
} else {
|
||||
results.Add(" FROM public.tag t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE t.\"value\" = @value ",
|
||||
" AND t.\"userId\" = @userId; "
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
|
Reference in New Issue
Block a user