import { useState, type SyntheticEvent } from 'react' import { PICGO_CLOUD_UPLOADER_TYPE } from '#/utils/static' import { usePicGoCloudBillingQuery } from '@/queries/picgo-cloud-billing' import { PICGO_CLOUD_IMAGE_UNAVAILABLE_SVG_FILENAME, PREVIEW_UNAVAILABLE_SVG_FILENAME } from '@/utils/consts' import { getRendererStaticFileUrl } from '@/utils/static' export const PICGO_CLOUD_UNAVAILABLE_SVG_URL = getRendererStaticFileUrl( PICGO_CLOUD_IMAGE_UNAVAILABLE_SVG_FILENAME ) export const PREVIEW_UNAVAILABLE_SVG_URL = getRendererStaticFileUrl( PREVIEW_UNAVAILABLE_SVG_FILENAME ) /** * 解析图片的最终展示地址,处理两类失败场景: * - PicGo Cloud + lifecycle ∈ {frozen, pending_cleanup}:直接返回 PicGo Cloud 专属占位 * SVG(避免远端 503 / 破图)。仅在 type === PICGO_CLOUD_UPLOADER_TYPE 时生效。 * - 任意 type + 图片实际加载失败(onError 触发):返回通用「Preview unavailable」占位。 * 覆盖非图片文件(txt 等)、自定义域名失效、临时网络异常等。 * * motion.img / 自定义 img 渲染器无法直接复用 `CloudImage` 组件,可改用此 hook: * const { src, onError } = useCloudImageSrc(photo.type, photo.imgUrl) * */ export function useCloudImageSrc ( type: string | undefined, originalSrc: string | undefined ): { src: string | undefined onError: (event?: SyntheticEvent) => void } { const { data: billing } = usePicGoCloudBillingQuery() const phase = billing?.lifecycle?.phase const isPicGoCloud = type === PICGO_CLOUD_UPLOADER_TYPE const isBlocked = isPicGoCloud && (phase === 'frozen' || phase === 'pending_cleanup') // failedSrc 记住"上次失败的 src",originalSrc 变化时自动失效(preview 切图场景) const [failedSrc, setFailedSrc] = useState(undefined) const isLoadFailed = failedSrc !== undefined && failedSrc === originalSrc let src = originalSrc if (isBlocked) { src = PICGO_CLOUD_UNAVAILABLE_SVG_URL } else if (isLoadFailed) { src = PREVIEW_UNAVAILABLE_SVG_URL } return { src, onError: () => { if (!isBlocked && !isLoadFailed) { setFailedSrc(originalSrc) } } } }