More Fixes (#1993)
* Strip just isbn: from epub isbns and log when it's back (books) * Tweaked to allow invalid GTINs but only valid ISBN 10/13s will be saved to Kavita. * Fixed a bug with parsing series from a filename that is just a chapter range and no chapter/volume keywords. * Show the media issue count before you open accordion * Added a inpage filter for Media issues * Cleanup styles * Fixed up some code in epub isbn parsing when it's null * Encode filenames when downloading so that non english characters can be passed properly to UI. * Added support to parse ComicInfo's with Empty Tags. * Reset development settings. * Tweaked the code in generating reading lists to avoid extra work when not needed. * Fix comicvine's favicon * Fixed up a unit test * Tweaked the favicon code to ignore icons that have query parameters * More favicon work. Expanded ability to grab icons a bit. Added in ability to not keep requesting favicons when we failed to parse already. * Added a note for later * Fixed stats server url * Added more debugging * Fixed unit tests
This commit is contained in:
parent
cd8fca993b
commit
25703d6fe0
27 changed files with 171 additions and 75 deletions
|
|
@ -1,6 +1,16 @@
|
|||
<p>This table contains issues found during scan or reading of your media. This list is non-managed. You can clear it at any time and use Library (Force) Scan to perform analysis.</p>
|
||||
|
||||
<button class="btn btn-primary mb-2" (click)="clear()">Clear Alerts</button>
|
||||
<form [formGroup]="formGroup">
|
||||
<div class="row g-0 mb-3">
|
||||
<div class="col-md-12">
|
||||
<label for="filter" class="visually-hidden">Filter</label>
|
||||
<div class="input-group">
|
||||
<input id="filter" type="text" class="form-control" placeholder="Filter" formControlName="filter" />
|
||||
<button class="btn btn-primary" type="button" (click)="clear()">Clear Alerts</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="table table-light table-hover table-sm table-hover">
|
||||
<thead #header>
|
||||
<tr>
|
||||
|
|
@ -20,20 +30,22 @@
|
|||
</thead>
|
||||
<tbody #container>
|
||||
<tr *ngIf="isLoading"><td colspan="4" style="text-align: center;"><app-loading [loading]="isLoading"></app-loading></td></tr>
|
||||
<tr *ngIf="data.length === 0 && !isLoading"><td colspan="4" style="text-align: center;">No issues</td></tr>
|
||||
<tr *ngFor="let item of data; index as i">
|
||||
<td>
|
||||
{{item.extension}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.filePath}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.comment}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.details}}
|
||||
</td>
|
||||
</tr>
|
||||
<ng-container *ngIf="data | filter: filterList as filteredData">
|
||||
<tr *ngIf="filteredData.length === 0 && !isLoading"><td colspan="4" style="text-align: center;">No issues</td></tr>
|
||||
<tr *ngFor="let item of filteredData; index as i">
|
||||
<td>
|
||||
{{item.extension}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.filePath}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.comment}}
|
||||
</td>
|
||||
<td>
|
||||
{{item.details}}
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, QueryList, ViewChildren, inject } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, Output, QueryList, ViewChildren, inject } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject, combineLatest, filter, map, shareReplay, takeUntil } from 'rxjs';
|
||||
import { SortEvent, SortableHeader, compare } from 'src/app/_single-module/table/_directives/sortable-header.directive';
|
||||
import { KavitaMediaError } from '../_models/media-error';
|
||||
import { ServerService } from 'src/app/_services/server.service';
|
||||
import { EVENTS, MessageHubService } from 'src/app/_services/message-hub.service';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-alerts',
|
||||
|
|
@ -13,6 +14,7 @@ import { EVENTS, MessageHubService } from 'src/app/_services/message-hub.service
|
|||
})
|
||||
export class ManageAlertsComponent implements OnInit {
|
||||
|
||||
@Output() alertCount = new EventEmitter<number>();
|
||||
@ViewChildren(SortableHeader<KavitaMediaError>) headers!: QueryList<SortableHeader<KavitaMediaError>>;
|
||||
private readonly serverService = inject(ServerService);
|
||||
private readonly messageHub = inject(MessageHubService);
|
||||
|
|
@ -25,6 +27,9 @@ export class ManageAlertsComponent implements OnInit {
|
|||
|
||||
data: Array<KavitaMediaError> = [];
|
||||
isLoading = true;
|
||||
formGroup = new FormGroup({
|
||||
filter: new FormControl('', [])
|
||||
});
|
||||
|
||||
|
||||
constructor() {}
|
||||
|
|
@ -63,8 +68,7 @@ export class ManageAlertsComponent implements OnInit {
|
|||
this.serverService.getMediaErrors().subscribe(d => {
|
||||
this.data = d;
|
||||
this.isLoading = false;
|
||||
console.log(this.data)
|
||||
console.log(this.isLoading)
|
||||
this.alertCount.emit(d.length);
|
||||
this.cdRef.detectChanges();
|
||||
});
|
||||
}
|
||||
|
|
@ -72,4 +76,9 @@ export class ManageAlertsComponent implements OnInit {
|
|||
clear() {
|
||||
this.serverService.clearMediaAlerts().subscribe(_ => this.loadData());
|
||||
}
|
||||
|
||||
filterList = (listItem: KavitaMediaError) => {
|
||||
const query = (this.formGroup.get('filter')?.value || '').toLowerCase();
|
||||
return listItem.comment.toLowerCase().indexOf(query) >= 0 || listItem.filePath.toLowerCase().indexOf(query) >= 0 || listItem.details.indexOf(query) >= 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@
|
|||
</div>
|
||||
</form>
|
||||
|
||||
<ngb-accordion #a="ngbAccordion">
|
||||
<ngb-accordion #a="ngbAccordion" [destroyOnHide]="false">
|
||||
<ngb-panel>
|
||||
<ng-template ngbPanelTitle>
|
||||
Media Issues
|
||||
Media Issues <span class="ms-1" *ngIf="alertCount > 0">({{alertCount}})</span>
|
||||
</ng-template>
|
||||
<ng-template ngbPanelContent>
|
||||
<app-manage-alerts></app-manage-alerts>
|
||||
<app-manage-alerts (alertCount)="alertCount = $event"></app-manage-alerts>
|
||||
</ng-template>
|
||||
</ngb-panel>
|
||||
</ngb-accordion>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ export class ManageMediaSettingsComponent implements OnInit {
|
|||
serverSettings!: ServerSettings;
|
||||
settingsForm: FormGroup = new FormGroup({});
|
||||
|
||||
alertCount: number = 0;
|
||||
|
||||
get EncodeFormats() { return EncodeFormats; }
|
||||
|
||||
constructor(private settingsService: SettingsService, private toastr: ToastrService, private modalService: NgbModal, ) { }
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ export class DownloadService {
|
|||
private downloadsSource: BehaviorSubject<DownloadEvent[]> = new BehaviorSubject<DownloadEvent[]>([]);
|
||||
public activeDownloads$ = this.downloadsSource.asObservable();
|
||||
|
||||
|
||||
constructor(private httpClient: HttpClient, private confirmService: ConfirmService,
|
||||
@Inject(SAVER) private save: Saver, private accountService: AccountService) { }
|
||||
|
||||
|
|
@ -159,7 +160,7 @@ export class DownloadService {
|
|||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, filename);
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
finalize(() => this.finalizeDownloadState(downloadType, subtitle))
|
||||
|
|
@ -174,7 +175,7 @@ export class DownloadService {
|
|||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, filename);
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
finalize(() => this.finalizeDownloadState(downloadType, subtitle))
|
||||
|
|
@ -213,7 +214,7 @@ export class DownloadService {
|
|||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, filename);
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
finalize(() => this.finalizeDownloadState(downloadType, subtitle))
|
||||
|
|
@ -228,7 +229,7 @@ export class DownloadService {
|
|||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, filename);
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
finalize(() => this.finalizeDownloadState(downloadType, subtitle))
|
||||
|
|
@ -248,7 +249,7 @@ export class DownloadService {
|
|||
).pipe(
|
||||
throttleTime(DEBOUNCE_TIME, asyncScheduler, { leading: true, trailing: true }),
|
||||
download((blob, filename) => {
|
||||
this.save(blob, filename);
|
||||
this.save(blob, decodeURIComponent(filename));
|
||||
}),
|
||||
tap((d) => this.updateDownloadState(d, downloadType, subtitle)),
|
||||
finalize(() => this.finalizeDownloadState(downloadType, subtitle))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue