Skip to content

Commit

Permalink
Light Novel Library Type (Kareadita#2682)
Browse files Browse the repository at this point in the history
  • Loading branch information
majora2007 authored and ShivamAmin committed Feb 29, 2024
1 parent 9b8951c commit 7b76466
Show file tree
Hide file tree
Showing 26 changed files with 240 additions and 151 deletions.
38 changes: 0 additions & 38 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,48 +26,10 @@ jobs:
- name: Install dependencies
run: dotnet restore

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'

- uses: actions/upload-artifact@v3
with:
name: csproj
path: Kavita.Common/Kavita.Common.csproj

- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar

- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/cache@v3
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner

- name: Install SonarCloud scanner
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
shell: powershell
run: |
New-Item -Path .\.sonar\scanner -ItemType Directory
dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
- name: Sonar Scan
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"Kareadita_Kavita" /o:"kareadita" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
dotnet build --configuration Release
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
- name: Test
run: dotnet test --no-restore --verbosity normal
14 changes: 7 additions & 7 deletions .github/workflows/release-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,23 @@ jobs:
id: parse-body
run: |
body="${{ steps.findPr.outputs.body }}"
body=${body//\'/}
body=${body//'%'/'%25'}
body=${body//$'\n'/'%0A'}
body=${body//$'\r'/'%0D'}
body=${body//$'`'/'%60'}
body=${body//$'>'/'%3E'}
if [[ ${#body} -gt 1870 ]] ; then
body=${body:0:1870}
body="${body}...and much more.
Read full changelog: https://github.com/Kareadita/Kavita/releases/latest"
fi
body=${body//\'/}
body=${body//'%'/'%25'}
body=${body//$'\n'/'%0A'}
body=${body//$'\r'/'%0D'}
body=${body//$'`'/'%60'}
body=${body//$'>'/'%3E'}
echo $body
echo "BODY=$body" >> $GITHUB_OUTPUT
- name: Check Out Repo
uses: actions/checkout@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
<PackageReference Include="Hangfire.InMemory" Version="0.7.0" />
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.4.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.57" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.58" />
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.9" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
Expand Down
5 changes: 5 additions & 0 deletions API/Entities/Enums/LibraryType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ public enum LibraryType
/// </summary>
[Description("Image")]
Image = 3,
/// <summary>
/// Allows Books to Scrobble with AniList for Kavita+
/// </summary>
[Description("Light Novel")]
LightNovel = 4,
}
2 changes: 1 addition & 1 deletion API/Helpers/Builders/LibraryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public LibraryBuilder(string name, LibraryType type = LibraryType.Manga)
Series = new List<Series>(),
Folders = new List<FolderPath>(),
AppUsers = new List<AppUser>(),
AllowScrobbling = type is LibraryType.Book or LibraryType.Manga
AllowScrobbling = type is LibraryType.LightNovel or LibraryType.Manga
};
}

Expand Down
2 changes: 1 addition & 1 deletion API/Helpers/LibraryTypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static MediaFormat GetFormat(LibraryType libraryType)
{
LibraryType.Manga => MediaFormat.Manga,
LibraryType.Comic => MediaFormat.Comic,
LibraryType.Book => MediaFormat.LightNovel,
LibraryType.LightNovel => MediaFormat.LightNovel,
};
}
}
3 changes: 2 additions & 1 deletion API/Services/Plus/ExternalMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class ExternalMetadataService : IExternalMetadataService
private readonly IMapper _mapper;
private readonly ILicenseService _licenseService;
private readonly TimeSpan _externalSeriesMetadataCache = TimeSpan.FromDays(30);
public static readonly ImmutableArray<LibraryType> NonEligibleLibraryTypes = ImmutableArray.Create<LibraryType>(LibraryType.Comic);
public static readonly ImmutableArray<LibraryType> NonEligibleLibraryTypes = ImmutableArray.Create<LibraryType>(LibraryType.Comic, LibraryType.Book);
private readonly SeriesDetailPlusDto _defaultReturn = new()
{
Recommendations = null,
Expand Down Expand Up @@ -420,6 +420,7 @@ private static MediaFormat ConvertToMediaFormat(LibraryType libraryType, MangaFo
LibraryType.Manga => seriesFormat == MangaFormat.Epub ? MediaFormat.LightNovel : MediaFormat.Manga,
LibraryType.Comic => MediaFormat.Comic,
LibraryType.Book => MediaFormat.Book,
LibraryType.LightNovel => MediaFormat.LightNovel,
_ => MediaFormat.Unknown
};
}
Expand Down
9 changes: 9 additions & 0 deletions API/Services/Plus/ScrobblingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ public class ScrobblingService : IScrobblingService
private const int ScrobbleSleepTime = 1000; // We can likely tie this to AniList's 90 rate / min ((60 * 1000) / 90)

private static readonly IList<ScrobbleProvider> BookProviders = new List<ScrobbleProvider>()
{
};
private static readonly IList<ScrobbleProvider> LightNovelProviders = new List<ScrobbleProvider>()
{
ScrobbleProvider.AniList
};
Expand Down Expand Up @@ -877,6 +880,12 @@ private static bool DoesUserHaveProviderAndValid(ScrobbleEvent readEvent)
return true;
}

if (readEvent.Series.Library.Type == LibraryType.LightNovel &&
LightNovelProviders.Intersect(userProviders).Any())
{
return true;
}

return false;
}

Expand Down
1 change: 1 addition & 0 deletions API/Services/ReaderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ public static string FormatChapterName(LibraryType libraryType, bool includeHash
}
return "Issue" + (includeSpace ? " " : string.Empty);
case LibraryType.Book:
case LibraryType.LightNovel:
return "Book" + (includeSpace ? " " : string.Empty);
default:
throw new ArgumentOutOfRangeException(nameof(libraryType), libraryType, null);
Expand Down
13 changes: 9 additions & 4 deletions API/Services/SeriesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ public async Task<SeriesDetailDto> GetSeriesDetail(int seriesId, int userId)

// For books, the Name of the Volume is remapped to the actual name of the book, rather than Volume number.
var processedVolumes = new List<VolumeDto>();
if (libraryType == LibraryType.Book)
if (libraryType is LibraryType.Book or LibraryType.LightNovel)
{
var volumeLabel = await _localizationService.Translate(userId, "volume-num", string.Empty);
foreach (var volume in volumes)
Expand Down Expand Up @@ -533,7 +533,7 @@ public async Task<SeriesDetailDto> GetSeriesDetail(int seriesId, int userId)

// Don't show chapter 0 (aka single volume chapters) in the Chapters tab or books that are just single numbers (they show as volumes)
IEnumerable<ChapterDto> retChapters;
if (libraryType == LibraryType.Book)
if (libraryType is LibraryType.Book or LibraryType.LightNovel)
{
retChapters = Array.Empty<ChapterDto>();
} else
Expand Down Expand Up @@ -576,7 +576,7 @@ private static bool ShouldIncludeChapter(ChapterDto chapter)

public static void RenameVolumeName(ChapterDto firstChapter, VolumeDto volume, LibraryType libraryType, string volumeLabel = "Volume")
{
if (libraryType == LibraryType.Book)
if (libraryType is LibraryType.Book or LibraryType.LightNovel)
{
if (string.IsNullOrEmpty(firstChapter.TitleName))
{
Expand All @@ -587,6 +587,7 @@ public static void RenameVolumeName(ChapterDto firstChapter, VolumeDto volume, L
}
else if (volume.Name != "0")
{
// If the titleName has Volume inside it, let's just send that back?
volume.Name += $" - {firstChapter.TitleName}";
}
// else
Expand Down Expand Up @@ -614,6 +615,7 @@ public async Task<string> FormatChapterTitle(int userId, bool isSpecial, Library
return libraryType switch
{
LibraryType.Book => await _localizationService.Translate(userId, "book-num", chapterTitle),
LibraryType.LightNovel => await _localizationService.Translate(userId, "book-num", chapterTitle),
LibraryType.Comic => await _localizationService.Translate(userId, "issue-num", hashSpot, chapterTitle),
LibraryType.Manga => await _localizationService.Translate(userId, "chapter-num", chapterTitle),
_ => await _localizationService.Translate(userId, "chapter-num", ' ')
Expand All @@ -636,6 +638,7 @@ public async Task<string> FormatChapterName(int userId, LibraryType libraryType,
return (libraryType switch
{
LibraryType.Book => await _localizationService.Translate(userId, "book-num", string.Empty),
LibraryType.LightNovel => await _localizationService.Translate(userId, "book-num", string.Empty),
LibraryType.Comic => await _localizationService.Translate(userId, "issue-num", hashSpot, string.Empty),
LibraryType.Manga => await _localizationService.Translate(userId, "chapter-num", string.Empty),
_ => await _localizationService.Translate(userId, "chapter-num", ' ')
Expand Down Expand Up @@ -723,7 +726,8 @@ public async Task<NextExpectedChapterDto> GetEstimatedChapterCreationDate(int se
{
throw new UnauthorizedAccessException("user-no-access-library-from-series");
}
if (series.Metadata.PublicationStatus is not (PublicationStatus.OnGoing or PublicationStatus.Ended) || series.Library.Type == LibraryType.Book)
if (series.Metadata.PublicationStatus is not (PublicationStatus.OnGoing or PublicationStatus.Ended) ||
(series.Library.Type is LibraryType.Book or LibraryType.LightNovel))
{
return _emptyExpectedChapter;
}
Expand Down Expand Up @@ -803,6 +807,7 @@ public async Task<NextExpectedChapterDto> GetEstimatedChapterCreationDate(int se
LibraryType.Manga => await _localizationService.Translate(userId, "chapter-num", result.ChapterNumber),
LibraryType.Comic => await _localizationService.Translate(userId, "issue-num", "#", result.ChapterNumber),
LibraryType.Book => await _localizationService.Translate(userId, "book-num", result.ChapterNumber),
LibraryType.LightNovel => await _localizationService.Translate(userId, "book-num", result.ChapterNumber),
_ => await _localizationService.Translate(userId, "chapter-num", result.ChapterNumber)
};
}
Expand Down
3 changes: 2 additions & 1 deletion API/Services/StatisticService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,8 @@ public async Task<IEnumerable<TopReadDto>> GetTopUsers(int days)
{
UserId = userId,
Username = users.First(u => u.Id == userId).UserName,
BooksTime = user[userId].TryGetValue(LibraryType.Book, out var bookTime) ? bookTime : 0,
BooksTime = user[userId].TryGetValue(LibraryType.Book, out var bookTime) ? bookTime : 0 +
(user[userId].TryGetValue(LibraryType.LightNovel, out var bookTime2) ? bookTime2 : 0),
ComicsTime = user[userId].TryGetValue(LibraryType.Comic, out var comicTime) ? comicTime : 0,
MangaTime = user[userId].TryGetValue(LibraryType.Manga, out var mangaTime) ? mangaTime : 0,
})
Expand Down
4 changes: 3 additions & 1 deletion API/Services/Tasks/ScannerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ public async Task ScanFolder(string folder)
_logger.LogCritical("[ScannerService] Multiple series map to this folder. Library scan will be used for ScanFolder");
}
}
if (series != null && series.Library.Type != LibraryType.Book)

// TODO: Figure out why we have the library type restriction here
if (series != null && (series.Library.Type != LibraryType.Book || series.Library.Type != LibraryType.LightNovel))
{
if (TaskScheduler.HasScanTaskRunningForSeries(series.Id))
{
Expand Down
2 changes: 0 additions & 2 deletions API/Services/Tasks/VersionUpdaterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
using API.DTOs.Update;
using API.SignalR;
using Flurl.Http;
using HtmlAgilityPack;
using Kavita.Common.EnvironmentInfo;
using Kavita.Common.Helpers;
using MarkdownDeep;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace API.Services.Tasks;
Expand Down
2 changes: 1 addition & 1 deletion Kavita.Common/Kavita.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Company>kavitareader.com</Company>
<Product>Kavita</Product>
<AssemblyVersion>0.7.14.0</AssemblyVersion>
<AssemblyVersion>0.8.0.0</AssemblyVersion>
<NeutralLanguage>en</NeutralLanguage>
<TieredPGO>true</TieredPGO>
</PropertyGroup>
Expand Down
3 changes: 2 additions & 1 deletion UI/Web/src/app/_models/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export enum LibraryType {
Manga = 0,
Comic = 1,
Book = 2,
Images = 3
Images = 3,
LightNovel = 4
}

export interface Library {
Expand Down
3 changes: 3 additions & 0 deletions UI/Web/src/app/cards/entity-title/entity-title.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
<ng-container *ngSwitchCase="LibraryType.Book">
{{volumeTitle}}
</ng-container>
<ng-container *ngSwitchCase="LibraryType.LightNovel">
{{volumeTitle}}
</ng-container>
</ng-container>
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ <h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title'

</div>

<div class="row" [ngClass]="{'pt-3': !seriesMetadata || seriesMetadata?.summary?.length === 0}">
<div class="row" [ngClass]="{'pt-3': !seriesMetadata || seriesMetadata.summary.length === 0}">
<app-carousel-reel [items]="reviews" [alwaysShow]="true" [title]="t('user-reviews-alt')"
iconClasses="fa-solid fa-{{getUserReview().length > 0 ? 'pen' : 'plus'}}"
[clickableTitle]="true" (sectionClick)="openReviewModal()">
Expand All @@ -153,7 +153,7 @@ <h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title'
<ng-container *ngIf="series">

<ul ngbNav #nav="ngbNav" [(activeId)]="activeTabId" class="nav nav-tabs mb-2" [destroyOnHide]="false" (navChange)="onNavChange($event)">
<li [ngbNavItem]="TabID.Storyline" *ngIf="libraryType !== LibraryType.Book && (volumes.length > 0 || chapters.length > 0)">
<li [ngbNavItem]="TabID.Storyline" *ngIf="ShowStorylineTab">
<a ngbNavLink>{{t('storyline-tab')}}</a>
<ng-template ngbNavContent>
<virtual-scroller #scroll [items]="storylineItems" [bufferAmount]="1" [parentScroll]="scrollingBlock" [childHeight]="1">
Expand Down Expand Up @@ -181,8 +181,8 @@ <h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title'
</ng-template>
</li>

<li [ngbNavItem]="TabID.Volumes" *ngIf="volumes.length > 0">
<a ngbNavLink>{{libraryType === LibraryType.Book ? t('books-tab') : t('volumes-tab')}}</a>
<li [ngbNavItem]="TabID.Volumes" *ngIf="ShowVolumeTab">
<a ngbNavLink>{{UseBookLogic ? t('books-tab') : t('volumes-tab')}}</a>
<ng-template ngbNavContent>
<virtual-scroller #scroll [items]="volumes" [parentScroll]="scrollingBlock" [childHeight]="1">
<ng-container *ngIf="renderMode === PageLayoutMode.Cards; else volumeListLayout">
Expand All @@ -202,7 +202,7 @@ <h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title'
</ng-template>
</li>

<li [ngbNavItem]="TabID.Chapters" *ngIf="chapters.length > 0">
<li [ngbNavItem]="TabID.Chapters" *ngIf="ShowChaptersTab">
<a ngbNavLink>{{utilityService.formatChapterName(libraryType) + 's'}}</a>
<ng-template ngbNavContent>
<virtual-scroller #scroll [items]="chapters" [parentScroll]="scrollingBlock" [childHeight]="1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

.image-container {
max-height: 400px;
max-width: 280px;
}

.info-container {
Expand All @@ -63,4 +64,4 @@
border-bottom-right-radius: 6px !important;
border-top-left-radius: 0px !important;
border-bottom-left-radius: 0px !important;
}
}
Loading

0 comments on commit 7b76466

Please sign in to comment.