Ignore source/extension, tracker icon and thumbnails requests from image queue

The server is not requesting these images through an extension; thus, it is not a problem to send them directly to the server since there is no problem of getting the server "stuck" due to extension rate limits.
This commit is contained in:
schroda
2025-11-22 17:28:56 +01:00
parent 9ed05f3fc0
commit 890b304b4a
11 changed files with 60 additions and 22 deletions

View File

@@ -38,6 +38,7 @@ export interface SpinnerImageProps {
shouldDecode?: boolean; shouldDecode?: boolean;
useFetchApi?: boolean; useFetchApi?: boolean;
disableCors?: boolean; disableCors?: boolean;
ignoreQueue?: boolean;
priority?: Priority; priority?: Priority;
@@ -52,6 +53,7 @@ export const SpinnerImage = ({ ref, ...props }: SpinnerImageProps) => {
shouldDecode, shouldDecode,
useFetchApi, useFetchApi,
disableCors, disableCors,
ignoreQueue,
src, src,
alt, alt,
onLoad, onLoad,
@@ -111,6 +113,7 @@ export const SpinnerImage = ({ ref, ...props }: SpinnerImageProps) => {
shouldDecode, shouldDecode,
useFetchApi, useFetchApi,
disableCors, disableCors,
ignoreQueue,
}); });
if (!imageRequest.fromCache) { if (!imageRequest.fromCache) {

View File

@@ -102,7 +102,15 @@ export function ExtensionCard(props: IProps) {
<Card> <Card>
<OptionalCardActionAreaLink disabled={!isInstalled} to={AppRoutes.extension.childRoutes.info.path(pkgName)}> <OptionalCardActionAreaLink disabled={!isInstalled} to={AppRoutes.extension.childRoutes.info.path(pkgName)}>
<ListCardContent> <ListCardContent>
<ListCardAvatar iconUrl={requestManager.getValidImgUrlFor(iconUrl)} alt={name} /> <ListCardAvatar
iconUrl={requestManager.getValidImgUrlFor(iconUrl)}
alt={name}
slots={{
spinnerImageProps: {
ignoreQueue: true,
},
}}
/>
<Stack <Stack
sx={{ sx={{
justifyContent: 'center', justifyContent: 'center',

View File

@@ -67,7 +67,15 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
state={{ contentType: SourceContentType.POPULAR, clearCache: true }} state={{ contentType: SourceContentType.POPULAR, clearCache: true }}
> >
<ListCardContent> <ListCardContent>
<ListCardAvatar iconUrl={requestManager.getValidImgUrlFor(iconUrl)} alt={sourceName} /> <ListCardAvatar
iconUrl={requestManager.getValidImgUrlFor(iconUrl)}
alt={sourceName}
slots={{
spinnerImageProps: {
ignoreQueue: true,
},
}}
/>
<Stack <Stack
sx={{ sx={{
justifyContent: 'center', justifyContent: 'center',

View File

@@ -14,7 +14,7 @@ import { TExtension } from '@/features/extension/Extensions.types.ts';
export const Header = ({ name, pkgName, iconUrl, repo }: TExtension) => ( export const Header = ({ name, pkgName, iconUrl, repo }: TExtension) => (
<Stack sx={{ alignItems: 'center' }}> <Stack sx={{ alignItems: 'center' }}>
<SpinnerImage alt={name} src={requestManager.getValidImgUrlFor(iconUrl)} /> <SpinnerImage alt={name} src={requestManager.getValidImgUrlFor(iconUrl)} ignoreQueue />
<Typography variant="h5" component="h2"> <Typography variant="h5" component="h2">
{name} {name}
</Typography> </Typography>

View File

@@ -36,7 +36,15 @@ export const MigrationCard = ({ id, name, lang, iconUrl, mangaCount }: TMigratab
<CardActionArea component={Link} to={AppRoutes.migrate.path(id)}> <CardActionArea component={Link} to={AppRoutes.migrate.path(id)}>
<ListCardContent sx={{ justifyContent: 'space-between' }}> <ListCardContent sx={{ justifyContent: 'space-between' }}>
<Box sx={{ display: 'flex', gap: 1 }}> <Box sx={{ display: 'flex', gap: 1 }}>
<ListCardAvatar iconUrl={requestManager.getValidImgUrlFor(iconUrl)} alt={sourceName} /> <ListCardAvatar
iconUrl={requestManager.getValidImgUrlFor(iconUrl)}
alt={sourceName}
slots={{
spinnerImageProps: {
ignoreQueue: true,
},
}}
/>
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> <Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
<Typography variant="h6" component="h3"> <Typography variant="h6" component="h3">
{sourceName} {sourceName}

View File

@@ -147,6 +147,9 @@ export const SourceLanguageSelect = ({
height: 32, height: 32,
}, },
}, },
spinnerImageProps: {
ignoreQueue: true,
},
}} }}
/> />
</ListItemAvatar> </ListItemAvatar>

View File

@@ -91,6 +91,9 @@ export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) =>
variant: 'rounded', variant: 'rounded',
sx: { width: 64, height: 64 }, sx: { width: 64, height: 64 },
}, },
spinnerImageProps: {
ignoreQueue: true,
},
}} }}
/> />
</ListItemAvatar> </ListItemAvatar>

View File

@@ -211,6 +211,9 @@ const TrackerActiveHeader = ({
variant: 'rounded', variant: 'rounded',
sx: { width: 64, height: 64 }, sx: { width: 64, height: 64 },
}, },
spinnerImageProps: {
ignoreQueue: true,
},
}} }}
/> />
</TrackerActiveLink> </TrackerActiveLink>

View File

@@ -156,6 +156,7 @@ export const TrackerMangaCard = ({
<SpinnerImage <SpinnerImage
useFetchApi={false} useFetchApi={false}
disableCors disableCors
ignoreQueue
alt={manga.title} alt={manga.title}
src={manga.coverUrl} src={manga.coverUrl}
spinnerStyle={{ width: '100%', height: '100%' }} spinnerStyle={{ width: '100%', height: '100%' }}

View File

@@ -43,6 +43,9 @@ export const TrackerUntrackedCard = ({
variant: 'rounded', variant: 'rounded',
sx: { width: 64, height: 64 }, sx: { width: 64, height: 64 },
}, },
spinnerImageProps: {
ignoreQueue: true,
},
}} }}
/> />
<Button sx={{ flexGrow: '1' }} onClick={onClick}> <Button sx={{ flexGrow: '1' }} onClick={onClick}>

View File

@@ -392,6 +392,12 @@ type SubscriptionHookOptions<Data = any, Variables extends OperationVariables =
type AbortableRequest = { abortRequest: AbortController['abort'] }; type AbortableRequest = { abortRequest: AbortController['abort'] };
export type ImageRequest = { response: Promise<string>; cleanup: () => void; fromCache: boolean } & AbortableRequest; export type ImageRequest = { response: Promise<string>; cleanup: () => void; fromCache: boolean } & AbortableRequest;
type ImageRequestOptions = {
priority?: QueuePriority;
shouldDecode?: boolean;
disableCors?: boolean;
ignoreQueue?: boolean;
};
export type AbortabaleApolloQueryResponse<Data = any> = { export type AbortabaleApolloQueryResponse<Data = any> = {
response: Promise<ApolloQueryResult<MaybeMasked<Data>>>; response: Promise<ApolloQueryResult<MaybeMasked<Data>>>;
@@ -934,13 +940,15 @@ export class RequestManager {
url: string, url: string,
request: () => Promise<T>, request: () => Promise<T>,
priority?: QueuePriority, priority?: QueuePriority,
ignoreQueue?: boolean,
): Promise<ReturnType<typeof this.imageQueue.enqueue<T>> & { fromCache?: boolean }> { ): Promise<ReturnType<typeof this.imageQueue.enqueue<T>> & { fromCache?: boolean }> {
try { try {
if (await ImageCache.has(url)) { const isCached = await ImageCache.has(url);
if (!!ignoreQueue || isCached) {
return { return {
key: `image-cache-${url}`, key: `image-cache-${url}`,
promise: request(), promise: request(),
fromCache: true, fromCache: isCached,
}; };
} }
@@ -952,11 +960,7 @@ export class RequestManager {
private async fetchImageViaTag( private async fetchImageViaTag(
url: string, url: string,
{ { priority, shouldDecode, disableCors, ignoreQueue }: ImageRequestOptions = {},
priority,
shouldDecode,
disableCors,
}: { priority?: QueuePriority; shouldDecode?: boolean; disableCors?: boolean } = {},
): Promise<ImageRequest> { ): Promise<ImageRequest> {
const imgRequest = new ControlledPromise<string>(); const imgRequest = new ControlledPromise<string>();
imgRequest.promise.catch(() => {}); imgRequest.promise.catch(() => {});
@@ -1000,6 +1004,7 @@ export class RequestManager {
return imgRequest.promise; return imgRequest.promise;
}, },
priority, priority,
ignoreQueue,
); );
return { return {
@@ -1025,11 +1030,7 @@ export class RequestManager {
*/ */
private async fetchImageViaFetchApi( private async fetchImageViaFetchApi(
url: string, url: string,
{ { priority, shouldDecode, disableCors, ignoreQueue }: ImageRequestOptions = {},
priority,
shouldDecode,
disableCors,
}: { priority?: QueuePriority; shouldDecode?: boolean; disableCors?: boolean } = {},
): Promise<ImageRequest> { ): Promise<ImageRequest> {
let objectUrl: string = ''; let objectUrl: string = '';
const { abortRequest, signal } = this.createAbortController(); const { abortRequest, signal } = this.createAbortController();
@@ -1059,6 +1060,7 @@ export class RequestManager {
return imageUrl; return imageUrl;
}), }),
priority, priority,
ignoreQueue,
); );
return { return {
@@ -1077,17 +1079,13 @@ export class RequestManager {
*/ */
public async requestImage( public async requestImage(
url: string, url: string,
options: { options: ImageRequestOptions & { useFetchApi?: boolean } = {},
priority?: QueuePriority;
useFetchApi?: boolean;
shouldDecode?: boolean;
disableCors?: boolean;
} = {},
): Promise<ImageRequest> { ): Promise<ImageRequest> {
const finalOptions = { const finalOptions = {
useFetchApi: AuthManager.isAuthRequired(), useFetchApi: AuthManager.isAuthRequired(),
shouldDecode: false, shouldDecode: false,
disableCors: false, disableCors: false,
ignoreQueue: false,
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined)), ...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined)),
}; };