makes most classes internal and adds a download command to download original images from piwigo to the local folder (can be used for backup of a gallery)
All checks were successful
PiwigoDirectorySync/pipeline/head This commit looks good
All checks were successful
PiwigoDirectorySync/pipeline/head This commit looks good
This commit is contained in:
parent
303d69efe6
commit
96bce7c83a
@ -2,7 +2,7 @@ using Microsoft.Extensions.Configuration;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync;
|
namespace PiwigoDirectorySync;
|
||||||
|
|
||||||
public static class AppSettings
|
internal static class AppSettings
|
||||||
{
|
{
|
||||||
public static readonly IReadOnlySet<string> SupportedExtensions = new HashSet<string> { "jpg", "jpeg", "png" };
|
public static readonly IReadOnlySet<string> SupportedExtensions = new HashSet<string> { "jpg", "jpeg", "png" };
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ using Spectre.Console.Cli;
|
|||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global", Justification = "Done by parser")]
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global", Justification = "Done by parser")]
|
||||||
public class CommonCommandSettings : CommandSettings
|
internal class CommonCommandSettings : CommandSettings
|
||||||
{
|
{
|
||||||
[CommandArgument(0, "[PiwigoServerId]")]
|
[CommandArgument(0, "[PiwigoServerId]")]
|
||||||
[DefaultValue(1)]
|
[DefaultValue(1)]
|
||||||
|
33
PiwigoDirectorySync/Commands/DownloadImagesCommand.cs
Normal file
33
PiwigoDirectorySync/Commands/DownloadImagesCommand.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PiwigoDirectorySync.Services;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
|
internal class DownloadImagesCommand : AsyncCommand<DownloadImagesSettings>
|
||||||
|
{
|
||||||
|
private readonly IImageSynchronizer _imageSynchronizer;
|
||||||
|
private readonly ILogger<DownloadImagesCommand> _logger;
|
||||||
|
|
||||||
|
public DownloadImagesCommand(IImageSynchronizer imageSynchronizer, ILogger<DownloadImagesCommand> logger)
|
||||||
|
{
|
||||||
|
_imageSynchronizer = imageSynchronizer;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<int> ExecuteAsync(CommandContext context, DownloadImagesSettings settings)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Starting image download for piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId);
|
||||||
|
var stopWatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
await _imageSynchronizer.DownloadImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token);
|
||||||
|
|
||||||
|
stopWatch.Stop();
|
||||||
|
_logger.LogInformation("Synchronized all images with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId,
|
||||||
|
stopWatch.Elapsed.TotalSeconds);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
5
PiwigoDirectorySync/Commands/DownloadImagesSettings.cs
Normal file
5
PiwigoDirectorySync/Commands/DownloadImagesSettings.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
|
internal class DownloadImagesSettings : CommonCommandSettings
|
||||||
|
{
|
||||||
|
}
|
@ -6,7 +6,7 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class ScanCommand : AsyncCommand<ScanSettings>
|
internal class ScanCommand : AsyncCommand<ScanSettings>
|
||||||
{
|
{
|
||||||
private readonly IFileIndexer _fileIndexer;
|
private readonly IFileIndexer _fileIndexer;
|
||||||
private readonly IFileSystemScanner _fileSystemScanner;
|
private readonly IFileSystemScanner _fileSystemScanner;
|
||||||
|
@ -5,7 +5,7 @@ using Spectre.Console.Cli;
|
|||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
public class ScanSettings : CommonCommandSettings
|
internal class ScanSettings : CommonCommandSettings
|
||||||
{
|
{
|
||||||
[CommandOption("-d|--mark-for-delete")]
|
[CommandOption("-d|--mark-for-delete")]
|
||||||
[DefaultValue(false)]
|
[DefaultValue(false)]
|
||||||
|
@ -5,7 +5,7 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class SyncAlbumsCommand : AsyncCommand<SyncAlbumsSettings>
|
internal class SyncAlbumsCommand : AsyncCommand<SyncAlbumsSettings>
|
||||||
{
|
{
|
||||||
private readonly IAlbumSynchronizer _albumSynchronizer;
|
private readonly IAlbumSynchronizer _albumSynchronizer;
|
||||||
private readonly ILogger<SyncAlbumsCommand> _logger;
|
private readonly ILogger<SyncAlbumsCommand> _logger;
|
||||||
@ -18,7 +18,8 @@ public class SyncAlbumsCommand : AsyncCommand<SyncAlbumsSettings>
|
|||||||
|
|
||||||
public override async Task<int> ExecuteAsync(CommandContext context, SyncAlbumsSettings settings)
|
public override async Task<int> ExecuteAsync(CommandContext context, SyncAlbumsSettings settings)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Starting album synchronization");
|
_logger.LogInformation("Starting album synchronization for piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId);
|
||||||
|
|
||||||
var stopWatch = Stopwatch.StartNew();
|
var stopWatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
@ -3,6 +3,6 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
public class SyncAlbumsSettings : CommonCommandSettings
|
internal class SyncAlbumsSettings : CommonCommandSettings
|
||||||
{
|
{
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class SyncFullCommand : AsyncCommand<SyncFullSettings>
|
internal class SyncFullCommand : AsyncCommand<SyncFullSettings>
|
||||||
{
|
{
|
||||||
private readonly IAlbumSynchronizer _albumSynchronizer;
|
private readonly IAlbumSynchronizer _albumSynchronizer;
|
||||||
private readonly IFileIndexer _fileIndexer;
|
private readonly IFileIndexer _fileIndexer;
|
||||||
@ -37,7 +37,7 @@ public class SyncFullCommand : AsyncCommand<SyncFullSettings>
|
|||||||
await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationTokenSource.Token);
|
await _albumSynchronizer.SynchronizeAlbums(settings.PiwigoServerId, cancellationTokenSource.Token);
|
||||||
|
|
||||||
_logger.LogInformation("running image synchronization");
|
_logger.LogInformation("running image synchronization");
|
||||||
await _imageSynchronizer.SynchronizeImages(settings.PiwigoServerId, cancellationTokenSource.Token);
|
await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token);
|
||||||
|
|
||||||
stopWatch.Stop();
|
stopWatch.Stop();
|
||||||
_logger.LogInformation("Full synchronization for piwigo server {SettingsPiwigoServerId} finished in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId,
|
_logger.LogInformation("Full synchronization for piwigo server {SettingsPiwigoServerId} finished in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId,
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class SyncFullSettings : CommonCommandSettings {}
|
internal class SyncFullSettings : CommonCommandSettings {}
|
@ -5,7 +5,7 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class SyncImagesCommand : AsyncCommand<SyncImagesSettings>
|
internal class SyncImagesCommand : AsyncCommand<SyncImagesSettings>
|
||||||
{
|
{
|
||||||
private readonly IImageSynchronizer _imageSynchronizer;
|
private readonly IImageSynchronizer _imageSynchronizer;
|
||||||
private readonly ILogger<SyncImagesCommand> _logger;
|
private readonly ILogger<SyncImagesCommand> _logger;
|
||||||
@ -18,11 +18,11 @@ public class SyncImagesCommand : AsyncCommand<SyncImagesSettings>
|
|||||||
|
|
||||||
public override async Task<int> ExecuteAsync(CommandContext context, SyncImagesSettings settings)
|
public override async Task<int> ExecuteAsync(CommandContext context, SyncImagesSettings settings)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Starting image synchronization");
|
_logger.LogInformation("Starting image synchronization of piwigo server {SettingsPiwigoServerId}", settings.PiwigoServerId);
|
||||||
var stopWatch = Stopwatch.StartNew();
|
var stopWatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
await _imageSynchronizer.SynchronizeImages(settings.PiwigoServerId, cancellationTokenSource.Token);
|
await _imageSynchronizer.SynchronizeImagesAsync(settings.PiwigoServerId, cancellationTokenSource.Token);
|
||||||
|
|
||||||
stopWatch.Stop();
|
stopWatch.Stop();
|
||||||
_logger.LogInformation("Synchronized all images with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId,
|
_logger.LogInformation("Synchronized all images with piwigo server {SettingsPiwigoServerId} in {ElapsedTotalSeconds} seconds", settings.PiwigoServerId,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
public class SyncImagesSettings : CommonCommandSettings
|
internal class SyncImagesSettings : CommonCommandSettings
|
||||||
{
|
{
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ using Spectre.Console.Cli;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Infrastructure;
|
namespace PiwigoDirectorySync.Infrastructure;
|
||||||
|
|
||||||
public sealed class DependencyInjectionTypeRegistrar : ITypeRegistrar
|
internal sealed class DependencyInjectionTypeRegistrar : ITypeRegistrar
|
||||||
{
|
{
|
||||||
private readonly IServiceCollection _builder;
|
private readonly IServiceCollection _builder;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Infrastructure;
|
namespace PiwigoDirectorySync.Infrastructure;
|
||||||
|
|
||||||
public sealed class DependencyTypeResolver : ITypeResolver, IDisposable
|
internal sealed class DependencyTypeResolver : ITypeResolver, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _provider;
|
private readonly IServiceProvider _provider;
|
||||||
|
|
||||||
|
14
PiwigoDirectorySync/Infrastructure/FilesystemHelpers.cs
Normal file
14
PiwigoDirectorySync/Infrastructure/FilesystemHelpers.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Infrastructure;
|
||||||
|
|
||||||
|
internal static class FilesystemHelpers
|
||||||
|
{
|
||||||
|
public static async Task<string> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using PiwigoDirectorySync.Persistence;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Infrastructure;
|
namespace PiwigoDirectorySync.Infrastructure;
|
||||||
|
|
||||||
public interface IPiwigoClientFactory
|
internal interface IPiwigoClientFactory
|
||||||
{
|
{
|
||||||
Task<IPiwigoClient> GetPiwigoClientAsync(ServerEntity piwigoServer, CancellationToken ct);
|
Task<IPiwigoClient> GetPiwigoClientAsync(ServerEntity piwigoServer, CancellationToken ct);
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ using PiwigoDirectorySync.Persistence;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Infrastructure;
|
namespace PiwigoDirectorySync.Infrastructure;
|
||||||
|
|
||||||
public class PiwigoClientFactory : IPiwigoClientFactory
|
internal class PiwigoClientFactory : IPiwigoClientFactory
|
||||||
{
|
{
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
@ -45,11 +45,12 @@ app.Configure(config =>
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
config.AddCommand<ScanCommand>("scan");
|
config.AddCommand<ScanCommand>("scan");
|
||||||
|
config.AddCommand<DownloadImagesCommand>("download");
|
||||||
config.AddBranch("sync", c =>
|
config.AddBranch("sync", c =>
|
||||||
{
|
{
|
||||||
|
c.AddCommand<SyncFullCommand>("full");
|
||||||
c.AddCommand<SyncAlbumsCommand>("albums");
|
c.AddCommand<SyncAlbumsCommand>("albums");
|
||||||
c.AddCommand<SyncImagesCommand>("images");
|
c.AddCommand<SyncImagesCommand>("images");
|
||||||
c.AddCommand<SyncFullCommand>("full");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,6 +30,12 @@
|
|||||||
"commandLineArgs": "sync full",
|
"commandLineArgs": "sync full",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Download": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "download",
|
||||||
|
"environmentVariables": {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ using PiwigoDirectorySync.Persistence;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public class AlbumSynchronizer : IAlbumSynchronizer
|
internal class AlbumSynchronizer : IAlbumSynchronizer
|
||||||
{
|
{
|
||||||
private readonly ILogger<AlbumSynchronizer> _logger;
|
private readonly ILogger<AlbumSynchronizer> _logger;
|
||||||
private readonly PersistenceContext _persistenceContext;
|
private readonly PersistenceContext _persistenceContext;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Threading.Channels;
|
||||||
using System.Threading.Channels;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PiwigoDirectorySync.Infrastructure;
|
||||||
using PiwigoDirectorySync.Persistence;
|
using PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public class FileIndexer : IFileIndexer
|
internal class FileIndexer : IFileIndexer
|
||||||
{
|
{
|
||||||
private readonly IList<string> _failedFiles = new List<string>();
|
private readonly IList<string> _failedFiles = new List<string>();
|
||||||
private readonly ILogger<FileIndexer> _logger;
|
private readonly ILogger<FileIndexer> _logger;
|
||||||
@ -54,7 +54,7 @@ public class FileIndexer : IFileIndexer
|
|||||||
if (image.LastChange != fileInfo.LastWriteTimeUtc)
|
if (image.LastChange != fileInfo.LastWriteTimeUtc)
|
||||||
{
|
{
|
||||||
image.UploadRequired = true;
|
image.UploadRequired = true;
|
||||||
image.Md5Sum = await CalculateMd5SumAsync(fullFilePath, ct);
|
image.Md5Sum = await FilesystemHelpers.CalculateMd5SumAsync(fullFilePath, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
image.DeleteRequired = false;
|
image.DeleteRequired = false;
|
||||||
@ -125,12 +125,4 @@ public class FileIndexer : IFileIndexer
|
|||||||
|
|
||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ using PiwigoDirectorySync.Persistence;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public class FileSystemScanner : IFileSystemScanner
|
internal class FileSystemScanner : IFileSystemScanner
|
||||||
{
|
{
|
||||||
private readonly ILogger<FileSystemScanner> _logger;
|
private readonly ILogger<FileSystemScanner> _logger;
|
||||||
private readonly PersistenceContext _persistenceContext;
|
private readonly PersistenceContext _persistenceContext;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public interface IAlbumSynchronizer
|
internal interface IAlbumSynchronizer
|
||||||
{
|
{
|
||||||
Task SynchronizeAlbums(int piwigoServerId, CancellationToken ct);
|
Task SynchronizeAlbums(int piwigoServerId, CancellationToken ct);
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ using System.Threading.Channels;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public interface IFileIndexer
|
internal interface IFileIndexer
|
||||||
{
|
{
|
||||||
int TotalFilesScanned { get; }
|
int TotalFilesScanned { get; }
|
||||||
IReadOnlyCollection<string> FailedFiles { get; }
|
IReadOnlyCollection<string> FailedFiles { get; }
|
||||||
|
@ -2,7 +2,7 @@ using System.Threading.Channels;
|
|||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public interface IFileSystemScanner
|
internal interface IFileSystemScanner
|
||||||
{
|
{
|
||||||
Task ScanAsync(Channel<string> fileQueue, int piwigoServerId, CancellationToken ct);
|
Task ScanAsync(Channel<string> fileQueue, int piwigoServerId, CancellationToken ct);
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public interface IImageSynchronizer
|
internal interface IImageSynchronizer
|
||||||
{
|
{
|
||||||
Task SynchronizeImages(int piwigoServerId, CancellationToken ct);
|
Task SynchronizeImagesAsync(int piwigoServerId, CancellationToken ct);
|
||||||
|
Task DownloadImagesAsync(int piwigoServerId, CancellationToken ct);
|
||||||
}
|
}
|
@ -1,13 +1,15 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Flurl.Http;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Piwigo.Client;
|
using Piwigo.Client;
|
||||||
|
using Piwigo.Client.Albums;
|
||||||
using Piwigo.Client.Images;
|
using Piwigo.Client.Images;
|
||||||
using PiwigoDirectorySync.Infrastructure;
|
using PiwigoDirectorySync.Infrastructure;
|
||||||
using PiwigoDirectorySync.Persistence;
|
using PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
|
|
||||||
public class ImageSynchronizer : IImageSynchronizer
|
internal class ImageSynchronizer : IImageSynchronizer
|
||||||
{
|
{
|
||||||
private readonly ILogger<ImageSynchronizer> _logger;
|
private readonly ILogger<ImageSynchronizer> _logger;
|
||||||
private readonly PersistenceContext _persistenceContext;
|
private readonly PersistenceContext _persistenceContext;
|
||||||
@ -20,7 +22,34 @@ public class ImageSynchronizer : IImageSynchronizer
|
|||||||
_persistenceContext = persistenceContext;
|
_persistenceContext = persistenceContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SynchronizeImages(int piwigoServerId, CancellationToken ct)
|
public async Task DownloadImagesAsync(int piwigoServerId, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var piwigoServer = await _persistenceContext.PiwigoServers.FindAsync(new object?[] { piwigoServerId }, ct);
|
||||||
|
if (piwigoServer is null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Could not sync images with piwigo server {PiwigoServerId}", piwigoServerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Downloading missing images of piwigo server {PiwigoServerName} using base path {PiwigoServerRootDirectory}", piwigoServer.Name,
|
||||||
|
piwigoServer.RootDirectory);
|
||||||
|
|
||||||
|
var piwigoClient = await _piwigoClientFactory.GetPiwigoClientAsync(piwigoServer, ct);
|
||||||
|
|
||||||
|
var albumIdsToDownload = await _persistenceContext.PiwigoAlbums.Where(a => a.ServerAlbumId.HasValue).Select(a => a.ServerAlbumId!.Value).Distinct().ToListAsync(ct);
|
||||||
|
|
||||||
|
foreach (var albumId in albumIdsToDownload)
|
||||||
|
{
|
||||||
|
var albumInfos = await piwigoClient.Album.GetListAsync(albumId, false, false, ThumbnailSize.Thumb, ct);
|
||||||
|
var albumInfo = albumInfos.First();
|
||||||
|
|
||||||
|
_logger.LogInformation("Starting downloads for album {AlbumInfoName}", albumInfo.Name);
|
||||||
|
|
||||||
|
await DownloadImagesForAlbumAsync(piwigoClient, piwigoServer, albumId, albumInfo, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SynchronizeImagesAsync(int piwigoServerId, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var piwigoServer = await _persistenceContext.PiwigoServers.FindAsync(new object?[] { piwigoServerId }, ct);
|
var piwigoServer = await _persistenceContext.PiwigoServers.FindAsync(new object?[] { piwigoServerId }, ct);
|
||||||
if (piwigoServer is null)
|
if (piwigoServer is null)
|
||||||
@ -39,6 +68,75 @@ public class ImageSynchronizer : IImageSynchronizer
|
|||||||
await UploadChangedImagesToServerAsync(piwigoClient, piwigoServer, ct);
|
await UploadChangedImagesToServerAsync(piwigoClient, piwigoServer, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DownloadImagesForAlbumAsync(IPiwigoClient piwigoClient, ServerEntity piwigoServer, int albumId, Album albumInfo, CancellationToken ct)
|
||||||
|
{
|
||||||
|
if (albumInfo.NbImages is null or <= 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("No images to download for empty album {AlbumId} / {AlbumInfoName}", albumId, albumInfo.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int pageSize = 100;
|
||||||
|
var numberOfPages = albumInfo.NbImages.Value / pageSize + 1;
|
||||||
|
var currentPage = 0;
|
||||||
|
|
||||||
|
while (currentPage < numberOfPages)
|
||||||
|
{
|
||||||
|
var imagePagingInfo = new ImagePagingInfo(currentPage, pageSize, albumInfo.NbImages.Value);
|
||||||
|
var images = await piwigoClient.Image.GetImagesAsync(albumId, false, imagePagingInfo, ImageFilter.Empty, ImageOrder.Name, ct);
|
||||||
|
|
||||||
|
foreach (var image in images.Images)
|
||||||
|
{
|
||||||
|
await DownloadImageAsync(piwigoServer, albumInfo, image, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DownloadImageAsync(ServerEntity piwigoServer, Album albumInfo, Image image, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var localAlbum = await _persistenceContext.PiwigoAlbums.FindByServerIdAsync(piwigoServer.Id, albumInfo.Id, ct);
|
||||||
|
if (localAlbum is null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Could not add image {ImageId} / {ImageFile}: album with server id {AlbumInfoId} / {AlbumInfoName} not found", image.Id, image.File, albumInfo.Id,
|
||||||
|
albumInfo.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localImage = await GetOrAddImageFromServerAsync(localAlbum, image, ct);
|
||||||
|
|
||||||
|
var fileInfo = new FileInfo(Path.Combine(piwigoServer.RootDirectory, localImage.FilePath));
|
||||||
|
if (fileInfo.Exists)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Tried to download image {ImageFile} but it already exists", image.File);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await image.ElementUrl.DownloadFileAsync(fileInfo.Directory!.FullName, fileInfo.Name, cancellationToken: ct);
|
||||||
|
localImage.Md5Sum = await FilesystemHelpers.CalculateMd5SumAsync(fileInfo.FullName, ct);
|
||||||
|
await _persistenceContext.SaveChangesAsync(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ImageEntity> GetOrAddImageFromServerAsync(AlbumEntity album, Image image, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var imageEntity = await _persistenceContext.PiwigoImages.Where(i => i.AlbumId == album.Id && i.ServerImageId == image.Id).FirstOrDefaultAsync(ct);
|
||||||
|
if (imageEntity is null)
|
||||||
|
{
|
||||||
|
imageEntity = new ImageEntity
|
||||||
|
{
|
||||||
|
AlbumId = album.Id,
|
||||||
|
Album = album,
|
||||||
|
FilePath = Path.Combine(album.Path, image.File!),
|
||||||
|
UploadRequired = false,
|
||||||
|
DeleteRequired = false
|
||||||
|
};
|
||||||
|
_persistenceContext.PiwigoImages.Add(imageEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageEntity;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UploadChangedImagesToServerAsync(IPiwigoClient piwigoClient, ServerEntity piwigoServer, CancellationToken ct)
|
private async Task UploadChangedImagesToServerAsync(IPiwigoClient piwigoClient, ServerEntity piwigoServer, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var imagesToUpload = await _persistenceContext.PiwigoImages.Include(i => i.Album)
|
var imagesToUpload = await _persistenceContext.PiwigoImages.Include(i => i.Album)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace PiwigoDirectorySync;
|
namespace PiwigoDirectorySync;
|
||||||
|
|
||||||
public class Settings
|
internal class Settings
|
||||||
{
|
{
|
||||||
public string DbProvider { get; set; } = null!;
|
public string DbProvider { get; set; } = null!;
|
||||||
public string ImageRootDirectory { get; set; } = null!;
|
public string ImageRootDirectory { get; set; } = null!;
|
||||||
|
Loading…
Reference in New Issue
Block a user