Feature/performance pdf (#426)

#  Added
- Added: Added series format information to the search typeahead to help identify duplicate series in libraries

# Fixed
- Fixed: Fixed accent color not looking well on light theme
- Fixed: Attempted to fix the memory issues with PDF reading on Docker. Uses a Memory Pool for streams and removes a bitmap operation for fixing books with transparent backgrounds (#424)

# Changed
- Changed: Refactored download logs to use the same download code as rest of Kavita 

# Dev stuff
- Added timeout for Regex's to make sure during matching, malicious filenames doesn't crash user system
- Refactored a missing GetCoverImage to use Series Format rather than old Library Type

==================================================
* Added Timeout for Regex matching to ensure malicious filenames don't crash system

* Refactored GetCoverImage to use series format rather than library type

* Refactored download logs to use the download service

* Fixed accent color not looking well on light theme

* Refactored series format into dedicated component and added to search results

* Switch to using MemoryManager for Streams to attempt to minimize GC pressure and reduced bitmap manipulation for transparency hack.
This commit is contained in:
Joseph Milazzo 2021-07-24 16:17:13 -05:00 committed by GitHub
parent 78ad01f5ae
commit 81dfd63250
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 267 additions and 136 deletions

View file

@ -1,3 +1,5 @@
import { MangaFormat } from "./manga-format";
export interface SearchResult {
seriesId: number;
libraryId: number;
@ -6,4 +8,5 @@ export interface SearchResult {
originalName: string;
sortName: string;
coverImage: string; // byte64 encoded
format: MangaFormat;
}

View file

@ -16,10 +16,6 @@ export class ServerService {
return this.httpClient.post(this.baseUrl + 'server/restart', {});
}
fetchLogs() {
return this.httpClient.get(this.baseUrl + 'server/logs', {responseType: 'blob' as 'text'});
}
getServerInfo() {
return this.httpClient.get<ServerInfo>(this.baseUrl + 'server/server-info');
}

View file

@ -4,6 +4,7 @@ import { ToastrService } from 'ngx-toastr';
import { ServerService } from 'src/app/_services/server.service';
import { saveAs } from 'file-saver';
import { Title } from '@angular/platform-browser';
import { DownloadService } from 'src/app/shared/_services/download.service';
@ -23,7 +24,8 @@ export class DashboardComponent implements OnInit {
counter = this.tabs.length + 1;
active = this.tabs[0];
constructor(public route: ActivatedRoute, private serverService: ServerService, private toastr: ToastrService, private titleService: Title) {
constructor(public route: ActivatedRoute, private serverService: ServerService,
private toastr: ToastrService, private titleService: Title, private downloadService: DownloadService) {
this.route.fragment.subscribe(frag => {
const tab = this.tabs.filter(item => item.fragment === frag);
if (tab.length > 0) {
@ -46,10 +48,7 @@ export class DashboardComponent implements OnInit {
}
fetchLogs() {
this.serverService.fetchLogs().subscribe(res => {
const blob = new Blob([res], {type: 'text/plain;charset=utf-8'});
saveAs(blob, 'kavita.zip');
});
this.downloadService.downloadLogs();
}
}

View file

@ -1,11 +1,8 @@
@import '../../../assets/themes/dark.scss';
.accent {
font-style: italic;
font-size: 0.7rem;
background-color: $dark-form-background;
background-color: lightgray;
padding: 10px;
color: lightgray;
color: black;
border-radius: 6px;
box-shadow: inset 0px 0px 8px 1px $dark-form-background
}

View file

@ -34,6 +34,7 @@
<img class="mr-3 search-result" src="{{imageService.getSeriesCoverImage(item.seriesId)}}">
</div>
<div class="ml-1">
<app-series-format [format]="item.format"></app-series-format>
<span *ngIf="item.name.toLowerCase().indexOf(searchTerm) >= 0; else localizedName" [innerHTML]="item.name"></span>
<ng-template #localizedName>
<span [innerHTML]="item.localizedName"></span>

View file

@ -3,6 +3,7 @@ import { Component, HostListener, Inject, OnDestroy, OnInit, ViewChild } from '@
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { UtilityService } from '../shared/_services/utility.service';
import { SearchResult } from '../_models/search-result';
import { AccountService } from '../_services/account.service';
import { ImageService } from '../_services/image.service';

View file

@ -85,7 +85,7 @@
<h5>Type</h5>
</div>
<div class="col-md-8">
<app-tag-badge><i class="fa {{utilityService.mangaFormatIcon(series.format)}}" aria-hidden="true" title="{{utilityService.mangaFormat(series.format)}}"></i>&nbsp;{{utilityService.mangaFormat(series.format)}} </app-tag-badge>
<app-tag-badge><app-series-format [format]="series.format">{{utilityService.mangaFormat(series.format)}}</app-series-format></app-tag-badge>
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Series } from 'src/app/_models/series';
import { environment } from 'src/environments/environment';
@ -46,14 +46,18 @@ export class DownloadService {
return this.httpClient.get(this.baseUrl + 'download/chapter?chapterId=' + chapterId, {observe: 'response', responseType: 'blob' as 'text'});
}
downloadLogs() {
this.httpClient.get(this.baseUrl + 'server/logs', {observe: 'response', responseType: 'blob' as 'text'}).subscribe(resp => {
this.preformSave(resp.body || '', this.getFilenameFromHeader(resp.headers, 'logs'));
});
}
downloadSeries(series: Series) {
this.downloadSeriesSize(series.id).subscribe(async size => {
if (size >= this.SIZE_WARNING && !await this.confirmService.confirm('The series is ' + this.humanFileSize(size) + '. Are you sure you want to continue?')) {
return;
}
this.downloadSeriesAPI(series.id).subscribe(resp => {
//const filename = series.name + '.zip';
//this.preformSave(res, filename);
this.preformSave(resp.body || '', this.getFilenameFromHeader(resp.headers, series.name));
});
});

View file

@ -0,0 +1,4 @@
<ng-container *ngIf="format != MangaFormat.UNKNOWN">
<i class="fa {{utilityService.mangaFormatIcon(format)}}" aria-hidden="true" title="{{utilityService.mangaFormat(format)}}"></i>&nbsp;
<ng-content></ng-content>
</ng-container>

View file

@ -0,0 +1,23 @@
import { Component, Input, OnInit } from '@angular/core';
import { MangaFormat } from 'src/app/_models/manga-format';
import { UtilityService } from '../_services/utility.service';
@Component({
selector: 'app-series-format',
templateUrl: './series-format.component.html',
styleUrls: ['./series-format.component.scss']
})
export class SeriesFormatComponent implements OnInit {
@Input() format: MangaFormat = MangaFormat.UNKNOWN;
get MangaFormat(): typeof MangaFormat {
return MangaFormat;
}
constructor(public utilityService: UtilityService) { }
ngOnInit(): void {
}
}

View file

@ -16,6 +16,7 @@ import { TagBadgeComponent } from './tag-badge/tag-badge.component';
import { CardDetailLayoutComponent } from './card-detail-layout/card-detail-layout.component';
import { ShowIfScrollbarDirective } from './show-if-scrollbar.directive';
import { A11yClickDirective } from './a11y-click.directive';
import { SeriesFormatComponent } from './series-format/series-format.component';
@NgModule({
@ -31,7 +32,8 @@ import { A11yClickDirective } from './a11y-click.directive';
TagBadgeComponent,
CardDetailLayoutComponent,
ShowIfScrollbarDirective,
A11yClickDirective
A11yClickDirective,
SeriesFormatComponent
],
imports: [
CommonModule,
@ -54,7 +56,8 @@ import { A11yClickDirective } from './a11y-click.directive';
TagBadgeComponent,
CardDetailLayoutComponent,
ShowIfScrollbarDirective,
A11yClickDirective
A11yClickDirective,
SeriesFormatComponent
]
})
export class SharedModule { }

View file

@ -23,6 +23,12 @@ $dark-item-accent-bg: #292d32;
color: #4ac694;
}
.accent {
background-color: $dark-form-background !important;
color: lightgray !important;
box-shadow: inset 0px 0px 8px 1px $dark-form-background !important;
}
.breadcrumb {
background-color: $dark-item-accent-bg;