That one evil commit that means you've actually started development like a real developer. But before that you just wrote things
254 lines
7.3 KiB
C#
254 lines
7.3 KiB
C#
using Serilog;
|
|
using Spectre.Console;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
namespace DownloadManager;
|
|
|
|
record struct rule
|
|
{
|
|
public required string Name { get; init; }
|
|
public required PatternType Type { get; init; }
|
|
public required string Pattern { get; init; }
|
|
public required string Destination { get; init; }
|
|
}
|
|
|
|
/* PatternType is included here for ease of use */
|
|
enum PatternType
|
|
{
|
|
ExactMatch = 1,
|
|
Regex = 2,
|
|
Glob = 3,
|
|
Danbooru = 4,
|
|
}
|
|
|
|
/* Management class to make handing rules easier */
|
|
class RuleManager
|
|
{
|
|
|
|
private List<rule> _rules;
|
|
private configuration _config;
|
|
private static ImageProcessing IP = new();
|
|
|
|
public RuleManager(ref configuration config)
|
|
{
|
|
_rules = new(); /* Start with no rules and load them later */
|
|
_config = config;
|
|
loadRules();
|
|
}
|
|
|
|
// attempt to load as many rules as possible
|
|
private void loadRules()
|
|
{
|
|
string[] ruleDirectories = _config.ruleDirectories;
|
|
string[] ruleFiles = { };
|
|
Log.Information("Attempting to load rules");
|
|
|
|
if (ruleDirectories.Length == 0)
|
|
{
|
|
Log.Warning("No rule directories loaded");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
Log.Information("Attempting to find rules in {dir}", ruleDirectories.Last());
|
|
ruleFiles = Directory.GetFiles(ruleDirectories.Last()); /* Use last since it will be the users choice */
|
|
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
Log.Error(e, "{path} may be a file and not a directory", ruleDirectories.Last());
|
|
}
|
|
catch (UnauthorizedAccessException e)
|
|
{
|
|
Log.Error(e, "You do not have permission to open {path}", ruleDirectories.Last());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Fatal(e, "Unexpected exception occured, Please open a GitHub issue");
|
|
Environment.Exit(70);
|
|
}
|
|
|
|
|
|
Log.Information("found {count} rules in {path}", ruleFiles.Length, ruleDirectories.Last());
|
|
Log.Debug("{@rules}", ruleFiles);
|
|
|
|
if (ruleFiles.Length == 0)
|
|
{
|
|
Log.Warning("No rules loaded");
|
|
return;
|
|
}
|
|
|
|
Log.Information("Loading rules from ruleFiles");
|
|
|
|
foreach (var file in ruleFiles)
|
|
{
|
|
try
|
|
{
|
|
Log.Information("Attempting to load rule {name}", Path.GetFileName(file));
|
|
using (var ruleStream = File.OpenText(file))
|
|
{
|
|
string json = ruleStream.ReadToEnd();
|
|
Log.Debug("{json}", json);
|
|
rule r = JsonSerializer.Deserialize<rule>(json);
|
|
Log.Information("Deserialised rule {@rule}", r);
|
|
_rules.Add(r);
|
|
}
|
|
}
|
|
catch (JsonException e)
|
|
{
|
|
Log.Error(e, "Could not deserialise JSON rule");
|
|
}
|
|
catch (UnauthorizedAccessException e)
|
|
{
|
|
Log.Error(e, "I/O error while reading rule");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Fatal(e, "Unexpected exception occurred, Please open a GitHub issue");
|
|
Environment.Exit(70);
|
|
}
|
|
}
|
|
_rules.Sort(delegate (rule x, rule y)
|
|
{
|
|
return x.Name.CompareTo(y.Name);
|
|
});
|
|
}
|
|
|
|
public bool ApplyRules()
|
|
{
|
|
if (_rules.Count() == 0)
|
|
{
|
|
Log.Warning("ApplyRules was called but there are no rules configured");
|
|
return false;
|
|
}
|
|
|
|
Log.Information("Attempting to run {count} rules, Dryrun:{dryrun}", _rules.Count(), _config.dryRun);
|
|
|
|
foreach (var rule in _rules)
|
|
{
|
|
bool result = false;
|
|
switch (rule.Type)
|
|
{
|
|
case PatternType.ExactMatch:
|
|
result = ApplyExact(rule);
|
|
break;
|
|
case PatternType.Regex:
|
|
result = ApplyRegex(rule);
|
|
break;
|
|
case PatternType.Glob:
|
|
result = ApplyGlob(rule);
|
|
break;
|
|
case PatternType.Danbooru:
|
|
result = ApplyDanbooru(rule);
|
|
break;
|
|
}
|
|
if (result)
|
|
{
|
|
Log.Information("Successfully applied rule {name}", rule.Name);
|
|
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool ApplyExact(rule rule)
|
|
{
|
|
// this ruletype should only match one file
|
|
string? file = Directory.GetFiles(_config.downloadDirectory)
|
|
.Where(x => Path.GetFileName(x) == rule.Pattern)
|
|
.FirstOrDefault(defaultValue: null);
|
|
if (file is null)
|
|
{
|
|
Log.Information("Could not apply rule {name} as nothing matched {pattern}", rule.Name, rule.Pattern);
|
|
return false;
|
|
}
|
|
safeMove(file, rule.Destination);
|
|
return true;
|
|
}
|
|
|
|
private bool ApplyRegex(rule rule)
|
|
{
|
|
Regex rx = new Regex(rule.Pattern, RegexOptions.Compiled);
|
|
|
|
string[] files = Directory.GetFiles(_config.downloadDirectory)
|
|
.Where(path => rx.IsMatch(Path.GetFileName(path))) // Match against file name to make regex more logical
|
|
.ToArray();
|
|
|
|
if (files.Length == 0)
|
|
{
|
|
Log.Information("Could not apply rule {name} as nothing matched {pattern}", rule.Name, rule.Pattern);
|
|
return false;
|
|
}
|
|
|
|
foreach (var file in files)
|
|
{
|
|
safeMove(file, rule.Destination);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool ApplyGlob(rule rule) { return false; }
|
|
|
|
private bool ApplyDanbooru(rule rule)
|
|
{
|
|
string[] files = Directory.GetFiles(_config.downloadDirectory)
|
|
.Where(path => Path.GetFileName(path).Substring(0, 2) == "__")
|
|
.ToArray();
|
|
|
|
if (files.Length == 0)
|
|
{
|
|
Log.Information("Could not apply rule {name}, no files applicable", rule.Name);
|
|
}
|
|
|
|
foreach (var file in files)
|
|
{
|
|
string? aspect = IP.GetAspectRatioString(file);
|
|
|
|
if (aspect is null)
|
|
{
|
|
continue; // probably not an image since cannot calculate aspect ratio
|
|
}
|
|
|
|
string dest = Path.Combine(rule.Destination, aspect);
|
|
safeMove(file, dest);
|
|
}
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
// TODO: add appropriate exception avoidance/handling here
|
|
private void safeMove(string file, string targetDir)
|
|
{
|
|
Log.Information("Moving {file} to {targetdir}", file, targetDir);
|
|
string target = Path.Combine(targetDir, Path.GetFileName(file));
|
|
|
|
|
|
if (File.Exists(target))
|
|
{
|
|
Log.Warning("target {target} already exists", target);
|
|
target = Path.Combine(targetDir,
|
|
Path.GetFileNameWithoutExtension(file),
|
|
DateTime.Today.ToString("yyyy-MM-dd"),
|
|
Path.GetExtension(file));
|
|
Log.Warning("Saving as: {target}", target);
|
|
}
|
|
|
|
if (_config.dryRun) { return; }
|
|
|
|
if (_config.confirm)
|
|
{
|
|
if (!AnsiConsole.Confirm("Move file?"))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
Directory.CreateDirectory(targetDir);
|
|
File.Move(file, target);
|
|
}
|
|
}
|