Throw a toastr on matched metadata page when there is a rate limit issue.

This commit is contained in:
Joseph Milazzo 2025-06-20 16:03:27 -05:00
parent 224e839dad
commit 3a01e9af3a
6 changed files with 55 additions and 11 deletions

View file

@ -386,6 +386,9 @@ public class ExternalMetadataService : IExternalMetadataService
{
// We can't rethrow because Fix match is done in a background thread and Hangfire will requeue multiple times
_logger.LogInformation(ex, "Rate limit hit for matching {SeriesName} with Kavita+", series.Name);
// Fire SignalR event about this
await _eventHub.SendMessageAsync(MessageFactory.ExternalMatchRateLimitError,
MessageFactory.ExternalMatchRateLimitErrorEvent(series.Id, series.Name));
}
}

View file

@ -152,6 +152,10 @@ public static class MessageFactory
/// A Person merged has been merged into another
/// </summary>
public const string PersonMerged = "PersonMerged";
/// <summary>
/// A Rate limit error was hit when matching a series with Kavita+
/// </summary>
public const string ExternalMatchRateLimitError = "ExternalMatchRateLimitError";
public static SignalRMessage DashboardUpdateEvent(int userId)
{
@ -679,4 +683,16 @@ public static class MessageFactory
},
};
}
public static SignalRMessage ExternalMatchRateLimitErrorEvent(int seriesId, string seriesName)
{
return new SignalRMessage()
{
Name = ExternalMatchRateLimitError,
Body = new
{
seriesId = seriesId,
seriesName = seriesName,
},
};
}
}

View file

@ -0,0 +1,4 @@
export interface ExternalMatchRateLimitErrorEvent {
seriesId: number;
seriesName: string;
}

View file

@ -1,15 +1,16 @@
import { Injectable } from '@angular/core';
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
import { BehaviorSubject, ReplaySubject } from 'rxjs';
import { environment } from 'src/environments/environment';
import { LibraryModifiedEvent } from '../_models/events/library-modified-event';
import { NotificationProgressEvent } from '../_models/events/notification-progress-event';
import { ThemeProgressEvent } from '../_models/events/theme-progress-event';
import { UserUpdateEvent } from '../_models/events/user-update-event';
import { User } from '../_models/user';
import {Injectable} from '@angular/core';
import {HubConnection, HubConnectionBuilder} from '@microsoft/signalr';
import {BehaviorSubject, ReplaySubject} from 'rxjs';
import {environment} from 'src/environments/environment';
import {LibraryModifiedEvent} from '../_models/events/library-modified-event';
import {NotificationProgressEvent} from '../_models/events/notification-progress-event';
import {ThemeProgressEvent} from '../_models/events/theme-progress-event';
import {UserUpdateEvent} from '../_models/events/user-update-event';
import {User} from '../_models/user';
import {DashboardUpdateEvent} from "../_models/events/dashboard-update-event";
import {SideNavUpdateEvent} from "../_models/events/sidenav-update-event";
import {SiteThemeUpdatedEvent} from "../_models/events/site-theme-updated-event";
import {ExternalMatchRateLimitErrorEvent} from "../_models/events/external-match-rate-limit-error-event";
export enum EVENTS {
UpdateAvailable = 'UpdateAvailable',
@ -114,6 +115,10 @@ export enum EVENTS {
* A Person merged has been merged into another
*/
PersonMerged = 'PersonMerged',
/**
* A Rate limit error was hit when matching a series with Kavita+
*/
ExternalMatchRateLimitError = 'ExternalMatchRateLimitError'
}
export interface Message<T> {
@ -236,6 +241,13 @@ export class MessageHubService {
});
});
this.hubConnection.on(EVENTS.ExternalMatchRateLimitError, resp => {
this.messagesSource.next({
event: EVENTS.ExternalMatchRateLimitError,
payload: resp.body as ExternalMatchRateLimitErrorEvent
});
});
this.hubConnection.on(EVENTS.NotificationProgress, (resp: NotificationProgressEvent) => {
this.messagesSource.next({
event: EVENTS.NotificationProgress,

View file

@ -1,7 +1,7 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit} from '@angular/core';
import {LicenseService} from "../../_services/license.service";
import {Router} from "@angular/router";
import {TranslocoDirective} from "@jsverse/transloco";
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {ImageComponent} from "../../shared/image/image.component";
import {ImageService} from "../../_services/image.service";
import {Series} from "../../_models/series";
@ -23,6 +23,8 @@ import {EVENTS, MessageHubService} from "../../_services/message-hub.service";
import {ScanSeriesEvent} from "../../_models/events/scan-series-event";
import {LibraryTypePipe} from "../../_pipes/library-type.pipe";
import {allKavitaPlusMetadataApplicableTypes} from "../../_models/library/library";
import {ExternalMatchRateLimitErrorEvent} from "../../_models/events/external-match-rate-limit-error-event";
import {ToastrService} from "ngx-toastr";
@Component({
selector: 'app-manage-matched-metadata',
@ -55,6 +57,7 @@ export class ManageMatchedMetadataComponent implements OnInit {
private readonly manageService = inject(ManageService);
private readonly messageHub = inject(MessageHubService);
private readonly cdRef = inject(ChangeDetectorRef);
private readonly toastr = inject(ToastrService);
protected readonly imageService = inject(ImageService);
@ -81,6 +84,11 @@ export class ManageMatchedMetadataComponent implements OnInit {
}
}
if (message.event == EVENTS.ExternalMatchRateLimitError) {
const evt = message.payload as ExternalMatchRateLimitErrorEvent;
this.toastr.error(translate('toasts.external-match-rate-error', {seriesName: evt.seriesName}))
}
});

View file

@ -2743,7 +2743,8 @@
"webtoon-override": "Switching to Webtoon mode due to images representing a webtoon.",
"scrobble-gen-init": "Enqueued a job to generate scrobble events from past reading history and ratings, syncing them with connected services.",
"series-bound-to-reading-profile": "Series bound to Reading Profile {{name}}",
"library-bound-to-reading-profile": "Library bound to Reading Profile {{name}}"
"library-bound-to-reading-profile": "Library bound to Reading Profile {{name}}",
"external-match-rate-error": "Kavita ran out of rate looking up {{seriesName}}. Try again in 5 minutes."
},
"read-time-pipe": {