Float-based Volumes (#2659)

This commit is contained in:
Joe Milazzo 2024-01-28 11:37:38 -06:00 committed by GitHub
parent 6fdc9228df
commit f6af6d66be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 3106 additions and 184 deletions

View file

@ -0,0 +1,38 @@
using System;
using System.Threading.Tasks;
using API.Entities.Enums;
using API.Services.Tasks.Scanner.Parser;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace API.Data.ManualMigrations;
/// <summary>
/// Introduced in v0.7.14, this migrates the existing Volume Name -> Volume Min/Max Number
/// </summary>
public static class MigrateVolumeNumber
{
public static async Task Migrate(IUnitOfWork unitOfWork, DataContext dataContext, ILogger<Program> logger)
{
logger.LogCritical(
"Running MigrateVolumeNumber migration - Please be patient, this may take some time. This is not an error");
if (await dataContext.Volume.AnyAsync(v => v.MaxNumber > 0))
{
logger.LogCritical(
"Running MigrateVolumeNumber migration - Completed. This is not an error");
return;
}
// Get all volumes
foreach (var volume in dataContext.Volume)
{
volume.MinNumber = Parser.MinNumberFromRange(volume.Name);
volume.MaxNumber = Parser.MaxNumberFromRange(volume.Name);
}
await dataContext.SaveChangesAsync();
logger.LogCritical(
"Running MigrateVolumeNumber migration - Completed. This is not an error");
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace API.Data.Migrations
{
/// <inheritdoc />
public partial class VolumeMinMaxNumbers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<float>(
name: "MaxNumber",
table: "Volume",
type: "REAL",
nullable: false,
defaultValue: 0f);
migrationBuilder.AddColumn<float>(
name: "MinNumber",
table: "Volume",
type: "REAL",
nullable: false,
defaultValue: 0f);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaxNumber",
table: "Volume");
migrationBuilder.DropColumn(
name: "MinNumber",
table: "Volume");
}
}
}

View file

@ -1781,9 +1781,15 @@ namespace API.Data.Migrations
b.Property<int>("MaxHoursToRead")
.HasColumnType("INTEGER");
b.Property<float>("MaxNumber")
.HasColumnType("REAL");
b.Property<int>("MinHoursToRead")
.HasColumnType("INTEGER");
b.Property<float>("MinNumber")
.HasColumnType("REAL");
b.Property<string>("Name")
.HasColumnType("TEXT");

View file

@ -18,6 +18,6 @@ public class RecentlyAddedSeries
public string? ChapterRange { get; init; }
public string? ChapterTitle { get; init; }
public bool IsSpecial { get; init; }
public int VolumeNumber { get; init; }
public float VolumeNumber { get; init; }
public AgeRating AgeRating { get; init; }
}

View file

@ -32,7 +32,7 @@ public interface IAppUserProgressRepository
Task<ProgressDto?> GetUserProgressDtoAsync(int chapterId, int userId);
Task<bool> AnyUserProgressForSeriesAsync(int seriesId, int userId);
Task<int> GetHighestFullyReadChapterForSeries(int seriesId, int userId);
Task<int> GetHighestFullyReadVolumeForSeries(int seriesId, int userId);
Task<float> GetHighestFullyReadVolumeForSeries(int seriesId, int userId);
Task<DateTime?> GetLatestProgressForSeries(int seriesId, int userId);
Task<DateTime?> GetFirstProgressForSeries(int seriesId, int userId);
Task UpdateAllProgressThatAreMoreThanChapterPages();
@ -172,14 +172,14 @@ public class AppUserProgressRepository : IAppUserProgressRepository
return list.Count == 0 ? 0 : list.DefaultIfEmpty().Where(d => d != null).Max(d => (int) Math.Floor(Parser.MaxNumberFromRange(d)));
}
public async Task<int> GetHighestFullyReadVolumeForSeries(int seriesId, int userId)
public async Task<float> GetHighestFullyReadVolumeForSeries(int seriesId, int userId)
{
var list = await _context.AppUserProgresses
.Join(_context.Chapter, appUserProgresses => appUserProgresses.ChapterId, chapter => chapter.Id,
(appUserProgresses, chapter) => new {appUserProgresses, chapter})
.Where(p => p.appUserProgresses.SeriesId == seriesId && p.appUserProgresses.AppUserId == userId &&
p.appUserProgresses.PagesRead >= p.chapter.Pages)
.Select(p => p.chapter.Volume.Number)
.Select(p => p.chapter.Volume.MaxNumber)
.ToListAsync();
return list.Count == 0 ? 0 : list.DefaultIfEmpty().Max();
}

View file

@ -1836,7 +1836,7 @@ public class SeriesRepository : ISeriesRepository
ChapterNumber = c.Number,
ChapterRange = c.Range,
IsSpecial = c.IsSpecial,
VolumeNumber = c.Volume.Number,
VolumeNumber = c.Volume.MinNumber,
ChapterTitle = c.Title,
AgeRating = c.Volume.Series.Metadata.AgeRating
})

View file

@ -152,7 +152,7 @@ public class VolumeRepository : IVolumeRepository
.Include(vol => vol.Chapters)
.ThenInclude(c => c.Files)
.AsSplitQuery()
.OrderBy(vol => vol.Number)
.OrderBy(vol => vol.MinNumber)
.ToListAsync();
}
@ -185,7 +185,7 @@ public class VolumeRepository : IVolumeRepository
.ThenInclude(c => c.People)
.Include(vol => vol.Chapters)
.ThenInclude(c => c.Tags)
.OrderBy(volume => volume.Number)
.OrderBy(volume => volume.MinNumber)
.ProjectTo<VolumeDto>(_mapper.ConfigurationProvider)
.AsNoTracking()
.AsSplitQuery()
@ -215,7 +215,7 @@ public class VolumeRepository : IVolumeRepository
private static void SortSpecialChapters(IEnumerable<VolumeDto> volumes)
{
foreach (var v in volumes.Where(vDto => vDto.Number == 0))
foreach (var v in volumes.Where(vDto => vDto.MinNumber == 0))
{
v.Chapters = v.Chapters.OrderByNatural(x => x.Range).ToList();
}