Compare commits
16 commits
develop
...
feature/ge
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fad70432fb | ||
![]() |
5423526484 | ||
![]() |
6f4162d793 | ||
![]() |
9d31262448 | ||
![]() |
353d44a882 | ||
![]() |
4ccac5f479 | ||
![]() |
08cc7c7cbd | ||
![]() |
f5a31b9a02 | ||
![]() |
3e813534f9 | ||
![]() |
d29dd59964 | ||
![]() |
fc21073898 | ||
![]() |
58c77b32b1 | ||
![]() |
fc87dba0a7 | ||
![]() |
304fd8bc79 | ||
![]() |
4fa21fe1ca | ||
![]() |
42cd6e9b3a |
22 changed files with 207 additions and 43 deletions
|
@ -154,5 +154,25 @@ public class VolumeListExtensionsTests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Single volume (comicvine type style) with negative or non-numerical
|
||||||
|
/// </summary>
|
||||||
|
public void GetCoverImage_LooseChapters_WithSub1_InOneVolume()
|
||||||
|
{
|
||||||
|
var volumes = new List<Volume>()
|
||||||
|
{
|
||||||
|
new VolumeBuilder("2")
|
||||||
|
.WithChapter(new ChapterBuilder("-1").WithCoverImage("Chapter -1").Build())
|
||||||
|
.WithChapter(new ChapterBuilder("1").WithCoverImage("Chapter 1").Build())
|
||||||
|
.Build(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Not testable due to the code not actually doing the heavy lifting
|
||||||
|
// var actual = volumes.GetCoverImage(MangaFormat.Archive);
|
||||||
|
// Assert.NotNull(actual);
|
||||||
|
// Assert.Equal("Chapter 1", actual.CoverImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,7 @@ public class CollectionTagRepository : ICollectionTagRepository
|
||||||
.Where(t => t.Id == tag.Id)
|
.Where(t => t.Id == tag.Id)
|
||||||
.SelectMany(uc => uc.Items.Select(s => s.Metadata))
|
.SelectMany(uc => uc.Items.Select(s => s.Metadata))
|
||||||
.Select(sm => sm.AgeRating)
|
.Select(sm => sm.AgeRating)
|
||||||
|
.DefaultIfEmpty()
|
||||||
.MaxAsync();
|
.MaxAsync();
|
||||||
tag.AgeRating = maxAgeRating;
|
tag.AgeRating = maxAgeRating;
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
|
|
|
@ -34,5 +34,9 @@ public enum LibraryType
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("Comic (ComicVine)")]
|
[Description("Comic (ComicVine)")]
|
||||||
ComicVine = 5,
|
ComicVine = 5,
|
||||||
|
/// <summary>
|
||||||
|
/// This library requires custom regex from admin
|
||||||
|
/// </summary>
|
||||||
|
[Description("Generic")]
|
||||||
|
Generic = 6,
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,11 @@ public class Library : IEntityDate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Scrobbling requires a valid LicenseKey</remarks>
|
/// <remarks>Scrobbling requires a valid LicenseKey</remarks>
|
||||||
public bool AllowScrobbling { get; set; } = true;
|
public bool AllowScrobbling { get; set; } = true;
|
||||||
|
/// <summary>
|
||||||
|
/// Extra Regex that can be used for parsing
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This is only used for Generic Library</remarks>
|
||||||
|
//public string? ExtraParsingRegex { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
using API.Services.Tasks.Scanner.Parser;
|
using API.Services.Tasks.Scanner.Parser;
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class ReadingItemService : IReadingItemService
|
||||||
private readonly ImageParser _imageParser;
|
private readonly ImageParser _imageParser;
|
||||||
private readonly BookParser _bookParser;
|
private readonly BookParser _bookParser;
|
||||||
private readonly PdfParser _pdfParser;
|
private readonly PdfParser _pdfParser;
|
||||||
|
private readonly GenericLibraryParser _genericParser;
|
||||||
|
|
||||||
public ReadingItemService(IArchiveService archiveService, IBookService bookService, IImageService imageService,
|
public ReadingItemService(IArchiveService archiveService, IBookService bookService, IImageService imageService,
|
||||||
IDirectoryService directoryService, ILogger<ReadingItemService> logger)
|
IDirectoryService directoryService, ILogger<ReadingItemService> logger)
|
||||||
|
@ -43,6 +44,7 @@ public class ReadingItemService : IReadingItemService
|
||||||
_bookParser = new BookParser(directoryService, bookService, _basicParser);
|
_bookParser = new BookParser(directoryService, bookService, _basicParser);
|
||||||
_comicVineParser = new ComicVineParser(directoryService);
|
_comicVineParser = new ComicVineParser(directoryService);
|
||||||
_pdfParser = new PdfParser(directoryService);
|
_pdfParser = new PdfParser(directoryService);
|
||||||
|
_genericParser = new GenericLibraryParser(directoryService);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +179,10 @@ public class ReadingItemService : IReadingItemService
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private ParserInfo? Parse(string path, string rootPath, string libraryRoot, LibraryType type)
|
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))
|
if (_comicVineParser.IsApplicable(path, type))
|
||||||
{
|
{
|
||||||
return _comicVineParser.Parse(path, rootPath, libraryRoot, type, GetComicInfo(path));
|
return _comicVineParser.Parse(path, rootPath, libraryRoot, type, GetComicInfo(path));
|
||||||
|
|
|
@ -416,15 +416,12 @@ public class ParseScannedFiles
|
||||||
var folder = result.Folder;
|
var folder = result.Folder;
|
||||||
var libraryRoot = result.LibraryRoot;
|
var libraryRoot = result.LibraryRoot;
|
||||||
|
|
||||||
// When processing files for a folder and we do enter, we need to parse the information and combine parser infos
|
|
||||||
// NOTE: We might want to move the merge step later in the process, like return and combine.
|
|
||||||
_logger.LogDebug("[ScannerService] Found {Count} files for {Folder}", files.Count, folder);
|
_logger.LogDebug("[ScannerService] Found {Count} files for {Folder}", files.Count, folder);
|
||||||
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
|
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
|
||||||
MessageFactory.FileScanProgressEvent($"{files.Count} files in {folder}", library.Name, ProgressEventType.Updated));
|
MessageFactory.FileScanProgressEvent($"{files.Count} files in {folder}", library.Name, ProgressEventType.Updated));
|
||||||
if (files.Count == 0)
|
if (files.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("[ScannerService] {Folder} is empty, no longer in this location, or has no file types that match Library File Types", folder);
|
_logger.LogInformation("[ScannerService] {Folder} is empty or is no longer in this location", folder);
|
||||||
result.ParserInfos = ArraySegment<ParserInfo>.Empty;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
using API.Data.Metadata;
|
using API.Data.Metadata;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
@ -11,7 +12,8 @@ namespace API.Services.Tasks.Scanner.Parser;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BasicParser(IDirectoryService directoryService, IDefaultParser imageParser) : DefaultParser(directoryService)
|
public class BasicParser(IDirectoryService directoryService, IDefaultParser imageParser) : DefaultParser(directoryService)
|
||||||
{
|
{
|
||||||
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null)
|
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null)
|
||||||
{
|
{
|
||||||
var fileName = directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
|
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.
|
// TODO: Potential Bug: This will return null, but on Image libraries, if all images, we would want to include this.
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using API.Data.Metadata;
|
using System.Collections.Generic;
|
||||||
|
using API.Data.Metadata;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
|
||||||
namespace API.Services.Tasks.Scanner.Parser;
|
namespace API.Services.Tasks.Scanner.Parser;
|
||||||
|
|
||||||
public class BookParser(IDirectoryService directoryService, IBookService bookService, BasicParser basicParser) : DefaultParser(directoryService)
|
public class BookParser(IDirectoryService directoryService, IBookService bookService, IDefaultParser basicParser) : DefaultParser(directoryService)
|
||||||
{
|
{
|
||||||
public override ParserInfo Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo comicInfo = null)
|
public override ParserInfo Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null)
|
||||||
{
|
{
|
||||||
var info = bookService.ParseInfo(filePath);
|
var info = bookService.ParseInfo(filePath);
|
||||||
if (info == null) return null;
|
if (info == null) return null;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using API.Data.Metadata;
|
using API.Data.Metadata;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
@ -15,11 +16,8 @@ public class ComicVineParser(IDirectoryService directoryService) : DefaultParser
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This Parser generates Series name to be defined as Series + first Issue Volume, so "Batman (2020)".
|
/// This Parser generates Series name to be defined as Series + first Issue Volume, so "Batman (2020)".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath"></param>
|
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
/// <param name="rootPath"></param>
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null)
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null)
|
|
||||||
{
|
{
|
||||||
if (type != LibraryType.ComicVine) return null;
|
if (type != LibraryType.ComicVine) return null;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using API.Data.Metadata;
|
using API.Data.Metadata;
|
||||||
|
@ -8,7 +9,7 @@ namespace API.Services.Tasks.Scanner.Parser;
|
||||||
|
|
||||||
public interface IDefaultParser
|
public interface IDefaultParser
|
||||||
{
|
{
|
||||||
ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null);
|
ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null);
|
||||||
void ParseFromFallbackFolders(string filePath, string rootPath, LibraryType type, ref ParserInfo ret);
|
void ParseFromFallbackFolders(string filePath, string rootPath, LibraryType type, ref ParserInfo ret);
|
||||||
bool IsApplicable(string filePath, LibraryType type);
|
bool IsApplicable(string filePath, LibraryType type);
|
||||||
}
|
}
|
||||||
|
@ -26,8 +27,12 @@ public abstract class DefaultParser(IDirectoryService directoryService) : IDefau
|
||||||
/// <param name="filePath"></param>
|
/// <param name="filePath"></param>
|
||||||
/// <param name="rootPath">Root folder</param>
|
/// <param name="rootPath">Root folder</param>
|
||||||
/// <param name="type">Allows different Regex to be used for parsing.</param>
|
/// <param name="type">Allows different Regex to be used for parsing.</param>
|
||||||
|
/// <param name="type">Allows different Regex to be used for parsing.</param>
|
||||||
|
/// <param name="comicInfo">ComicInfo if present (for epub it si always present)</param>
|
||||||
|
/// <param name="extraRegex">The regex for the Generic Parser</param>
|
||||||
/// <returns><see cref="ParserInfo"/> or null if Series was empty</returns>
|
/// <returns><see cref="ParserInfo"/> or null if Series was empty</returns>
|
||||||
public abstract ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null);
|
public abstract ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills out <see cref="ParserInfo"/> by trying to parse volume, chapters, and series from folders
|
/// Fills out <see cref="ParserInfo"/> by trying to parse volume, chapters, and series from folders
|
||||||
|
|
99
API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs
Normal file
99
API/Services/Tasks/Scanner/Parser/GenericLibraryParser.cs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using API.Data.Metadata;
|
||||||
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
namespace API.Services.Tasks.Scanner.Parser;
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uses an at-runtime array of Regex to parse out information
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directoryService"></param>
|
||||||
|
public class GenericLibraryParser(IDirectoryService directoryService) : DefaultParser(directoryService)
|
||||||
|
{
|
||||||
|
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = 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<string>()
|
||||||
|
{
|
||||||
|
@"(?<Series>.*)(\b|_)v(?<Volume>\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);
|
||||||
|
var info = new ParserInfo()
|
||||||
|
{
|
||||||
|
Filename = Path.GetFileName(filePath),
|
||||||
|
Format = Parser.ParseFormat(filePath),
|
||||||
|
Title = Parser.RemoveExtensionIfSupported(fileName)!,
|
||||||
|
FullFilePath = filePath,
|
||||||
|
Series = string.Empty,
|
||||||
|
ComicInfo = comicInfo,
|
||||||
|
Chapters = Parser.ParseComicChapter(fileName),
|
||||||
|
Volumes = Parser.ParseComicVolume(fileName)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var regex in extraRegex)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var matchValue = group[matchKey].Value;
|
||||||
|
switch (matchKey)
|
||||||
|
{
|
||||||
|
case "Series":
|
||||||
|
info.Series = SetIfNotDefault(matchValue, info.Series);
|
||||||
|
break;
|
||||||
|
case "Chapter":
|
||||||
|
info.Chapters = SetIfNotDefault(matchValue, info.Chapters);
|
||||||
|
break;
|
||||||
|
case "Volume":
|
||||||
|
info.Volumes = SetIfNotDefault(matchValue, info.Volumes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the final info here: (cleaning values, setting internal encoding overrides)
|
||||||
|
if (info.IsSpecial)
|
||||||
|
{
|
||||||
|
info.Volumes = Parser.SpecialVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(info.Chapters))
|
||||||
|
{
|
||||||
|
info.Chapters = Parser.DefaultChapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.IsSpecial && string.IsNullOrEmpty(info.Volumes))
|
||||||
|
{
|
||||||
|
info.Chapters = Parser.LooseLeafVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return string.IsNullOrEmpty(info.Series) ? null : info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SetIfNotDefault(string value, string originalValue)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value)) return originalValue;
|
||||||
|
if (string.IsNullOrEmpty(originalValue)) return value;
|
||||||
|
|
||||||
|
return originalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsApplicable(string filePath, LibraryType type)
|
||||||
|
{
|
||||||
|
return type == LibraryType.Generic;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
using API.Data.Metadata;
|
using API.Data.Metadata;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
@ -7,7 +8,8 @@ namespace API.Services.Tasks.Scanner.Parser;
|
||||||
|
|
||||||
public class ImageParser(IDirectoryService directoryService) : DefaultParser(directoryService)
|
public class ImageParser(IDirectoryService directoryService) : DefaultParser(directoryService)
|
||||||
{
|
{
|
||||||
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo? comicInfo = null)
|
public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null)
|
||||||
{
|
{
|
||||||
if (type != LibraryType.Image || !Parser.IsImage(filePath)) return null;
|
if (type != LibraryType.Image || !Parser.IsImage(filePath)) return null;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ public static class Parser
|
||||||
public const string SupportedExtensions =
|
public const string SupportedExtensions =
|
||||||
ArchiveFileExtensions + "|" + ImageFileExtensions + "|" + BookFileExtensions;
|
ArchiveFileExtensions + "|" + ImageFileExtensions + "|" + BookFileExtensions;
|
||||||
|
|
||||||
private const RegexOptions MatchOptions =
|
public const RegexOptions MatchOptions =
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant;
|
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant;
|
||||||
|
|
||||||
private static readonly ImmutableArray<string> FormatTagSpecialKeywords = ImmutableArray.Create(
|
private static readonly ImmutableArray<string> FormatTagSpecialKeywords = ImmutableArray.Create(
|
||||||
|
@ -1149,7 +1149,7 @@ public static class Parser
|
||||||
|
|
||||||
public static string? ExtractFilename(string fileUrl)
|
public static string? ExtractFilename(string fileUrl)
|
||||||
{
|
{
|
||||||
var matches = Parser.CssImageUrlRegex.Matches(fileUrl);
|
var matches = CssImageUrlRegex.Matches(fileUrl);
|
||||||
foreach (Match match in matches)
|
foreach (Match match in matches)
|
||||||
{
|
{
|
||||||
if (!match.Success) continue;
|
if (!match.Success) continue;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
using API.Data.Metadata;
|
using API.Data.Metadata;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
@ -6,7 +7,8 @@ namespace API.Services.Tasks.Scanner.Parser;
|
||||||
|
|
||||||
public class PdfParser(IDirectoryService directoryService) : DefaultParser(directoryService)
|
public class PdfParser(IDirectoryService directoryService) : DefaultParser(directoryService)
|
||||||
{
|
{
|
||||||
public override ParserInfo Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, ComicInfo comicInfo = null)
|
public override ParserInfo Parse(string filePath, string rootPath, string libraryRoot, LibraryType type,
|
||||||
|
ComicInfo? comicInfo = null, IEnumerable<string>? extraRegex = null)
|
||||||
{
|
{
|
||||||
var fileName = directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
|
var fileName = directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
|
||||||
var ret = new ParserInfo
|
var ret = new ParserInfo
|
||||||
|
|
|
@ -6,7 +6,8 @@ export enum LibraryType {
|
||||||
Book = 2,
|
Book = 2,
|
||||||
Images = 3,
|
Images = 3,
|
||||||
LightNovel = 4,
|
LightNovel = 4,
|
||||||
ComicVine = 5
|
ComicVine = 5,
|
||||||
|
Generic = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Library {
|
export interface Library {
|
||||||
|
|
|
@ -26,6 +26,8 @@ export class LibraryTypePipe implements PipeTransform {
|
||||||
return this.translocoService.translate('library-type-pipe.manga');
|
return this.translocoService.translate('library-type-pipe.manga');
|
||||||
case LibraryType.LightNovel:
|
case LibraryType.LightNovel:
|
||||||
return this.translocoService.translate('library-type-pipe.lightNovel');
|
return this.translocoService.translate('library-type-pipe.lightNovel');
|
||||||
|
case LibraryType.Generic:
|
||||||
|
return this.translocoService.translate('library-type-pipe.generic');
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ export class UtilityService {
|
||||||
switch(libraryType) {
|
switch(libraryType) {
|
||||||
case LibraryType.Book:
|
case LibraryType.Book:
|
||||||
case LibraryType.LightNovel:
|
case LibraryType.LightNovel:
|
||||||
|
case LibraryType.Generic:
|
||||||
return this.translocoService.translate('common.book-num') + (includeSpace ? ' ' : '');
|
return this.translocoService.translate('common.book-num') + (includeSpace ? ' ' : '');
|
||||||
case LibraryType.Comic:
|
case LibraryType.Comic:
|
||||||
case LibraryType.ComicVine:
|
case LibraryType.ComicVine:
|
||||||
|
|
|
@ -200,6 +200,7 @@ export class SideNavComponent implements OnInit {
|
||||||
getLibraryTypeIcon(format: LibraryType) {
|
getLibraryTypeIcon(format: LibraryType) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case LibraryType.Book:
|
case LibraryType.Book:
|
||||||
|
case LibraryType.Generic:
|
||||||
case LibraryType.LightNovel:
|
case LibraryType.LightNovel:
|
||||||
return 'fa-book';
|
return 'fa-book';
|
||||||
case LibraryType.Comic:
|
case LibraryType.Comic:
|
||||||
|
|
|
@ -196,6 +196,12 @@ export class LibrarySettingsModalComponent implements OnInit {
|
||||||
this.libraryForm.get(FileTypeGroup.Pdf + '')?.setValue(false);
|
this.libraryForm.get(FileTypeGroup.Pdf + '')?.setValue(false);
|
||||||
this.libraryForm.get(FileTypeGroup.Epub + '')?.setValue(false);
|
this.libraryForm.get(FileTypeGroup.Epub + '')?.setValue(false);
|
||||||
break;
|
break;
|
||||||
|
case LibraryType.Generic:
|
||||||
|
this.libraryForm.get(FileTypeGroup.Archive + '')?.setValue(false);
|
||||||
|
this.libraryForm.get(FileTypeGroup.Images + '')?.setValue(false);
|
||||||
|
this.libraryForm.get(FileTypeGroup.Pdf + '')?.setValue(true);
|
||||||
|
this.libraryForm.get(FileTypeGroup.Epub + '')?.setValue(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.libraryForm.get('allowScrobbling')?.setValue(this.IsKavitaPlusEligible);
|
this.libraryForm.get('allowScrobbling')?.setValue(this.IsKavitaPlusEligible);
|
||||||
|
|
|
@ -518,7 +518,8 @@
|
||||||
"manga": "Manga",
|
"manga": "Manga",
|
||||||
"comicVine": "ComicVine",
|
"comicVine": "ComicVine",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"lightNovel": "Light Novel"
|
"lightNovel": "Light Novel",
|
||||||
|
"generic": "Generic"
|
||||||
},
|
},
|
||||||
|
|
||||||
"age-rating-pipe": {
|
"age-rating-pipe": {
|
||||||
|
|
36
openapi.json
36
openapi.json
|
@ -7,7 +7,7 @@
|
||||||
"name": "GPL-3.0",
|
"name": "GPL-3.0",
|
||||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||||
},
|
},
|
||||||
"version": "0.7.14.12"
|
"version": "0.7.14.13"
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
|
@ -3138,7 +3138,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -3152,7 +3153,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -3166,7 +3168,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -3854,7 +3857,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -14157,7 +14161,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -14782,7 +14787,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "Library type",
|
"description": "Library type",
|
||||||
|
@ -16616,7 +16622,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -16651,6 +16658,7 @@
|
||||||
},
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Extra Regex that can be used for parsing",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
|
@ -16731,7 +16739,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -17802,7 +17811,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -17856,7 +17866,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
@ -20248,7 +20259,8 @@
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5
|
5,
|
||||||
|
6
|
||||||
],
|
],
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue