const MEDIA_PROXY_PATH = "/api/media/proxy"; /** 浏览器可直接加载的公开图床,无需经 MinIO 代理缓存 */ const DIRECT_MEDIA_HOSTS = [ "images.unsplash.com", "unsplash.com", "i.pravatar.cc", "api.dicebear.com", "logo.clearbit.com", "avatars.githubusercontent.com", ]; function configuredMinioPublicUrl(): string { return ( process.env.NEXT_PUBLIC_MINIO_PUBLIC_URL || process.env.MINIO_PUBLIC_URL || "" ).replace(/\/$/, ""); } function isDirectMediaHost(hostname: string): boolean { const host = hostname.toLowerCase(); return DIRECT_MEDIA_HOSTS.some( (allowed) => host === allowed || host.endsWith(`.${allowed}`) ); } export function isExternalMediaUrl(value: string): boolean { return /^https?:\/\//i.test(value); } export function isMinioUrl(value: string): boolean { const publicUrl = configuredMinioPublicUrl(); return Boolean(publicUrl && value.startsWith(`${publicUrl}/`)); } export function mediaUrl(value?: string | null): string { const url = String(value || "").trim(); if (!url) return ""; if (/^(data:|blob:|#|mailto:|tel:)/i.test(url)) return url; if (/^file:/i.test(url)) return ""; if (url.startsWith("/") && !url.startsWith("//")) { const publicUrl = configuredMinioPublicUrl(); return publicUrl ? `${publicUrl}${url}` : url; } if (!isExternalMediaUrl(url)) return url; if (isMinioUrl(url)) return url; try { const parsed = new URL(url); if (isDirectMediaHost(parsed.hostname)) return url; } catch { return ""; } return `${MEDIA_PROXY_PATH}?src=${encodeURIComponent(url)}`; } export function mediaUrls(values: string[]): string[] { return values.map(mediaUrl).filter(Boolean); }