fix(canvas): 远程媒体 - 统一资源地址并校验视频缓存
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { cacheResourceObjectUrl } from "@/services/resource-blob-cache";
|
||||
import { resourceIdFromStorageKey } from "@/services/api/resources";
|
||||
import { resourceFileUrl, resourceIdFromStorageKey } from "@/services/api/resources";
|
||||
|
||||
export type CanvasAudioSource = {
|
||||
nodeId: string;
|
||||
@@ -255,9 +254,9 @@ function sameSource(left: CanvasAudioSource, right: CanvasAudioSource) {
|
||||
}
|
||||
|
||||
async function resolveAudioSource(source: CanvasAudioSource) {
|
||||
if (source.storageKey && resourceIdFromStorageKey(source.storageKey)) {
|
||||
const cached = await cacheResourceObjectUrl(source.storageKey).catch(() => "");
|
||||
return cached || source.content;
|
||||
if (source.storageKey) {
|
||||
const resourceId = resourceIdFromStorageKey(source.storageKey);
|
||||
if (resourceId) return resourceFileUrl(resourceId);
|
||||
}
|
||||
return source.content;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getActiveUserScope } from "@/lib/user-scope";
|
||||
import { captureVideoPoster, detectVideoAudioTrackFromBlob } from "@/lib/video-poster";
|
||||
import { resourceFileUrl, resourceIdFromStorageKey, resourceStorageKey, ResourceUploadError, uploadResourceFile } from "@/services/api/resources";
|
||||
import { uploadImage, type UploadedImage } from "@/services/image-storage";
|
||||
import { getCachedResourceBlob, getCachedResourceObjectUrl, primeResourceBlobCache } from "@/services/resource-blob-cache";
|
||||
import { getCachedResourceBlob, primeResourceBlobCache } from "@/services/resource-blob-cache";
|
||||
|
||||
export type UploadedFile = {
|
||||
url: string;
|
||||
@@ -115,8 +115,8 @@ export async function resolveMediaUrl(storageKey?: string, fallback = "") {
|
||||
if (!storageKey) return fallback;
|
||||
const resourceId = resourceIdFromStorageKey(storageKey);
|
||||
if (resourceId) {
|
||||
const cached = await getCachedResourceObjectUrl(storageKey).catch(() => "");
|
||||
return cached || resourceFileUrl(resourceId);
|
||||
// 远程资源展示统一走稳定的云端/资源文件地址;Blob 缓存仅服务于字节读取和媒体处理。
|
||||
return resourceFileUrl(resourceId);
|
||||
}
|
||||
const cached = objectUrls.get(storageKey);
|
||||
if (cached) return cached;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { nanoid } from "nanoid";
|
||||
import { readImageMeta } from "@/lib/image-utils";
|
||||
import { getActiveUserScope } from "@/lib/user-scope";
|
||||
import { importResourceFromUrl, isResourceUrl, resourceFileUrl, resourceIdFromStorageKey, resourceStorageKey, ResourceUploadError, uploadResourceFile } from "@/services/api/resources";
|
||||
import { cacheResourceObjectUrl, getCachedResourceBlob, getCachedResourceObjectUrl, primeResourceBlobCache } from "@/services/resource-blob-cache";
|
||||
import { getCachedResourceBlob, primeResourceBlobCache } from "@/services/resource-blob-cache";
|
||||
|
||||
export type UploadedImage = {
|
||||
url: string;
|
||||
@@ -81,12 +81,7 @@ export async function resolveImageUrl(storageKey?: string, fallback = "", option
|
||||
if (!storageKey) return fallback;
|
||||
const resourceId = resourceIdFromStorageKey(storageKey);
|
||||
if (resourceId) {
|
||||
const cached = await getCachedResourceObjectUrl(storageKey).catch(() => "");
|
||||
if (cached) return cached;
|
||||
if (options?.cacheMiss) {
|
||||
const populated = await cacheResourceObjectUrl(storageKey).catch(() => "");
|
||||
if (populated) return populated;
|
||||
}
|
||||
// 远程资源展示不返回 blob: URL,确保节点、素材库和弹窗都使用云端稳定地址。
|
||||
return resourceFileUrl(resourceId);
|
||||
}
|
||||
const cached = objectUrls.get(storageKey);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { uploadGeneratedAssetToConfiguredSources } from "@/services/external-ass
|
||||
import { getImageBlob, resolveImageUrl, setImageBlob } from "@/services/image-storage";
|
||||
import { generationArtifactStorageKey, loadOrStoreGenerationArtifact } from "@/services/generation-artifact-sink";
|
||||
import { createProviderNeutralGenerationTaskEffectStore } from "@/services/provider-neutral-generation-effects";
|
||||
import { getCachedResourceBlob } from "@/services/resource-blob-cache";
|
||||
import { saveRemoteUserDataNow } from "@/services/user-data-sync";
|
||||
import { getActiveUserScope } from "@/lib/user-scope";
|
||||
import { normalizeAssetCategory } from "@/lib/asset-category";
|
||||
@@ -265,6 +266,26 @@ async function storedGenerationMedia(dataUrl: string, effectKey: string, mediaTy
|
||||
};
|
||||
}
|
||||
|
||||
async function cachedRemoteGenerationVideo(video: NonNullable<BackendGenerationResult["video"]>, signal?: AbortSignal) {
|
||||
if (!video.storageKey) throw new Error("生成视频缺少云端资源标识");
|
||||
throwIfAborted(signal);
|
||||
const blob = await getCachedResourceBlob(video.storageKey);
|
||||
throwIfAborted(signal);
|
||||
if (!blob) throw new Error("生成视频资源缓存失败,未标记为成功");
|
||||
const url = await resolveMediaUrl(video.storageKey, video.dataUrl);
|
||||
throwIfAborted(signal);
|
||||
if (!url) throw new Error("生成视频资源地址为空,未标记为成功");
|
||||
return {
|
||||
url,
|
||||
storageKey: video.storageKey,
|
||||
width: video.width || 0,
|
||||
height: video.height || 0,
|
||||
durationMs: video.durationMs,
|
||||
bytes: video.bytes || blob.size,
|
||||
mimeType: video.mimeType || blob.type || "video/mp4",
|
||||
};
|
||||
}
|
||||
|
||||
async function generationOutputAsset(input: Parameters<MaterializeGenerationTaskOutput>[0], scope: string): Promise<NewAsset> {
|
||||
throwIfAborted(input.signal);
|
||||
const result = generationTaskResult(input.task);
|
||||
@@ -305,15 +326,7 @@ async function generationOutputAsset(input: Parameters<MaterializeGenerationTask
|
||||
const video = result.video;
|
||||
if (!video) throw new Error("生成任务缺少视频输出");
|
||||
const stored = video.storageKey
|
||||
? {
|
||||
url: await resolveMediaUrl(video.storageKey, video.dataUrl),
|
||||
storageKey: video.storageKey,
|
||||
width: video.width || 0,
|
||||
height: video.height || 0,
|
||||
durationMs: video.durationMs,
|
||||
bytes: video.bytes || 0,
|
||||
mimeType: video.mimeType || "video/mp4",
|
||||
}
|
||||
? await cachedRemoteGenerationVideo(video, input.signal)
|
||||
: await storedGenerationMedia(
|
||||
video.dataUrl,
|
||||
input.effectKey,
|
||||
|
||||
Reference in New Issue
Block a user