A ton of random bugs and polish (#3668)

This commit is contained in:
Joe Milazzo 2025-03-23 17:06:20 -05:00 committed by GitHub
parent b45d92ea5c
commit de651215f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
144 changed files with 852 additions and 848 deletions

View File

@ -1,6 +1,7 @@
# Editor configuration, see https://editorconfig.org # Editor configuration, see https://editorconfig.org
root = true root = true
[*] [*]
charset = utf-8 charset = utf-8
indent_style = space indent_style = space
@ -22,3 +23,7 @@ indent_size = 2
[*.csproj] [*.csproj]
indent_size = 2 indent_size = 2
[*.cs]
# Disable SonarLint warning S1075 (Don't use hardcoded url)
dotnet_diagnostic.S1075.severity = none

View File

@ -1,8 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.IO;
using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
@ -13,7 +10,6 @@ using API.Helpers.Builders;
using API.Services; using API.Services;
using AutoMapper; using AutoMapper;
using Hangfire; using Hangfire;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;

View File

@ -1,5 +1,4 @@
using API.Helpers.Converters; using API.Helpers.Converters;
using Hangfire;
using Xunit; using Xunit;
namespace API.Tests.Converters; namespace API.Tests.Converters;

View File

@ -7,7 +7,6 @@ using API.Extensions;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;
using API.Tests.Helpers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;

View File

@ -1,11 +1,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using API.Data;
using API.Data.Misc; using API.Data.Misc;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Person;
using API.Extensions;
using API.Extensions.QueryExtensions; using API.Extensions.QueryExtensions;
using API.Helpers.Builders; using API.Helpers.Builders;
using Xunit; using Xunit;

View File

@ -3,7 +3,6 @@ using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions; using API.Extensions;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Tests.Helpers;
using Xunit; using Xunit;
namespace API.Tests.Extensions; namespace API.Tests.Extensions;

View File

@ -2,8 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Threading;
using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;

View File

@ -1,8 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services.Tasks.Scanner; using API.Services.Tasks.Scanner;

View File

@ -1,15 +1,5 @@
using System; using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data;
using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using API.Helpers;
using API.Helpers.Builders;
using API.Services.Tasks.Scanner.Parser;
using Xunit;
namespace API.Tests.Helpers; namespace API.Tests.Helpers;

View File

@ -26,6 +26,7 @@ using NSubstitute;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace API.Tests.Helpers; namespace API.Tests.Helpers;
#nullable enable
public class ScannerHelper public class ScannerHelper
{ {

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using API.Data;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions; using API.Extensions;

View File

@ -1,5 +1,4 @@
using System; using API.Helpers;
using API.Helpers;
using Xunit; using Xunit;
namespace API.Tests.Helpers; namespace API.Tests.Helpers;

View File

@ -1,5 +1,4 @@
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using API.Data.Metadata;
using API.Entities.Enums; using API.Entities.Enums;
using API.Services; using API.Services;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;

View File

@ -1,18 +1,10 @@
using API.Entities.Enums; using API.Entities.Enums;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace API.Tests.Parsing; namespace API.Tests.Parsing;
public class MangaParsingTests public class MangaParsingTests
{ {
private readonly ITestOutputHelper _testOutputHelper;
public MangaParsingTests(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
[Theory] [Theory]
[InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")] [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")]
[InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "1")] [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "1")]
@ -84,6 +76,7 @@ public class MangaParsingTests
[InlineData("Accel World Chapter 001 Volume 002", "2")] [InlineData("Accel World Chapter 001 Volume 002", "2")]
[InlineData("Accel World Volume 2", "2")] [InlineData("Accel World Volume 2", "2")]
[InlineData("Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.31 Omake", "30")] [InlineData("Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.31 Omake", "30")]
[InlineData("Zom 100 - Bucket List of the Dead v01", "1")]
public void ParseVolumeTest(string filename, string expected) public void ParseVolumeTest(string filename, string expected)
{ {
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename, LibraryType.Manga)); Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename, LibraryType.Manga));
@ -212,6 +205,8 @@ public class MangaParsingTests
[InlineData("不安の種\uff0b - 01", "不安の種\uff0b")] [InlineData("不安の種\uff0b - 01", "不安の種\uff0b")]
[InlineData("Giant Ojou-sama - Ch. 33.5 - Volume 04 Bonus Chapter", "Giant Ojou-sama")] [InlineData("Giant Ojou-sama - Ch. 33.5 - Volume 04 Bonus Chapter", "Giant Ojou-sama")]
[InlineData("[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE", "")] [InlineData("[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE", "")]
[InlineData("Monster #8 Ch. 001", "Monster #8")]
[InlineData("Zom 100 - Bucket List of the Dead v01", "Zom 100 - Bucket List of the Dead")]
public void ParseSeriesTest(string filename, string expected) public void ParseSeriesTest(string filename, string expected)
{ {
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename, LibraryType.Manga)); Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename, LibraryType.Manga));
@ -304,6 +299,7 @@ public class MangaParsingTests
[InlineData("เด็กคนนี้ขอลาออกจากการเป็นเจ้าของปราสาท เล่ม 1 ตอนที่ 3", "3")] [InlineData("เด็กคนนี้ขอลาออกจากการเป็นเจ้าของปราสาท เล่ม 1 ตอนที่ 3", "3")]
[InlineData("Max Level Returner ตอนที่ 5", "5")] [InlineData("Max Level Returner ตอนที่ 5", "5")]
[InlineData("หนึ่งความคิด นิจนิรันดร์ บทที่ 112", "112")] [InlineData("หนึ่งความคิด นิจนิรันดร์ บทที่ 112", "112")]
[InlineData("Monster #8 Ch. 001", "1")]
public void ParseChaptersTest(string filename, string expected) public void ParseChaptersTest(string filename, string expected)
{ {
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename, LibraryType.Manga)); Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename, LibraryType.Manga));

View File

@ -1,6 +1,5 @@
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using Xunit; using Xunit;
using static API.Services.Tasks.Scanner.Parser.Parser; using static API.Services.Tasks.Scanner.Parser.Parser;

View File

@ -15,7 +15,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit;
namespace API.Tests.Repository; namespace API.Tests.Repository;

View File

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using API.Data; using API.Data;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;

View File

@ -7,7 +7,6 @@ using System.Linq;
using API.Archive; using API.Archive;
using API.Entities.Enums; using API.Entities.Enums;
using API.Services; using API.Services;
using EasyCaching.Core;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NetVips; using NetVips;
using NSubstitute; using NSubstitute;

View File

@ -1,11 +1,8 @@
using System.Collections.Generic; using System.Data.Common;
using System.Data.Common;
using System.IO;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;

View File

@ -1,7 +1,6 @@
using System.IO; using System.IO;
using System.IO.Abstractions; using System.IO.Abstractions;
using API.Services; using API.Services;
using EasyCaching.Core;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
@ -92,18 +91,17 @@ public class BookServiceTests
Assert.Equal("Georges Bizet \\(1838-1875\\)", comicInfo.Writer); Assert.Equal("Georges Bizet \\(1838-1875\\)", comicInfo.Writer);
} }
// TODO: Get the file from microtherion //[Fact]
// [Fact] public void ShouldUsePdfInfoDict()
// public void ShouldUsePdfInfoDict() {
// { var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ScannerService/Library/Books/PDFs");
// var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ScannerService/Library/Books/PDFs"); var document = Path.Join(testDirectory, "Rollo at Work SP01.pdf");
// var document = Path.Join(testDirectory, "Rollo at Work SP01.pdf"); var comicInfo = _bookService.GetComicInfo(document);
// var comicInfo = _bookService.GetComicInfo(document); Assert.NotNull(comicInfo);
// Assert.NotNull(comicInfo); Assert.Equal("Rollo at Work", comicInfo.Title);
// Assert.Equal("Rollo at Work", comicInfo.Title); Assert.Equal("Jacob Abbott", comicInfo.Writer);
// Assert.Equal("Jacob Abbott", comicInfo.Writer); Assert.Equal(2008, comicInfo.Year);
// Assert.Equal(2008, comicInfo.Year); }
// }
[Fact] [Fact]
public void ShouldHandleIndirectPdfObjects() public void ShouldHandleIndirectPdfObjects()

View File

@ -9,12 +9,9 @@ using API.Data.Repositories;
using API.DTOs.Reader; using API.DTOs.Reader;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
using API.SignalR;
using AutoMapper; using AutoMapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;

View File

@ -1,12 +1,10 @@
using System.Collections.Generic; using System.Data.Common;
using System.Data.Common;
using System.IO; using System.IO;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
using API.Data.Metadata; using API.Data.Metadata;
using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;

View File

@ -1,16 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data;
using API.Data.Repositories; using API.Data.Repositories;
using API.DTOs.Filtering; using API.DTOs.Filtering;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions; using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;

View File

@ -13,7 +13,6 @@ using API.Services;
using API.Services.Plus; using API.Services.Plus;
using API.SignalR; using API.SignalR;
using Kavita.Common; using Kavita.Common;
using Microsoft.EntityFrameworkCore;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Constants; using API.Constants;
@ -12,6 +11,7 @@ using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.MetadataMatching; using API.Entities.MetadataMatching;
using API.Entities.Person;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services.Plus; using API.Services.Plus;
using API.Services.Tasks.Metadata; using API.Services.Tasks.Metadata;
@ -21,8 +21,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
using Xunit.Abstractions;
using YamlDotNet.Serialization;
namespace API.Tests.Services; namespace API.Tests.Services;
@ -31,17 +29,14 @@ namespace API.Tests.Services;
/// </summary> /// </summary>
public class ExternalMetadataServiceTests : AbstractDbTest public class ExternalMetadataServiceTests : AbstractDbTest
{ {
private readonly ITestOutputHelper _testOutputHelper;
private readonly ExternalMetadataService _externalMetadataService; private readonly ExternalMetadataService _externalMetadataService;
private readonly Dictionary<string, Genre> _genreLookup = new Dictionary<string, Genre>(); private readonly Dictionary<string, Genre> _genreLookup = new Dictionary<string, Genre>();
private readonly Dictionary<string, Tag> _tagLookup = new Dictionary<string, Tag>(); private readonly Dictionary<string, Tag> _tagLookup = new Dictionary<string, Tag>();
private readonly Dictionary<string, Person> _personLookup = new Dictionary<string, Person>(); private readonly Dictionary<string, Person> _personLookup = new Dictionary<string, Person>();
public ExternalMetadataServiceTests(ITestOutputHelper testOutputHelper) public ExternalMetadataServiceTests()
{ {
_testOutputHelper = testOutputHelper;
// Set up Hangfire to use in-memory storage for testing // Set up Hangfire to use in-memory storage for testing
GlobalConfiguration.Configuration.UseInMemoryStorage(); GlobalConfiguration.Configuration.UseInMemoryStorage();

View File

@ -1,14 +1,9 @@
using System.Drawing; using System.IO;
using System.IO;
using System.IO.Abstractions;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using API.Entities.Enums; using API.Entities.Enums;
using API.Services; using API.Services;
using EasyCaching.Core;
using Microsoft.Extensions.Logging;
using NetVips; using NetVips;
using NSubstitute;
using Xunit; using Xunit;
using Image = NetVips.Image; using Image = NetVips.Image;
@ -28,6 +23,7 @@ public class ImageServiceTests
public void GenerateBaseline() public void GenerateBaseline()
{ {
GenerateFiles(BaselinePattern); GenerateFiles(BaselinePattern);
Assert.True(true);
} }
/// <summary> /// <summary>
@ -38,6 +34,7 @@ public class ImageServiceTests
{ {
GenerateFiles(OutputPattern); GenerateFiles(OutputPattern);
GenerateHtmlFile(); GenerateHtmlFile();
Assert.True(true);
} }
private void GenerateFiles(string outputExtension) private void GenerateFiles(string outputExtension)
@ -159,7 +156,7 @@ public class ImageServiceTests
// Step 4: Generate HTML file // Step 4: Generate HTML file
GenerateHtmlFileForColorScape(); GenerateHtmlFileForColorScape();
Assert.True(true);
} }
private static void GenerateColorImage(string hexColor, string outputPath) private static void GenerateColorImage(string hexColor, string outputPath)

View File

@ -1,29 +1,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common;
using System.IO; using System.IO;
using System.IO.Abstractions; using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data;
using API.Data.Metadata; using API.Data.Metadata;
using API.Data.Repositories; using API.Data.Repositories;
using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions;
using API.Helpers.Builders;
using API.Services; using API.Services;
using API.Services.Tasks.Scanner; using API.Services.Tasks.Scanner;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;
using API.SignalR; using API.SignalR;
using API.Tests.Helpers; using API.Tests.Helpers;
using AutoMapper;
using Hangfire; using Hangfire;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
@ -391,7 +381,7 @@ public class ParseScannedFilesTests : AbstractDbTest
var executionerAndHerWayOfLife = postLib.Series.First(x => x.Name == "The Executioner and Her Way of Life"); var executionerAndHerWayOfLife = postLib.Series.First(x => x.Name == "The Executioner and Her Way of Life");
Assert.Equal(2, executionerAndHerWayOfLife.Volumes.Count); Assert.Equal(2, executionerAndHerWayOfLife.Volumes.Count);
Thread.Sleep(1100); // Ensure at least one second has passed since library scan await Task.Delay(1100); // Ensure at least one second has passed since library scan
// Add a new chapter to a volume of the series, and scan. Validate that only, and all directories of this // Add a new chapter to a volume of the series, and scan. Validate that only, and all directories of this
// series are marked as HasChanged // series are marked as HasChanged
@ -440,7 +430,7 @@ public class ParseScannedFilesTests : AbstractDbTest
var frieren = postLib.Series.First(x => x.Name == "Frieren - Beyond Journey's End"); var frieren = postLib.Series.First(x => x.Name == "Frieren - Beyond Journey's End");
Assert.Equal(2, frieren.Volumes.Count); Assert.Equal(2, frieren.Volumes.Count);
Thread.Sleep(1100); // Ensure at least one second has passed since library scan await Task.Delay(1100); // Ensure at least one second has passed since library scan
// Add a volume to a series, and scan. Ensure only this series is marked as HasChanged // Add a volume to a series, and scan. Ensure only this series is marked as HasChanged
var executionerCopyDir = Path.Join(Path.Join(testDirectoryPath, "YenPress"), "The Executioner and Her Way of Life"); var executionerCopyDir = Path.Join(Path.Join(testDirectoryPath, "YenPress"), "The Executioner and Her Way of Life");
@ -483,7 +473,7 @@ public class ParseScannedFilesTests : AbstractDbTest
// Needs to be actual time as the write time is now, so if we set LastFolderChecked in the past // Needs to be actual time as the write time is now, so if we set LastFolderChecked in the past
// it'll always a scan as it was changed since the last scan. // it'll always a scan as it was changed since the last scan.
Thread.Sleep(1100); // Ensure at least one second has passed since library scan await Task.Delay(1100); // Ensure at least one second has passed since library scan
var res = await psf.ScanFiles(testDirectoryPath, true, var res = await psf.ScanFiles(testDirectoryPath, true,
await _unitOfWork.SeriesRepository.GetFolderPathMap(postLib.Id), postLib); await _unitOfWork.SeriesRepository.GetFolderPathMap(postLib.Id), postLib);

View File

@ -1,19 +1,4 @@
using System.IO; namespace API.Tests.Services;
using API.Data;
using API.Data.Metadata;
using API.Entities;
using API.Entities.Enums;
using API.Helpers;
using API.Helpers.Builders;
using API.Services;
using API.Services.Tasks.Metadata;
using API.Services.Tasks.Scanner;
using API.SignalR;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
namespace API.Tests.Services;
public class ProcessSeriesTests public class ProcessSeriesTests
{ {

View File

@ -1,25 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.Globalization;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
using API.Data.Repositories; using API.Data.Repositories;
using API.DTOs;
using API.DTOs.Progress; using API.DTOs.Progress;
using API.DTOs.Reader; using API.DTOs.Reader;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions; using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
using API.Services.Plus; using API.Services.Plus;
using API.Services.Tasks;
using API.SignalR; using API.SignalR;
using API.Tests.Helpers;
using AutoMapper; using AutoMapper;
using Hangfire; using Hangfire;
using Hangfire.InMemory; using Hangfire.InMemory;

View File

@ -11,15 +11,11 @@ using API.DTOs.ReadingLists;
using API.DTOs.ReadingLists.CBL; using API.DTOs.ReadingLists.CBL;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
using API.Services.Plus; using API.Services.Plus;
using API.Services.Tasks;
using API.SignalR; using API.SignalR;
using API.Tests.Helpers;
using AutoMapper; using AutoMapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;

View File

@ -1,34 +1,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Abstractions;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using API.Data;
using API.Data.Metadata; using API.Data.Metadata;
using API.Data.Repositories; using API.Data.Repositories;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions; using API.Extensions;
using API.Helpers;
using API.Helpers.Builders;
using API.Services;
using API.Services.Plus;
using API.Services.Tasks;
using API.Services.Tasks.Metadata;
using API.Services.Tasks.Scanner;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;
using API.SignalR;
using API.Tests.Helpers; using API.Tests.Helpers;
using Hangfire; using Hangfire;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;

View File

@ -12,6 +12,7 @@ using API.DTOs.SeriesDetail;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
@ -809,6 +810,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.Genres.Select(g1 => g1.Title).All(g2 => g2 == "New Genre".SentenceCase())); Assert.True(series.Metadata.Genres.Select(g1 => g1.Title).All(g2 => g2 == "New Genre".SentenceCase()));
Assert.False(series.Metadata.GenresLocked); // GenreLocked is false unless the UI Explicitly says it should be locked Assert.False(series.Metadata.GenresLocked); // GenreLocked is false unless the UI Explicitly says it should be locked
@ -847,6 +849,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.People.Select(g => g.Person.Name).All(personName => personName == "Existing Person")); Assert.True(series.Metadata.People.Select(g => g.Person.Name).All(personName => personName == "Existing Person"));
Assert.False(series.Metadata.PublisherLocked); // PublisherLocked is false unless the UI Explicitly says it should be locked Assert.False(series.Metadata.PublisherLocked); // PublisherLocked is false unless the UI Explicitly says it should be locked
@ -887,6 +890,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.People.Select(g => g.Person.Name).All(personName => personName == "Existing Person")); Assert.True(series.Metadata.People.Select(g => g.Person.Name).All(personName => personName == "Existing Person"));
Assert.True(series.Metadata.PublisherLocked); Assert.True(series.Metadata.PublisherLocked);
@ -976,6 +980,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.False(series.Metadata.People.Any()); Assert.False(series.Metadata.People.Any());
} }
@ -1010,6 +1015,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.Genres.Select(g => g.Title).All(g => g == "Existing Genre".SentenceCase())); Assert.True(series.Metadata.Genres.Select(g => g.Title).All(g => g == "Existing Genre".SentenceCase()));
Assert.True(series.Metadata.GenresLocked); Assert.True(series.Metadata.GenresLocked);
@ -1039,6 +1045,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.Equal(0, series.Metadata.ReleaseYear); Assert.Equal(0, series.Metadata.ReleaseYear);
Assert.False(series.Metadata.ReleaseYearLocked); Assert.False(series.Metadata.ReleaseYearLocked);
@ -1071,6 +1078,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.Contains("New Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title)); Assert.Contains("New Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title));
Assert.False(series.Metadata.GenresLocked); // Ensure the lock is not activated unless specified. Assert.False(series.Metadata.GenresLocked); // Ensure the lock is not activated unless specified.
@ -1104,6 +1112,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.DoesNotContain("Existing Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title)); Assert.DoesNotContain("Existing Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title));
Assert.Contains("New Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title)); Assert.Contains("New Genre".SentenceCase(), series.Metadata.Genres.Select(g => g.Title));
@ -1137,6 +1146,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.Empty(series.Metadata.Genres); Assert.Empty(series.Metadata.Genres);
} }
@ -1168,6 +1178,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.Contains("New Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title)); Assert.Contains("New Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title));
} }
@ -1200,6 +1211,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.DoesNotContain("Existing Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title)); Assert.DoesNotContain("Existing Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title));
Assert.Contains("New Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title)); Assert.Contains("New Tag".SentenceCase(), series.Metadata.Tags.Select(t => t.Title));
@ -1233,6 +1245,7 @@ public class SeriesServiceTests : AbstractDbTest
Assert.True(success); Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(s.Id);
Assert.NotNull(series);
Assert.NotNull(series.Metadata); Assert.NotNull(series.Metadata);
Assert.Empty(series.Metadata.Tags); Assert.Empty(series.Metadata.Tags);
} }
@ -1363,7 +1376,7 @@ public class SeriesServiceTests : AbstractDbTest
#endregion #endregion
#region SeriesRelation #region Series Relation
[Fact] [Fact]
public async Task UpdateRelatedSeries_ShouldAddAllRelations() public async Task UpdateRelatedSeries_ShouldAddAllRelations()
{ {
@ -1431,6 +1444,7 @@ public class SeriesServiceTests : AbstractDbTest
addRelationDto.Sequels.Add(2); addRelationDto.Sequels.Add(2);
await _seriesService.UpdateRelatedSeries(addRelationDto); await _seriesService.UpdateRelatedSeries(addRelationDto);
Assert.NotNull(series1); Assert.NotNull(series1);
Assert.NotNull(series2);
Assert.Equal(2, series1.Relations.Single(s => s.TargetSeriesId == 2).TargetSeriesId); Assert.Equal(2, series1.Relations.Single(s => s.TargetSeriesId == 2).TargetSeriesId);
Assert.Equal(1, series2.Relations.Single(s => s.TargetSeriesId == 1).TargetSeriesId); Assert.Equal(1, series2.Relations.Single(s => s.TargetSeriesId == 1).TargetSeriesId);
} }
@ -1473,8 +1487,9 @@ public class SeriesServiceTests : AbstractDbTest
// Remove relations // Remove relations
var removeRelationDto = CreateRelationsDto(series1); var removeRelationDto = CreateRelationsDto(series1);
await _seriesService.UpdateRelatedSeries(removeRelationDto); await _seriesService.UpdateRelatedSeries(removeRelationDto);
Assert.Empty(series1.Relations.Where(s => s.TargetSeriesId == 1)); Assert.NotNull(series1);
Assert.Empty(series1.Relations.Where(s => s.TargetSeriesId == 2)); Assert.DoesNotContain(series1.Relations, s => s.TargetSeriesId == 1);
Assert.DoesNotContain(series1.Relations, s => s.TargetSeriesId == 2);
} }
@ -1507,6 +1522,8 @@ public class SeriesServiceTests : AbstractDbTest
var addRelationDto = CreateRelationsDto(series1); var addRelationDto = CreateRelationsDto(series1);
addRelationDto.Adaptations.Add(2); addRelationDto.Adaptations.Add(2);
await _seriesService.UpdateRelatedSeries(addRelationDto); await _seriesService.UpdateRelatedSeries(addRelationDto);
Assert.NotNull(series1);
Assert.Equal(2, series1.Relations.Single(s => s.TargetSeriesId == 2).TargetSeriesId); Assert.Equal(2, series1.Relations.Single(s => s.TargetSeriesId == 2).TargetSeriesId);
_context.Series.Remove(await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(2)); _context.Series.Remove(await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(2));

View File

@ -1,7 +1,5 @@
using API.Extensions; using API.Helpers.Builders;
using API.Helpers.Builders;
using API.Services.Plus; using API.Services.Plus;
using API.Services.Tasks;
namespace API.Tests.Services; namespace API.Tests.Services;
using System.Collections.Generic; using System.Collections.Generic;
@ -16,7 +14,6 @@ using API.Entities.Enums;
using API.Helpers; using API.Helpers;
using API.Services; using API.Services;
using SignalR; using SignalR;
using Helpers;
using AutoMapper; using AutoMapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;

View File

@ -1,16 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.DTOs.Update; using API.DTOs.Update;
using API.Extensions;
using API.Services; using API.Services;
using API.Services.Tasks; using API.Services.Tasks;
using API.SignalR; using API.SignalR;
using Flurl.Http;
using Flurl.Http.Testing; using Flurl.Http.Testing;
using Kavita.Common.EnvironmentInfo; using Kavita.Common.EnvironmentInfo;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -11,10 +10,8 @@ using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
using API.Services; using API.Services;
using API.Services.Plus; using API.Services.Plus;
using API.Services.Tasks;
using API.Services.Tasks.Metadata; using API.Services.Tasks.Metadata;
using API.SignalR; using API.SignalR;
using API.Tests.Helpers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;

View File

@ -98,10 +98,10 @@
</PackageReference> </PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" /> <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.6.1" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.7.0" />
<PackageReference Include="System.IO.Abstractions" Version="22.0.12" /> <PackageReference Include="System.IO.Abstractions" Version="22.0.12" />
<PackageReference Include="System.Drawing.Common" Version="9.0.3" /> <PackageReference Include="System.Drawing.Common" Version="9.0.3" />
<PackageReference Include="VersOne.Epub" Version="3.3.2" /> <PackageReference Include="VersOne.Epub" Version="3.3.3" />
<PackageReference Include="YamlDotNet" Version="16.3.0" /> <PackageReference Include="YamlDotNet" Version="16.3.0" />
</ItemGroup> </ItemGroup>

View File

@ -8,6 +8,7 @@ using API.Data.Repositories;
using API.DTOs; using API.DTOs;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Services; using API.Services;

View File

@ -351,27 +351,6 @@ public class LibraryController : BaseApiController
return Ok(); return Ok();
} }
[Authorize(Policy = "RequireAdminRole")]
[HttpPost("analyze")]
public ActionResult Analyze(int libraryId)
{
_taskScheduler.AnalyzeFilesForLibrary(libraryId, true);
return Ok();
}
[Authorize(Policy = "RequireAdminRole")]
[HttpPost("analyze-multiple")]
public ActionResult AnalyzeMultiple(BulkActionDto dto)
{
foreach (var libraryId in dto.Ids)
{
_taskScheduler.AnalyzeFilesForLibrary(libraryId, dto.Force ?? false);
}
return Ok();
}
/// <summary> /// <summary>
/// Copy the library settings (adv tab + optional type) to a set of other libraries. /// Copy the library settings (adv tab + optional type) to a set of other libraries.
/// </summary> /// </summary>

View File

@ -9,7 +9,6 @@ using API.DTOs.ReadingLists;
using API.Extensions; using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Services; using API.Services;
using API.SignalR;
using Kavita.Common; using Kavita.Common;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -39,7 +38,7 @@ public class ReadingListController : BaseApiController
/// <param name="readingListId"></param> /// <param name="readingListId"></param>
/// <returns></returns> /// <returns></returns>
[HttpGet] [HttpGet]
public async Task<ActionResult<ReadingListDto?>> GetList(int readingListId) public async Task<ActionResult<ReadingListDto>> GetList(int readingListId)
{ {
var readingList = await _unitOfWork.ReadingListRepository.GetReadingListDtoByIdAsync(readingListId, User.GetUserId()); var readingList = await _unitOfWork.ReadingListRepository.GetReadingListDtoByIdAsync(readingListId, User.GetUserId());
if (readingList == null) if (readingList == null)
@ -268,7 +267,7 @@ public class ReadingListController : BaseApiController
var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId);
if (readingList == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "reading-list-doesnt-exist")); if (readingList == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "reading-list-doesnt-exist"));
var chapterIdsForSeries = var chapterIdsForSeries =
await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new [] {dto.SeriesId}); await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync([dto.SeriesId]);
// If there are adds, tell tracking this has been modified // If there are adds, tell tracking this has been modified
if (await _readingListService.AddChaptersToReadingList(dto.SeriesId, chapterIdsForSeries, readingList)) if (await _readingListService.AddChaptersToReadingList(dto.SeriesId, chapterIdsForSeries, readingList))

View File

@ -54,7 +54,7 @@ public class ScrobblingController : BaseApiController
} }
/// <summary> /// <summary>
/// Get the current user's MAL token & username /// Get the current user's MAL token and username
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpGet("mal-token")] [HttpGet("mal-token")]

View File

@ -2,6 +2,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace API.DTOs.Account; namespace API.DTOs.Account;
#nullable enable
public record UpdateUserDto public record UpdateUserDto
{ {

View File

@ -5,6 +5,7 @@ using API.Entities.Enums;
using API.Entities.Interfaces; using API.Entities.Interfaces;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
/// <summary> /// <summary>
/// A Chapter is the lowest grouping of a reading medium. A Chapter contains a set of MangaFiles which represents the underlying /// A Chapter is the lowest grouping of a reading medium. A Chapter contains a set of MangaFiles which represents the underlying
@ -188,8 +189,8 @@ public class ChapterDto : IHasReadTimeEstimate, IHasCoverImage
#endregion #endregion
public string CoverImage { get; set; } public string CoverImage { get; set; }
public string PrimaryColor { get; set; } public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape() public void ResetColorScape()
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.Collection; namespace API.DTOs.Collection;
#nullable enable
/// <summary> /// <summary>
/// Represents an Interest Stack from MAL /// Represents an Interest Stack from MAL

View File

@ -1,4 +1,5 @@
namespace API.DTOs; namespace API.DTOs;
#nullable enable
/// <summary> /// <summary>
/// A primary and secondary color /// A primary and secondary color

View File

@ -1,6 +1,7 @@
using API.DTOs.Scrobbling; using API.DTOs.Scrobbling;
namespace API.DTOs.KavitaPlus.ExternalMetadata; namespace API.DTOs.KavitaPlus.ExternalMetadata;
#nullable enable
/// <summary> /// <summary>
/// Used for matching and fetching metadata on a series /// Used for matching and fetching metadata on a series

View File

@ -2,6 +2,7 @@
using API.DTOs.Scrobbling; using API.DTOs.Scrobbling;
namespace API.DTOs.KavitaPlus.ExternalMetadata; namespace API.DTOs.KavitaPlus.ExternalMetadata;
#nullable enable
internal class MatchSeriesRequestDto internal class MatchSeriesRequestDto
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.License; namespace API.DTOs.KavitaPlus.License;
#nullable enable
public class EncryptLicenseDto public class EncryptLicenseDto
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.License; namespace API.DTOs.KavitaPlus.License;
#nullable enable
public class UpdateLicenseDto public class UpdateLicenseDto
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.Metadata; namespace API.DTOs.KavitaPlus.Metadata;
#nullable enable
public enum CharacterRole public enum CharacterRole
{ {

View File

@ -2,6 +2,7 @@
using API.Entities.Enums; using API.Entities.Enums;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
public class MangaFileDto public class MangaFileDto
{ {

View File

@ -1,4 +1,7 @@
using System.Runtime.Serialization;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
public class PersonDto public class PersonDto
{ {
@ -6,12 +9,12 @@ public class PersonDto
public required string Name { get; set; } public required string Name { get; set; }
public bool CoverImageLocked { get; set; } public bool CoverImageLocked { get; set; }
public string PrimaryColor { get; set; } public string? PrimaryColor { get; set; }
public string SecondaryColor { get; set; } public string? SecondaryColor { get; set; }
public string? CoverImage { get; set; } public string? CoverImage { get; set; }
public string Description { get; set; } public string? Description { get; set; }
/// <summary> /// <summary>
/// ASIN for person /// ASIN for person
/// </summary> /// </summary>

View File

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
public class UpdatePersonDto public class UpdatePersonDto
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.Reader; namespace API.DTOs.Reader;
#nullable enable
public class CreatePersonalToCDto public class CreatePersonalToCDto
{ {

View File

@ -2,6 +2,7 @@
using API.Services.Plus; using API.Services.Plus;
namespace API.DTOs.Scrobbling; namespace API.DTOs.Scrobbling;
#nullable enable
public record MediaRecommendationDto public record MediaRecommendationDto
{ {

View File

@ -1,4 +1,5 @@
namespace API.DTOs.Scrobbling; namespace API.DTOs.Scrobbling;
#nullable enable
/// <summary> /// <summary>
/// Represents information about a potential Series for Kavita+ /// Represents information about a potential Series for Kavita+

View File

@ -1,6 +1,7 @@
using System; using System;
namespace API.DTOs.Scrobbling; namespace API.DTOs.Scrobbling;
#nullable enable
public class ScrobbleEventDto public class ScrobbleEventDto
{ {

View File

@ -2,6 +2,7 @@
using API.DTOs.Recommendation; using API.DTOs.Recommendation;
namespace API.DTOs.SeriesDetail; namespace API.DTOs.SeriesDetail;
#nullable enable
/// <summary> /// <summary>
/// All the data from Kavita+ for Series Detail /// All the data from Kavita+ for Series Detail

View File

@ -79,8 +79,8 @@ public class SeriesDto : IHasReadTimeEstimate, IHasCoverImage
#endregion #endregion
public string? CoverImage { get; set; } public string? CoverImage { get; set; }
public string PrimaryColor { get; set; } public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape() public void ResetColorScape()
{ {

View File

@ -3,6 +3,7 @@ using API.Entities.Enums;
using API.Services; using API.Services;
namespace API.DTOs.Settings; namespace API.DTOs.Settings;
#nullable enable
public class ServerSettingDto public class ServerSettingDto
{ {

View File

@ -2,6 +2,7 @@
using API.Entities.Enums; using API.Entities.Enums;
namespace API.DTOs.SideNav; namespace API.DTOs.SideNav;
#nullable enable
public class SideNavStreamDto public class SideNavStreamDto
{ {

View File

@ -1,6 +1,7 @@
using API.Entities.Enums; using API.Entities.Enums;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
/// <summary> /// <summary>
/// Used on Person Profile page /// Used on Person Profile page

View File

@ -1,6 +1,7 @@
using System; using System;
namespace API.DTOs.Statistics; namespace API.DTOs.Statistics;
#nullable enable
/// <summary> /// <summary>
/// Represents a single User's reading event /// Represents a single User's reading event

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace API.DTOs.Statistics; namespace API.DTOs.Statistics;
#nullable enable
public class UserReadStatistics public class UserReadStatistics
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
namespace API.DTOs.Stats; namespace API.DTOs.Stats;
#nullable enable
/// <summary> /// <summary>
/// This is just for the Server tab on UI /// This is just for the Server tab on UI

View File

@ -1,4 +1,5 @@
namespace API.DTOs; namespace API.DTOs;
#nullable enable
/// <summary> /// <summary>
/// This is explicitly for Tachiyomi. Number field was removed in v0.8.0, but Tachiyomi needs it for the hacks. /// This is explicitly for Tachiyomi. Number field was removed in v0.8.0, but Tachiyomi needs it for the hacks.

View File

@ -1,4 +1,5 @@
namespace API.DTOs; namespace API.DTOs;
#nullable enable
public class UpdateSeriesDto public class UpdateSeriesDto
{ {

View File

@ -5,6 +5,7 @@ using API.Entities.Enums;
using API.Entities.Enums.UserPreferences; using API.Entities.Enums.UserPreferences;
namespace API.DTOs; namespace API.DTOs;
#nullable enable
public class UserPreferencesDto public class UserPreferencesDto
{ {

View File

@ -66,8 +66,8 @@ public class VolumeDto : IHasReadTimeEstimate, IHasCoverImage
public string CoverImage { get; set; } public string CoverImage { get; set; }
private bool CoverImageLocked { get; set; } private bool CoverImageLocked { get; set; }
public string PrimaryColor { get; set; } public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape() public void ResetColorScape()
{ {

View File

@ -12,6 +12,7 @@ using API.Entities.History;
using API.Entities.Interfaces; using API.Entities.Interfaces;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.MetadataMatching; using API.Entities.MetadataMatching;
using API.Entities.Person;
using API.Entities.Scrobble; using API.Entities.Scrobble;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;

View File

@ -16,6 +16,7 @@ using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable #nullable enable
public interface IAppUserProgressRepository public interface IAppUserProgressRepository
{ {
void Update(AppUserProgress userProgress); void Update(AppUserProgress userProgress);
@ -41,7 +42,7 @@ public interface IAppUserProgressRepository
Task UpdateAllProgressThatAreMoreThanChapterPages(); Task UpdateAllProgressThatAreMoreThanChapterPages();
Task<IList<FullProgressDto>> GetUserProgressForChapter(int chapterId, int userId = 0); Task<IList<FullProgressDto>> GetUserProgressForChapter(int chapterId, int userId = 0);
} }
#nullable disable
public class AppUserProgressRepository : IAppUserProgressRepository public class AppUserProgressRepository : IAppUserProgressRepository
{ {
private readonly DataContext _context; private readonly DataContext _context;

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using API.DTOs.CoverDb; using API.DTOs.CoverDb;
using API.Entities; using API.Entities;
using API.Entities.Person;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NamingConventions;

View File

@ -12,6 +12,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface IGenreRepository public interface IGenreRepository
{ {

View File

@ -9,6 +9,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface IMediaErrorRepository public interface IMediaErrorRepository
{ {

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using API.DTOs; using API.DTOs;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Extensions.QueryExtensions; using API.Extensions.QueryExtensions;
using API.Helpers; using API.Helpers;
@ -14,6 +15,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface IPersonRepository public interface IPersonRepository
{ {

View File

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
[Flags] [Flags]
public enum ReadingListIncludes public enum ReadingListIncludes

View File

@ -12,6 +12,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface IScrobbleRepository public interface IScrobbleRepository
{ {

View File

@ -39,6 +39,7 @@ using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
[Flags] [Flags]
public enum SeriesIncludes public enum SeriesIncludes

View File

@ -13,6 +13,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface ISettingsRepository public interface ISettingsRepository
{ {

View File

@ -8,6 +8,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface ISiteThemeRepository public interface ISiteThemeRepository
{ {

View File

@ -11,6 +11,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
public interface ITagRepository public interface ITagRepository
{ {

View File

@ -23,6 +23,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
[Flags] [Flags]
public enum AppUserIncludes public enum AppUserIncludes

View File

@ -15,6 +15,7 @@ using Kavita.Common;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories; namespace API.Data.Repositories;
#nullable enable
[Flags] [Flags]
public enum VolumeIncludes public enum VolumeIncludes

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Interfaces; using API.Entities.Interfaces;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;

View File

@ -12,7 +12,7 @@ public enum LibraryType
/// <summary> /// <summary>
/// Uses Comic regex for filename parsing /// Uses Comic regex for filename parsing
/// </summary> /// </summary>
[Description("Comic")] [Description("Comic (Legacy)")]
Comic = 1, Comic = 1,
/// <summary> /// <summary>
/// Uses Manga regex for filename parsing also uses epub metadata /// Uses Manga regex for filename parsing also uses epub metadata
@ -30,8 +30,8 @@ public enum LibraryType
[Description("Light Novel")] [Description("Light Novel")]
LightNovel = 4, LightNovel = 4,
/// <summary> /// <summary>
/// Uses Comic regex for filename parsing, uses Comic Vine type of Parsing. Will replace Comic type in future /// Uses Comic regex for filename parsing, uses Comic Vine type of Parsing
/// </summary> /// </summary>
[Description("Comic (Comic Vine)")] [Description("Comic")]
ComicVine = 5, ComicVine = 5,
} }

View File

@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Interfaces; using API.Entities.Interfaces;
using API.Entities.Person;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Entities.Metadata; namespace API.Entities.Metadata;

View File

@ -1,6 +1,6 @@
using API.Entities.Enums; using API.Entities.Enums;
namespace API.Entities; namespace API.Entities.Person;
public class ChapterPeople public class ChapterPeople
{ {

View File

@ -1,10 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using API.Entities.Enums;
using API.Entities.Interfaces; using API.Entities.Interfaces;
using API.Entities.Metadata;
using API.Services.Plus;
namespace API.Entities; namespace API.Entities.Person;
public class Person : IHasCoverImage public class Person : IHasCoverImage
{ {

View File

@ -1,8 +1,7 @@
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Services.Plus;
namespace API.Entities; namespace API.Entities.Person;
public class SeriesMetadataPeople public class SeriesMetadataPeople
{ {

View File

@ -4,6 +4,7 @@ using Kavita.Common;
using Kavita.Common.EnvironmentInfo; using Kavita.Common.EnvironmentInfo;
namespace API.Extensions; namespace API.Extensions;
#nullable enable
public static class FlurlExtensions public static class FlurlExtensions
{ {

View File

@ -4,7 +4,7 @@ using API.Data.Misc;
using API.Data.Repositories; using API.Data.Repositories;
using API.Entities; using API.Entities;
using API.Entities.Metadata; using API.Entities.Metadata;
using AutoMapper.QueryableExtensions; using API.Entities.Person;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Extensions.QueryExtensions.Filtering; namespace API.Extensions.QueryExtensions.Filtering;

View File

@ -3,6 +3,7 @@ using System.Linq;
using API.Data.Misc; using API.Data.Misc;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Person;
namespace API.Extensions.QueryExtensions; namespace API.Extensions.QueryExtensions;
#nullable enable #nullable enable

View File

@ -30,6 +30,7 @@ using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.MetadataMatching; using API.Entities.MetadataMatching;
using API.Entities.Person;
using API.Entities.Scrobble; using API.Entities.Scrobble;
using API.Extensions.QueryExtensions.Filtering; using API.Extensions.QueryExtensions.Filtering;
using API.Helpers.Converters; using API.Helpers.Converters;

View File

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO; using System.IO;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Person;
using API.Services.Tasks.Scanner.Parser; using API.Services.Tasks.Scanner.Parser;
namespace API.Helpers.Builders; namespace API.Helpers.Builders;

View File

@ -2,6 +2,7 @@
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
namespace API.Helpers.Builders; namespace API.Helpers.Builders;

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.Person;
namespace API.Helpers.Builders; namespace API.Helpers.Builders;

View File

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
@ -7,6 +6,7 @@ using API.DTOs;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Helpers.Builders; using API.Helpers.Builders;

View File

@ -56,9 +56,6 @@ public class Program
Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty); Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty);
} }
Configuration.KavitaPlusApiUrl = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development
? "http://localhost:5020" : "https://plus.kavitareader.com";
try try
{ {
var host = CreateHostBuilder(args).Build(); var host = CreateHostBuilder(args).Build();

View File

@ -73,12 +73,27 @@ public class BookService : IBookService
private const string BookApiUrl = "book-resources?file="; private const string BookApiUrl = "book-resources?file=";
private readonly PdfComicInfoExtractor _pdfComicInfoExtractor; private readonly PdfComicInfoExtractor _pdfComicInfoExtractor;
/// <summary>
/// Setup the most lenient book parsing options possible as people have some really bad epubs
/// </summary>
public static readonly EpubReaderOptions BookReaderOptions = new() public static readonly EpubReaderOptions BookReaderOptions = new()
{ {
PackageReaderOptions = new PackageReaderOptions PackageReaderOptions = new PackageReaderOptions
{ {
IgnoreMissingToc = true, IgnoreMissingToc = true,
SkipInvalidManifestItems = true SkipInvalidManifestItems = true,
},
Epub2NcxReaderOptions = new Epub2NcxReaderOptions
{
IgnoreMissingContentForNavigationPoints = true
},
SpineReaderOptions = new SpineReaderOptions
{
IgnoreMissingManifestItems = true
},
BookCoverReaderOptions = new BookCoverReaderOptions
{
Epub2MetadataIgnoreMissingManifestItem = true
} }
}; };

View File

@ -11,6 +11,7 @@ using API.DTOs.SeriesDetail;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Entities.Metadata; using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions; using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Helpers.Builders; using API.Helpers.Builders;
@ -73,7 +74,7 @@ public class SeriesService : ISeriesService
} }
/// <summary> /// <summary>
/// Returns the first chapter for a series to extract metadata from (ie Summary, etc) /// Returns the first chapter for a series to extract metadata from (ie Summary, etc.)
/// </summary> /// </summary>
/// <param name="series">The full series with all volumes and chapters on it</param> /// <param name="series">The full series with all volumes and chapters on it</param>
/// <returns></returns> /// <returns></returns>
@ -324,7 +325,7 @@ public class SeriesService : ISeriesService
await _unitOfWork.CommitAsync(); await _unitOfWork.CommitAsync();
// Trigger code to cleanup tags, collections, people, etc // Trigger code to clean up tags, collections, people, etc
try try
{ {
await _taskScheduler.CleanupDbEntries(); await _taskScheduler.CleanupDbEntries();
@ -915,19 +916,19 @@ public class SeriesService : ISeriesService
// Calculate the time differences between consecutive chapters // Calculate the time differences between consecutive chapters
var timeDifferences = new List<TimeSpan>(); var timeDifferences = new List<TimeSpan>();
DateTime? previousChapterTime = null; DateTime? previousChapterTime = null;
foreach (var chapter in chapters) foreach (var chapterCreatedUtc in chapters.Select(c => c.CreatedUtc))
{ {
if (previousChapterTime.HasValue && (chapter.CreatedUtc - previousChapterTime.Value) <= TimeSpan.FromHours(1)) if (previousChapterTime.HasValue && (chapterCreatedUtc - previousChapterTime.Value) <= TimeSpan.FromHours(1))
{ {
continue; // Skip this chapter if it's within an hour of the previous one continue; // Skip this chapter if it's within an hour of the previous one
} }
if ((chapter.CreatedUtc - previousChapterTime ?? TimeSpan.Zero) != TimeSpan.Zero) if ((chapterCreatedUtc - previousChapterTime ?? TimeSpan.Zero) != TimeSpan.Zero)
{ {
timeDifferences.Add(chapter.CreatedUtc - previousChapterTime ?? TimeSpan.Zero); timeDifferences.Add(chapterCreatedUtc - previousChapterTime ?? TimeSpan.Zero);
} }
previousChapterTime = chapter.CreatedUtc; previousChapterTime = chapterCreatedUtc;
} }
if (timeDifferences.Count < minimumTimeDeltas) if (timeDifferences.Count < minimumTimeDeltas)

Some files were not shown because too many files have changed in this diff Show More