moves scan classes into one namespace, makes file scanner work, adds user secrets support to config
This commit is contained in:
parent
2e130e8aad
commit
0a25ce2cc0
5
.gitignore
vendored
5
.gitignore
vendored
@ -303,8 +303,6 @@ node_modules/
|
|||||||
*.dsp
|
*.dsp
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
# Visual Studio 6 technical files
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# Visual Studio LightSwitch build output
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
@ -400,4 +398,7 @@ FodyWeavers.xsd
|
|||||||
|
|
||||||
# sqlite databases
|
# sqlite databases
|
||||||
*.db
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
/.idea/.idea.PiwigoDirectorySync/.idea/dataSources.xml
|
||||||
|
@ -4,14 +4,18 @@ namespace PiwigoDirectorySync;
|
|||||||
|
|
||||||
public static class AppSettings
|
public static class AppSettings
|
||||||
{
|
{
|
||||||
|
public static readonly IReadOnlySet<string> SupportedExtensions = new HashSet<string> { "jpg", "jpeg", "png" };
|
||||||
|
|
||||||
public static IConfigurationRoot Config { get; } = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory)
|
public static IConfigurationRoot Config { get; } = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory)
|
||||||
.AddJsonFile("appsettings.json", true)
|
.AddJsonFile("appsettings.json", true)
|
||||||
.AddJsonFile(Path.Combine(Environment.CurrentDirectory, "appsettings.json"), true)
|
.AddJsonFile(Path.Combine(Environment.CurrentDirectory, "appsettings.json"), true)
|
||||||
.AddJsonFile("/etc/PiwigoDirectorySync/appsettings.json", true)
|
.AddJsonFile("/etc/PiwigoDirectorySync/appsettings.json", true)
|
||||||
|
.AddUserSecrets<Program>(true)
|
||||||
.AddEnvironmentVariables()
|
.AddEnvironmentVariables()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
public static Settings Settings { get; } = Config.GetSection("settings").Get<Settings>() ?? throw new InvalidOperationException("Could not parse settings");
|
public static Settings Settings { get; } = Config.GetSection("settings").Get<Settings>() ?? throw new InvalidOperationException("Could not parse settings");
|
||||||
|
|
||||||
public static string ConnectionString => Config.GetConnectionString(Settings.DbProvider) ?? throw new InvalidOperationException($"Could not find connection string for provider {Settings.DbProvider}");
|
public static string ConnectionString =>
|
||||||
|
Config.GetConnectionString(Settings.DbProvider) ?? throw new InvalidOperationException($"Could not find connection string for provider {Settings.DbProvider}");
|
||||||
}
|
}
|
36
PiwigoDirectorySync/Commands/Scan/FileIndexer.cs
Normal file
36
PiwigoDirectorySync/Commands/Scan/FileIndexer.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Threading.Channels;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands.Scan;
|
||||||
|
|
||||||
|
public class FileIndexer
|
||||||
|
{
|
||||||
|
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
private readonly Channel<string> _fileQueue;
|
||||||
|
private readonly int _piwigoServerId;
|
||||||
|
|
||||||
|
public FileIndexer(Channel<string> fileQueue, int piwigoServerId)
|
||||||
|
{
|
||||||
|
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
||||||
|
_piwigoServerId = piwigoServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TotalFilesScanned { get; private set; }
|
||||||
|
|
||||||
|
public async Task StartProcessingAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
await foreach (var filePath in _fileQueue.Reader.ReadAllAsync(ct))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Info($"Indexing file {filePath}");
|
||||||
|
TotalFilesScanned++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex, $"could not delete file {filePath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
PiwigoDirectorySync/Commands/Scan/FileSystemScanner.cs
Normal file
76
PiwigoDirectorySync/Commands/Scan/FileSystemScanner.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System.Threading.Channels;
|
||||||
|
using NLog;
|
||||||
|
using PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands.Scan;
|
||||||
|
|
||||||
|
public class FileSystemScanner
|
||||||
|
{
|
||||||
|
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
private readonly Channel<string> _fileQueue;
|
||||||
|
private readonly int _piwigoServerId;
|
||||||
|
|
||||||
|
public FileSystemScanner(Channel<string> fileQueue, int piwigoServerId)
|
||||||
|
{
|
||||||
|
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
||||||
|
_piwigoServerId = piwigoServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ScanAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
await using var db = new PersistenceContext();
|
||||||
|
|
||||||
|
var piwigoServer = await db.PiwigoServers.GetByIdAsync(_piwigoServerId, ct);
|
||||||
|
Logger.Info($"Scanning files for piwigo server {piwigoServer.Name} in directory {piwigoServer.RootDirectory}");
|
||||||
|
|
||||||
|
await ScanRootDirectory(new DirectoryInfo(piwigoServer.RootDirectory), ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask ScanRootDirectory(DirectoryInfo directory, CancellationToken ct)
|
||||||
|
{
|
||||||
|
Logger.Info($"Scanning root directory {directory.FullName} for sidecars to delete");
|
||||||
|
var parallelOptions = new ParallelOptions
|
||||||
|
{
|
||||||
|
CancellationToken = ct
|
||||||
|
};
|
||||||
|
await Parallel.ForEachAsync(GetDirectories(directory), parallelOptions, FindAndEnqueueFilesToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask FindAndEnqueueFilesToAdd(DirectoryInfo directory, CancellationToken ct)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Info($"Scanning directory {directory.FullName} for images");
|
||||||
|
|
||||||
|
var imageFiles = AppSettings.SupportedExtensions.SelectMany(ext => directory.GetFiles($"*.{ext}", SearchOption.TopDirectoryOnly))
|
||||||
|
.Select(f => f.FullName)
|
||||||
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (!imageFiles.Any())
|
||||||
|
{
|
||||||
|
Logger.Debug($"No iamges in {directory.FullName} found, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var imageFile in imageFiles.Select(f => new FileInfo(f)))
|
||||||
|
{
|
||||||
|
Logger.Debug($"Found image {imageFile.FullName}, enqueue index");
|
||||||
|
await _fileQueue.Writer.WriteAsync(imageFile.FullName, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex, $"could not scan directory {directory.FullName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<DirectoryInfo> GetDirectories(DirectoryInfo directoryInfo)
|
||||||
|
{
|
||||||
|
yield return directoryInfo;
|
||||||
|
foreach (var directory in directoryInfo.EnumerateDirectories().SelectMany(GetDirectories))
|
||||||
|
{
|
||||||
|
yield return directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using NLog;
|
using NLog;
|
||||||
using PiwigoDirectorySync.Service;
|
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
namespace PiwigoDirectorySync.Commands.Scan;
|
||||||
|
|
||||||
public class ScanCommand : AsyncCommand<ScanSettings>
|
public class ScanCommand : AsyncCommand<ScanSettings>
|
||||||
{
|
{
|
||||||
@ -19,10 +18,10 @@ public class ScanCommand : AsyncCommand<ScanSettings>
|
|||||||
|
|
||||||
var fileQueue = Channel.CreateUnbounded<string>();
|
var fileQueue = Channel.CreateUnbounded<string>();
|
||||||
|
|
||||||
var indexer = new FileIndexer(fileQueue);
|
var indexer = new FileIndexer(fileQueue, settings.PiwigoServerId);
|
||||||
var indexerTask = indexer.StartProcessingAsync(cancellationTokenSource.Token);
|
var indexerTask = indexer.StartProcessingAsync(cancellationTokenSource.Token);
|
||||||
|
|
||||||
var scanner = new FileScanner(fileQueue);
|
var scanner = new FileSystemScanner(fileQueue, settings.PiwigoServerId);
|
||||||
await scanner.ScanAsync(cancellationTokenSource.Token);
|
await scanner.ScanAsync(cancellationTokenSource.Token);
|
||||||
|
|
||||||
fileQueue.Writer.Complete();
|
fileQueue.Writer.Complete();
|
16
PiwigoDirectorySync/Commands/Scan/ScanSettings.cs
Normal file
16
PiwigoDirectorySync/Commands/Scan/ScanSettings.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands.Scan;
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
|
public class ScanSettings : CommandSettings
|
||||||
|
{
|
||||||
|
[CommandArgument(0, "<PiwigoServerId>")]
|
||||||
|
public int PiwigoServerId { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("-d|--mark-for-delete")]
|
||||||
|
[DefaultValue(false)]
|
||||||
|
public bool MarkForDelete { get; set; }
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
using Spectre.Console.Cli;
|
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Commands;
|
|
||||||
|
|
||||||
public class ScanSettings : CommandSettings
|
|
||||||
{
|
|
||||||
}
|
|
11
PiwigoDirectorySync/Persistence/ExtensionMethods.cs
Normal file
11
PiwigoDirectorySync/Persistence/ExtensionMethods.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
public static class ExtensionMethods
|
||||||
|
{
|
||||||
|
public static Task<PiwigoServerEntity> GetByIdAsync(this DbSet<PiwigoServerEntity> dbSet, int serverId, CancellationToken ct)
|
||||||
|
{
|
||||||
|
return dbSet.Where(a => a.Id == serverId).FirstAsync(ct);
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ namespace PiwigoDirectorySync.Persistence;
|
|||||||
|
|
||||||
public class PersistenceContext : DbContext
|
public class PersistenceContext : DbContext
|
||||||
{
|
{
|
||||||
public DbSet<PiwigoServerEntity> PiwigoServers { get; set; }
|
public DbSet<PiwigoServerEntity> PiwigoServers { get; set; } = null!;
|
||||||
public DbSet<AlbumEntity> PiwigoAlbums { get; set; }
|
public DbSet<AlbumEntity> PiwigoAlbums { get; set; } = null!;
|
||||||
public DbSet<ImageEntity> PiwigoImages { get; set; }
|
public DbSet<ImageEntity> PiwigoImages { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||||
<PackageReference Include="Piwigo.Client" Version="0.1.0.17"/>
|
<PackageReference Include="Piwigo.Client" Version="0.1.0.17"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0"/>
|
||||||
@ -40,7 +41,10 @@
|
|||||||
<None Update="appsettings.json">
|
<None Update="appsettings.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Extensions.Logging;
|
using NLog.Extensions.Logging;
|
||||||
using PiwigoDirectorySync;
|
using PiwigoDirectorySync;
|
||||||
using PiwigoDirectorySync.Commands;
|
using PiwigoDirectorySync.Commands.Scan;
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
LogManager.Configuration = new NLogLoggingConfiguration(AppSettings.Config.GetSection("NLog"));
|
LogManager.Configuration = new NLogLoggingConfiguration(AppSettings.Config.GetSection("NLog"));
|
||||||
@ -10,6 +10,14 @@ var logger = logFactory.GetCurrentClassLogger();
|
|||||||
|
|
||||||
logger.Info("Starting command app");
|
logger.Info("Starting command app");
|
||||||
var app = new CommandApp();
|
var app = new CommandApp();
|
||||||
app.Configure(c => { c.AddCommand<ScanCommand>("scan"); });
|
app.Configure(config =>
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
config.PropagateExceptions();
|
||||||
|
config.ValidateExamples();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
config.AddCommand<ScanCommand>("scan");
|
||||||
|
});
|
||||||
|
|
||||||
return app.Run(args);
|
return app.Run(args);
|
11
PiwigoDirectorySync/Properties/launchSettings.json
Normal file
11
PiwigoDirectorySync/Properties/launchSettings.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"PiwigoDirectorySync": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "scan 1",
|
||||||
|
"environmentVariables": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
using System.Threading.Channels;
|
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Service;
|
|
||||||
|
|
||||||
public class FileIndexer
|
|
||||||
{
|
|
||||||
private readonly Channel<string> _fileQueue;
|
|
||||||
|
|
||||||
public FileIndexer(Channel<string> fileQueue)
|
|
||||||
{
|
|
||||||
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int TotalFilesScanned { get; }
|
|
||||||
|
|
||||||
public Task StartProcessingAsync(CancellationToken token) => throw new NotImplementedException();
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
using System.Threading.Channels;
|
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Service;
|
|
||||||
|
|
||||||
public class FileScanner
|
|
||||||
{
|
|
||||||
private readonly Channel<string> _fileQueue;
|
|
||||||
|
|
||||||
public FileScanner(Channel<string> fileQueue)
|
|
||||||
{
|
|
||||||
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ScanAsync(CancellationToken token) => throw new NotImplementedException();
|
|
||||||
}
|
|
@ -17,8 +17,8 @@ When you configure your environment for the first time and you do not like the d
|
|||||||
|
|
||||||
``
|
``
|
||||||
cd PiwigoDirectorySync
|
cd PiwigoDirectorySync
|
||||||
dotnet user-secrets set "DbProvider" "MariaDb"
|
dotnet user-secrets set "Settings:DbProvider" "Sqlite"
|
||||||
dotnet user-secrets set "ConnectionStrings:MariaDb" "Server=localhost;User Id=photowfdev;Password=password123;Database=photowfdev"
|
dotnet user-secrets set "ConnectionStrings:Sqlite" "Data Source=.\piwigoSync.db"
|
||||||
``
|
``
|
||||||
|
|
||||||
You'll find your secrets under `~/.microsoft/usersecrets/c68c0447-8c7d-4e88-bcc6-96a9853828c7/secrets.json`
|
You'll find your secrets under `~/.microsoft/usersecrets/c68c0447-8c7d-4e88-bcc6-96a9853828c7/secrets.json`
|
||||||
|
Loading…
Reference in New Issue
Block a user