'use client'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { processImageUrl, tryApplyBangumiImageFallback, tryApplyDoubanImageFallback, } from '@/lib/utils'; interface ProxyImageProps extends React.ImgHTMLAttributes { originalSrc: string; displaySrc?: string; retryDelay?: number; retryOnError?: boolean; } const ProxyImage: React.FC = ({ 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(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) => { 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 ( ); }; export default ProxyImage;