mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
Width Override Fixes + Swagger (again) (#3034)
This commit is contained in:
parent
2326c9f437
commit
8cc1edc38d
@ -489,8 +489,6 @@ public class ScannerService : IScannerService
|
||||
// We don't need to send SignalR event as this is a background job that user doesn't need insight into
|
||||
_logger.LogInformation("[ScannerService] Scan library invoked via nightly scan job but a task is already running for {LibraryName}. Rescheduling for 4 hours", lib.Name);
|
||||
await Task.Delay(TimeSpan.FromHours(4));
|
||||
//BackgroundJob.Schedule(() => ScanLibraries(forceUpdate), TimeSpan.FromHours(4));
|
||||
//return;
|
||||
}
|
||||
|
||||
await ScanLibrary(lib.Id, forceUpdate, true);
|
||||
|
@ -137,7 +137,7 @@ public class Startup
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Version = "2.0",
|
||||
Version = "3.1.0",
|
||||
Title = "Kavita",
|
||||
Description = $"Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v{BuildInfo.Version.ToString()}",
|
||||
License = new OpenApiLicense
|
||||
@ -176,7 +176,7 @@ public class Startup
|
||||
Url = "{protocol}://{hostpath}",
|
||||
Variables = new Dictionary<string, OpenApiServerVariable>
|
||||
{
|
||||
{ "protocol", new OpenApiServerVariable { Default = "http", Enum = new List<string> { "http", "https" } } },
|
||||
{ "protocol", new OpenApiServerVariable { Default = "http", Enum = ["http", "https"]} },
|
||||
{ "hostpath", new OpenApiServerVariable { Default = "localhost:5000" } }
|
||||
}
|
||||
});
|
||||
@ -207,7 +207,7 @@ public class Startup
|
||||
.UseSimpleAssemblyNameTypeSerializer()
|
||||
.UseRecommendedSerializerSettings()
|
||||
.UseInMemoryStorage());
|
||||
//.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted (and locking can cause high utilization)
|
||||
//.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted (and locking can cause high utilization) (NOTE: There is code to clear jobs on startup a redditor gave me)
|
||||
|
||||
// Add the processing server as IHostedService
|
||||
services.AddHangfireServer(options =>
|
||||
|
@ -1,39 +1,49 @@
|
||||
<ng-container *transloco="let t; read: 'infinite-scroller'">
|
||||
|
||||
<div class="fixed-top overlay" *ngIf="showDebugBar()">
|
||||
<strong>Captures Scroll Events:</strong> {{!this.isScrolling && this.allImagesLoaded}}
|
||||
<strong>Is Scrolling:</strong> {{isScrollingForwards() ? 'Forwards' : 'Backwards'}} {{this.isScrolling}}
|
||||
<strong>All Images Loaded:</strong> {{this.allImagesLoaded}}
|
||||
<strong>Prefetched</strong> {{minPageLoaded}}-{{maxPageLoaded}}
|
||||
<strong>Pages:</strong> {{pageNum}} / {{totalPages - 1}}
|
||||
<strong>At Top:</strong> {{atTop}}
|
||||
<strong>At Bottom:</strong> {{atBottom}}
|
||||
<strong>Total Height:</strong> {{getTotalHeight()}}
|
||||
<strong>Total Scroll:</strong> {{getTotalScroll()}}
|
||||
<strong>Scroll Top:</strong> {{getScrollTop()}}
|
||||
</div>
|
||||
|
||||
<div *ngIf="atTop" #topSpacer class="spacer top" role="alert" (click)="loadPrevChapter.emit()">
|
||||
<div style="height: 200px"></div>
|
||||
<div>
|
||||
<button class="btn btn-icon mx-auto">
|
||||
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
|
||||
</button>
|
||||
<span class="mx-auto text">{{t('continuous-reading-prev-chapter')}}</span>
|
||||
<button class="btn btn-icon mx-auto">
|
||||
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
|
||||
</button>
|
||||
<span class="visually-hidden">{{t('continuous-reading-prev-chapter-alt')}}</span>
|
||||
@if (showDebugBar()) {
|
||||
<div class="fixed-top overlay">
|
||||
<strong>Captures Scroll Events:</strong> {{!this.isScrolling && this.allImagesLoaded}}
|
||||
<strong>Is Scrolling:</strong> {{isScrollingForwards() ? 'Forwards' : 'Backwards'}} {{this.isScrolling}}
|
||||
<strong>All Images Loaded:</strong> {{this.allImagesLoaded}}
|
||||
<strong>Prefetched</strong> {{minPageLoaded}}-{{maxPageLoaded}}
|
||||
<strong>Pages:</strong> {{pageNum}} / {{totalPages - 1}}
|
||||
<strong>At Top:</strong> {{atTop}}
|
||||
<strong>At Bottom:</strong> {{atBottom}}
|
||||
<strong>Total Height:</strong> {{getTotalHeight()}}
|
||||
<strong>Total Scroll:</strong> {{getTotalScroll()}}
|
||||
<strong>Scroll Top:</strong> {{getScrollTop()}}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (atTop) {
|
||||
<div #topSpacer class="spacer top" role="alert" (click)="loadPrevChapter.emit()">
|
||||
<div class="empty-space"></div>
|
||||
<div>
|
||||
<button class="btn btn-icon mx-auto">
|
||||
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
|
||||
</button>
|
||||
<span class="mx-auto text">{{t('continuous-reading-prev-chapter')}}</span>
|
||||
<button class="btn btn-icon mx-auto">
|
||||
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
|
||||
</button>
|
||||
<span class="visually-hidden">{{t('continuous-reading-prev-chapter-alt')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div infinite-scroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50">
|
||||
<ng-container *ngFor="let item of webtoonImages | async; let index = index;">
|
||||
<img src="{{item.src}}" style="display: block; width: {{widthOverride$ | async}}"
|
||||
@for(item of webtoonImages | async; let index = $index; track item.src) {
|
||||
<img src="{{item.src}}" style="display: block;" [ngStyle]="{'width': widthOverride$ | async}"
|
||||
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
|
||||
class="mx-auto {{pageNum === item.page && showDebugOutline() ? 'active': ''}} {{areImagesWiderThanWindow ? 'full-width' : ''}}"
|
||||
rel="nofollow" alt="image" (load)="onImageLoad($event)" id="page-{{item.page}}" [attr.page]="item.page" ondragstart="return false;" onselectstart="return false;">
|
||||
</ng-container>
|
||||
rel="nofollow"
|
||||
alt="image"
|
||||
(load)="onImageLoad($event)"
|
||||
id="page-{{item.page}}"
|
||||
[attr.page]="item.page"
|
||||
ondragstart="return false;"
|
||||
onselectstart="return false;">
|
||||
}
|
||||
</div>
|
||||
|
||||
<div #bottomSpacer class="spacer bottom" role="alert" (click)="loadNextChapter.emit()">
|
||||
@ -47,7 +57,7 @@
|
||||
</button>
|
||||
<span class="visually-hidden">{{t('continuous-reading-next-chapter-alt')}}</span>
|
||||
</div>
|
||||
<div style="height: 200px"></div>
|
||||
<div class="empty-space"></div>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
@ -21,8 +21,12 @@
|
||||
|
||||
.text {
|
||||
z-index: 101;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.empty-space {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DOCUMENT, NgIf, NgFor, AsyncPipe } from '@angular/common';
|
||||
import {DOCUMENT, AsyncPipe, NgStyle} from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
@ -16,7 +16,7 @@ import {
|
||||
Renderer2,
|
||||
SimpleChanges, ViewChild
|
||||
} from '@angular/core';
|
||||
import {BehaviorSubject, filter, fromEvent, map, Observable, of, ReplaySubject} from 'rxjs';
|
||||
import {BehaviorSubject, fromEvent, map, Observable, of, ReplaySubject} from 'rxjs';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { ScrollService } from 'src/app/_services/scroll.service';
|
||||
import { ReaderService } from '../../../_services/reader.service';
|
||||
@ -62,7 +62,7 @@ const enum DEBUG_MODES {
|
||||
styleUrls: ['./infinite-scroller.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgIf, NgFor, AsyncPipe, TranslocoDirective, InfiniteScrollModule, SafeStylePipe]
|
||||
imports: [AsyncPipe, TranslocoDirective, InfiniteScrollModule, SafeStylePipe, NgStyle]
|
||||
})
|
||||
export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
|
||||
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
BehaviorSubject,
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
forkJoin,
|
||||
fromEvent,
|
||||
map,
|
||||
@ -399,7 +400,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
*/
|
||||
debugMode: boolean = false;
|
||||
/**
|
||||
* Width override label for maunal width control
|
||||
* Width override label for manual width control
|
||||
*/
|
||||
widthOverrideLabel$ : Observable<string> = new Observable<string>();
|
||||
|
||||
@ -554,55 +555,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {});
|
||||
|
||||
//only enable the width override slider under certain conditions
|
||||
// width mode selected
|
||||
// splitting is set to fit to screen, otherwise disable
|
||||
// when disable set the value to 0
|
||||
// to use the default of the current single page reader
|
||||
this.generalSettingsForm.get('pageSplitOption')?.valueChanges.pipe(
|
||||
tap(val => {
|
||||
const fitting = this.generalSettingsForm.get('fittingOption')?.value;
|
||||
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
|
||||
|
||||
if (PageSplitOption.FitSplit == val && FITTING_OPTION.WIDTH == fitting) {
|
||||
widthOverrideControl?.enable();
|
||||
} else {
|
||||
widthOverrideControl?.setValue(0);
|
||||
widthOverrideControl?.disable();
|
||||
}
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {});
|
||||
|
||||
//only enable the width override slider under certain conditions
|
||||
// width mode selected
|
||||
// splitting is set to fit to screen, otherwise disable
|
||||
// when disable set the value to 0
|
||||
// to use the default of the current single page reader
|
||||
this.generalSettingsForm.get('fittingOption')?.valueChanges.pipe(
|
||||
tap(val => {
|
||||
const splitting = this.generalSettingsForm.get('pageSplitOption')?.value;
|
||||
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
|
||||
|
||||
if (PageSplitOption.FitSplit == splitting && FITTING_OPTION.WIDTH == val){
|
||||
widthOverrideControl?.enable();
|
||||
} else {
|
||||
widthOverrideControl?.setValue(0);
|
||||
widthOverrideControl?.disable();
|
||||
}
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {});
|
||||
|
||||
//sets the default override to 0, fixing the none% bug
|
||||
this.generalSettingsForm.get('widthSlider')!.setValue(0);
|
||||
|
||||
//send the current width override value to the label
|
||||
this.widthOverrideLabel$ = this.readerSettings$?.pipe(
|
||||
map(values => (parseInt(values.widthSlider) <= 0) ? '' : values.widthSlider + '%'),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.setupWidthOverrideTriggers();
|
||||
|
||||
this.generalSettingsForm.get('layoutMode')?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(val => {
|
||||
|
||||
@ -746,6 +699,68 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Width override is only valid under the following conditions:
|
||||
* Image Scaling is Width
|
||||
* Reader Mode is Webtoon
|
||||
*
|
||||
* In all other cases, the form will be disabled and set to 0 which indicates default/off state.
|
||||
*/
|
||||
setupWidthOverrideTriggers() {
|
||||
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
|
||||
|
||||
const enableWidthOverride = () => {
|
||||
widthOverrideControl.enable();
|
||||
};
|
||||
|
||||
const disableWidthOverride = () => {
|
||||
widthOverrideControl.setValue(0);
|
||||
widthOverrideControl.disable();
|
||||
};
|
||||
|
||||
const handleControlChanges = () => {
|
||||
const fitting = this.generalSettingsForm.get('fittingOption')?.value;
|
||||
const splitting = this.generalSettingsForm.get('pageSplitOption')?.value;
|
||||
|
||||
if ((PageSplitOption.FitSplit == splitting && FITTING_OPTION.WIDTH == fitting) || this.readerMode === ReaderMode.Webtoon) {
|
||||
enableWidthOverride();
|
||||
} else {
|
||||
disableWidthOverride();
|
||||
}
|
||||
};
|
||||
|
||||
// Reader mode changes
|
||||
this.readerModeSubject.asObservable()
|
||||
.pipe(
|
||||
filter(v => v === ReaderMode.Webtoon),
|
||||
tap(enableWidthOverride),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
// Page split option changes
|
||||
this.generalSettingsForm.get('pageSplitOption')?.valueChanges.pipe(
|
||||
distinctUntilChanged(),
|
||||
tap(handleControlChanges),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
|
||||
// Fitting option changes
|
||||
this.generalSettingsForm.get('fittingOption')?.valueChanges.pipe(
|
||||
tap(handleControlChanges),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
|
||||
// Set the default override to 0
|
||||
widthOverrideControl.setValue(0);
|
||||
|
||||
//send the current width override value to the label
|
||||
this.widthOverrideLabel$ = this.readerSettings$?.pipe(
|
||||
map(values => (parseInt(values.widthSlider) <= 0) ? '' : values.widthSlider + '%'),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
}
|
||||
|
||||
createReaderSettingsUpdate() {
|
||||
return {
|
||||
pageSplit: parseInt(this.generalSettingsForm.get('pageSplitOption')?.value, 10),
|
||||
|
2074
openapi.json
2074
openapi.json
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user