PDF Reader Settings, New Reading Modes, and lots of fixes (#2828)
Co-authored-by: Elry <144011449+ElryWeeb@users.noreply.github.com> Co-authored-by: AlienHack <the4got10@windowslive.com> Co-authored-by: William Brockhus <pickeringw@gmail.com> Co-authored-by: Shivam Amin <xShivam.Amin@gmail.com>
This commit is contained in:
parent
f22f30b5a9
commit
2bde0ac82a
55 changed files with 4410 additions and 439 deletions
|
@ -69,7 +69,7 @@
|
|||
<PackageReference Include="Hangfire.InMemory" Version="0.8.1" />
|
||||
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
|
||||
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.4.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.59" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.60" />
|
||||
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||
|
@ -81,8 +81,8 @@
|
|||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
|
||||
<PackageReference Include="MimeTypeMapOfficial" Version="1.0.17" />
|
||||
<PackageReference Include="Nager.ArticleNumber" Version="1.0.7" />
|
||||
<PackageReference Include="NetVips" Version="2.4.0" />
|
||||
<PackageReference Include="NetVips.Native" Version="8.15.1" />
|
||||
<PackageReference Include="NetVips" Version="2.4.1" />
|
||||
<PackageReference Include="NetVips.Native" Version="8.15.2" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.2.0" />
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||
|
@ -95,14 +95,14 @@
|
|||
<PackageReference Include="Serilog.Sinks.SignalR.Core" Version="0.1.2" />
|
||||
<PackageReference Include="SharpCompress" Version="0.36.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.21.0.86780">
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.23.0.88079">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.1" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.4.0" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="20.0.28" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.0" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="21.0.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.3" />
|
||||
<PackageReference Include="VersOne.Epub" Version="3.3.1" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||
using API.Constants;
|
||||
using API.Data;
|
||||
using API.DTOs.Uploads;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
|
@ -98,6 +99,7 @@ public class UploadController : BaseApiController
|
|||
try
|
||||
{
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(uploadFileDto.Id);
|
||||
|
||||
if (series == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "series-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetSeriesFormat(uploadFileDto.Id)}");
|
||||
|
||||
|
@ -225,17 +227,14 @@ public class UploadController : BaseApiController
|
|||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-cover-reading-list-save"));
|
||||
}
|
||||
|
||||
private async Task<string> CreateThumbnail(UploadFileDto uploadFileDto, string filename, int thumbnailSize = 0)
|
||||
private async Task<string> CreateThumbnail(UploadFileDto uploadFileDto, string filename)
|
||||
{
|
||||
var encodeFormat = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EncodeMediaAs;
|
||||
if (thumbnailSize > 0)
|
||||
{
|
||||
return _imageService.CreateThumbnailFromBase64(uploadFileDto.Url,
|
||||
filename, encodeFormat, thumbnailSize);
|
||||
}
|
||||
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||
var encodeFormat = settings.EncodeMediaAs;
|
||||
var coverImageSize = settings.CoverImageSize;
|
||||
|
||||
return _imageService.CreateThumbnailFromBase64(uploadFileDto.Url,
|
||||
filename, encodeFormat);
|
||||
filename, encodeFormat, coverImageSize.GetDimensions().Width);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -326,8 +325,7 @@ public class UploadController : BaseApiController
|
|||
try
|
||||
{
|
||||
var filePath = await CreateThumbnail(uploadFileDto,
|
||||
$"{ImageService.GetLibraryFormat(uploadFileDto.Id)}",
|
||||
ImageService.LibraryThumbnailWidth);
|
||||
$"{ImageService.GetLibraryFormat(uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
|
|
|
@ -118,6 +118,12 @@ public class UsersController : BaseApiController
|
|||
existingPreferences.SwipeToPaginate = preferencesDto.SwipeToPaginate;
|
||||
existingPreferences.CollapseSeriesRelationships = preferencesDto.CollapseSeriesRelationships;
|
||||
existingPreferences.ShareReviews = preferencesDto.ShareReviews;
|
||||
|
||||
existingPreferences.PdfTheme = preferencesDto.PdfTheme;
|
||||
existingPreferences.PdfLayoutMode = preferencesDto.PdfLayoutMode;
|
||||
existingPreferences.PdfScrollMode = preferencesDto.PdfScrollMode;
|
||||
existingPreferences.PdfSpreadMode = preferencesDto.PdfSpreadMode;
|
||||
|
||||
if (_localizationService.GetLocales().Contains(preferencesDto.Locale))
|
||||
{
|
||||
existingPreferences.Locale = preferencesDto.Locale;
|
||||
|
|
|
@ -152,4 +152,25 @@ public class UserPreferencesDto
|
|||
/// </summary>
|
||||
[Required]
|
||||
public string Locale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PDF Reader: Theme of the Reader
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PdfTheme PdfTheme { get; set; } = PdfTheme.Dark;
|
||||
/// <summary>
|
||||
/// PDF Reader: Scroll mode of the reader
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PdfScrollMode PdfScrollMode { get; set; } = PdfScrollMode.Vertical;
|
||||
/// <summary>
|
||||
/// PDF Reader: Layout Mode of the reader
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PdfLayoutMode PdfLayoutMode { get; set; } = PdfLayoutMode.Multiple;
|
||||
/// <summary>
|
||||
/// PDF Reader: Spread Mode of the reader
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PdfSpreadMode PdfSpreadMode { get; set; } = PdfSpreadMode.None;
|
||||
}
|
||||
|
|
2916
API/Data/Migrations/20240328130057_PdfSettings.Designer.cs
generated
Normal file
2916
API/Data/Migrations/20240328130057_PdfSettings.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
62
API/Data/Migrations/20240328130057_PdfSettings.cs
Normal file
62
API/Data/Migrations/20240328130057_PdfSettings.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class PdfSettings : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PdfLayoutMode",
|
||||
table: "AppUserPreferences",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PdfScrollMode",
|
||||
table: "AppUserPreferences",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PdfSpreadMode",
|
||||
table: "AppUserPreferences",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PdfTheme",
|
||||
table: "AppUserPreferences",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PdfLayoutMode",
|
||||
table: "AppUserPreferences");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PdfScrollMode",
|
||||
table: "AppUserPreferences");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PdfSpreadMode",
|
||||
table: "AppUserPreferences");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PdfTheme",
|
||||
table: "AppUserPreferences");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -355,6 +355,18 @@ namespace API.Data.Migrations
|
|||
b.Property<int>("PageSplitOption")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PdfLayoutMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PdfScrollMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PdfSpreadMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PdfTheme")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("PromptForDownloadSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ namespace API.Entities;
|
|||
public class AppUserPreferences
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
#region MangaReader
|
||||
|
||||
/// <summary>
|
||||
/// Manga Reader Option: What direction should the next/prev page buttons go
|
||||
/// </summary>
|
||||
|
@ -51,6 +54,11 @@ public class AppUserPreferences
|
|||
/// Manga Reader Option: Should swiping trigger pagination
|
||||
/// </summary>
|
||||
public bool SwipeToPaginate { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region EpubReader
|
||||
|
||||
/// <summary>
|
||||
/// Book Reader Option: Override extra Margin
|
||||
/// </summary>
|
||||
|
@ -75,17 +83,11 @@ public class AppUserPreferences
|
|||
/// Book Reader Option: What direction should the next/prev page buttons go
|
||||
/// </summary>
|
||||
public ReadingDirection BookReaderReadingDirection { get; set; } = ReadingDirection.LeftToRight;
|
||||
|
||||
/// <summary>
|
||||
/// Book Reader Option: Defines the writing styles vertical/horizontal
|
||||
/// </summary>
|
||||
public WritingStyle BookReaderWritingStyle { get; set; } = WritingStyle.Horizontal;
|
||||
/// <summary>
|
||||
/// UI Site Global Setting: The UI theme the user should use.
|
||||
/// </summary>
|
||||
/// <remarks>Should default to Dark</remarks>
|
||||
public required SiteTheme Theme { get; set; } = Seed.DefaultThemes[0];
|
||||
/// <summary>
|
||||
/// Book Reader Option: The color theme to decorate the book contents
|
||||
/// </summary>
|
||||
/// <remarks>Should default to Dark</remarks>
|
||||
|
@ -101,6 +103,37 @@ public class AppUserPreferences
|
|||
/// </summary>
|
||||
/// <remarks>Defaults to false</remarks>
|
||||
public bool BookReaderImmersiveMode { get; set; } = false;
|
||||
#endregion
|
||||
|
||||
#region PdfReader
|
||||
|
||||
/// <summary>
|
||||
/// PDF Reader: Theme of the Reader
|
||||
/// </summary>
|
||||
public PdfTheme PdfTheme { get; set; } = PdfTheme.Dark;
|
||||
/// <summary>
|
||||
/// PDF Reader: Scroll mode of the reader
|
||||
/// </summary>
|
||||
public PdfScrollMode PdfScrollMode { get; set; } = PdfScrollMode.Vertical;
|
||||
/// <summary>
|
||||
/// PDF Reader: Layout Mode of the reader
|
||||
/// </summary>
|
||||
public PdfLayoutMode PdfLayoutMode { get; set; } = PdfLayoutMode.Multiple;
|
||||
/// <summary>
|
||||
/// PDF Reader: Spread Mode of the reader
|
||||
/// </summary>
|
||||
public PdfSpreadMode PdfSpreadMode { get; set; } = PdfSpreadMode.None;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Global
|
||||
|
||||
/// <summary>
|
||||
/// UI Site Global Setting: The UI theme the user should use.
|
||||
/// </summary>
|
||||
/// <remarks>Should default to Dark</remarks>
|
||||
public required SiteTheme Theme { get; set; } = Seed.DefaultThemes[0];
|
||||
/// <summary>
|
||||
/// Global Site Option: If the UI should layout items as Cards or List items
|
||||
/// </summary>
|
||||
|
@ -132,6 +165,8 @@ public class AppUserPreferences
|
|||
/// </summary>
|
||||
public string Locale { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public AppUser AppUser { get; set; } = null!;
|
||||
public int AppUserId { get; set; }
|
||||
}
|
||||
|
|
21
API/Entities/Enums/UserPreferences/PdfBookMode.cs
Normal file
21
API/Entities/Enums/UserPreferences/PdfBookMode.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace API.Entities.Enums.UserPreferences;
|
||||
|
||||
public enum PdfLayoutMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Multiple pages render stacked (normal pdf experience)
|
||||
/// </summary>
|
||||
[Description("Multiple")]
|
||||
Multiple = 0,
|
||||
// [Description("Single")]
|
||||
// Single = 1,
|
||||
/// <summary>
|
||||
/// A book mode where page turns are animated and layout is side-by-side
|
||||
/// </summary>
|
||||
[Description("Book")]
|
||||
Book = 2,
|
||||
// [Description("Infinite Scroll")]
|
||||
// InfiniteScroll = 3
|
||||
}
|
21
API/Entities/Enums/UserPreferences/PdfScrollMode.cs
Normal file
21
API/Entities/Enums/UserPreferences/PdfScrollMode.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace API.Entities.Enums.UserPreferences;
|
||||
|
||||
/// <summary>
|
||||
/// Enum values match PdfViewer's enums
|
||||
/// </summary>
|
||||
public enum PdfScrollMode
|
||||
{
|
||||
[Description("Vertical")]
|
||||
Vertical = 0,
|
||||
[Description("Horizontal")]
|
||||
Horizontal = 1,
|
||||
// [Description("Wrapped")]
|
||||
// Wrapped = 2,
|
||||
/// <summary>
|
||||
/// Single page view (tap to pagninate)
|
||||
/// </summary>
|
||||
[Description("Page")]
|
||||
Page = 3
|
||||
}
|
13
API/Entities/Enums/UserPreferences/PdfSpreadMode.cs
Normal file
13
API/Entities/Enums/UserPreferences/PdfSpreadMode.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace API.Entities.Enums.UserPreferences;
|
||||
|
||||
public enum PdfSpreadMode
|
||||
{
|
||||
[Description("None")]
|
||||
None = 0,
|
||||
[Description("Odd")]
|
||||
Odd = 1,
|
||||
[Description("Even")]
|
||||
Even = 2
|
||||
}
|
11
API/Entities/Enums/UserPreferences/PdfTheme.cs
Normal file
11
API/Entities/Enums/UserPreferences/PdfTheme.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace API.Entities.Enums.UserPreferences;
|
||||
|
||||
public enum PdfTheme
|
||||
{
|
||||
[Description("Dark")]
|
||||
Dark = 0,
|
||||
[Description("Light")]
|
||||
Light = 1
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using API.Entities;
|
||||
using API.Helpers;
|
||||
using API.Helpers.Builders;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
|
||||
namespace API.Extensions;
|
||||
|
@ -24,6 +25,7 @@ public static class ChapterListExtensions
|
|||
/// Gets a single chapter (or null if doesn't exist) where Range matches the info.Chapters property. If the info
|
||||
/// is <see cref="ParserInfo.IsSpecial"/> then, the filename is used to search against Range or if filename exists within Files of said Chapter.
|
||||
/// </summary>
|
||||
/// <remarks>This uses GetNumberTitle() to calculate the Range to compare against the info.Chapters</remarks>
|
||||
/// <param name="chapters"></param>
|
||||
/// <param name="info"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -31,9 +33,12 @@ public static class ChapterListExtensions
|
|||
{
|
||||
var normalizedPath = Parser.NormalizePath(info.FullFilePath);
|
||||
var specialTreatment = info.IsSpecialInfo();
|
||||
// NOTE: This can fail to find the chapter when Range is "1.0" as the chapter will store it as "1" hence why we need to emulate a Chapter
|
||||
var fakeChapter = new ChapterBuilder(info.Chapters, info.Chapters).Build();
|
||||
fakeChapter.UpdateFrom(info);
|
||||
return specialTreatment
|
||||
? chapters.FirstOrDefault(c => c.Range == Parser.RemoveExtensionIfSupported(info.Filename) || c.Files.Select(f => Parser.NormalizePath(f.FilePath)).Contains(normalizedPath))
|
||||
: chapters.FirstOrDefault(c => c.Range == info.Chapters);
|
||||
: chapters.FirstOrDefault(c => c.Range == fakeChapter.GetNumberTitle());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -164,7 +164,9 @@ public static class IncludesExtensions
|
|||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.UserPreferences))
|
||||
{
|
||||
query = query.Include(u => u.UserPreferences);
|
||||
query = query
|
||||
.Include(u => u.UserPreferences)
|
||||
.ThenInclude(p => p.Theme);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.WantToRead))
|
||||
|
|
|
@ -36,7 +36,7 @@ public class ChapterBuilder : IEntityBuilder<Chapter>
|
|||
var specialTitle = specialTreatment ? Parser.RemoveExtensionIfSupported(info.Filename) : info.Chapters;
|
||||
var builder = new ChapterBuilder(Parser.DefaultChapter);
|
||||
|
||||
return builder.WithNumber(Parser.RemoveExtensionIfSupported(info.Chapters))
|
||||
return builder.WithNumber(Parser.RemoveExtensionIfSupported(info.Chapters)!)
|
||||
.WithRange(specialTreatment ? info.Filename : info.Chapters)
|
||||
.WithTitle((specialTreatment && info.Format == MangaFormat.Epub)
|
||||
? info.Title
|
||||
|
|
|
@ -382,7 +382,7 @@ public class BookService : IBookService
|
|||
}
|
||||
}
|
||||
|
||||
var styleNodes = doc.DocumentNode.SelectNodes("/html/head/link");
|
||||
var styleNodes = doc.DocumentNode.SelectNodes("/html/head/link[@href]");
|
||||
if (styleNodes != null)
|
||||
{
|
||||
foreach (var styleLinks in styleNodes)
|
||||
|
|
|
@ -148,14 +148,14 @@ public class LibraryWatcher : ILibraryWatcher
|
|||
|
||||
private void OnChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
_logger.LogDebug("[LibraryWatcher] Changed: {FullPath}, {Name}, {ChangeType}", e.FullPath, e.Name, e.ChangeType);
|
||||
_logger.LogTrace("[LibraryWatcher] Changed: {FullPath}, {Name}, {ChangeType}", e.FullPath, e.Name, e.ChangeType);
|
||||
if (e.ChangeType != WatcherChangeTypes.Changed) return;
|
||||
BackgroundJob.Enqueue(() => ProcessChange(e.FullPath, string.IsNullOrEmpty(_directoryService.FileSystem.Path.GetExtension(e.Name))));
|
||||
}
|
||||
|
||||
private void OnCreated(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
_logger.LogDebug("[LibraryWatcher] Created: {FullPath}, {Name}", e.FullPath, e.Name);
|
||||
_logger.LogTrace("[LibraryWatcher] Created: {FullPath}, {Name}", e.FullPath, e.Name);
|
||||
BackgroundJob.Enqueue(() => ProcessChange(e.FullPath, !_directoryService.FileSystem.File.Exists(e.Name)));
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ public class LibraryWatcher : ILibraryWatcher
|
|||
private void OnDeleted(object sender, FileSystemEventArgs e) {
|
||||
var isDirectory = string.IsNullOrEmpty(_directoryService.FileSystem.Path.GetExtension(e.Name));
|
||||
if (!isDirectory) return;
|
||||
_logger.LogDebug("[LibraryWatcher] Deleted: {FullPath}, {Name}", e.FullPath, e.Name);
|
||||
_logger.LogTrace("[LibraryWatcher] Deleted: {FullPath}, {Name}", e.FullPath, e.Name);
|
||||
BackgroundJob.Enqueue(() => ProcessChange(e.FullPath, true));
|
||||
}
|
||||
|
||||
|
@ -285,10 +285,10 @@ public class LibraryWatcher : ILibraryWatcher
|
|||
|
||||
var rootFolder = _directoryService.GetFoldersTillRoot(libraryFolder, filePath).ToList();
|
||||
_logger.LogTrace("[LibraryWatcher] Root Folders: {RootFolders}", rootFolder);
|
||||
if (!rootFolder.Any()) return string.Empty;
|
||||
if (rootFolder.Count == 0) return string.Empty;
|
||||
|
||||
// Select the first folder and join with library folder, this should give us the folder to scan.
|
||||
return Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(libraryFolder, rootFolder[rootFolder.Count - 1]));
|
||||
return Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(libraryFolder, rootFolder[rootFolder.Count - 1]));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -115,13 +115,21 @@ public abstract class DefaultParser(IDirectoryService directoryService) : IDefau
|
|||
{
|
||||
info.LocalizedSeries = info.ComicInfo.LocalizedSeries.Trim();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(info.ComicInfo.Format) && Parser.HasComicInfoSpecial(info.ComicInfo.Format))
|
||||
{
|
||||
info.IsSpecial = true;
|
||||
info.Chapters = Parser.DefaultChapter;
|
||||
info.Volumes = Parser.SpecialVolume;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(info.ComicInfo.Number))
|
||||
{
|
||||
info.Chapters = info.ComicInfo.Number;
|
||||
if (info.IsSpecial && Parser.DefaultChapter != info.Chapters)
|
||||
{
|
||||
info.IsSpecial = false;
|
||||
info.Volumes = $"{Parser.SpecialVolumeNumber}";
|
||||
info.Volumes = Parser.SpecialVolume;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +138,7 @@ public abstract class DefaultParser(IDirectoryService directoryService) : IDefau
|
|||
{
|
||||
info.SeriesSort = info.ComicInfo.TitleSort.Trim();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract bool IsApplicable(string filePath, LibraryType type);
|
||||
|
|
|
@ -121,6 +121,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] MangaVolumeRegex = new[]
|
||||
{
|
||||
// Thai Volume: เล่ม n -> Volume n
|
||||
new Regex(
|
||||
@"(เล่ม|เล่มที่)(\s)?(\.?)(\s|_)?(?<Volume>\d+(\-\d+)?(\.\d+)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Dance in the Vampire Bund v16-17
|
||||
new Regex(
|
||||
@"(?<Series>.*)(\b|_)v(?<Volume>\d+-?\d+)( |_)",
|
||||
|
@ -194,6 +198,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] MangaSeriesRegex = new[]
|
||||
{
|
||||
// Thai Volume: เล่ม n -> Volume n
|
||||
new Regex(
|
||||
@"(?<Series>.+?)(เล่ม|เล่มที่)(\s)?(\.?)(\s|_)?(?<Volume>\d+(\-\d+)?(\.\d+)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Russian Volume: Том n -> Volume n, Тома n -> Volume
|
||||
new Regex(
|
||||
@"(?<Series>.+?)Том(а?)(\.?)(\s|_)?(?<Volume>\d+(?:(\-)\d+)?)",
|
||||
|
@ -368,6 +376,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] ComicSeriesRegex = new[]
|
||||
{
|
||||
// Thai Volume: เล่ม n -> Volume n
|
||||
new Regex(
|
||||
@"(?<Series>.+?)(เล่ม|เล่มที่)(\s)?(\.?)(\s|_)?(?<Volume>\d+(\-\d+)?(\.\d+)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Russian Volume: Том n -> Volume n, Тома n -> Volume
|
||||
new Regex(
|
||||
@"(?<Series>.+?)Том(а?)(\.?)(\s|_)?(?<Volume>\d+(?:(\-)\d+)?)",
|
||||
|
@ -456,6 +468,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] ComicVolumeRegex = new[]
|
||||
{
|
||||
// Thai Volume: เล่ม n -> Volume n
|
||||
new Regex(
|
||||
@"(เล่ม|เล่มที่)(\s)?(\.?)(\s|_)?(?<Volume>\d+(\-\d+)?(\.\d+)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)
|
||||
new Regex(
|
||||
@"^(?<Series>.+?)(?: |_)(t|v)(?<Volume>" + NumberRange + @")",
|
||||
|
@ -492,6 +508,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] ComicChapterRegex = new[]
|
||||
{
|
||||
// Thai Volume: บทที่ n -> Chapter n, ตอนที่ n -> Chapter n
|
||||
new Regex(
|
||||
@"(บทที่|ตอนที่)(\s)?(\.?)(\s|_)?(?<Chapter>\d+(\-\d+)?(\.\d+)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Batman & Wildcat (1 of 3)
|
||||
new Regex(
|
||||
@"(?<Series>.*(\d{4})?)( |_)(?:\((?<Chapter>\d+) of \d+)",
|
||||
|
@ -557,6 +577,10 @@ public static class Parser
|
|||
|
||||
private static readonly Regex[] MangaChapterRegex = new[]
|
||||
{
|
||||
// Thai Chapter: บทที่ n -> Chapter n, ตอนที่ n -> Chapter n, เล่ม n -> Volume n, เล่มที่ n -> Volume n
|
||||
new Regex(
|
||||
@"(?<Volume>((เล่ม|เล่มที่))?(\s|_)?\.?\d+)(\s|_)(บทที่|ตอนที่)\.?(\s|_)?(?<Chapter>\d+)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Historys Strongest Disciple Kenichi_v11_c90-98.zip, ...c90.5-100.5
|
||||
new Regex(
|
||||
@"(\b|_)(c|ch)(\.?\s?)(?<Chapter>(\d+(\.\d)?)(-c?\d+(\.\d)?)?)",
|
||||
|
|
|
@ -701,7 +701,8 @@ public class ProcessSeries : IProcessSeries
|
|||
{
|
||||
if (existingChapter.Files.Count == 0 || !parsedInfos.HasInfo(existingChapter))
|
||||
{
|
||||
_logger.LogDebug("[ScannerService] Removed chapter {Chapter} for Volume {VolumeNumber} on {SeriesName}", existingChapter.Range, volume.Name, parsedInfos[0].Series);
|
||||
_logger.LogDebug("[ScannerService] Removed chapter {Chapter} for Volume {VolumeNumber} on {SeriesName}",
|
||||
existingChapter.Range, volume.Name, parsedInfos[0].Series);
|
||||
volume.Chapters.Remove(existingChapter);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue