More Bugfixes (EPUB Mainly) (#2004)
* Fixed an issue with downloading where spaces turned into plus signs. * If the refresh token is invalid, but the auth token still has life in it, don't invalidate. * Fixed docker users unable to save settings * Show a default error icon until favicon loads * Fixed a bug in mappings (keys/files) to pages that caused some links not to map appropriately. Updated epub-reader to v3.3.2. * Expanded Table of Content generation by also checking for any files that are named Navigation.xhtml to have Kavita generate a simple ToC from (instead of just TOC.xhtml) * Added another hack to massage key to page lookups when rewriting anchors. * Cleaned up debugging notes
This commit is contained in:
parent
5f607b3dab
commit
64666540cf
16 changed files with 131 additions and 307 deletions
|
@ -771,7 +771,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
const links = this.readingSectionElemRef.nativeElement.querySelectorAll('a');
|
||||
links.forEach((link: any) => {
|
||||
link.addEventListener('click', (e: any) => {
|
||||
console.log('Link clicked: ', e);
|
||||
if (!e.target.attributes.hasOwnProperty('kavita-page')) { return; }
|
||||
const page = parseInt(e.target.attributes['kavita-page'].value, 10);
|
||||
if (this.adhocPageHistory.peek()?.page !== this.pageNum) {
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
</div>
|
||||
<div class="col-md-8">
|
||||
<a class="col me-1" [href]="link | safeHtml" target="_blank" rel="noopener noreferrer" *ngFor="let link of links" [title]="link">
|
||||
<img width="24px" height="24px" #img class="lazyload img-placeholder"
|
||||
src="data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
|
||||
[attr.data-src]="imageService.getWebLinkImage(link)"
|
||||
(error)="imageService.updateErroredWebLinkImage($event)"
|
||||
<img width="24px" height="24px" #img class="lazyload img-placeholder"
|
||||
[src]="imageService.errorWebLinkImage"
|
||||
[attr.data-src]="imageService.getWebLinkImage(link)"
|
||||
(error)="imageService.updateErroredWebLinkImage($event)"
|
||||
aria-hidden="true">
|
||||
</a>
|
||||
</div>
|
||||
|
@ -28,7 +28,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.genres">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Genres, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.tags">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Tags, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,7 +54,7 @@
|
|||
<app-tag-badge a11y-click="13,32" class="col-auto" routerLink="/collections/{{item.id}}" [selectionMode]="TagBadgeCursor.Clickable">
|
||||
{{item.title}}
|
||||
</app-tag-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -72,7 +72,7 @@
|
|||
</span>
|
||||
{{item.title}}
|
||||
</app-tag-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -84,7 +84,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.writers">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Writers, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -98,11 +98,11 @@
|
|||
<app-badge-expander [items]="seriesMetadata.coverArtists">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.CoverArtists, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row g-0 mt-1" *ngIf="seriesMetadata.characters && seriesMetadata.characters.length > 0">
|
||||
<div class="col-md-4">
|
||||
<h5>Characters</h5>
|
||||
|
@ -111,7 +111,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.characters">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Character, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -124,7 +124,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.colorists">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Colorist, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -137,7 +137,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.editors">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Editor, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -150,7 +150,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.inkers">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Inker, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.letterers">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Letterer, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -175,11 +175,11 @@
|
|||
<app-badge-expander [items]="seriesMetadata.translators">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Translator, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row g-0 mt-1" *ngIf="seriesMetadata.pencillers && seriesMetadata.pencillers.length > 0">
|
||||
<div class="col-md-4">
|
||||
<h5>Pencillers</h5>
|
||||
|
@ -188,7 +188,7 @@
|
|||
<app-badge-expander [items]="seriesMetadata.pencillers">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Penciller, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -201,20 +201,20 @@
|
|||
<app-badge-expander [items]="seriesMetadata.publishers">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Publisher, item.id)" [person]="item"></app-person-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-0">
|
||||
<hr class="col mt-3" *ngIf="hasExtendedProperites" >
|
||||
<a [class.hidden]="hasExtendedProperites" *ngIf="hasExtendedProperites"
|
||||
class="col col-md-auto align-self-end read-more-link" (click)="toggleView()">
|
||||
<hr class="col mt-3" *ngIf="hasExtendedProperties" >
|
||||
<a [class.hidden]="hasExtendedProperties" *ngIf="hasExtendedProperties"
|
||||
class="col col-md-auto align-self-end read-more-link" (click)="toggleView()">
|
||||
<i aria-hidden="true" class="fa fa-caret-{{isCollapsed ? 'down' : 'up'}} me-1" aria-controls="extended-series-metadata"></i>
|
||||
See {{isCollapsed ? 'More' : 'Less'}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- This first row will have random information about the series-->
|
||||
<app-series-info-cards [series]="series" [seriesMetadata]="seriesMetadata" (goTo)="handleGoTo($event)" [hasReadingProgress]="hasReadingProgress"></app-series-info-cards>
|
||||
<app-series-info-cards [series]="series" [seriesMetadata]="seriesMetadata" (goTo)="handleGoTo($event)" [hasReadingProgress]="hasReadingProgress"></app-series-info-cards>
|
||||
|
|
|
@ -29,7 +29,7 @@ export class SeriesMetadataDetailComponent implements OnChanges {
|
|||
@Input() series!: Series;
|
||||
|
||||
isCollapsed: boolean = true;
|
||||
hasExtendedProperites: boolean = false;
|
||||
hasExtendedProperties: boolean = false;
|
||||
|
||||
imageService = inject(ImageService);
|
||||
|
||||
|
@ -55,20 +55,20 @@ export class SeriesMetadataDetailComponent implements OnChanges {
|
|||
return this.seriesMetadata?.webLinks.split(',') || [];
|
||||
}
|
||||
|
||||
constructor(public utilityService: UtilityService, public metadataService: MetadataService,
|
||||
constructor(public utilityService: UtilityService, public metadataService: MetadataService,
|
||||
private router: Router, public readerService: ReaderService,
|
||||
private readonly cdRef: ChangeDetectorRef) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
this.hasExtendedProperites = this.seriesMetadata.colorists.length > 0 ||
|
||||
this.seriesMetadata.editors.length > 0 ||
|
||||
this.seriesMetadata.coverArtists.length > 0 ||
|
||||
this.hasExtendedProperties = this.seriesMetadata.colorists.length > 0 ||
|
||||
this.seriesMetadata.editors.length > 0 ||
|
||||
this.seriesMetadata.coverArtists.length > 0 ||
|
||||
this.seriesMetadata.inkers.length > 0 ||
|
||||
this.seriesMetadata.letterers.length > 0 ||
|
||||
this.seriesMetadata.pencillers.length > 0 ||
|
||||
this.seriesMetadata.publishers.length > 0 ||
|
||||
this.seriesMetadata.publishers.length > 0 ||
|
||||
this.seriesMetadata.translators.length > 0 ||
|
||||
this.seriesMetadata.tags.length > 0;
|
||||
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
import { ElementRef, Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DomHelperService {
|
||||
|
||||
constructor() {}
|
||||
// from: https://stackoverflow.com/questions/40597658/equivalent-of-angular-equals-in-angular2#44649659
|
||||
deepEquals(x: any, y: any) {
|
||||
if (x === y) {
|
||||
return true; // if both x and y are null or undefined and exactly the same
|
||||
} else if (!(x instanceof Object) || !(y instanceof Object)) {
|
||||
return false; // if they are not strictly equal, they both need to be Objects
|
||||
} else if (x.constructor !== y.constructor) {
|
||||
// they must have the exact same prototype chain, the closest we can do is
|
||||
// test their constructor.
|
||||
return false;
|
||||
} else {
|
||||
for (const p in x) {
|
||||
if (!x.hasOwnProperty(p)) {
|
||||
continue; // other properties were tested using x.constructor === y.constructor
|
||||
}
|
||||
if (!y.hasOwnProperty(p)) {
|
||||
return false; // allows to compare x[ p ] and y[ p ] when set to undefined
|
||||
}
|
||||
if (x[p] === y[p]) {
|
||||
continue; // if they have the same strict value or identity then they are equal
|
||||
}
|
||||
if (typeof (x[p]) !== 'object') {
|
||||
return false; // Numbers, Strings, Functions, Booleans must be strictly equal
|
||||
}
|
||||
if (!this.deepEquals(x[p], y[p])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const p in y) {
|
||||
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
isHidden(node: ElementRef){
|
||||
const el = node.nativeElement?node.nativeElement:node;
|
||||
const elemStyle = window.getComputedStyle(el);
|
||||
|
||||
return el.style.display === 'none' || elemStyle.visibility === 'hidden' || el.hasAttribute('hidden') || elemStyle.display === 'none';
|
||||
}
|
||||
|
||||
isTabable(node: ElementRef): boolean {
|
||||
const el = node.nativeElement?node.nativeElement:node;
|
||||
const tagName = el.tagName;
|
||||
|
||||
if(this.isHidden(node)){
|
||||
return false;
|
||||
}
|
||||
// el.attribute:NamdedNodeMap
|
||||
if (el.attributes.hasOwnProperty('tabindex')) {
|
||||
return (parseInt(el.attributes.getNamedItem('tabindex'),10) >= 0);
|
||||
}
|
||||
if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
|
||||
if (tagName === 'A' || tagName === 'AREA') {
|
||||
return (el.attributes.getNamedItem('href') !== '');
|
||||
}
|
||||
return !el.attributes.hasOwnProperty('disabled'); // check for cases when: disabled="true" and disabled="false"
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private isValidChild(child: any): boolean { // child:ElementRef.nativeElement
|
||||
return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
|
||||
}
|
||||
|
||||
private hasValidParent(obj: any) { // obj:ElementRef.nativeElement
|
||||
return (this.isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');
|
||||
}
|
||||
|
||||
private traverse(obj: any, fromTop: boolean): ElementRef | undefined | boolean {
|
||||
// obj:ElementRef||ElementRef.nativeElement
|
||||
var obj = obj? (obj.nativeElement?obj.nativeElement:obj) : document.getElementsByTagName('body')[0];
|
||||
if (this.isValidChild(obj) && this.isTabable(obj)) {
|
||||
return obj;
|
||||
}
|
||||
// If object is hidden, skip it's children
|
||||
if (this.isValidChild(obj) && this.isHidden(obj)) {
|
||||
return undefined;
|
||||
}
|
||||
// If object is hidden, skip it's children
|
||||
if (obj.classList && obj.classList.contains('ng-hide')) { // some nodes don't have classList?!
|
||||
return false;
|
||||
}
|
||||
if (obj.hasChildNodes()) {
|
||||
var child;
|
||||
if (fromTop) {
|
||||
child = obj.firstChild;
|
||||
} else {
|
||||
child = obj.lastChild;
|
||||
}
|
||||
while(child) {
|
||||
var res = this.traverse(child, fromTop);
|
||||
if(res){
|
||||
return res;
|
||||
}
|
||||
else{
|
||||
if (fromTop) {
|
||||
child = child.nextSibling;
|
||||
} else {
|
||||
child = child.previousSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
previousElement(el: any, isFocusable: boolean): any { // ElementRef | undefined | boolean
|
||||
|
||||
var elem = el.nativeElement ? el.nativeElement : el;
|
||||
if (el.hasOwnProperty('length')) {
|
||||
elem = el[0];
|
||||
}
|
||||
|
||||
var parent = elem.parentElement;
|
||||
var previousElem = undefined;
|
||||
|
||||
if(isFocusable) {
|
||||
if (this.hasValidParent(elem)) {
|
||||
var siblings = parent.children;
|
||||
if (siblings.length > 0) {
|
||||
// Good practice to splice out the elem from siblings if there, saving some time.
|
||||
// We allow for a quick check for jumping to parent first before removing.
|
||||
if (siblings[0] === elem) {
|
||||
// If we are looking at immidiate parent and elem is first child, we need to go higher
|
||||
var e = this.previousElement(elem.parentNode, isFocusable);
|
||||
if (this.isTabable(e)) {
|
||||
return e;
|
||||
}
|
||||
} else {
|
||||
// I need to filter myself and any nodes next to me from the siblings
|
||||
var indexOfElem = Array.prototype.indexOf.call(siblings, elem);
|
||||
const that = this;
|
||||
siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {
|
||||
if (!that.deepEquals(elem, item) && itemIndex < indexOfElem) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// We need to search backwards
|
||||
for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {
|
||||
var ret = this.traverse(siblings[i], false);
|
||||
if (ret !== undefined) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
var e = this.previousElement(elem.parentNode, isFocusable);
|
||||
if (this.isTabable(e)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var siblings = parent.children;
|
||||
if (siblings.length > 1) {
|
||||
// Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()
|
||||
var index = Array.prototype.indexOf.call(siblings, elem);
|
||||
previousElem = siblings[index-1];
|
||||
}
|
||||
}
|
||||
return previousElem;
|
||||
};
|
||||
lastTabableElement(el: any) {
|
||||
/* This will return the first tabable element from the parent el */
|
||||
var elem = el.nativeElement?el.nativeElement:el;
|
||||
if (el.hasOwnProperty('length')) {
|
||||
elem = el[0];
|
||||
}
|
||||
|
||||
return this.traverse(elem, false);
|
||||
};
|
||||
|
||||
firstTabableElement(el: any) {
|
||||
/* This will return the first tabable element from the parent el */
|
||||
var elem = el.nativeElement ? el.nativeElement : el;
|
||||
if (el.hasOwnProperty('length')) {
|
||||
elem = el[0];
|
||||
}
|
||||
|
||||
return this.traverse(elem, true);
|
||||
};
|
||||
|
||||
isInDOM(obj: Node) {
|
||||
return document.documentElement.contains(obj);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ export interface DownloadEvent {
|
|||
/**
|
||||
* Progress of the download itself
|
||||
*/
|
||||
progress: number;
|
||||
progress: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ export interface DownloadEvent {
|
|||
*/
|
||||
export type DownloadEntityType = 'volume' | 'chapter' | 'series' | 'bookmark' | 'logs';
|
||||
/**
|
||||
* Valid entities for downloading. Undefined exclusively for logs.
|
||||
* Valid entities for downloading. Undefined exclusively for logs.
|
||||
*/
|
||||
export type DownloadEntity = Series | Volume | Chapter | PageBookmark[] | undefined;
|
||||
|
||||
|
@ -56,14 +56,14 @@ export class DownloadService {
|
|||
public activeDownloads$ = this.downloadsSource.asObservable();
|
||||
|
||||
|
||||
constructor(private httpClient: HttpClient, private confirmService: ConfirmService,
|
||||
constructor(private httpClient: HttpClient, private confirmService: ConfirmService,
|
||||
@Inject(SAVER) private save: Saver, private accountService: AccountService) { }
|
||||
|
||||
/**
|
||||
* Returns the entity subtitle (for the event widget) for a given entity
|
||||
* @param downloadEntityType
|
||||
* @param downloadEntity
|
||||
* @returns
|
||||
* @param downloadEntityType
|
||||
* @param downloadEntity
|
||||
* @returns
|
||||
*/
|
||||
downloadSubtitle(downloadEntityType: DownloadEntityType, downloadEntity: DownloadEntity | undefined) {
|
||||
switch (downloadEntityType) {
|
||||
|
@ -82,13 +82,13 @@ export class DownloadService {
|
|||
|
||||
/**
|
||||
* Downloads the entity to the user's system. This handles everything around downloads. This will prompt the user based on size checks and UserPreferences.PromptForDownload.
|
||||
* This will perform the download at a global level, if you need a handle to the download in question, use downloadService.activeDownloads$ and perform a filter on it.
|
||||
* @param entityType
|
||||
* @param entity
|
||||
* This will perform the download at a global level, if you need a handle to the download in question, use downloadService.activeDownloads$ and perform a filter on it.
|
||||
* @param entityType
|
||||
* @param entity
|
||||
* @param callback Optional callback. Returns the download or undefined (if the download is complete).
|
||||
*/
|
||||
download(entityType: DownloadEntityType, entity: DownloadEntity, callback?: (d: Download | undefined) => void) {
|
||||
let sizeCheckCall: Observable<number>;
|
||||
let sizeCheckCall: Observable<number>;
|
||||
let downloadCall: Observable<Download>;
|
||||
switch (entityType) {
|
||||
case 'series':
|
||||
|
@ -155,10 +155,10 @@ export class DownloadService {
|
|||
private downloadLogs() {
|
||||
const downloadType = 'logs';
|
||||
const subtitle = this.downloadSubtitle(downloadType, undefined);
|
||||
return this.httpClient.get(this.baseUrl + 'server/logs',
|
||||
return this.httpClient.get(this.baseUrl + 'server/logs',
|
||||
{observe: 'events', responseType: 'blob', reportProgress: true}
|
||||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
|
@ -170,10 +170,10 @@ export class DownloadService {
|
|||
private downloadSeries(series: Series) {
|
||||
const downloadType = 'series';
|
||||
const subtitle = this.downloadSubtitle(downloadType, series);
|
||||
return this.httpClient.get(this.baseUrl + 'download/series?seriesId=' + series.id,
|
||||
return this.httpClient.get(this.baseUrl + 'download/series?seriesId=' + series.id,
|
||||
{observe: 'events', responseType: 'blob', reportProgress: true}
|
||||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
|
@ -209,11 +209,12 @@ export class DownloadService {
|
|||
private downloadChapter(chapter: Chapter) {
|
||||
const downloadType = 'chapter';
|
||||
const subtitle = this.downloadSubtitle(downloadType, chapter);
|
||||
return this.httpClient.get(this.baseUrl + 'download/chapter?chapterId=' + chapter.id,
|
||||
return this.httpClient.get(this.baseUrl + 'download/chapter?chapterId=' + chapter.id,
|
||||
{observe: 'events', responseType: 'blob', reportProgress: true}
|
||||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
console.log('saving: ', filename)
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
|
@ -224,10 +225,10 @@ export class DownloadService {
|
|||
private downloadVolume(volume: Volume): Observable<Download> {
|
||||
const downloadType = 'volume';
|
||||
const subtitle = this.downloadSubtitle(downloadType, volume);
|
||||
return this.httpClient.get(this.baseUrl + 'download/volume?volumeId=' + volume.id,
|
||||
return this.httpClient.get(this.baseUrl + 'download/volume?volumeId=' + volume.id,
|
||||
{observe: 'events', responseType: 'blob', reportProgress: true}
|
||||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
|
@ -244,10 +245,10 @@ export class DownloadService {
|
|||
const downloadType = 'bookmark';
|
||||
const subtitle = this.downloadSubtitle(downloadType, bookmarks);
|
||||
|
||||
return this.httpClient.post(this.baseUrl + 'download/bookmarks', {bookmarks},
|
||||
return this.httpClient.post(this.baseUrl + 'download/bookmarks', {bookmarks},
|
||||
{observe: 'events', responseType: 'blob', reportProgress: true}
|
||||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue