Float-based Volumes (#2659)
This commit is contained in:
parent
6fdc9228df
commit
f6af6d66be
44 changed files with 3106 additions and 184 deletions
38
API/Data/ManualMigrations/MigrateVolumeNumber.cs
Normal file
38
API/Data/ManualMigrations/MigrateVolumeNumber.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
2793
API/Data/Migrations/20240128153433_VolumeMinMaxNumbers.Designer.cs
generated
Normal file
2793
API/Data/Migrations/20240128153433_VolumeMinMaxNumbers.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
40
API/Data/Migrations/20240128153433_VolumeMinMaxNumbers.cs
Normal file
40
API/Data/Migrations/20240128153433_VolumeMinMaxNumbers.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue