refactor: deduplicate media store writes

This commit is contained in:
Peter Steinberger 2026-03-13 16:25:54 +00:00
parent f4ed317083
commit a37e25fa21
1 changed files with 50 additions and 21 deletions

View File

@ -255,6 +255,48 @@ export type SavedMedia = {
contentType?: string; contentType?: string;
}; };
function buildSavedMediaId(params: {
baseId: string;
ext: string;
originalFilename?: string;
}): string {
if (!params.originalFilename) {
return params.ext ? `${params.baseId}${params.ext}` : params.baseId;
}
const base = path.parse(params.originalFilename).name;
const sanitized = sanitizeFilename(base);
return sanitized
? `${sanitized}---${params.baseId}${params.ext}`
: `${params.baseId}${params.ext}`;
}
function buildSavedMediaResult(params: {
dir: string;
id: string;
size: number;
contentType?: string;
}): SavedMedia {
return {
id: params.id,
path: path.join(params.dir, params.id),
size: params.size,
contentType: params.contentType,
};
}
async function writeSavedMediaBuffer(params: {
dir: string;
id: string;
buffer: Buffer;
}): Promise<string> {
const dest = path.join(params.dir, params.id);
await retryAfterRecreatingDir(params.dir, () =>
fs.writeFile(dest, params.buffer, { mode: MEDIA_FILE_MODE }),
);
return dest;
}
export type SaveMediaSourceErrorCode = export type SaveMediaSourceErrorCode =
| "invalid-path" | "invalid-path"
| "not-found" | "not-found"
@ -321,20 +363,19 @@ export async function saveMediaSource(
filePath: source, filePath: source,
}); });
const ext = extensionForMime(mime) ?? path.extname(new URL(source).pathname); const ext = extensionForMime(mime) ?? path.extname(new URL(source).pathname);
const id = ext ? `${baseId}${ext}` : baseId; const id = buildSavedMediaId({ baseId, ext });
const finalDest = path.join(dir, id); const finalDest = path.join(dir, id);
await fs.rename(tempDest, finalDest); await fs.rename(tempDest, finalDest);
return { id, path: finalDest, size, contentType: mime }; return buildSavedMediaResult({ dir, id, size, contentType: mime });
} }
// local path // local path
try { try {
const { buffer, stat } = await readLocalFileSafely({ filePath: source, maxBytes: MAX_BYTES }); const { buffer, stat } = await readLocalFileSafely({ filePath: source, maxBytes: MAX_BYTES });
const mime = await detectMime({ buffer, filePath: source }); const mime = await detectMime({ buffer, filePath: source });
const ext = extensionForMime(mime) ?? path.extname(source); const ext = extensionForMime(mime) ?? path.extname(source);
const id = ext ? `${baseId}${ext}` : baseId; const id = buildSavedMediaId({ baseId, ext });
const dest = path.join(dir, id); await writeSavedMediaBuffer({ dir, id, buffer });
await retryAfterRecreatingDir(dir, () => fs.writeFile(dest, buffer, { mode: MEDIA_FILE_MODE })); return buildSavedMediaResult({ dir, id, size: stat.size, contentType: mime });
return { id, path: dest, size: stat.size, contentType: mime };
} catch (err) { } catch (err) {
if (err instanceof SafeOpenError) { if (err instanceof SafeOpenError) {
throw toSaveMediaSourceError(err); throw toSaveMediaSourceError(err);
@ -359,19 +400,7 @@ export async function saveMediaBuffer(
const headerExt = extensionForMime(contentType?.split(";")[0]?.trim() ?? undefined); const headerExt = extensionForMime(contentType?.split(";")[0]?.trim() ?? undefined);
const mime = await detectMime({ buffer, headerMime: contentType }); const mime = await detectMime({ buffer, headerMime: contentType });
const ext = headerExt ?? extensionForMime(mime) ?? ""; const ext = headerExt ?? extensionForMime(mime) ?? "";
const id = buildSavedMediaId({ baseId: uuid, ext, originalFilename });
let id: string; await writeSavedMediaBuffer({ dir, id, buffer });
if (originalFilename) { return buildSavedMediaResult({ dir, id, size: buffer.byteLength, contentType: mime });
// Embed original name: {sanitized}---{uuid}.ext
const base = path.parse(originalFilename).name;
const sanitized = sanitizeFilename(base);
id = sanitized ? `${sanitized}---${uuid}${ext}` : `${uuid}${ext}`;
} else {
// Legacy: just UUID
id = ext ? `${uuid}${ext}` : uuid;
}
const dest = path.join(dir, id);
await retryAfterRecreatingDir(dir, () => fs.writeFile(dest, buffer, { mode: MEDIA_FILE_MODE }));
return { id, path: dest, size: buffer.byteLength, contentType: mime };
} }