mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Tachiyomi Enhancements (#845)
* Added a new endpoint to get all Series with Progress info. * Fixed up some potential NPEs during scan * Commented out filter code, not ready for it. * Fixed up a parsing case for european comics * Refactored FilterDto to allow for specifying multiple formats to return. * Refactored FilterDto to allow for specifying multiple formats to return. * Refactored the UI to show OPDS as 3rd Party Clients since Tachiyomi now uses OPDS url scheme for authentication.
This commit is contained in:
parent
658ca290e1
commit
384ebcef5c
@ -77,6 +77,7 @@ namespace API.Tests.Parser
|
|||||||
[InlineData("Max_l_explorateur-_Tome_0", "Max l explorateur")]
|
[InlineData("Max_l_explorateur-_Tome_0", "Max l explorateur")]
|
||||||
[InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "Chevaliers d'Héliopolis")]
|
[InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "Chevaliers d'Héliopolis")]
|
||||||
[InlineData("Bd Fr-Aldebaran-Antares-t6", "Aldebaran-Antares")]
|
[InlineData("Bd Fr-Aldebaran-Antares-t6", "Aldebaran-Antares")]
|
||||||
|
[InlineData("Tintin - T22 Vol 714 pour Sydney", "Tintin")]
|
||||||
public void ParseComicSeriesTest(string filename, string expected)
|
public void ParseComicSeriesTest(string filename, string expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, API.Parser.Parser.ParseComicSeries(filename));
|
Assert.Equal(expected, API.Parser.Parser.ParseComicSeries(filename));
|
||||||
|
@ -206,6 +206,14 @@ public class DefaultParserTests
|
|||||||
FullFilePath = filepath, IsSpecial = false
|
FullFilePath = filepath, IsSpecial = false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
filepath = @"E:\Manga\Air Gear\Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz";
|
||||||
|
expected.Add(filepath, new ParserInfo
|
||||||
|
{
|
||||||
|
Series = "Air Gear", Volumes = "1", Edition = "Omnibus",
|
||||||
|
Chapters = "0", Filename = "Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz", Format = MangaFormat.Archive,
|
||||||
|
FullFilePath = filepath, IsSpecial = false
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
foreach (var file in expected.Keys)
|
foreach (var file in expected.Keys)
|
||||||
{
|
{
|
||||||
|
@ -169,6 +169,7 @@ namespace API.Tests.Parser
|
|||||||
[InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")]
|
[InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")]
|
||||||
[InlineData("Kaiju No. 8 036 (2021) (Digital)", "Kaiju No. 8")]
|
[InlineData("Kaiju No. 8 036 (2021) (Digital)", "Kaiju No. 8")]
|
||||||
[InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
|
[InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
|
||||||
|
[InlineData("Love Hina - Volume 01 [Scans].pdf", "Love Hina")]
|
||||||
public void ParseSeriesTest(string filename, string expected)
|
public void ParseSeriesTest(string filename, string expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename));
|
Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename));
|
||||||
@ -258,6 +259,7 @@ namespace API.Tests.Parser
|
|||||||
[InlineData("Chobits Omnibus Edition v01 [Dark Horse]", "Omnibus Edition")]
|
[InlineData("Chobits Omnibus Edition v01 [Dark Horse]", "Omnibus Edition")]
|
||||||
[InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "")]
|
[InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "")]
|
||||||
[InlineData("AKIRA - c003 (v01) [Full Color] [Darkhorse].cbz", "Full Color")]
|
[InlineData("AKIRA - c003 (v01) [Full Color] [Darkhorse].cbz", "Full Color")]
|
||||||
|
[InlineData("Love Hina Omnibus v05 (2015) (Digital-HD) (Asgard-Empire).cbz", "Omnibus")]
|
||||||
public void ParseEditionTest(string input, string expected)
|
public void ParseEditionTest(string input, string expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, API.Parser.Parser.ParseEdition(input));
|
Assert.Equal(expected, API.Parser.Parser.ParseEdition(input));
|
||||||
|
@ -11,6 +11,7 @@ using API.DTOs.CollectionTags;
|
|||||||
using API.DTOs.Filtering;
|
using API.DTOs.Filtering;
|
||||||
using API.DTOs.OPDS;
|
using API.DTOs.OPDS;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
|
using API.Entities.Enums;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
using API.Helpers;
|
using API.Helpers;
|
||||||
using API.Services;
|
using API.Services;
|
||||||
@ -33,7 +34,7 @@ public class OpdsController : BaseApiController
|
|||||||
private const string Prefix = "/api/opds/";
|
private const string Prefix = "/api/opds/";
|
||||||
private readonly FilterDto _filterDto = new FilterDto()
|
private readonly FilterDto _filterDto = new FilterDto()
|
||||||
{
|
{
|
||||||
MangaFormat = null
|
Formats = new List<MangaFormat>()
|
||||||
};
|
};
|
||||||
private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer();
|
private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer();
|
||||||
|
|
||||||
|
@ -233,6 +233,23 @@ namespace API.Controllers
|
|||||||
return Ok(series);
|
return Ok(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("all")]
|
||||||
|
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetAllSeries(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0)
|
||||||
|
{
|
||||||
|
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
||||||
|
var series =
|
||||||
|
await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, userParams, filterDto);
|
||||||
|
|
||||||
|
// Apply progress/rating information (I can't work out how to do this in initial query)
|
||||||
|
if (series == null) return BadRequest("Could not get series");
|
||||||
|
|
||||||
|
await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series);
|
||||||
|
|
||||||
|
Response.AddPaginationHeader(series.CurrentPage, series.PageSize, series.TotalCount, series.TotalPages);
|
||||||
|
|
||||||
|
return Ok(series);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fetches series that are on deck aka have progress on them.
|
/// Fetches series that are on deck aka have progress on them.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
using API.Entities.Enums;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using API.Entities.Enums;
|
||||||
|
|
||||||
namespace API.DTOs.Filtering
|
namespace API.DTOs.Filtering
|
||||||
{
|
{
|
||||||
public class FilterDto
|
public class FilterDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pass null if you want all formats
|
/// The type of Formats you want to be returned. An empty list will return all formats back
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MangaFormat? MangaFormat { get; init; } = null;
|
public IList<MangaFormat> Formats { get; init; } = new List<MangaFormat>();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,20 @@ namespace API.Data.Metadata
|
|||||||
/// <remarks>See reference of the loose spec here: https://github.com/Kussie/ComicInfoStandard/blob/main/ComicInfo.xsd</remarks>
|
/// <remarks>See reference of the loose spec here: https://github.com/Kussie/ComicInfoStandard/blob/main/ComicInfo.xsd</remarks>
|
||||||
public class ComicInfo
|
public class ComicInfo
|
||||||
{
|
{
|
||||||
public string Summary { get; set; }
|
public string Summary { get; set; } = string.Empty;
|
||||||
public string Title { get; set; }
|
public string Title { get; set; } = string.Empty;
|
||||||
public string Series { get; set; }
|
public string Series { get; set; } = string.Empty;
|
||||||
public string Number { get; set; }
|
public string Number { get; set; } = string.Empty;
|
||||||
public string Volume { get; set; }
|
public string Volume { get; set; } = string.Empty;
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; } = string.Empty;
|
||||||
public string Genre { get; set; }
|
public string Genre { get; set; } = string.Empty;
|
||||||
public int PageCount { get; set; }
|
public int PageCount { get; set; }
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public string LanguageISO { get; set; }
|
public string LanguageISO { get; set; } = string.Empty;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the link to where the data was scraped from
|
/// This is the link to where the data was scraped from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Web { get; set; }
|
public string Web { get; set; } = string.Empty;
|
||||||
public int Day { get; set; }
|
public int Day { get; set; }
|
||||||
public int Month { get; set; }
|
public int Month { get; set; }
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
@ -33,29 +33,23 @@ namespace API.Data.Metadata
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rating based on the content. Think PG-13, R for movies. See <see cref="AgeRating"/> for valid types
|
/// Rating based on the content. Think PG-13, R for movies. See <see cref="AgeRating"/> for valid types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AgeRating { get; set; }
|
public string AgeRating { get; set; } = string.Empty;
|
||||||
|
|
||||||
// public AgeRating AgeRating
|
|
||||||
// {
|
|
||||||
// get => ConvertAgeRatingToEnum(_AgeRating);
|
|
||||||
// set => ConvertAgeRatingToEnum(value);
|
|
||||||
// }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User's rating of the content
|
/// User's rating of the content
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float UserRating { get; set; }
|
public float UserRating { get; set; }
|
||||||
|
|
||||||
public string AlternateSeries { get; set; }
|
public string AlternateSeries { get; set; } = string.Empty;
|
||||||
public string StoryArc { get; set; }
|
public string StoryArc { get; set; } = string.Empty;
|
||||||
public string SeriesGroup { get; set; }
|
public string SeriesGroup { get; set; } = string.Empty;
|
||||||
public string AlternativeSeries { get; set; }
|
public string AlternativeSeries { get; set; } = string.Empty;
|
||||||
public string AlternativeNumber { get; set; }
|
public string AlternativeNumber { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is Epub only: calibre:title_sort
|
/// This is Epub only: calibre:title_sort
|
||||||
/// Represents the sort order for the title
|
/// Represents the sort order for the title
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TitleSort { get; set; }
|
public string TitleSort { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -63,14 +57,14 @@ namespace API.Data.Metadata
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the Author. For Books, we map creator tag in OPF to this field. Comma separated if multiple.
|
/// This is the Author. For Books, we map creator tag in OPF to this field. Comma separated if multiple.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Writer { get; set; }
|
public string Writer { get; set; } = string.Empty;
|
||||||
public string Penciller { get; set; }
|
public string Penciller { get; set; } = string.Empty;
|
||||||
public string Inker { get; set; }
|
public string Inker { get; set; } = string.Empty;
|
||||||
public string Colorist { get; set; }
|
public string Colorist { get; set; } = string.Empty;
|
||||||
public string Letterer { get; set; }
|
public string Letterer { get; set; } = string.Empty;
|
||||||
public string CoverArtist { get; set; }
|
public string CoverArtist { get; set; } = string.Empty;
|
||||||
public string Editor { get; set; }
|
public string Editor { get; set; } = string.Empty;
|
||||||
public string Publisher { get; set; }
|
public string Publisher { get; set; } = string.Empty;
|
||||||
|
|
||||||
public static AgeRating ConvertAgeRatingToEnum(string value)
|
public static AgeRating ConvertAgeRatingToEnum(string value)
|
||||||
{
|
{
|
||||||
|
@ -178,8 +178,11 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
public async Task<PagedList<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
public async Task<PagedList<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
||||||
{
|
{
|
||||||
var formats = filter.GetSqlFilter();
|
var formats = filter.GetSqlFilter();
|
||||||
|
|
||||||
|
var userLibraries = await GetUserLibraries(libraryId, userId);
|
||||||
|
|
||||||
var query = _context.Series
|
var query = _context.Series
|
||||||
.Where(s => s.LibraryId == libraryId && formats.Contains(s.Format))
|
.Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format))
|
||||||
.OrderBy(s => s.SortName)
|
.OrderBy(s => s.SortName)
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
.AsNoTracking();
|
.AsNoTracking();
|
||||||
@ -187,6 +190,24 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
return await PagedList<SeriesDto>.CreateAsync(query, userParams.PageNumber, userParams.PageSize);
|
return await PagedList<SeriesDto>.CreateAsync(query, userParams.PageNumber, userParams.PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<List<int>> GetUserLibraries(int libraryId, int userId)
|
||||||
|
{
|
||||||
|
if (libraryId == 0)
|
||||||
|
{
|
||||||
|
return await _context.Library
|
||||||
|
.Include(l => l.AppUsers)
|
||||||
|
.Where(library => library.AppUsers.Any(user => user.Id == userId))
|
||||||
|
.AsNoTracking()
|
||||||
|
.Select(library => library.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<int>()
|
||||||
|
{
|
||||||
|
libraryId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchResultDto>> SearchSeries(int[] libraryIds, string searchQuery)
|
public async Task<IEnumerable<SearchResultDto>> SearchSeries(int[] libraryIds, string searchQuery)
|
||||||
{
|
{
|
||||||
return await _context.Series
|
return await _context.Series
|
||||||
@ -357,26 +378,10 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
{
|
{
|
||||||
var formats = filter.GetSqlFilter();
|
var formats = filter.GetSqlFilter();
|
||||||
|
|
||||||
if (libraryId == 0)
|
var userLibraries = await GetUserLibraries(libraryId, userId);
|
||||||
{
|
|
||||||
var userLibraries = _context.Library
|
|
||||||
.Include(l => l.AppUsers)
|
|
||||||
.Where(library => library.AppUsers.Any(user => user.Id == userId))
|
|
||||||
.AsNoTracking()
|
|
||||||
.Select(library => library.Id)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var allQuery = _context.Series
|
|
||||||
.Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format))
|
|
||||||
.OrderByDescending(s => s.Created)
|
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
|
||||||
.AsNoTracking();
|
|
||||||
|
|
||||||
return await PagedList<SeriesDto>.CreateAsync(allQuery, userParams.PageNumber, userParams.PageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
var query = _context.Series
|
var query = _context.Series
|
||||||
.Where(s => s.LibraryId == libraryId && formats.Contains(s.Format))
|
.Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format))
|
||||||
.OrderByDescending(s => s.Created)
|
.OrderByDescending(s => s.Created)
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
@ -397,20 +402,8 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
public async Task<IEnumerable<SeriesDto>> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter)
|
public async Task<IEnumerable<SeriesDto>> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter)
|
||||||
{
|
{
|
||||||
var formats = filter.GetSqlFilter();
|
var formats = filter.GetSqlFilter();
|
||||||
IList<int> userLibraries;
|
|
||||||
if (libraryId == 0)
|
var userLibraries = await GetUserLibraries(libraryId, userId);
|
||||||
{
|
|
||||||
userLibraries = _context.Library
|
|
||||||
.Include(l => l.AppUsers)
|
|
||||||
.Where(library => library.AppUsers.Any(user => user.Id == userId))
|
|
||||||
.AsNoTracking()
|
|
||||||
.Select(library => library.Id)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
userLibraries = new List<int>() {libraryId};
|
|
||||||
}
|
|
||||||
|
|
||||||
var series = _context.Series
|
var series = _context.Series
|
||||||
.Where(s => formats.Contains(s.Format) && userLibraries.Contains(s.LibraryId))
|
.Where(s => formats.Contains(s.Format) && userLibraries.Contains(s.LibraryId))
|
||||||
|
@ -11,15 +11,12 @@ namespace API.Extensions
|
|||||||
|
|
||||||
public static IList<MangaFormat> GetSqlFilter(this FilterDto filter)
|
public static IList<MangaFormat> GetSqlFilter(this FilterDto filter)
|
||||||
{
|
{
|
||||||
var format = filter.MangaFormat;
|
if (filter.Formats == null || filter.Formats.Count == 0)
|
||||||
if (format != null)
|
|
||||||
{
|
{
|
||||||
return new List<MangaFormat>()
|
|
||||||
{
|
|
||||||
(MangaFormat) format
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return AllFormats;
|
return AllFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return filter.Formats;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,9 +237,13 @@ namespace API.Parser
|
|||||||
|
|
||||||
private static readonly Regex[] ComicSeriesRegex = new[]
|
private static readonly Regex[] ComicSeriesRegex = new[]
|
||||||
{
|
{
|
||||||
|
// Tintin - T22 Vol 714 pour Sydney
|
||||||
|
new Regex(
|
||||||
|
@"(?<Series>.+?)\s?(\b|_|-)\s?((vol|tome|t)\.?)(?<Volume>\d+(-\d+)?)",
|
||||||
|
MatchOptions, RegexTimeout),
|
||||||
// Invincible Vol 01 Family matters (2005) (Digital)
|
// Invincible Vol 01 Family matters (2005) (Digital)
|
||||||
new Regex(
|
new Regex(
|
||||||
@"(?<Series>.*)(\b|_)((vol|tome|t)\.?)( |_)(?<Volume>\d+(-\d+)?)",
|
@"(?<Series>.+?)(\b|_)((vol|tome|t)\.?)(\s|_)(?<Volume>\d+(-\d+)?)",
|
||||||
MatchOptions, RegexTimeout),
|
MatchOptions, RegexTimeout),
|
||||||
// Batman Beyond 2.0 001 (2013)
|
// Batman Beyond 2.0 001 (2013)
|
||||||
new Regex(
|
new Regex(
|
||||||
|
@ -287,7 +287,7 @@ public class MetadataService : IMetadataService
|
|||||||
series.Metadata.ReleaseYear = series.Volumes
|
series.Metadata.ReleaseYear = series.Volumes
|
||||||
.SelectMany(volume => volume.Chapters).Min(c => c.ReleaseDate.Year);
|
.SelectMany(volume => volume.Chapters).Min(c => c.ReleaseDate.Year);
|
||||||
|
|
||||||
var genres = comicInfos.SelectMany(i => i.Genre.Split(",")).Distinct().ToList();
|
var genres = comicInfos.SelectMany(i => i?.Genre.Split(",")).Distinct().ToList();
|
||||||
var people = series.Volumes.SelectMany(volume => volume.Chapters).SelectMany(c => c.People).ToList();
|
var people = series.Volumes.SelectMany(volume => volume.Chapters).SelectMany(c => c.People).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"TokenKey": "super secret unguessable key",
|
"TokenKey": "super secret unguessable key",
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Debug",
|
||||||
"Microsoft": "Information",
|
"Microsoft": "Information",
|
||||||
"Microsoft.Hosting.Lifetime": "Error",
|
"Microsoft.Hosting.Lifetime": "Error",
|
||||||
"Hangfire": "Information",
|
"Hangfire": "Information",
|
||||||
|
6
UI/Web/package-lock.json
generated
6
UI/Web/package-lock.json
generated
@ -12384,7 +12384,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
@ -12589,7 +12590,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
|
@ -7,7 +7,7 @@ export interface FilterItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SeriesFilter {
|
export interface SeriesFilter {
|
||||||
mangaFormat: MangaFormat | null;
|
formats: Array<MangaFormat>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mangaFormatFilters = [
|
export const mangaFormatFilters = [
|
||||||
|
@ -177,11 +177,13 @@ export class SeriesService {
|
|||||||
|
|
||||||
createSeriesFilter(filter?: SeriesFilter) {
|
createSeriesFilter(filter?: SeriesFilter) {
|
||||||
const data: SeriesFilter = {
|
const data: SeriesFilter = {
|
||||||
mangaFormat: null
|
formats: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
data.mangaFormat = filter.mangaFormat;
|
if (filter.formats != null) {
|
||||||
|
data.formats = filter.formats;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -41,7 +41,7 @@ export class CollectionDetailComponent implements OnInit, OnDestroy {
|
|||||||
isAdmin: boolean = false;
|
isAdmin: boolean = false;
|
||||||
filters: Array<FilterItem> = mangaFormatFilters;
|
filters: Array<FilterItem> = mangaFormatFilters;
|
||||||
filter: SeriesFilter = {
|
filter: SeriesFilter = {
|
||||||
mangaFormat: null
|
formats: []
|
||||||
};
|
};
|
||||||
|
|
||||||
private onDestory: Subject<void> = new Subject<void>();
|
private onDestory: Subject<void> = new Subject<void>();
|
||||||
@ -175,7 +175,7 @@ export class CollectionDetailComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateFilter(data: UpdateFilterEvent) {
|
updateFilter(data: UpdateFilterEvent) {
|
||||||
this.filter.mangaFormat = data.filterItem.value;
|
this.filter.formats = [data.filterItem.value];
|
||||||
if (this.seriesPagination !== undefined && this.seriesPagination !== null) {
|
if (this.seriesPagination !== undefined && this.seriesPagination !== null) {
|
||||||
this.seriesPagination.currentPage = 1;
|
this.seriesPagination.currentPage = 1;
|
||||||
this.onPageChange(this.seriesPagination);
|
this.onPageChange(this.seriesPagination);
|
||||||
|
@ -32,7 +32,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
|
|||||||
actions: ActionItem<Library>[] = [];
|
actions: ActionItem<Library>[] = [];
|
||||||
filters: Array<FilterItem> = mangaFormatFilters;
|
filters: Array<FilterItem> = mangaFormatFilters;
|
||||||
filter: SeriesFilter = {
|
filter: SeriesFilter = {
|
||||||
mangaFormat: null
|
formats: []
|
||||||
};
|
};
|
||||||
onDestroy: Subject<void> = new Subject<void>();
|
onDestroy: Subject<void> = new Subject<void>();
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateFilter(data: UpdateFilterEvent) {
|
updateFilter(data: UpdateFilterEvent) {
|
||||||
this.filter.mangaFormat = data.filterItem.value;
|
this.filter.formats = [data.filterItem.value];
|
||||||
if (this.pagination !== undefined && this.pagination !== null) {
|
if (this.pagination !== undefined && this.pagination !== null) {
|
||||||
this.pagination.currentPage = 1;
|
this.pagination.currentPage = 1;
|
||||||
this.onPageChange(this.pagination);
|
this.onPageChange(this.pagination);
|
||||||
|
@ -25,7 +25,7 @@ export class OnDeckComponent implements OnInit {
|
|||||||
libraryId!: number;
|
libraryId!: number;
|
||||||
filters: Array<FilterItem> = mangaFormatFilters;
|
filters: Array<FilterItem> = mangaFormatFilters;
|
||||||
filter: SeriesFilter = {
|
filter: SeriesFilter = {
|
||||||
mangaFormat: null
|
formats: []
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title,
|
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title,
|
||||||
@ -64,7 +64,7 @@ export class OnDeckComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateFilter(data: UpdateFilterEvent) {
|
updateFilter(data: UpdateFilterEvent) {
|
||||||
this.filter.mangaFormat = data.filterItem.value;
|
this.filter.formats = [data.filterItem.value];
|
||||||
if (this.pagination !== undefined && this.pagination !== null) {
|
if (this.pagination !== undefined && this.pagination !== null) {
|
||||||
this.pagination.currentPage = 1;
|
this.pagination.currentPage = 1;
|
||||||
this.onPageChange(this.pagination);
|
this.onPageChange(this.pagination);
|
||||||
|
@ -32,7 +32,7 @@ export class RecentlyAddedComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
filters: Array<FilterItem> = mangaFormatFilters;
|
filters: Array<FilterItem> = mangaFormatFilters;
|
||||||
filter: SeriesFilter = {
|
filter: SeriesFilter = {
|
||||||
mangaFormat: null
|
formats: []
|
||||||
};
|
};
|
||||||
|
|
||||||
onDestroy: Subject<void> = new Subject();
|
onDestroy: Subject<void> = new Subject();
|
||||||
@ -82,7 +82,8 @@ export class RecentlyAddedComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateFilter(data: UpdateFilterEvent) {
|
updateFilter(data: UpdateFilterEvent) {
|
||||||
this.filter.mangaFormat = data.filterItem.value;
|
// TODO: Move this into card-layout component. It's the same except for callback
|
||||||
|
this.filter.formats = [data.filterItem.value];
|
||||||
if (this.pagination !== undefined && this.pagination !== null) {
|
if (this.pagination !== undefined && this.pagination !== null) {
|
||||||
this.pagination.currentPage = 1;
|
this.pagination.currentPage = 1;
|
||||||
this.onPageChange(this.pagination);
|
this.onPageChange(this.pagination);
|
||||||
|
@ -213,21 +213,18 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
<ngb-panel id="api-panel" title="OPDS">
|
<ngb-panel id="api-panel" title="3rd Party Clients">
|
||||||
<ng-template ngbPanelHeader>
|
<ng-template ngbPanelHeader>
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<button ngbPanelToggle class="btn container-fluid text-left pl-0 accordion-header">OPDS</button>
|
<button ngbPanelToggle class="btn container-fluid text-left pl-0 accordion-header">3rd Party Clients</button>
|
||||||
<span class="pull-right"><i class="fa fa-angle-{{acc.isExpanded('api-panel') ? 'down' : 'up'}}" aria-hidden="true"></i></span>
|
<span class="pull-right"><i class="fa fa-angle-{{acc.isExpanded('api-panel') ? 'down' : 'up'}}" aria-hidden="true"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<p class="alert alert-danger" role="alert" *ngIf="!opdsEnabled">
|
<p>All 3rd Party clients will either use the API key or the Connection Url below. These are like passwords, keep it private.</p>
|
||||||
OPDS is not enabled on this server!
|
<p class="alert alert-warning" role="alert" *ngIf="!opdsEnabled">OPDS is not enabled on this server.</p>
|
||||||
</p>
|
|
||||||
<ng-container *ngIf="opdsEnabled">
|
|
||||||
<app-api-key tooltipText="The API key is like a password. Keep it secret, Keep it safe."></app-api-key>
|
<app-api-key tooltipText="The API key is like a password. Keep it secret, Keep it safe."></app-api-key>
|
||||||
<app-api-key title="OPDS URL" [showRefresh]="false" [transform]="makeUrl"></app-api-key>
|
<app-api-key title="OPDS URL" [showRefresh]="false" [transform]="makeUrl"></app-api-key>
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
</ngb-accordion>
|
</ngb-accordion>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user