91 lines
2.0 KiB
TypeScript
91 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import {
|
|
processImageUrl,
|
|
tryApplyBangumiImageFallback,
|
|
tryApplyDoubanImageFallback,
|
|
} from '@/lib/utils';
|
|
|
|
interface ProxyImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
|
|
originalSrc: string;
|
|
displaySrc?: string;
|
|
retryDelay?: number;
|
|
retryOnError?: boolean;
|
|
}
|
|
|
|
const ProxyImage: React.FC<ProxyImageProps> = ({
|
|
originalSrc,
|
|
displaySrc,
|
|
retryDelay = 2000,
|
|
retryOnError = true,
|
|
loading = 'lazy',
|
|
decoding = 'async',
|
|
onError,
|
|
src: _src,
|
|
...props
|
|
}) => {
|
|
const initialSrc = useMemo(
|
|
() => displaySrc || processImageUrl(originalSrc),
|
|
[displaySrc, originalSrc]
|
|
);
|
|
const [currentSrc, setCurrentSrc] = useState(initialSrc);
|
|
const imgRef = useRef<HTMLImageElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
setCurrentSrc(initialSrc);
|
|
}, [initialSrc]);
|
|
|
|
useEffect(() => {
|
|
if (displaySrc) return;
|
|
|
|
const timer = window.setTimeout(() => {
|
|
const img = imgRef.current;
|
|
if (!img || img.complete || img.dataset.bangumiBackupTried === 'true') {
|
|
return;
|
|
}
|
|
|
|
if (tryApplyBangumiImageFallback(img, originalSrc)) {
|
|
setCurrentSrc(img.src);
|
|
}
|
|
}, 5000);
|
|
|
|
return () => window.clearTimeout(timer);
|
|
}, [currentSrc, displaySrc, originalSrc]);
|
|
|
|
const handleError = (e: React.SyntheticEvent<HTMLImageElement, Event>) => {
|
|
const img = e.currentTarget;
|
|
|
|
if (
|
|
tryApplyDoubanImageFallback(img, originalSrc) ||
|
|
tryApplyBangumiImageFallback(img, originalSrc)
|
|
) {
|
|
setCurrentSrc(img.src);
|
|
return;
|
|
}
|
|
|
|
if (retryOnError && !img.dataset.retried) {
|
|
img.dataset.retried = 'true';
|
|
window.setTimeout(() => {
|
|
setCurrentSrc(initialSrc);
|
|
}, retryDelay);
|
|
}
|
|
|
|
onError?.(e);
|
|
};
|
|
|
|
return (
|
|
<img
|
|
{...props}
|
|
ref={imgRef}
|
|
src={currentSrc}
|
|
loading={loading}
|
|
decoding={decoding}
|
|
onError={handleError}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default ProxyImage;
|