diff --git a/src/components/ProxyImage.tsx b/src/components/ProxyImage.tsx index 7f9e2fa..e8a16d2 100644 --- a/src/components/ProxyImage.tsx +++ b/src/components/ProxyImage.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { + clearBangumiImageFallbackCacheIfFailed, processImageUrl, tryApplyBangumiImageFallback, tryApplyDoubanImageFallback, @@ -65,6 +66,11 @@ const ProxyImage: React.FC = ({ return; } + if (clearBangumiImageFallbackCacheIfFailed(img, originalSrc)) { + setCurrentSrc(processImageUrl(originalSrc)); + return; + } + if (retryOnError && !img.dataset.retried) { img.dataset.retried = 'true'; window.setTimeout(() => { diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index f55b7dd..2bf72f8 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -35,6 +35,7 @@ import { import { isNetdiskSource } from '@/lib/netdisk/source'; import { base58Decode, + clearBangumiImageFallbackCacheIfFailed, getBangumiImageFallbackUrl, getDoubanImageFallbackUrl, markBangumiImageFallbackActive, @@ -981,6 +982,14 @@ const VideoCard = forwardRef( return; } + if ( + clearBangumiImageFallbackCacheIfFailed(img, actualPoster) + ) { + clearBangumiImageTimeout(); + setDisplayPoster(processedPoster); + return; + } + // 图片加载失败时的重试机制 if (!img.dataset.retried) { img.dataset.retried = 'true'; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 85db5d2..3396eda 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -233,6 +233,47 @@ export function markBangumiImageFallbackActive(): void { ); } +function normalizeComparableUrl(url: string): string { + if (typeof window === 'undefined') return url; + + try { + return new URL(url, window.location.href).href; + } catch { + return url; + } +} + +export function clearBangumiImageFallbackCacheIfFailed( + target: HTMLImageElement, + originalUrl: string +): boolean { + if (!originalUrl || !isBangumiImageUrl(originalUrl)) { + return false; + } + + const fallbackUrl = getBangumiImageFallbackUrl(originalUrl); + if (!fallbackUrl) { + return false; + } + + const normalizedFallbackUrl = normalizeComparableUrl(fallbackUrl); + const failedUrls = [target.currentSrc, target.src] + .filter(Boolean) + .map(normalizeComparableUrl); + const isFallbackFailure = + target.dataset.bangumiBackupTried === 'true' || + failedUrls.includes(normalizedFallbackUrl); + + if (!isFallbackFailure) { + return false; + } + + target.dataset.bangumiBackupFailed = 'true'; + delete target.dataset.bangumiBackupTried; + clearBangumiImageFallbackCache(); + return true; +} + function isBangumiImageFallbackActive(): boolean { if (typeof window === 'undefined') return false; @@ -329,6 +370,10 @@ export function tryApplyBangumiImageFallback( return false; } + if (target.dataset.bangumiBackupFailed === 'true') { + return false; + } + const fallbackUrl = getBangumiImageFallbackUrl(originalUrl); if ( !fallbackUrl ||