feat: 图片扫描和发布命令 #5

Merged
jackfiled merged 3 commits from refeat-image into master 2024-08-25 15:38:59 +08:00
5 changed files with 123 additions and 2 deletions
Showing only changes of commit 6ac162a124 - Show all commits

View File

@ -7,4 +7,6 @@ public interface IEssayScanService
public Task<BlogContents> ScanContents();
public Task SaveBlogContent(BlogContent content, bool isDraft = true);
public Task<ImageScanResult> ScanImages();
}

View File

@ -0,0 +1,3 @@
namespace YaeBlog.Core.Models;
public record struct ImageScanResult(List<FileInfo> UnusedImages, List<FileInfo> NotFoundImages);

View File

@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using YaeBlog.Core.Abstractions;
@ -9,7 +10,7 @@ using YamlDotNet.Serialization;
namespace YaeBlog.Core.Services;
public class EssayScanService(
public partial class EssayScanService(
ISerializer yamlSerializer,
IDeserializer yamlDeserializer,
IOptions<BlogOptions> blogOptions,
@ -96,6 +97,79 @@ public class EssayScanService(
return contents;
}
public async Task<ImageScanResult> ScanImages()
{
BlogContents contents = await ScanContents();
ValidateDirectory(_blogOptions.Root, out DirectoryInfo drafts, out DirectoryInfo posts);
List<FileInfo> unusedFiles = [];
List<FileInfo> notFoundFiles = [];
ImageScanResult draftResult = await ScanUnusedImagesInternal(contents.Drafts, drafts);
ImageScanResult postResult = await ScanUnusedImagesInternal(contents.Posts, posts);
unusedFiles.AddRange(draftResult.UnusedImages);
notFoundFiles.AddRange(draftResult.NotFoundImages);
unusedFiles.AddRange(postResult.UnusedImages);
notFoundFiles.AddRange(postResult.NotFoundImages);
return new ImageScanResult(unusedFiles, notFoundFiles);
}
private Task<ImageScanResult> ScanUnusedImagesInternal(IEnumerable<BlogContent> contents,
DirectoryInfo root)
{
Regex imageRegex = ImageRegex();
ConcurrentBag<FileInfo> unusedImage = [];
ConcurrentBag<FileInfo> notFoundImage = [];
Parallel.ForEach(contents, content =>
{
MatchCollection result = imageRegex.Matches(content.FileContent);
DirectoryInfo imageDirectory = new(Path.Combine(root.FullName, content.FileName));
Dictionary<string, bool> usedDictionary;
if (imageDirectory.Exists)
{
usedDictionary = (from file in imageDirectory.EnumerateFiles()
select new KeyValuePair<string, bool>(file.FullName, false)).ToDictionary();
}
else
{
usedDictionary = [];
}
foreach (Match match in result)
{
string imageName = match.Groups[1].Value;
FileInfo usedFile = imageName.Contains(content.FileName)
? new FileInfo(Path.Combine(root.FullName, imageName))
: new FileInfo(Path.Combine(root.FullName, content.FileName, imageName));
if (usedDictionary.TryGetValue(usedFile.FullName, out _))
{
usedDictionary[usedFile.FullName] = true;
}
else
{
notFoundImage.Add(usedFile);
}
}
foreach (KeyValuePair<string, bool> pair in usedDictionary.Where(p => !p.Value))
{
unusedImage.Add(new FileInfo(pair.Key));
}
});
return Task.FromResult(new ImageScanResult(unusedImage.ToList(), notFoundImage.ToList()));
}
[GeneratedRegex(@"\!\[.*?\]\((.*?)\)")]
private static partial Regex ImageRegex();
private void ValidateDirectory(string root, out DirectoryInfo drafts, out DirectoryInfo posts)
{
root = Path.Combine(Environment.CurrentDirectory, root);

View File

@ -96,7 +96,7 @@ public static class CommandExtensions
public static void AddListCommand(this RootCommand rootCommand)
{
Command command = new("list", "List all blogs");
rootCommand.Add(command);
rootCommand.AddCommand(command);
command.SetHandler(async (_, _, essyScanService) =>
{
@ -115,4 +115,45 @@ public static class CommandExtensions
}
}, new BlogOptionsBinder(), new LoggerBinder<EssayScanService>(), new EssayScanServiceBinder());
}
public static void AddScanCommand(this RootCommand rootCommand)
{
Command command = new("scan", "Scan unused and not found images.");
rootCommand.AddCommand(command);
Option<bool> removeOption =
new(name: "--rm", description: "Remove unused images.", getDefaultValue: () => false);
command.AddOption(removeOption);
command.SetHandler(async (_, _, essayScanService, removeOptionValue) =>
{
ImageScanResult result = await essayScanService.ScanImages();
if (result.UnusedImages.Count != 0)
{
Console.WriteLine("Found unused images:");
Console.WriteLine("HINT: use '--rm' to remove unused images.");
}
foreach (FileInfo image in result.UnusedImages)
{
Console.WriteLine($" - {image.FullName}");
}
if (removeOptionValue)
{
foreach (FileInfo image in result.UnusedImages)
{
image.Delete();
}
}
Console.WriteLine("Used not existed images:");
foreach (FileInfo image in result.NotFoundImages)
{
Console.WriteLine($" - {image.FullName}");
}
}, new BlogOptionsBinder(), new LoggerBinder<EssayScanService>(), new EssayScanServiceBinder(), removeOption);
}
}

View File

@ -7,5 +7,6 @@ rootCommand.AddServeCommand();
rootCommand.AddNewCommand();
rootCommand.AddListCommand();
rootCommand.AddWatchCommand();
rootCommand.AddScanCommand();
await rootCommand.InvokeAsync(args);