v0.6.1 Hotfix RC (#1635)

* Swapped out SQLite for Memory, but the one from hangfire. Added DisableConcurrentExecution on ProcessChange to avoid duplication when multiple threads execute at once.

* Fixed the Hangfire SQL issues with CPU/ram utilization some users are facing

* Fixed a case in SharpCompress fallback where an invalid ComicInfo wasn't picked up.

* When parsing epubs, if there is a volume in the epub title, try to parse and group. This is beneficial for Light Novels which are generally tagged this way.

* Fixed delete series in series detail not triggering

* Fixed some parsing logic for how we treat specials, like Annual and Omnibus.

* When scanning files, if the file is the cover image (loose leaf image), we reject it more quickly than previously.

* Added a potential bug marker

* Fixed a bug where Info was only showing Error level loggers

* Code smells
This commit is contained in:
Joe Milazzo 2022-11-05 09:56:48 -04:00 committed by GitHub
parent 6dd79d8c6a
commit 3f51cb2a02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 96 additions and 15 deletions

View file

@ -54,6 +54,7 @@
<PackageReference Include="Flurl.Http" Version="3.2.4" />
<PackageReference Include="Hangfire" Version="1.7.31" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.31" />
<PackageReference Include="Hangfire.InMemory" Version="0.3.4" />
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.3.2" />

View file

@ -71,7 +71,7 @@ public static class LogLevelOptions
AspNetCoreLogLevelSwitch.MinimumLevel = LogEventLevel.Warning;
break;
case "Information":
LogLevelSwitch.MinimumLevel = LogEventLevel.Error;
LogLevelSwitch.MinimumLevel = LogEventLevel.Information;
MicrosoftLogLevelSwitch.MinimumLevel = LogEventLevel.Error;
MicrosoftHostingLifetimeLogLevelSwitch.MinimumLevel = LogEventLevel.Error;
AspNetCoreLogLevelSwitch.MinimumLevel = LogEventLevel.Error;

View file

@ -331,7 +331,7 @@ public class ArchiveService : IArchiveService
private static bool IsComicInfoArchiveEntry(string fullName, string name)
{
return !Tasks.Scanner.Parser.Parser.HasBlacklistedFolderInPath(fullName)
&& name.Equals(ComicInfoFilename, StringComparison.OrdinalIgnoreCase)
&& name.EndsWith(ComicInfoFilename, StringComparison.OrdinalIgnoreCase)
&& !name.StartsWith(Tasks.Scanner.Parser.Parser.MacOsMetadataFileStartsWith);
}

View file

@ -451,9 +451,22 @@ public class BookService : IBookService
info.Series = metadataItem.Content;
info.SeriesSort = metadataItem.Content;
break;
case "calibre:series_index":
info.Volume = metadataItem.Content;
break;
}
}
var hasVolumeInSeries = !Tasks.Scanner.Parser.Parser.ParseVolume(info.Title)
.Equals(Tasks.Scanner.Parser.Parser.DefaultVolume);
if (string.IsNullOrEmpty(info.Volume) && hasVolumeInSeries && (!info.Series.Equals(info.Title) || string.IsNullOrEmpty(info.Series)))
{
// This is likely a light novel for which we can set series from parsed title
info.Series = Tasks.Scanner.Parser.Parser.ParseSeries(info.Title);
info.Volume = Tasks.Scanner.Parser.Parser.ParseVolume(info.Title);
}
return info;
}
catch (Exception ex)

View file

@ -72,8 +72,23 @@ public class ReadingItemService : IReadingItemService
// This catches when original library type is Manga/Comic and when parsing with non
if (Tasks.Scanner.Parser.Parser.IsEpub(path) && Tasks.Scanner.Parser.Parser.ParseVolume(info.Series) != Tasks.Scanner.Parser.Parser.DefaultVolume) // Shouldn't this be info.Volume != DefaultVolume?
{
var info2 = _defaultParser.Parse(path, rootPath, LibraryType.Book);
info.Merge(info2);
var hasVolumeInTitle = !Tasks.Scanner.Parser.Parser.ParseVolume(info.Title)
.Equals(Tasks.Scanner.Parser.Parser.DefaultVolume);
var hasVolumeInSeries = !Tasks.Scanner.Parser.Parser.ParseVolume(info.Series)
.Equals(Tasks.Scanner.Parser.Parser.DefaultVolume);
if (string.IsNullOrEmpty(info.ComicInfo?.Volume) && hasVolumeInTitle && (hasVolumeInSeries || string.IsNullOrEmpty(info.Series)))
{
// This is likely a light novel for which we can set series from parsed title
info.Series = Tasks.Scanner.Parser.Parser.ParseSeries(info.Title);
info.Volumes = Tasks.Scanner.Parser.Parser.ParseVolume(info.Title);
}
else
{
var info2 = _defaultParser.Parse(path, rootPath, LibraryType.Book);
info.Merge(info2);
}
}
info.ComicInfo = GetComicInfo(path);

View file

@ -192,6 +192,7 @@ public class LibraryWatcher : ILibraryWatcher
/// <remarks>This is public only because Hangfire will invoke it. Do not call external to this class.</remarks>
/// <param name="filePath">File or folder that changed</param>
/// <param name="isDirectoryChange">If the change is on a directory and not a file</param>
[DisableConcurrentExecution(60)]
// ReSharper disable once MemberCanBePrivate.Global
public async Task ProcessChange(string filePath, bool isDirectoryChange = false)
{

View file

@ -38,7 +38,10 @@ public class SeriesModified
public IEnumerable<string> LibraryRoots { get; set; }
}
/// <summary>
/// Responsible for taking parsed info from ReadingItemService and DirectoryService and combining them to emit DB work
/// on a series by series.
/// </summary>
public class ParseScannedFiles
{
private readonly ILogger _logger;

View file

@ -34,6 +34,8 @@ public class DefaultParser : IDefaultParser
public ParserInfo Parse(string filePath, string rootPath, LibraryType type = LibraryType.Manga)
{
var fileName = _directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
// TODO: Potential Bug: This will return null, but on Image libraries, if all images, we would want to include this.
if (Parser.IsCoverImage(_directoryService.FileSystem.Path.GetFileName(filePath))) return null;
ParserInfo ret;
if (Parser.IsEpub(filePath))
@ -62,7 +64,6 @@ public class DefaultParser : IDefaultParser
};
}
if (Parser.IsCoverImage(_directoryService.FileSystem.Path.GetFileName(filePath))) return null;
if (Parser.IsImage(filePath))
{

View file

@ -200,11 +200,11 @@ public static class Parser
MatchOptions, RegexTimeout),
// [dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz
new Regex(
@"(?<Series>.*) (\b|_|-)(vol)\.?(\s|-|_)?\d+",
@"(?<Series>.+?):? (\b|_|-)(vol)\.?(\s|-|_)?\d+",
MatchOptions, RegexTimeout),
// [xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]
new Regex(
@"(?<Series>.*) (\b|_|-)(vol)(ume)",
@"(?<Series>.+?):? (\b|_|-)(vol)(ume)",
MatchOptions,
RegexTimeout),
//Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans]
@ -596,7 +596,7 @@ public static class Parser
private static readonly Regex ComicSpecialRegex = new Regex(
// All Keywords, does not account for checking if contains volume/chapter identification. Parser.Parse() will handle.
$@"\b(?:{CommonSpecial}|\d.+?\WAnnual|Annual\W\d.+?|Book \d.+?|Compendium \d.+?|Omnibus \d.+?|FCBD \d.+?|Absolute \d.+?|Preview \d.+?|Hors[ -]S[ée]rie|TPB|HS|THS)\b",
$@"\b(?:{CommonSpecial}|\d.+?(\W|-|^)Annual|Annual(\W|-|$)|Book \d.+?|Compendium(\W|-|$|\s.+?)|Omnibus(\W|-|$|\s.+?)|FCBD \d.+?|Absolute(\W|-|$|\s.+?)|Preview(\W|-|$|\s.+?)|Hors[ -]S[ée]rie|TPB|HS|THS)\b",
MatchOptions, RegexTimeout
);

View file

@ -160,6 +160,7 @@ public class ScannerService : IScannerService
var sw = Stopwatch.StartNew();
var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId);
var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId);
if (series == null) return; // This can occur when UI deletes a series but doesn't update and user re-requests update
var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new[] {seriesId});
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(series.LibraryId, LibraryIncludes.Folders);
var libraryPaths = library.Folders.Select(f => f.Path).ToList();

View file

@ -177,7 +177,8 @@ public class Startup
services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted
.UseInMemoryStorage());
//.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted (and locking can cause high utilization)
// Add the processing server as IHostedService
services.AddHangfireServer(options =>