fix(media): 视频播放 - 资源视频改走 playback 变体,失败后刷新签名并重试
画布预览、生成回填和项目水合都解析浏览器可播地址;播放失败时绕过展示缓存,等待转码完成后强制刷新 playback 地址。
This commit is contained in:
1 parent
0b1d5073e8
commit
9997422fcd
8 files changed
+285
-101
No files matched your search
@@ -3,7 +3,7 @@ import { nanoid } from "nanoid";
|
||||
|
||||
import { getActiveUserScope } from "@/lib/user-scope";
|
||||
import { captureVideoPoster, detectVideoAudioTrackFromBlob } from "@/lib/video-poster";
|
||||
import { getResourceAccess, resolveResourceAccessURL, resourceFileUrl, resourceIdFromStorageKey, resourceStorageKey, ResourceUploadError, uploadResourceFile } from "@/services/api/resources";
|
||||
import { getResourceAccess, resolveResourceAccessURL, resourceFileUrl, resourceIdFromStorageKey, resourceStorageKey, ResourceUploadError, uploadResourceFile, type ResourceAccessVariant } from "@/services/api/resources";
|
||||
import { uploadImage, type UploadedImage } from "@/services/image-storage";
|
||||
import { getCachedResourceBlob, primeResourceBlobCache } from "@/services/resource-blob-cache";
|
||||
|
||||
@@ -93,7 +93,17 @@ export async function uploadMediaFile(input: Blob, prefix = "file", onProgress?:
|
||||
// 缓存只影响后续读取性能,服务端资源已经成功落盘,不得把缓存失败误报为上传失败。
|
||||
console.warn("预热媒体缓存失败,服务端资源已保存", { resourceId: resource.id, error });
|
||||
}
|
||||
return { url: resource.publicUrl || resourceFileUrl(resource.id), storageKey: resourceStorageKey(resource.id), bytes: resource.size || blob.size, mimeType: resource.mimeType || blob.type || "application/octet-stream", width: resource.width || meta.width, height: resource.height || meta.height, durationMs: resource.durationMs || meta.durationMs, hasAudio: meta.hasAudio, preview: poster };
|
||||
return {
|
||||
url: resource.publicUrl || resourceFileUrl(resource.id),
|
||||
storageKey: resourceStorageKey(resource.id),
|
||||
bytes: resource.size || blob.size,
|
||||
mimeType: resource.mimeType || blob.type || "application/octet-stream",
|
||||
width: resource.width || meta.width,
|
||||
height: resource.height || meta.height,
|
||||
durationMs: resource.durationMs || meta.durationMs,
|
||||
hasAudio: meta.hasAudio,
|
||||
preview: poster,
|
||||
};
|
||||
} catch (error) {
|
||||
// 与图片上传同一套判定:永久性失败必须当场暴露,不能混进“稍后自动同步”。
|
||||
if (error instanceof ResourceUploadError && error.permanent) throw error;
|
||||
@@ -111,12 +121,12 @@ export async function uploadMediaFile(input: Blob, prefix = "file", onProgress?:
|
||||
}
|
||||
}
|
||||
|
||||
export async function resolveMediaUrl(storageKey?: string, fallback = "") {
|
||||
export async function resolveMediaUrl(storageKey?: string, fallback = "", variant: ResourceAccessVariant = "original") {
|
||||
if (!storageKey) return fallback;
|
||||
const resourceId = resourceIdFromStorageKey(storageKey);
|
||||
if (resourceId) {
|
||||
// 展示直接命中 OSS/CDN;平台资源文件接口只保留给私有源站代理或本地存储兜底。
|
||||
return resolveResourceAccessURL((await getResourceAccess(storageKey, "display")).url);
|
||||
return resolveResourceAccessURL((await getResourceAccess(storageKey, "display", variant)).url);
|
||||
}
|
||||
const cached = objectUrls.get(storageKey);
|
||||
if (cached) return cached;
|
||||
@@ -127,6 +137,11 @@ export async function resolveMediaUrl(storageKey?: string, fallback = "") {
|
||||
return url;
|
||||
}
|
||||
|
||||
/** Resolve a video through the browser-compatible playback variant when one exists. */
|
||||
export function resolveVideoMediaUrl(storageKey?: string, fallback = "") {
|
||||
return resolveMediaUrl(storageKey, fallback, "playback");
|
||||
}
|
||||
|
||||
export async function getMediaBlob(storageKey: string) {
|
||||
if (resourceIdFromStorageKey(storageKey)) return getCachedResourceBlob(storageKey);
|
||||
return store.getItem<Blob>(storageKey);
|
||||
|
||||
Reference in new issue
Block a user