feat: 图片扫描和发布命令 (#5)
All checks were successful
Build blog docker image / Build-Blog-Image (push) Successful in 1m26s

Reviewed-on: #5
This commit is contained in:
2024-08-25 15:38:58 +08:00
parent 9111affeec
commit 4085b0d99c
18 changed files with 208 additions and 31 deletions

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,
@@ -34,6 +35,11 @@ public class EssayScanService(
? new FileInfo(Path.Combine(drafts.FullName, content.FileName + ".md"))
: new FileInfo(Path.Combine(posts.FullName, content.FileName + ".md"));
if (!isDraft)
{
content.Metadata.Date = DateTime.Now;
}
if (targetFile.Exists)
{
logger.LogWarning("Blog {} exists, overriding.", targetFile.Name);
@@ -44,7 +50,15 @@ public class EssayScanService(
await writer.WriteAsync("---\n");
await writer.WriteAsync(yamlSerializer.Serialize(content.Metadata));
await writer.WriteAsync("---\n");
await writer.WriteAsync("<!--more-->\n");
if (isDraft)
{
await writer.WriteLineAsync("<!--more-->");
}
else
{
await writer.WriteAsync(content.FileContent);
}
}
private async Task<ConcurrentBag<BlogContent>> ScanContentsInternal(DirectoryInfo directory)
@@ -96,6 +110,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 static 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);