diff --git a/API.Tests/Parser/ParserTest.cs b/API.Tests/Parser/ParserTest.cs
index 6d75d564d..d24c03067 100644
--- a/API.Tests/Parser/ParserTest.cs
+++ b/API.Tests/Parser/ParserTest.cs
@@ -171,6 +171,8 @@ namespace API.Tests.Parser
[InlineData("TEST/Love Hina - Special.jpg", false)]
[InlineData("__macosx/Love Hina/", false)]
[InlineData("MACOSX/Love Hina/", false)]
+ [InlineData("._Love Hina/Love Hina/", true)]
+ [InlineData("@Recently-Snapshot/Love Hina/", true)]
public void HasBlacklistedFolderInPathTest(string inputPath, bool expected)
{
Assert.Equal(expected, HasBlacklistedFolderInPath(inputPath));
diff --git a/API/API.csproj b/API/API.csproj
index 92671bce9..06a00518a 100644
--- a/API/API.csproj
+++ b/API/API.csproj
@@ -62,6 +62,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/API/Data/Metadata/ComicInfo.cs b/API/Data/Metadata/ComicInfo.cs
index c34a305fd..7e53bb486 100644
--- a/API/Data/Metadata/ComicInfo.cs
+++ b/API/Data/Metadata/ComicInfo.cs
@@ -76,6 +76,7 @@ namespace API.Data.Metadata
public string CoverArtist { get; set; } = string.Empty;
public string Editor { get; set; } = string.Empty;
public string Publisher { get; set; } = string.Empty;
+ public string Characters { get; set; } = string.Empty;
public static AgeRating ConvertAgeRatingToEnum(string value)
{
diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs
index fb50cb880..410ec5c47 100644
--- a/API/Parser/Parser.cs
+++ b/API/Parser/Parser.cs
@@ -1097,7 +1097,7 @@ namespace API.Parser
public static bool HasBlacklistedFolderInPath(string path)
{
- return path.Contains("__MACOSX");
+ return path.Contains("__MACOSX") || path.StartsWith("@Recently-Snapshot");
}
diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs
index fa0cb9068..ae8dc7e55 100644
--- a/API/Services/ArchiveService.cs
+++ b/API/Services/ArchiveService.cs
@@ -346,6 +346,7 @@ namespace API.Services
info.Letterer = Parser.Parser.CleanAuthor(info.Letterer);
info.Penciller = Parser.Parser.CleanAuthor(info.Penciller);
info.Publisher = Parser.Parser.CleanAuthor(info.Publisher);
+ info.Characters = Parser.Parser.CleanAuthor(info.Characters);
if (!string.IsNullOrEmpty(info.Web))
{
diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs
index 6af4de9f9..d08229778 100644
--- a/API/Services/BookService.cs
+++ b/API/Services/BookService.cs
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
using System.IO;
using System.Linq;
-using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -20,7 +17,10 @@ using ExCSS;
using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
using Microsoft.IO;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
using VersOne.Epub;
+using Image = SixLabors.ImageSharp.Image;
namespace API.Services
{
@@ -445,31 +445,25 @@ namespace API.Services
return null;
}
- private static void AddBytesToBitmap(Bitmap bmp, byte[] rawBytes)
- {
- var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
-
- var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
- var pNative = bmpData.Scan0;
-
- Marshal.Copy(rawBytes, 0, pNative, rawBytes.Length);
- bmp.UnlockBits(bmpData);
- }
-
+ ///
+ /// Extracts a pdf into images to a target directory. Uses multi-threaded implementation since docnet is slow normally.
+ ///
+ ///
+ ///
public void ExtractPdfImages(string fileFilePath, string targetDirectory)
{
_directoryService.ExistOrCreate(targetDirectory);
using var docReader = DocLib.Instance.GetDocReader(fileFilePath, new PageDimensions(1080, 1920));
var pages = docReader.GetPageCount();
- using var stream = StreamManager.GetStream("BookService.GetPdfPage");
- for (var pageNumber = 0; pageNumber < pages; pageNumber++)
+ Parallel.For(0, pages, pageNumber =>
{
+ using var stream = StreamManager.GetStream("BookService.GetPdfPage");
GetPdfPage(docReader, pageNumber, stream);
using var fileStream = File.Create(Path.Combine(targetDirectory, "Page-" + pageNumber + ".png"));
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
- }
+ });
}
///
@@ -536,20 +530,14 @@ namespace API.Services
private static void GetPdfPage(IDocReader docReader, int pageNumber, Stream stream)
{
- // TODO: BUG: Most of this Bitmap code is only supported on Windows. Refactor.
using var pageReader = docReader.GetPageReader(pageNumber);
var rawBytes = pageReader.GetImage(new NaiveTransparencyRemover());
var width = pageReader.GetPageWidth();
var height = pageReader.GetPageHeight();
- using var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
- AddBytesToBitmap(bmp, rawBytes);
- // Removes 1px margin on left/right side after bitmap is copied out
- for (var y = 0; y < bmp.Height; y++)
- {
- bmp.SetPixel(bmp.Width - 1, y, bmp.GetPixel(bmp.Width - 2, y));
- }
+ var image = Image.LoadPixelData(rawBytes, width, height);
+
stream.Seek(0, SeekOrigin.Begin);
- bmp.Save(stream, ImageFormat.Jpeg);
+ image.SaveAsPng(stream);
stream.Seek(0, SeekOrigin.Begin);
}
diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs
index 4a28b7998..0054ad62f 100644
--- a/API/Services/MetadataService.cs
+++ b/API/Services/MetadataService.cs
@@ -113,6 +113,14 @@ public class MetadataService : IMetadataService
person => PersonHelper.AddPersonIfNotExists(chapter.People, person));
}
+ if (!string.IsNullOrEmpty(comicInfo.Characters))
+ {
+ var people = comicInfo.Characters.Split(",");
+ PersonHelper.RemovePeople(chapter.People, people, PersonRole.Character);
+ PersonHelper.UpdatePeople(allPeople, people, PersonRole.Character,
+ person => PersonHelper.AddPersonIfNotExists(chapter.People, person));
+ }
+
if (!string.IsNullOrEmpty(comicInfo.Translator))
{
var people = comicInfo.Translator.Split(",");
@@ -220,7 +228,6 @@ public class MetadataService : IMetadataService
{
if (series == null) return;
- //var firstFile = series.Volumes.FirstWithChapters().Chapters.Fir
if (!_cacheHelper.ShouldUpdateCoverImage(_directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, series.CoverImage),
null, series.Created, forceUpdate, series.CoverImageLocked))
return;