mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
Scanner Bugfixes (#2818)
This commit is contained in:
parent
829a610579
commit
93a8883fe4
6
.github/workflows/build-and-test.yml
vendored
6
.github/workflows/build-and-test.yml
vendored
@ -10,12 +10,12 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
@ -26,7 +26,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: csproj
|
||||
path: Kavita.Common/Kavita.Common.csproj
|
||||
|
28
.github/workflows/canary-workflow.yml
vendored
28
.github/workflows/canary-workflow.yml
vendored
@ -12,11 +12,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: csproj
|
||||
path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -26,12 +26,12 @@ jobs:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
@ -59,14 +59,14 @@ jobs:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: canary
|
||||
|
||||
- name: NodeJS to Compile WebUI
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18.13.x'
|
||||
node-version: 20
|
||||
- run: |
|
||||
cd UI/Web || exit
|
||||
echo 'Installing web dependencies'
|
||||
@ -81,7 +81,7 @@ jobs:
|
||||
cd ../ || exit
|
||||
|
||||
- name: Get csproj Version
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v1
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v2
|
||||
id: get-version
|
||||
with:
|
||||
proj-path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
run: echo "${{steps.get-version.outputs.assembly-version}}"
|
||||
|
||||
- name: Compile dotnet app
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
@ -106,28 +106,28 @@ jobs:
|
||||
- run: ./monorepo-build.sh
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
|
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Swashbuckle CLI
|
||||
shell: bash
|
||||
|
28
.github/workflows/develop-workflow.yml
vendored
28
.github/workflows/develop-workflow.yml
vendored
@ -21,11 +21,11 @@ jobs:
|
||||
if: github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: csproj
|
||||
path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -36,12 +36,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
@ -89,14 +89,14 @@ jobs:
|
||||
echo "BODY=$body" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: develop
|
||||
|
||||
- name: NodeJS to Compile WebUI
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18.13.x'
|
||||
node-version: 20
|
||||
- run: |
|
||||
cd UI/Web || exit
|
||||
echo 'Installing web dependencies'
|
||||
@ -111,7 +111,7 @@ jobs:
|
||||
cd ../ || exit
|
||||
|
||||
- name: Get csproj Version
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v1
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v2
|
||||
id: get-version
|
||||
with:
|
||||
proj-path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -126,7 +126,7 @@ jobs:
|
||||
run: echo "${{steps.get-version.outputs.assembly-version}}"
|
||||
|
||||
- name: Compile dotnet app
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
@ -136,28 +136,28 @@ jobs:
|
||||
- run: ./monorepo-build.sh
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
|
26
.github/workflows/release-workflow.yml
vendored
26
.github/workflows/release-workflow.yml
vendored
@ -30,11 +30,11 @@ jobs:
|
||||
if: github.event.pull_request.merged == true && contains(github.head_ref, 'release')
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: csproj
|
||||
path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -77,14 +77,14 @@ jobs:
|
||||
echo "BODY=$body" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: develop
|
||||
|
||||
- name: NodeJS to Compile WebUI
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18.13.x'
|
||||
node-version: 20
|
||||
- run: |
|
||||
|
||||
cd UI/Web || exit
|
||||
@ -100,7 +100,7 @@ jobs:
|
||||
cd ../ || exit
|
||||
|
||||
- name: Get csproj Version
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v1
|
||||
uses: kzrnm/get-net-sdk-project-versions-action@v2
|
||||
id: get-version
|
||||
with:
|
||||
proj-path: Kavita.Common/Kavita.Common.csproj
|
||||
@ -117,7 +117,7 @@ jobs:
|
||||
id: parse-version
|
||||
|
||||
- name: Compile dotnet app
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Install Swashbuckle CLI
|
||||
@ -126,28 +126,28 @@ jobs:
|
||||
- run: ./monorepo-build.sh
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push stable
|
||||
id: docker_build_stable
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
@ -156,7 +156,7 @@ jobs:
|
||||
|
||||
- name: Build and push nightly
|
||||
id: docker_build_nightly
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
|
@ -206,6 +206,7 @@ public class MangaParsingTests
|
||||
[InlineData("test 2 years 1권", "test 2 years")]
|
||||
[InlineData("test 2 years 1화", "test 2 years")]
|
||||
[InlineData("Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.30 Omake", "Nagasarete Airantou")]
|
||||
[InlineData("Cynthia The Mission - c000 - c006 (v06)", "Cynthia The Mission")]
|
||||
public void ParseSeriesTest(string filename, string expected)
|
||||
{
|
||||
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
|
||||
|
@ -66,7 +66,7 @@
|
||||
<PackageReference Include="Flurl" Version="3.0.7" />
|
||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||
<PackageReference Include="Hangfire" Version="1.8.11" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="0.8.0" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="0.8.1" />
|
||||
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
|
||||
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.4.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.59" />
|
||||
|
@ -113,7 +113,35 @@ public static class MigrateLooseLeafChapters
|
||||
//UpdateCoverImage(directoryService, logger, chapter, extension, newVolume);
|
||||
}
|
||||
|
||||
// Update the progress table with the new VolumeId
|
||||
|
||||
var oldVolumeBookmarks = await dataContext.AppUserBookmark
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Bookmarks from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumeBookmarks.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var bookmark in oldVolumeBookmarks)
|
||||
{
|
||||
bookmark.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
|
||||
var oldVolumePersonalToC = await dataContext.AppUserTableOfContent
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Personal ToC from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumePersonalToC.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var pToc in oldVolumePersonalToC)
|
||||
{
|
||||
pToc.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
var oldVolumeReadingListItems = await dataContext.ReadingListItem
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Personal ToC from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumeReadingListItems.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var readingListItem in oldVolumeReadingListItems)
|
||||
{
|
||||
readingListItem.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
|
||||
await dataContext.SaveChangesAsync();
|
||||
}
|
||||
|
@ -129,6 +129,35 @@ public static class MigrateMixedSpecials
|
||||
|
||||
//UpdateCoverImage(directoryService, logger, specialChapter, extension, newVolume);
|
||||
}
|
||||
|
||||
var oldVolumeBookmarks = await dataContext.AppUserBookmark
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Bookmarks from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumeBookmarks.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var bookmark in oldVolumeBookmarks)
|
||||
{
|
||||
bookmark.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
|
||||
var oldVolumePersonalToC = await dataContext.AppUserTableOfContent
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Personal ToC from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumePersonalToC.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var pToc in oldVolumePersonalToC)
|
||||
{
|
||||
pToc.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
var oldVolumeReadingListItems = await dataContext.ReadingListItem
|
||||
.Where(p => p.VolumeId == distinctVolume.Volume.Id).ToListAsync();
|
||||
logger.LogInformation("Moving {Count} existing Personal ToC from Volume Id {OldVolumeId} to New Volume {NewVolumeId}",
|
||||
oldVolumeReadingListItems.Count, distinctVolume.Volume.Id, newVolume.Id);
|
||||
foreach (var readingListItem in oldVolumeReadingListItems)
|
||||
{
|
||||
readingListItem.VolumeId = newVolume.Id;
|
||||
}
|
||||
|
||||
await dataContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ namespace API.Entities;
|
||||
/// <summary>
|
||||
/// Represents the progress a single user has on a given Chapter.
|
||||
/// </summary>
|
||||
public class AppUserProgress : IEntityDate
|
||||
public class AppUserProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of Entity
|
||||
@ -59,4 +59,10 @@ public class AppUserProgress : IEntityDate
|
||||
/// User this progress belongs to
|
||||
/// </summary>
|
||||
public int AppUserId { get; set; }
|
||||
|
||||
public void MarkModified()
|
||||
{
|
||||
LastModified = DateTime.Now;
|
||||
LastModifiedUtc = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public static class ChapterListExtensions
|
||||
{
|
||||
var normalizedPath = Parser.NormalizePath(info.FullFilePath);
|
||||
var specialTreatment = info.IsSpecialInfo();
|
||||
return specialTreatment
|
||||
return specialTreatment
|
||||
? chapters.FirstOrDefault(c => c.Range == Parser.RemoveExtensionIfSupported(info.Filename) || c.Files.Select(f => Parser.NormalizePath(f.FilePath)).Contains(normalizedPath))
|
||||
: chapters.FirstOrDefault(c => c.Range == info.Chapters);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public static class SeriesSort
|
||||
SortField.TimeToRead => query.DoOrderBy(s => s.AvgHoursToRead, sortOptions),
|
||||
SortField.ReleaseYear => query.DoOrderBy(s => s.Metadata.ReleaseYear, sortOptions),
|
||||
SortField.ReadProgress => query.DoOrderBy(s => s.Progress.Where(p => p.SeriesId == s.Id && p.AppUserId == userId)
|
||||
.Select(p => p.LastModified)
|
||||
.Select(p => p.LastModified) // TODO: Migrate this to UTC
|
||||
.Max(), sortOptions),
|
||||
SortField.AverageRating => query.DoOrderBy(s => s.ExternalSeriesMetadata.ExternalRatings
|
||||
.Where(p => p.SeriesId == s.Id).Average(p => p.AverageScore), sortOptions),
|
||||
|
@ -134,7 +134,11 @@ public class ReaderService : IReaderService
|
||||
VolumeId = chapter.VolumeId,
|
||||
SeriesId = seriesId,
|
||||
ChapterId = chapter.Id,
|
||||
LibraryId = series.LibraryId
|
||||
LibraryId = series.LibraryId,
|
||||
Created = DateTime.Now,
|
||||
CreatedUtc = DateTime.UtcNow,
|
||||
LastModified = DateTime.Now,
|
||||
LastModifiedUtc = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -144,6 +148,8 @@ public class ReaderService : IReaderService
|
||||
userProgress.VolumeId = chapter.VolumeId;
|
||||
}
|
||||
|
||||
userProgress?.MarkModified();
|
||||
|
||||
await _eventHub.SendMessageAsync(MessageFactory.UserProgressUpdate,
|
||||
MessageFactory.UserProgressUpdateEvent(user.Id, user.UserName!, seriesId, chapter.VolumeId, chapter.Id, chapter.Pages));
|
||||
|
||||
@ -177,6 +183,7 @@ public class ReaderService : IReaderService
|
||||
userProgress.PagesRead = 0;
|
||||
userProgress.SeriesId = seriesId;
|
||||
userProgress.VolumeId = chapter.VolumeId;
|
||||
userProgress.MarkModified();
|
||||
|
||||
await _eventHub.SendMessageAsync(MessageFactory.UserProgressUpdate,
|
||||
MessageFactory.UserProgressUpdateEvent(user.Id, user.UserName!, userProgress.SeriesId, userProgress.VolumeId, userProgress.ChapterId, 0));
|
||||
@ -266,7 +273,11 @@ public class ReaderService : IReaderService
|
||||
SeriesId = progressDto.SeriesId,
|
||||
ChapterId = progressDto.ChapterId,
|
||||
LibraryId = progressDto.LibraryId,
|
||||
BookScrollId = progressDto.BookScrollId
|
||||
BookScrollId = progressDto.BookScrollId,
|
||||
Created = DateTime.Now,
|
||||
CreatedUtc = DateTime.UtcNow,
|
||||
LastModified = DateTime.Now,
|
||||
LastModifiedUtc = DateTime.UtcNow
|
||||
});
|
||||
_unitOfWork.UserRepository.Update(userWithProgress);
|
||||
}
|
||||
@ -280,6 +291,8 @@ public class ReaderService : IReaderService
|
||||
_unitOfWork.AppUserProgressRepository.Update(userProgress);
|
||||
}
|
||||
|
||||
userProgress?.MarkModified();
|
||||
|
||||
if (!_unitOfWork.HasChanges() || await _unitOfWork.CommitAsync())
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
|
@ -31,7 +31,7 @@ public class BookParser(IDirectoryService directoryService, IBookService bookSer
|
||||
{
|
||||
var info2 = basicParser.Parse(filePath, rootPath, libraryRoot, LibraryType.Book, comicInfo);
|
||||
info.Merge(info2);
|
||||
if (type == LibraryType.LightNovel && hasVolumeInSeries && info2 != null && Parser.ParseVolume(info2.Series)
|
||||
if (hasVolumeInSeries && info2 != null && Parser.ParseVolume(info2.Series)
|
||||
.Equals(Parser.LooseLeafVolume))
|
||||
{
|
||||
// Override the Series name so it groups appropriately
|
||||
|
@ -107,11 +107,11 @@ public abstract class DefaultParser(IDirectoryService directoryService) : IDefau
|
||||
{
|
||||
info.Volumes = info.ComicInfo.Volume;
|
||||
}
|
||||
if (string.IsNullOrEmpty(info.Series) && !string.IsNullOrEmpty(info.ComicInfo.Series))
|
||||
if (!string.IsNullOrEmpty(info.ComicInfo.Series))
|
||||
{
|
||||
info.Series = info.ComicInfo.Series.Trim();
|
||||
}
|
||||
if (string.IsNullOrEmpty(info.LocalizedSeries) && !string.IsNullOrEmpty(info.ComicInfo.LocalizedSeries))
|
||||
if (!string.IsNullOrEmpty(info.ComicInfo.LocalizedSeries))
|
||||
{
|
||||
info.LocalizedSeries = info.ComicInfo.LocalizedSeries.Trim();
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ public static class Parser
|
||||
RegexTimeout),
|
||||
// Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA], Black Bullet - v4 c17 [batoto]
|
||||
new Regex(
|
||||
@"(?<Series>.*)( - )(?:v|vo|c|chapters)\d",
|
||||
@"(?<Series>.+?)( - )(?:v|vo|c|chapters)\d",
|
||||
MatchOptions, RegexTimeout),
|
||||
// Kedouin Makoto - Corpse Party Musume, Chapter 19 [Dametrans].zip
|
||||
new Regex(
|
||||
|
@ -22,6 +22,11 @@ public class PdfParser(IDirectoryService directoryService) : DefaultParser(direc
|
||||
: Parser.ParseChapter(fileName)
|
||||
};
|
||||
|
||||
if (type == LibraryType.Book)
|
||||
{
|
||||
ret.Chapters = Parser.DefaultChapter;
|
||||
}
|
||||
|
||||
ret.Series = type == LibraryType.Comic ? Parser.ParseComicSeries(fileName) : Parser.ParseSeries(fileName);
|
||||
ret.Volumes = type == LibraryType.Comic ? Parser.ParseComicVolume(fileName) : Parser.ParseVolume(fileName);
|
||||
|
||||
|
@ -14,6 +14,6 @@ export class FilterPipe implements PipeTransform {
|
||||
const ret = items.filter(item => callback(item));
|
||||
if (ret.length === items.length) return items; // This will prevent a re-render
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -339,6 +339,9 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||
|
||||
get ShowStorylineTab() {
|
||||
if (this.libraryType === LibraryType.ComicVine) return false;
|
||||
// Edge case for bad pdf parse
|
||||
if (this.libraryType === LibraryType.Book && (this.volumes.length === 0 && this.chapters.length === 0 && this.storyChapters.length > 0)) return true;
|
||||
|
||||
return (this.libraryType !== LibraryType.Book && this.libraryType !== LibraryType.LightNovel && this.libraryType !== LibraryType.Comic)
|
||||
&& (this.volumes.length > 0 || this.chapters.length > 0);
|
||||
}
|
||||
@ -727,7 +730,12 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||
// Book libraries only have Volumes or Specials enabled
|
||||
if (this.libraryType === LibraryType.Book || this.libraryType === LibraryType.LightNovel) {
|
||||
if (this.volumes.length === 0) {
|
||||
this.activeTabId = TabID.Specials;
|
||||
if (this.specials.length === 0 && this.storyChapters.length > 0) {
|
||||
// NOTE: This is an edge case caused by bad parsing of pdf files. Once the new pdf parser is in place, this should be removed
|
||||
this.activeTabId = TabID.Storyline;
|
||||
} else {
|
||||
this.activeTabId = TabID.Specials;
|
||||
}
|
||||
} else {
|
||||
this.activeTabId = TabID.Volumes;
|
||||
}
|
||||
|
@ -258,7 +258,10 @@ export class LibrarySettingsModalComponent implements OnInit {
|
||||
|
||||
forceScan() {
|
||||
this.libraryService.scan(this.library!.id, true)
|
||||
.subscribe(() => this.toastr.info(translate('toasts.forced-scan-queued', {name: this.library!.name})));
|
||||
.subscribe(() => {
|
||||
this.toastr.info(translate('toasts.forced-scan-queued', {name: this.library!.name}));
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
||||
async save() {
|
||||
|
@ -1,37 +1,23 @@
|
||||
<ng-container *transloco="let t; read: 'kavitaplus-metadata-breakdown-stats'">
|
||||
<div class="dashboard-card-content">
|
||||
<h4>{{t('title')}}</h4>
|
||||
<p>{{t('description')}}</p>
|
||||
|
||||
@if(breakdown) {
|
||||
@if(breakdown.totalSeries === 0 || breakdown.seriesCompleted === 0) {
|
||||
<div>{{t('no-data')}}</div>
|
||||
}
|
||||
@if (percentDone >= 1) {
|
||||
<p>{{t('complete') }}</p>
|
||||
} @else {
|
||||
<p>{{t('total-series-progress-label', {percent: percentDone * 100 | percent}) }}</p>
|
||||
|
||||
<div class="day-breakdown-chart">
|
||||
<table class="charts-css pie show-labels">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<th scope="row">{{t('completed-series-label')}}</th>
|
||||
<td class="completed" style="--start: 0; --end: ' + {{ completedEnd }}">
|
||||
<span class="data">{{ breakdown.seriesCompleted }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th scope="row">{{t('errored-series-label')}}</th>
|
||||
<td class="error" style="--start: ' + {{ errorStart }}; --end: {{ errorEnd }}'">
|
||||
<span class="data">{{ breakdown.erroredSeries }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<ngb-progressbar-stacked>
|
||||
<ngb-progressbar type="danger" [value]="errorPercent" [ngbTooltip]="t('errored-series-label') + ' ' + breakdown.erroredSeries"></ngb-progressbar>
|
||||
<ngb-progressbar type="success" [value]="completedPercent" [ngbTooltip]="t('completed-series-label') + ' ' + breakdown.seriesCompleted"></ngb-progressbar>
|
||||
</ngb-progressbar-stacked>
|
||||
@if (breakdown.seriesCompleted >= breakdown.totalSeries) {
|
||||
<p>{{t('complete') }}
|
||||
@if (breakdown.erroredSeries > 0) {
|
||||
{{t('errored-series-label') }} {{breakdown.erroredSeries}}
|
||||
}
|
||||
</p>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
@ -3,13 +3,17 @@ import {StatisticsService} from "../../../_services/statistics.service";
|
||||
import {KavitaPlusMetadataBreakdown} from "../../_models/kavitaplus-metadata-breakdown";
|
||||
import {TranslocoDirective} from "@ngneat/transloco";
|
||||
import {PercentPipe} from "@angular/common";
|
||||
import {NgbProgressbar, NgbProgressbarStacked, NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
|
||||
|
||||
@Component({
|
||||
selector: 'app-kavitaplus-metadata-breakdown-stats',
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslocoDirective,
|
||||
PercentPipe
|
||||
PercentPipe,
|
||||
NgbProgressbarStacked,
|
||||
NgbProgressbar,
|
||||
NgbTooltip
|
||||
],
|
||||
templateUrl: './kavitaplus-metadata-breakdown-stats.component.html',
|
||||
styleUrl: './kavitaplus-metadata-breakdown-stats.component.scss',
|
||||
@ -20,20 +24,18 @@ export class KavitaplusMetadataBreakdownStatsComponent {
|
||||
private readonly statsService = inject(StatisticsService);
|
||||
|
||||
breakdown: KavitaPlusMetadataBreakdown | undefined;
|
||||
completedStart!: number;
|
||||
completedEnd!: number;
|
||||
errorStart!: number;
|
||||
errorEnd!: number;
|
||||
percentDone!: number;
|
||||
|
||||
errorPercent!: number;
|
||||
completedPercent!: number;
|
||||
|
||||
|
||||
constructor() {
|
||||
this.statsService.getKavitaPlusMetadataBreakdown().subscribe(res => {
|
||||
this.breakdown = res;
|
||||
this.completedStart = 0;
|
||||
this.completedEnd = ((res.seriesCompleted - res.erroredSeries) / res.totalSeries);
|
||||
this.errorStart = this.completedEnd;
|
||||
this.errorEnd = Math.max(1, ((res.seriesCompleted) / res.totalSeries));
|
||||
this.percentDone = res.seriesCompleted / res.totalSeries;
|
||||
|
||||
this.errorPercent = (res.erroredSeries / res.totalSeries) * 100;
|
||||
this.completedPercent = ((res.seriesCompleted - res.erroredSeries) / res.totalSeries) * 100;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
@ -579,7 +579,7 @@
|
||||
"published-label": "Published: ",
|
||||
"available": "Available",
|
||||
"description": "If you do not see an {{installed}}",
|
||||
"description-continued": "tag, you are on a nightly release. Only major versions will show as available."
|
||||
"description-continued": "tag, you are on a nightly release. Only major versions will show as available. A nightly tag will show when on a nightly from that stable."
|
||||
},
|
||||
|
||||
"invite-user": {
|
||||
@ -1786,10 +1786,10 @@
|
||||
|
||||
"kavitaplus-metadata-breakdown-stats": {
|
||||
"title": "Kavita+ Metadata Breakdown",
|
||||
"description": "Kavita fetches metadata (ratings, reviews, recommendations, etc) slowly over time for eligible series.",
|
||||
"no-data": "No data",
|
||||
"errored-series-label": "Errored Series",
|
||||
"completed-series-label": "Completed Series",
|
||||
"total-series-progress-label": "Series Processed: {{percent}}",
|
||||
"complete": "All Series have metadata"
|
||||
},
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
"name": "GPL-3.0",
|
||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||
},
|
||||
"version": "0.7.14.8"
|
||||
"version": "0.7.14.9"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user