refactor(chat): tighten media cache boundaries

This commit is contained in:
2026-06-30 16:12:02 +08:00
parent ccd2d6bd48
commit 9cff16e2d9
17 changed files with 388 additions and 146 deletions
@@ -14,7 +14,12 @@ import { ChevronLeft } from "lucide-react";
import Image from "next/image";
import { useEffect } from "react";
import { useCachedChatMediaUrl } from "../hooks/use-cached-chat-media-url";
import {
isBrowserLocalChatImageSource,
normalizeChatImageSource,
} from "@/lib/chat/chat_media_url";
import { useCachedChatMediaUrl } from "@/lib/chat/use_cached_chat_media_url";
import styles from "./fullscreen-image-viewer.module.css";
export interface FullscreenImageViewerProps {
@@ -46,13 +51,8 @@ export function FullscreenImageViewer({
return () => document.removeEventListener("keydown", handleKey);
}, [onClose]);
const sourceUrl = mediaUrl || imageUrl;
const src = sourceUrl.startsWith("data:") ||
sourceUrl.startsWith("http") ||
sourceUrl.startsWith("blob:")
? sourceUrl
: `data:image/png;base64,${sourceUrl}`;
const shouldUseNativeImage = isBrowserLocalImageSrc(src);
const src = normalizeChatImageSource(mediaUrl || imageUrl);
const shouldUseNativeImage = isBrowserLocalChatImageSource(src);
if (imagePaywalled) {
return (
@@ -131,7 +131,3 @@ export function FullscreenImageViewer({
</div>
);
}
function isBrowserLocalImageSrc(src: string): boolean {
return src.startsWith("blob:") || src.startsWith("data:");
}
+7 -17
View File
@@ -13,8 +13,12 @@ import { useRouter } from "next/navigation";
import { useState } from "react";
import { ROUTE_BUILDERS } from "@/router/routes";
import {
isBrowserLocalChatImageSource,
normalizeChatImageSource,
} from "@/lib/chat/chat_media_url";
import { useCachedChatMediaUrl } from "@/lib/chat/use_cached_chat_media_url";
import { useCachedChatMediaUrl } from "../hooks/use-cached-chat-media-url";
import styles from "./image-bubble.module.css";
export interface ImageBubbleProps {
@@ -36,9 +40,9 @@ export function ImageBubble({
kind: "image",
});
const src = decodeBase64Image(mediaUrl || imageUrl);
const src = normalizeChatImageSource(mediaUrl || imageUrl);
const canOpen = Boolean(messageId);
const shouldUseNativeImage = isBrowserLocalImageSrc(src);
const shouldUseNativeImage = isBrowserLocalChatImageSource(src);
const openImage = () => {
if (!messageId) return;
@@ -85,17 +89,3 @@ export function ImageBubble({
</div>
);
}
/** 解析 base64 data URI`data:image/png;base64,...`),否则原样返回 */
function decodeBase64Image(uri: string): string {
// 已是 data URI 或 http(s) URL:直接返回
if (uri.startsWith("data:") || uri.startsWith("http")) {
return uri;
}
// 裸 base64 字符串 → 包装成 data URIPNG 兜底)
return `data:image/png;base64,${uri}`;
}
function isBrowserLocalImageSrc(src: string): boolean {
return src.startsWith("blob:") || src.startsWith("data:");
}
+1 -1
View File
@@ -3,7 +3,7 @@
import { LockKeyhole, Pause, Play } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useCachedChatMediaUrl } from "../hooks/use-cached-chat-media-url";
import { useCachedChatMediaUrl } from "@/lib/chat/use_cached_chat_media_url";
import styles from "./voice-bubble.module.css";
export interface VoiceBubbleProps {