diff --git a/PiwigoDirectorySync/Commands/Scan/FileIndexer.cs b/PiwigoDirectorySync/Commands/Scan/FileIndexer.cs index 8289c84..a0bc32d 100644 --- a/PiwigoDirectorySync/Commands/Scan/FileIndexer.cs +++ b/PiwigoDirectorySync/Commands/Scan/FileIndexer.cs @@ -1,11 +1,15 @@ -using System.Threading.Channels; +using System.Security.Cryptography; +using System.Threading.Channels; +using Microsoft.EntityFrameworkCore; using NLog; +using PiwigoDirectorySync.Persistence; namespace PiwigoDirectorySync.Commands.Scan; public class FileIndexer { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + private readonly IList _failedFiles = new List(); private readonly Channel _fileQueue; private readonly int _piwigoServerId; @@ -17,20 +21,119 @@ public class FileIndexer } public int TotalFilesScanned { get; private set; } + public IReadOnlyCollection FailedFiles => _failedFiles.AsReadOnly(); public async Task StartProcessingAsync(CancellationToken ct) { - await foreach (var filePath in _fileQueue.Reader.ReadAllAsync(ct)) + await using var db = new PersistenceContext(); + var piwigoServer = await db.PiwigoServers.GetByIdAsync(_piwigoServerId, ct); + + await foreach (var fullFilePath in _fileQueue.Reader.ReadAllAsync(ct)) { try { - Logger.Info($"Indexing file {filePath}"); + if (ct.IsCancellationRequested) + { + Logger.Warn("Indexing cancelled"); + break; + } + + Logger.Info($"Indexing file {fullFilePath}"); + var fileInfo = new FileInfo(fullFilePath); + + if (!fileInfo.Exists) + { + Logger.Warn($"File {fullFilePath} not found"); + _failedFiles.Add(fullFilePath); + continue; + } + + var relativePath = Path.GetRelativePath(piwigoServer.RootDirectory, fullFilePath); + + var album = await GetOrAddAlbumAsync(db, piwigoServer, fileInfo.Directory!, ct); + + var image = await GetOrAddImageAsync(db, album, relativePath, ct); + + if (image.LastChange != fileInfo.LastWriteTimeUtc) + { + image.UploadRequired = true; + image.Md5Sum = await CalculateMd5SumAsync(fullFilePath, ct); + } + + image.DeleteRequired = false; + image.LastChange = fileInfo.LastWriteTimeUtc; + + await db.SaveChangesAsync(ct); + TotalFilesScanned++; } catch (Exception ex) { - Logger.Error(ex, $"could not delete file {filePath}"); + _failedFiles.Add(fullFilePath); + Logger.Error(ex, $"could not delete file {fullFilePath}"); } } } + + private static async Task GetOrAddImageAsync(PersistenceContext db, AlbumEntity album, string relativePath, CancellationToken ct) + { + var imageEntity = await db.PiwigoImages.Where(i => i.AlbumId == album.Id && i.FilePath == relativePath).FirstOrDefaultAsync(ct); + if (imageEntity is null) + { + imageEntity = new ImageEntity + { + AlbumId = album.Id, + Album = album, + FilePath = relativePath, + UploadRequired = true, + DeleteRequired = false + }; + db.PiwigoImages.Add(imageEntity); + } + + return imageEntity; + } + + private async Task GetOrAddAlbumAsync(PersistenceContext db, ServerEntity server, DirectoryInfo directory, CancellationToken ct) + { + var albumPath = Path.GetRelativePath(server.RootDirectory, directory.FullName); + var album = await db.PiwigoAlbums.FindByServerAndPathAsync(server.Id, albumPath, ct); + if (album != null) + { + return album; + } + + AlbumEntity? parentAlbum; + if (string.Equals(new DirectoryInfo(server.RootDirectory).FullName, directory.Parent!.FullName)) + { + parentAlbum = null; + } + else + { + parentAlbum = await GetOrAddAlbumAsync(db, server, directory.Parent!, ct); + } + + album = new AlbumEntity + { + ServerId = server.Id, + Server = server, + Name = directory.Name, + Path = albumPath, + ParentId = parentAlbum?.Id, + Parent = parentAlbum + }; + db.PiwigoAlbums.Add(album); + + await db.SaveChangesAsync(ct); + + return album; + } + + private static async Task CalculateMd5SumAsync(string imageFileFullPath, CancellationToken stoppingToken) + { + using var md5 = MD5.Create(); + await using var stream = File.OpenRead(imageFileFullPath); + var hash = await md5.ComputeHashAsync(stream, stoppingToken); + return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant(); + } } \ No newline at end of file diff --git a/PiwigoDirectorySync/Commands/Scan/ScanCommand.cs b/PiwigoDirectorySync/Commands/Scan/ScanCommand.cs index e57d59d..591938d 100644 --- a/PiwigoDirectorySync/Commands/Scan/ScanCommand.cs +++ b/PiwigoDirectorySync/Commands/Scan/ScanCommand.cs @@ -11,6 +11,8 @@ public class ScanCommand : AsyncCommand public override async Task ExecuteAsync(CommandContext context, ScanSettings settings) { + //TODO: check files for deletion -> files in db but no longer exist + Logger.Info("Starting scanner and remover"); var stopWatch = Stopwatch.StartNew(); diff --git a/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.Designer.cs b/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.Designer.cs new file mode 100644 index 0000000..a054d45 --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.Designer.cs @@ -0,0 +1,152 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PiwigoDirectorySync.Persistence; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + [DbContext(typeof(PersistenceContext))] + [Migration("20230830212128_Update_path_handling")] + partial class Update_path_handling + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.10"); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PiwigoAlbumId") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("PiwigoAlbumId"); + + b.HasIndex("ServerId"); + + b.ToTable("PiwigoAlbums"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AlbumId") + .HasColumnType("INTEGER"); + + b.Property("DeleteRequired") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastChange") + .HasColumnType("TEXT"); + + b.Property("Md5Sum") + .HasColumnType("TEXT"); + + b.Property("ServerImageId") + .HasColumnType("INTEGER"); + + b.Property("UploadRequired") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AlbumId"); + + b.ToTable("PiwigoImages"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ServerEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RootDirectory") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("PiwigoServers"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.HasOne("PiwigoDirectorySync.Persistence.ServerEntity", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Album") + .WithMany() + .HasForeignKey("AlbumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Album"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.cs b/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.cs new file mode 100644 index 0000000..298dd3e --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830212128_Update_path_handling.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + /// + public partial class Update_path_handling : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "DirectoryName", + table: "PiwigoAlbums", + newName: "Path"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "Path", + table: "PiwigoAlbums", + newName: "DirectoryName"); + } + } +} diff --git a/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.Designer.cs b/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.Designer.cs new file mode 100644 index 0000000..3084b46 --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.Designer.cs @@ -0,0 +1,154 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PiwigoDirectorySync.Persistence; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + [DbContext(typeof(PersistenceContext))] + [Migration("20230830212412_Update_indices_and_rename_piwigoServerAlbumId")] + partial class Update_indices_and_rename_piwigoServerAlbumId + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.10"); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerAlbumId") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("ServerAlbumId"); + + b.HasIndex("ServerId"); + + b.ToTable("PiwigoAlbums"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AlbumId") + .HasColumnType("INTEGER"); + + b.Property("DeleteRequired") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastChange") + .HasColumnType("TEXT"); + + b.Property("Md5Sum") + .HasColumnType("TEXT"); + + b.Property("ServerImageId") + .HasColumnType("INTEGER"); + + b.Property("UploadRequired") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ServerImageId"); + + b.HasIndex("AlbumId", "FilePath"); + + b.ToTable("PiwigoImages"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ServerEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RootDirectory") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("PiwigoServers"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.HasOne("PiwigoDirectorySync.Persistence.ServerEntity", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Album") + .WithMany() + .HasForeignKey("AlbumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Album"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.cs b/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.cs new file mode 100644 index 0000000..86a2d39 --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830212412_Update_indices_and_rename_piwigoServerAlbumId.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + /// + public partial class Update_indices_and_rename_piwigoServerAlbumId : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PiwigoImages_AlbumId", + table: "PiwigoImages"); + + migrationBuilder.RenameColumn( + name: "PiwigoAlbumId", + table: "PiwigoAlbums", + newName: "ServerAlbumId"); + + migrationBuilder.RenameIndex( + name: "IX_PiwigoAlbums_PiwigoAlbumId", + table: "PiwigoAlbums", + newName: "IX_PiwigoAlbums_ServerAlbumId"); + + migrationBuilder.CreateIndex( + name: "IX_PiwigoImages_AlbumId_FilePath", + table: "PiwigoImages", + columns: new[] { "AlbumId", "FilePath" }); + + migrationBuilder.CreateIndex( + name: "IX_PiwigoImages_ServerImageId", + table: "PiwigoImages", + column: "ServerImageId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PiwigoImages_AlbumId_FilePath", + table: "PiwigoImages"); + + migrationBuilder.DropIndex( + name: "IX_PiwigoImages_ServerImageId", + table: "PiwigoImages"); + + migrationBuilder.RenameColumn( + name: "ServerAlbumId", + table: "PiwigoAlbums", + newName: "PiwigoAlbumId"); + + migrationBuilder.RenameIndex( + name: "IX_PiwigoAlbums_ServerAlbumId", + table: "PiwigoAlbums", + newName: "IX_PiwigoAlbums_PiwigoAlbumId"); + + migrationBuilder.CreateIndex( + name: "IX_PiwigoImages_AlbumId", + table: "PiwigoImages", + column: "AlbumId"); + } + } +} diff --git a/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.Designer.cs b/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.Designer.cs new file mode 100644 index 0000000..89daf53 --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.Designer.cs @@ -0,0 +1,158 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PiwigoDirectorySync.Persistence; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + [DbContext(typeof(PersistenceContext))] + [Migration("20230830213341_Adds_directory_name_to_Album")] + partial class Adds_directory_name_to_Album + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.10"); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerAlbumId") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("ServerAlbumId"); + + b.HasIndex("ServerId"); + + b.ToTable("PiwigoAlbums"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AlbumId") + .HasColumnType("INTEGER"); + + b.Property("DeleteRequired") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastChange") + .HasColumnType("TEXT"); + + b.Property("Md5Sum") + .HasColumnType("TEXT"); + + b.Property("ServerImageId") + .HasColumnType("INTEGER"); + + b.Property("UploadRequired") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ServerImageId"); + + b.HasIndex("AlbumId", "FilePath"); + + b.ToTable("PiwigoImages"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ServerEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RootDirectory") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("PiwigoServers"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.AlbumEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.HasOne("PiwigoDirectorySync.Persistence.ServerEntity", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ImageEntity", b => + { + b.HasOne("PiwigoDirectorySync.Persistence.AlbumEntity", "Album") + .WithMany() + .HasForeignKey("AlbumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Album"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.cs b/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.cs new file mode 100644 index 0000000..f34a2ad --- /dev/null +++ b/PiwigoDirectorySync/Migrations/20230830213341_Adds_directory_name_to_Album.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PiwigoDirectorySync.Migrations +{ + /// + public partial class Adds_directory_name_to_Album : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Name", + table: "PiwigoAlbums", + type: "TEXT", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Name", + table: "PiwigoAlbums"); + } + } +} diff --git a/PiwigoDirectorySync/Migrations/PersistenceContextModelSnapshot.cs b/PiwigoDirectorySync/Migrations/PersistenceContextModelSnapshot.cs index 0ae48b7..a04fa60 100644 --- a/PiwigoDirectorySync/Migrations/PersistenceContextModelSnapshot.cs +++ b/PiwigoDirectorySync/Migrations/PersistenceContextModelSnapshot.cs @@ -23,14 +23,18 @@ namespace PiwigoDirectorySync.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("DirectoryName") + b.Property("Name") .IsRequired() .HasColumnType("TEXT"); b.Property("ParentId") .HasColumnType("INTEGER"); - b.Property("PiwigoAlbumId") + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerAlbumId") .HasColumnType("INTEGER"); b.Property("ServerId") @@ -40,7 +44,7 @@ namespace PiwigoDirectorySync.Migrations b.HasIndex("ParentId"); - b.HasIndex("PiwigoAlbumId"); + b.HasIndex("ServerAlbumId"); b.HasIndex("ServerId"); @@ -77,12 +81,14 @@ namespace PiwigoDirectorySync.Migrations b.HasKey("Id"); - b.HasIndex("AlbumId"); + b.HasIndex("ServerImageId"); + + b.HasIndex("AlbumId", "FilePath"); b.ToTable("PiwigoImages"); }); - modelBuilder.Entity("PiwigoDirectorySync.Persistence.PiwigoServerEntity", b => + modelBuilder.Entity("PiwigoDirectorySync.Persistence.ServerEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -122,7 +128,7 @@ namespace PiwigoDirectorySync.Migrations .WithMany() .HasForeignKey("ParentId"); - b.HasOne("PiwigoDirectorySync.Persistence.PiwigoServerEntity", "Server") + b.HasOne("PiwigoDirectorySync.Persistence.ServerEntity", "Server") .WithMany() .HasForeignKey("ServerId") .OnDelete(DeleteBehavior.Cascade) diff --git a/PiwigoDirectorySync/Persistence/AlbumEntity.cs b/PiwigoDirectorySync/Persistence/AlbumEntity.cs index ea62072..a645fa6 100644 --- a/PiwigoDirectorySync/Persistence/AlbumEntity.cs +++ b/PiwigoDirectorySync/Persistence/AlbumEntity.cs @@ -5,22 +5,21 @@ using Microsoft.EntityFrameworkCore; namespace PiwigoDirectorySync.Persistence; [Index(nameof(ParentId))] -[Index(nameof(PiwigoAlbumId))] +[Index(nameof(ServerAlbumId))] public class AlbumEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } - public int? PiwigoAlbumId { get; set; } - public required string DirectoryName { get; set; } + public int? ServerAlbumId { get; set; } + public required string Name { get; set; } + public required string Path { get; set; } public int? ParentId { get; set; } public AlbumEntity? Parent { get; set; } public required int ServerId { get; set; } - public PiwigoServerEntity Server { get; set; } = null!; + public ServerEntity Server { get; set; } = null!; - public string FullPath => - Parent is not null ? $"{Parent.FullPath}{Path.DirectorySeparatorChar}{DirectoryName}" : $"{Server.RootDirectory}{Path.DirectorySeparatorChar}{DirectoryName}"; } \ No newline at end of file diff --git a/PiwigoDirectorySync/Persistence/ExtensionMethods.cs b/PiwigoDirectorySync/Persistence/ExtensionMethods.cs index a6c4340..22de747 100644 --- a/PiwigoDirectorySync/Persistence/ExtensionMethods.cs +++ b/PiwigoDirectorySync/Persistence/ExtensionMethods.cs @@ -4,8 +4,13 @@ namespace PiwigoDirectorySync.Persistence; public static class ExtensionMethods { - public static Task GetByIdAsync(this DbSet dbSet, int serverId, CancellationToken ct) + public static Task GetByIdAsync(this DbSet dbSet, int serverId, CancellationToken ct) { return dbSet.Where(a => a.Id == serverId).FirstAsync(ct); } + + public static async Task FindByServerAndPathAsync(this DbSet dbSet, int serverId, string relativePath, CancellationToken ct) + { + return await dbSet.Where(a => a.ServerId == serverId && a.Path == relativePath).FirstOrDefaultAsync(ct); + } } \ No newline at end of file diff --git a/PiwigoDirectorySync/Persistence/ImageEntity.cs b/PiwigoDirectorySync/Persistence/ImageEntity.cs index d319c41..3141473 100644 --- a/PiwigoDirectorySync/Persistence/ImageEntity.cs +++ b/PiwigoDirectorySync/Persistence/ImageEntity.cs @@ -4,7 +4,8 @@ using Microsoft.EntityFrameworkCore; namespace PiwigoDirectorySync.Persistence; -[Index(nameof(AlbumId))] +[Index(nameof(AlbumId), nameof(FilePath))] +[Index(nameof(ServerImageId))] public class ImageEntity { [Key] diff --git a/PiwigoDirectorySync/Persistence/PersistenceContext.cs b/PiwigoDirectorySync/Persistence/PersistenceContext.cs index e560a2d..deab50d 100644 --- a/PiwigoDirectorySync/Persistence/PersistenceContext.cs +++ b/PiwigoDirectorySync/Persistence/PersistenceContext.cs @@ -4,7 +4,7 @@ namespace PiwigoDirectorySync.Persistence; public class PersistenceContext : DbContext { - public DbSet PiwigoServers { get; set; } = null!; + public DbSet PiwigoServers { get; set; } = null!; public DbSet PiwigoAlbums { get; set; } = null!; public DbSet PiwigoImages { get; set; } = null!; diff --git a/PiwigoDirectorySync/Persistence/PiwigoServerEntity.cs b/PiwigoDirectorySync/Persistence/ServerEntity.cs similarity index 92% rename from PiwigoDirectorySync/Persistence/PiwigoServerEntity.cs rename to PiwigoDirectorySync/Persistence/ServerEntity.cs index 063077e..c481b0a 100644 --- a/PiwigoDirectorySync/Persistence/PiwigoServerEntity.cs +++ b/PiwigoDirectorySync/Persistence/ServerEntity.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore; namespace PiwigoDirectorySync.Persistence; [Index(nameof(Name), IsUnique = true)] -public class PiwigoServerEntity +public class ServerEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] diff --git a/PiwigoDirectorySync/Properties/launchSettings.json b/PiwigoDirectorySync/Properties/launchSettings.json index 3856d80..e0dfd81 100644 --- a/PiwigoDirectorySync/Properties/launchSettings.json +++ b/PiwigoDirectorySync/Properties/launchSettings.json @@ -6,6 +6,12 @@ "commandLineArgs": "scan 1", "environmentVariables": { } + }, + "PiwigoDirectorySyncPng": { + "commandName": "Project", + "commandLineArgs": "scan 2", + "environmentVariables": { + } } } }