diff --git a/API/Data/Repositories/CollectionTagRepository.cs b/API/Data/Repositories/CollectionTagRepository.cs
index 5a45c117e..dc0ab8b7f 100644
--- a/API/Data/Repositories/CollectionTagRepository.cs
+++ b/API/Data/Repositories/CollectionTagRepository.cs
@@ -193,6 +193,7 @@ public class CollectionTagRepository : ICollectionTagRepository
.Where(t => t.Id == tag.Id)
.SelectMany(uc => uc.Items.Select(s => s.Metadata))
.Select(sm => sm.AgeRating)
+ .DefaultIfEmpty()
.MaxAsync();
tag.AgeRating = maxAgeRating;
await _context.SaveChangesAsync();
diff --git a/API/Entities/Library.cs b/API/Entities/Library.cs
index aa53b6651..503f1e257 100644
--- a/API/Entities/Library.cs
+++ b/API/Entities/Library.cs
@@ -40,8 +40,11 @@ public class Library : IEntityDate
///
/// Scrobbling requires a valid LicenseKey
public bool AllowScrobbling { get; set; } = true;
-
-
+ ///
+ /// Extra Regex that can be used for parsing
+ ///
+ /// This is only used for Generic Library
+ //public string? ExtraParsingRegex { get; set; }
diff --git a/API/Services/ReadingItemService.cs b/API/Services/ReadingItemService.cs
index 34360efa5..419c3440b 100644
--- a/API/Services/ReadingItemService.cs
+++ b/API/Services/ReadingItemService.cs
@@ -28,6 +28,7 @@ public class ReadingItemService : IReadingItemService
private readonly ImageParser _imageParser;
private readonly BookParser _bookParser;
private readonly PdfParser _pdfParser;
+ private readonly GenericLibraryParser _genericParser;
public ReadingItemService(IArchiveService archiveService, IBookService bookService, IImageService imageService,
IDirectoryService directoryService, ILogger logger)
@@ -43,6 +44,7 @@ public class ReadingItemService : IReadingItemService
_bookParser = new BookParser(directoryService, bookService, _basicParser);
_comicVineParser = new ComicVineParser(directoryService);
_pdfParser = new PdfParser(directoryService);
+ _genericParser = new GenericLibraryParser(directoryService);
}
@@ -177,6 +179,10 @@ public class ReadingItemService : IReadingItemService
///
private ParserInfo? Parse(string path, string rootPath, string libraryRoot, LibraryType type)
{
+ if (_genericParser.IsApplicable(path, type))
+ {
+ return _genericParser.Parse(path, rootPath, libraryRoot, type, GetComicInfo(path));
+ }
if (_comicVineParser.IsApplicable(path, type))
{
return _comicVineParser.Parse(path, rootPath, libraryRoot, type, GetComicInfo(path));
diff --git a/API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs b/API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs
index ebcb1264c..1dd6f674b 100644
--- a/API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs
+++ b/API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs
@@ -17,7 +17,13 @@ public class GenericLibraryParser(IDirectoryService directoryService) : DefaultP
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
ComicInfo? comicInfo = null, IEnumerable? extraRegex = null)
{
- if (extraRegex == null) return null;
+ //if (extraRegex == null) return null;
+
+ // It can be very difficult for the user to supply all the regex needed to properly parse, we might need to let them override (but not sure how this will work)
+ extraRegex = new List()
+ {
+ @"(?.*)(\b|_)v(?\d+-?\d+)( |_)"
+ };
// The idea is this is passed in as a default param. Only Generic will use it
var fileName = directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
@@ -36,7 +42,7 @@ public class GenericLibraryParser(IDirectoryService directoryService) : DefaultP
foreach (var regex in extraRegex)
{
- var matches = new Regex(regex, RegexOptions.IgnoreCase).Matches(fileName);
+ var matches = new Regex(regex, Parser.MatchOptions, Parser.RegexTimeout).Matches(fileName);
foreach (var group in matches.Select(match => match.Groups))
{
foreach (var matchKey in group.Keys)
@@ -50,6 +56,9 @@ public class GenericLibraryParser(IDirectoryService directoryService) : DefaultP
case "Chapter":
info.Chapters = SetIfNotDefault(matchValue, info.Chapters);
break;
+ case "Volume":
+ info.Volumes = SetIfNotDefault(matchValue, info.Volumes);
+ break;
}
}
}
diff --git a/API/Services/Tasks/Scanner/Parser/Parser.cs b/API/Services/Tasks/Scanner/Parser/Parser.cs
index 8c5aaaf84..f157de617 100644
--- a/API/Services/Tasks/Scanner/Parser/Parser.cs
+++ b/API/Services/Tasks/Scanner/Parser/Parser.cs
@@ -36,7 +36,7 @@ public static class Parser
public const string SupportedExtensions =
ArchiveFileExtensions + "|" + ImageFileExtensions + "|" + BookFileExtensions;
- private const RegexOptions MatchOptions =
+ public const RegexOptions MatchOptions =
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant;
private static readonly ImmutableArray FormatTagSpecialKeywords = ImmutableArray.Create(
@@ -1149,7 +1149,7 @@ public static class Parser
public static string? ExtractFilename(string fileUrl)
{
- var matches = Parser.CssImageUrlRegex.Matches(fileUrl);
+ var matches = CssImageUrlRegex.Matches(fileUrl);
foreach (Match match in matches)
{
if (!match.Success) continue;
diff --git a/openapi.json b/openapi.json
index 068719bcb..2efbf7c84 100644
--- a/openapi.json
+++ b/openapi.json
@@ -16658,6 +16658,7 @@
},
"created": {
"type": "string",
+ "description": "Extra Regex that can be used for parsing",
"format": "date-time"
},
"lastModified": {