mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-06-23 15:30:34 -04:00
* Add ability to save readinglist comicinfo fields in Chapter. * Added the appropriate fields and migration for Reading List generation. * Started the reading list code * Started building out the CBL import code with some initial unit tests. * Fixed first unit test * Started refactoring control code into services and writing unit tests for ReadingLists. Found a logic issue around reading list title between create/update. Will be corrected in this branch with unit tests. * Can't figure out how to mock UserManager, so had to uncomment a few tests. * Tooltip for total pages read shows the full number * Tweaked the math a bit for average reading per week. * Fixed up the reading list unit tests. Fixed an issue where when inserting chapters into a blank reading list, the initial reading list item would have an order of 1 instead of 0. * Cleaned up the code to allow the reading list code to be localized easily and fixed up a bug in last PR. * Fixed a sorting issue on reading activity * Tweaked the code around reading list actionables not showing due to some weird filter. * Fixed edit library settings not opening on library detail page * Fixed a bug where reading activity dates would be out of order due to a bug in how charts works. A temp hack has been added. * Disable promotion in edit reading list modal since non-admins can (and should have) been able to use it. * Fixed a bug where non-admins couldn't update their OWN reading lists. Made uploading a cover image for readinglists now check against the user's reading list access to allow non-admin's to set images. * Fixed an issue introduced earlier in PR where adding chapters to reading list could cause order to get skewed. * Fixed another regression from earlier commit * Hooked in Import CBL flow. No functionality yet. * Code is a mess. Shifting how the whole import process is going to be done. Commiting so I can pivot drastically. * Very rough code for first step is done. * Ui has started, I've run out of steam for this feature. * Cleaned up the UI code a bit to make the step tracker nature easier without a dedicated component. * Much flow implementation and tweaking to how validation checks and what is sent back. * Removed import via cbl code as it's not done. Pushing to next release.
162 lines
6.4 KiB
C#
162 lines
6.4 KiB
C#
using System;
|
|
using System.Linq;
|
|
using API.Entities;
|
|
using API.Entities.Enums;
|
|
using Kavita.Common.Extensions;
|
|
|
|
namespace API.Data.Metadata;
|
|
|
|
/// <summary>
|
|
/// A representation of a ComicInfo.xml file
|
|
/// </summary>
|
|
/// <remarks>See reference of the loose spec here: https://anansi-project.github.io/docs/comicinfo/documentation</remarks>
|
|
public class ComicInfo
|
|
{
|
|
public string Summary { get; set; } = string.Empty;
|
|
public string Title { get; set; } = string.Empty;
|
|
public string Series { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Localized Series name. Not standard.
|
|
/// </summary>
|
|
public string LocalizedSeries { get; set; } = string.Empty;
|
|
public string SeriesSort { get; set; } = string.Empty;
|
|
public string Number { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// The total number of items in the series.
|
|
/// </summary>
|
|
[System.ComponentModel.DefaultValueAttribute(0)]
|
|
public int Count { get; set; } = 0;
|
|
public string Volume { get; set; } = string.Empty;
|
|
public string Notes { get; set; } = string.Empty;
|
|
public string Genre { get; set; } = string.Empty;
|
|
public int PageCount { get; set; }
|
|
// ReSharper disable once InconsistentNaming
|
|
/// <summary>
|
|
/// IETF BCP 47 Code to represent the language of the content
|
|
/// </summary>
|
|
public string LanguageISO { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// This is the link to where the data was scraped from
|
|
/// </summary>
|
|
public string Web { get; set; } = string.Empty;
|
|
[System.ComponentModel.DefaultValueAttribute(0)]
|
|
public int Day { get; set; } = 0;
|
|
[System.ComponentModel.DefaultValueAttribute(0)]
|
|
public int Month { get; set; } = 0;
|
|
[System.ComponentModel.DefaultValueAttribute(0)]
|
|
public int Year { get; set; } = 0;
|
|
|
|
|
|
/// <summary>
|
|
/// Rating based on the content. Think PG-13, R for movies. See <see cref="AgeRating"/> for valid types
|
|
/// </summary>
|
|
public string AgeRating { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// User's rating of the content
|
|
/// </summary>
|
|
public float UserRating { get; set; }
|
|
/// <summary>
|
|
/// Can contain multiple comma separated strings, each create a <see cref="CollectionTag"/>
|
|
/// </summary>
|
|
public string SeriesGroup { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string StoryArc { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Can contain multiple comma separated numbers that match with StoryArc
|
|
/// </summary>
|
|
public string StoryArcNumber { get; set; } = string.Empty;
|
|
public string AlternateNumber { get; set; } = string.Empty;
|
|
public string AlternateSeries { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Not used
|
|
/// </summary>
|
|
[System.ComponentModel.DefaultValueAttribute(0)]
|
|
public int AlternateCount { get; set; } = 0;
|
|
|
|
/// <summary>
|
|
/// This is Epub only: calibre:title_sort
|
|
/// Represents the sort order for the title
|
|
/// </summary>
|
|
public string TitleSort { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// This comes from ComicInfo and is free form text. We use this to validate against a set of tags and mark a file as
|
|
/// special.
|
|
/// </summary>
|
|
public string Format { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// The translator, can be comma separated. This is part of ComicInfo.xml draft v2.1
|
|
/// </summary>
|
|
/// See https://github.com/anansi-project/comicinfo/issues/2 for information about this tag
|
|
public string Translator { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Misc tags. This is part of ComicInfo.xml draft v2.1
|
|
/// </summary>
|
|
/// See https://github.com/anansi-project/comicinfo/issues/1 for information about this tag
|
|
public string Tags { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// This is the Author. For Books, we map creator tag in OPF to this field. Comma separated if multiple.
|
|
/// </summary>
|
|
public string Writer { get; set; } = string.Empty;
|
|
public string Penciller { get; set; } = string.Empty;
|
|
public string Inker { get; set; } = string.Empty;
|
|
public string Colorist { get; set; } = string.Empty;
|
|
public string Letterer { get; set; } = string.Empty;
|
|
public string CoverArtist { get; set; } = string.Empty;
|
|
public string Editor { get; set; } = string.Empty;
|
|
public string Publisher { get; set; } = string.Empty;
|
|
public string Characters { get; set; } = string.Empty;
|
|
|
|
public static AgeRating ConvertAgeRatingToEnum(string value)
|
|
{
|
|
if (string.IsNullOrEmpty(value)) return Entities.Enums.AgeRating.Unknown;
|
|
return Enum.GetValues<AgeRating>()
|
|
.SingleOrDefault(t => t.ToDescription().ToUpperInvariant().Equals(value.ToUpperInvariant()), Entities.Enums.AgeRating.Unknown);
|
|
}
|
|
|
|
public static void CleanComicInfo(ComicInfo info)
|
|
{
|
|
if (info == null) return;
|
|
|
|
info.Series = info.Series.Trim();
|
|
info.SeriesSort = info.SeriesSort.Trim();
|
|
info.LocalizedSeries = info.LocalizedSeries.Trim();
|
|
|
|
info.Writer = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Writer);
|
|
info.Colorist = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Colorist);
|
|
info.Editor = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Editor);
|
|
info.Inker = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Inker);
|
|
info.Letterer = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Letterer);
|
|
info.Penciller = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Penciller);
|
|
info.Publisher = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Publisher);
|
|
info.Characters = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Characters);
|
|
info.Translator = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.Translator);
|
|
info.CoverArtist = Services.Tasks.Scanner.Parser.Parser.CleanAuthor(info.CoverArtist);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Uses both Volume and Number to make an educated guess as to what count refers to and it's highest number.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public int CalculatedCount()
|
|
{
|
|
if (!string.IsNullOrEmpty(Number) && float.Parse(Number) > 0)
|
|
{
|
|
return (int) Math.Floor(float.Parse(Number));
|
|
}
|
|
if (!string.IsNullOrEmpty(Volume) && float.Parse(Volume) > 0)
|
|
{
|
|
return Math.Max(Count, (int) Math.Floor(float.Parse(Volume)));
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
}
|