mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
More Reader Fixes (#1696)
* Fixed resizing or layout changes causing page change on double reader * Implemented the debug log pattern on double renderers. Fixed a case when navigation backwards and showing only one page. Updated so go to page or slider update will handle selecting the right page number for pair display. * All Spread cases for double working * Cleanup dead code * Ensure we can jump to last page
This commit is contained in:
parent
90d5834ffa
commit
c640ae3637
@ -310,6 +310,16 @@ public class StatisticService : IStatisticService
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public void ReadCountByDay()
|
||||
{
|
||||
// _context.AppUserProgresses
|
||||
// .GroupBy(p => p.LastModified.Day)
|
||||
// .Select(g =>
|
||||
// {
|
||||
// Day = g.Key,
|
||||
// })
|
||||
}
|
||||
|
||||
public Task<IEnumerable<ReadHistoryEvent>> GetHistory()
|
||||
{
|
||||
// _context.AppUserProgresses
|
||||
|
@ -162,6 +162,7 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
return needsSplitting;
|
||||
}
|
||||
|
||||
|
||||
isValid() {
|
||||
return this.renderWithCanvas;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { ReaderService } from 'src/app/_services/reader.service';
|
||||
import { LayoutMode } from '../../_models/layout-mode';
|
||||
import { FITTING_OPTION, PAGING_DIRECTION } from '../../_models/reader-enums';
|
||||
import { ReaderSetting } from '../../_models/reader-setting';
|
||||
import { ImageRenderer } from '../../_models/renderer';
|
||||
import { DEBUG_MODES, ImageRenderer } from '../../_models/renderer';
|
||||
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||
|
||||
/**
|
||||
@ -26,11 +26,10 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
@Input() bookmark$!: Observable<number>;
|
||||
@Input() showClickOverlay$!: Observable<boolean>;
|
||||
@Input() pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
|
||||
@Input() getPage!: (pageNum: number) => HTMLImageElement;
|
||||
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.None;
|
||||
imageFitClass$!: Observable<string>;
|
||||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
@ -61,6 +60,7 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
*/
|
||||
shouldRenderDouble$!: Observable<boolean>;
|
||||
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
@ -172,22 +172,27 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
if (!this.isValid()) return false;
|
||||
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Not rendering double as current page is cover image');
|
||||
this.debugLog('Not rendering double as current page is cover image');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum) ) {
|
||||
console.log('Not rendering double as current page is wide image');
|
||||
this.debugLog('Not rendering double as current page is wide image');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||
this.debugLog('Not rendering double as current page is last');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Not rendering double as current page is last and there are an odd number of pages');
|
||||
this.debugLog('Not rendering double as current page is last');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1) ) {
|
||||
console.log('Not rendering double as next page is wide image');
|
||||
this.debugLog('Not rendering double as next page is wide image');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -225,49 +230,66 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
switch (direction) {
|
||||
case PAGING_DIRECTION.FORWARD:
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Moving forward 1 page as on cover image');
|
||||
this.debugLog('Moving forward 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
console.log('Moving forward 1 page as current page is wide');
|
||||
this.debugLog('Moving forward 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1)) {
|
||||
console.log('Moving forward 1 page as next page is wide');
|
||||
this.debugLog('Moving forward 1 page as next page is wide');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Moving forward 1 page as 2 pages left');
|
||||
this.debugLog('Moving forward 1 page as 2 pages left');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Moving forward 1 page as 1 page left');
|
||||
this.debugLog('Moving forward 1 page as 1 page left');
|
||||
return 1;
|
||||
}
|
||||
console.log('Moving forward 2 pages');
|
||||
this.debugLog('Moving forward 2 pages');
|
||||
return 2;
|
||||
case PAGING_DIRECTION.BACKWARDS:
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Moving back 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
console.log('Moving back 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 1)) {
|
||||
console.log('Moving back 1 page as prev page is wide');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||
console.log('Moving back 1 page as 2 pages back is wide');
|
||||
this.debugLog('Moving back 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
|
||||
console.log('Moving back 2 pages');
|
||||
if (this.mangaReaderService.adjustForDoubleReader(this.pageNum - 1) != this.pageNum - 1 && !this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||
this.debugLog('Moving back 2 pages as previous pair should be in a pair');
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
this.debugLog('Moving back 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 1)) {
|
||||
this.debugLog('Moving back 1 page as prev page is wide');
|
||||
return 1;
|
||||
}
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||
this.debugLog('Moving back 1 page as 2 pages back is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
this.debugLog('Moving back 2 pages');
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
reset(): void {}
|
||||
|
||||
debugLog(message: string, extraData?: any) {
|
||||
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { ReaderService } from 'src/app/_services/reader.service';
|
||||
import { LayoutMode } from '../../_models/layout-mode';
|
||||
import { FITTING_OPTION, PAGING_DIRECTION } from '../../_models/reader-enums';
|
||||
import { ReaderSetting } from '../../_models/reader-setting';
|
||||
import { ImageRenderer } from '../../_models/renderer';
|
||||
import { DEBUG_MODES, ImageRenderer } from '../../_models/renderer';
|
||||
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||
|
||||
/**
|
||||
@ -28,11 +28,11 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
||||
@Input() bookmark$!: Observable<number>;
|
||||
@Input() showClickOverlay$!: Observable<boolean>;
|
||||
@Input() pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
|
||||
@Input() getPage!: (pageNum: number) => HTMLImageElement;
|
||||
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.None;
|
||||
|
||||
imageFitClass$!: Observable<string>;
|
||||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
@ -115,8 +115,8 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
||||
|
||||
this.shouldRenderDouble$ = this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
map((_) => this.shouldRenderDouble()),
|
||||
filter(_ => this.isValid()),
|
||||
map(() => this.shouldRenderDouble()),
|
||||
filter(() => this.isValid()),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
@ -173,22 +173,27 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
||||
if (!this.isValid()) return false;
|
||||
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Not rendering double as current page is cover image');
|
||||
this.debugLog('Not rendering double as current page is cover image');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
console.log('Not rendering double as current page is wide image');
|
||||
this.debugLog('Not rendering double as current page is wide image');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||
this.debugLog('Not rendering double as current page is last');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1) ) {
|
||||
console.log('Not rendering double as next page is wide image');
|
||||
this.debugLog('Not rendering double as next page is wide image');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Not rendering double as current page is last and there are an odd number of pages');
|
||||
this.debugLog('Not rendering double as current page is last and there are an odd number of pages');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -219,92 +224,85 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
||||
switch (direction) {
|
||||
case PAGING_DIRECTION.FORWARD:
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Moving forward 1 page as on cover image');
|
||||
this.debugLog('Moving forward 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
this.debugLog('Moving forward 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1)) {
|
||||
this.debugLog('Moving forward 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Moving forward 1 page as 2 pages left');
|
||||
this.debugLog('Moving forward 1 page as 2 pages left');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
console.log('Moving forward 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1)) {
|
||||
console.log('Moving forward 1 page as current page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isLastImage(this.pageNum + 1, this.maxPages)) {
|
||||
console.log('Moving forward 2 pages as right image is the last page and we just rendered double page');
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (this.pageNum === this.maxPages - 1) {
|
||||
console.log('Moving forward 0 page as on last page');
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Moving forward 1 page as 1 page left');
|
||||
return 1;
|
||||
}
|
||||
|
||||
console.log('Moving forward 2 pages');
|
||||
return 2;
|
||||
case PAGING_DIRECTION.BACKWARDS:
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
console.log('Moving back 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 1)) {
|
||||
console.log('Moving back 2 page as right page is wide');
|
||||
this.debugLog('Moving forward 2 pages as right image is the last page and we just rendered double page');
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 2)) {
|
||||
console.log('Moving back 1 page as coming from wide page');
|
||||
this.debugLog('Moving forward 2 pages');
|
||||
return 2;
|
||||
case PAGING_DIRECTION.BACKWARDS:
|
||||
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||
this.debugLog('Moving back 1 page as on cover image');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.adjustForDoubleReader(this.pageNum - 1) != this.pageNum - 1 && !this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||
this.debugLog('Moving back 2 pages as previous pair should be in a pair');
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||
console.log('Moving back 1 page as left page is wide');
|
||||
this.debugLog('Moving back 1 page as left page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum) && (!this.mangaReaderService.isWidePage(this.pageNum - 4))) {
|
||||
console.log('Moving back 1 page as left page is wide');
|
||||
this.debugLog('Moving back 1 page as left page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 1)) {
|
||||
console.log('Moving back 1 page as prev page is wide');
|
||||
this.debugLog('Moving back 1 page as prev page is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||
console.log('Moving back 1 page as 2 pages back is wide');
|
||||
this.debugLog('Moving back 1 page as 2 pages back is wide');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.mangaReaderService.isWidePage(this.pageNum + 2)) {
|
||||
console.log('Moving back 2 page as 2 pages back is wide');
|
||||
this.debugLog('Moving back 2 page as 2 pages back is wide');
|
||||
return 1;
|
||||
}
|
||||
// Not sure about this condition on moving backwards
|
||||
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||
console.log('Moving back 1 page as 2 pages left');
|
||||
this.debugLog('Moving back 1 page as 2 pages left');
|
||||
return 1;
|
||||
}
|
||||
console.log('Moving back 2 pages');
|
||||
this.debugLog('Moving back 2 pages');
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
reset(): void {}
|
||||
|
||||
debugLog(message: string, extraData?: any) {
|
||||
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ const enum DEBUG_MODES {
|
||||
* Turn on Page outline
|
||||
*/
|
||||
Outline = 8
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
@ -473,16 +473,12 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.generalSettingsForm.get('pageSplitOption')?.disable();
|
||||
this.generalSettingsForm.get('fittingOption')?.setValue(this.mangaReaderService.translateScalingOption(ScalingOption.FitToHeight));
|
||||
this.generalSettingsForm.get('fittingOption')?.disable();
|
||||
|
||||
// If we are in double mode, we need to check if our current page is on a right edge or not, if so adjust by decrementing by 1
|
||||
if (this.readerMode !== ReaderMode.Webtoon) {
|
||||
this.setPageNum(this.mangaReaderService.adjustForDoubleReader(this.pageNum));
|
||||
}
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// Re-render the current page when we switch layouts
|
||||
if (changeOccurred) {
|
||||
this.setPageNum(this.adjustPagesForDoubleRenderer(this.pageNum));
|
||||
this.loadPage();
|
||||
}
|
||||
});
|
||||
@ -604,6 +600,15 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
};
|
||||
}
|
||||
|
||||
// If we are in double mode, we need to check if our current page is on a right edge or not, if so adjust by decrementing by 1
|
||||
adjustPagesForDoubleRenderer(pageNum: number) {
|
||||
if (pageNum === this.maxPages - 1) return pageNum;
|
||||
if (this.readerMode !== ReaderMode.Webtoon && this.layoutMode !== LayoutMode.Single) {
|
||||
return this.mangaReaderService.adjustForDoubleReader(pageNum);
|
||||
}
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
disableDoubleRendererIfScreenTooSmall() {
|
||||
if (window.innerWidth > window.innerHeight) {
|
||||
this.generalSettingsForm.get('layoutMode')?.enable();
|
||||
@ -736,10 +741,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
page = this.maxPages - 1;
|
||||
}
|
||||
|
||||
// If we are in double mode, we need to check if our current page is on a right edge or not, if so adjust by decrementing by 1
|
||||
if (this.layoutMode !== LayoutMode.Single && this.readerMode !== ReaderMode.Webtoon) {
|
||||
page = this.mangaReaderService.adjustForDoubleReader(page);
|
||||
}
|
||||
page = this.adjustPagesForDoubleRenderer(page);
|
||||
|
||||
this.setPageNum(page); // first call
|
||||
this.goToPageEvent = new BehaviorSubject<number>(this.pageNum);
|
||||
@ -1121,9 +1123,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.pagingDirectionSubject.next(PAGING_DIRECTION.BACKWARDS);
|
||||
}
|
||||
|
||||
this.setPageNum(page);
|
||||
this.setPageNum(this.adjustPagesForDoubleRenderer(page));
|
||||
this.refreshSlider.emit();
|
||||
this.goToPageEvent.next(page);
|
||||
this.goToPageEvent.next(this.pageNum);
|
||||
this.render();
|
||||
}
|
||||
|
||||
@ -1179,7 +1181,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.pagingDirectionSubject.next(PAGING_DIRECTION.BACKWARDS);
|
||||
}
|
||||
|
||||
this.setPageNum(page);
|
||||
this.setPageNum(this.adjustPagesForDoubleRenderer(page));
|
||||
this.goToPageEvent.next(page);
|
||||
this.render();
|
||||
}
|
||||
|
@ -58,6 +58,8 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
tap(pageInfo => {
|
||||
this.pageNum = pageInfo.pageNum;
|
||||
this.maxPages = pageInfo.maxPages;
|
||||
|
||||
// TODO: Put this here this.currentImage = this.getPagez
|
||||
}),
|
||||
).subscribe(() => {});
|
||||
|
||||
@ -125,11 +127,6 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
||||
if (img === null || img.length === 0 || img[0] === null) return;
|
||||
if (!this.isValid()) return;
|
||||
|
||||
// This seems to cause a problem after rendering a split
|
||||
//if (this.mangaReaderService.shouldSplit(this.currentImage, this.pageSplit)) return;
|
||||
|
||||
|
||||
|
||||
this.currentImage = img[0];
|
||||
this.cdRef.markForCheck();
|
||||
this.imageHeight.emit(this.currentImage.height);
|
||||
|
@ -2,6 +2,21 @@ import { Observable } from "rxjs";
|
||||
import { PAGING_DIRECTION } from "./reader-enums";
|
||||
import { ReaderSetting } from "./reader-setting";
|
||||
|
||||
|
||||
/**
|
||||
* Bitwise enums for configuring how much debug information we want
|
||||
*/
|
||||
export const enum DEBUG_MODES {
|
||||
/**
|
||||
* No Debug information
|
||||
*/
|
||||
None = 0,
|
||||
/**
|
||||
* Turn on debug logging
|
||||
*/
|
||||
Logs = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic interface for an image renderer
|
||||
*/
|
||||
@ -40,6 +55,4 @@ export interface ImageRenderer {
|
||||
* This should reset any needed state, but not unset the image.
|
||||
*/
|
||||
reset(): void;
|
||||
|
||||
|
||||
}
|
@ -39,6 +39,7 @@ export class ManagaReaderService {
|
||||
|
||||
i++;
|
||||
});
|
||||
console.log('pairs: ', this.pairs);
|
||||
}
|
||||
|
||||
adjustForDoubleReader(page: number) {
|
||||
@ -94,7 +95,7 @@ export class ManagaReaderService {
|
||||
* If the current page is second to last image
|
||||
*/
|
||||
isSecondLastImage(pageNum: number, maxPages: number) {
|
||||
return maxPages - 2 === pageNum;
|
||||
return (maxPages - 2) === pageNum;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@
|
||||
"name": "GPL-3.0",
|
||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||
},
|
||||
"version": "0.6.1.14"
|
||||
"version": "0.6.1.15"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user