You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

63 lines
1.7 KiB

import fs from "node:fs/promises";
import path from "node:path";
import { RELATIVE_ASSETS_DIR } from "../../constants/media";
import { listExportUserMediaAssets } from "./build-data";
type ExportFileAsset = {
storageKey: string;
};
export type BuildExportFilesResult = {
files: Array<{ file: string; bytes: number }>;
missingCount: number;
};
function resolveAssetsBaseDir(): string {
return path.resolve(process.cwd(), RELATIVE_ASSETS_DIR);
}
export async function buildExportMediaFiles(params: {
userId: number;
cutoffAt: Date;
outputFilesDir: string;
}): Promise<BuildExportFilesResult> {
await fs.mkdir(params.outputFilesDir, { recursive: true });
const mediaAssets: ExportFileAsset[] = await listExportUserMediaAssets({
userId: params.userId,
cutoffAt: params.cutoffAt,
});
const assetsBaseDir = resolveAssetsBaseDir();
let missingCount = 0;
const files: Array<{ file: string; bytes: number }> = [];
for (const asset of mediaAssets) {
const key = asset.storageKey;
if (!key || key.includes("..") || path.isAbsolute(key)) {
missingCount += 1;
continue;
}
const fromPath = path.resolve(assetsBaseDir, key);
const toPath = path.resolve(params.outputFilesDir, key);
const relativeOutputPath = `files/${key}`;
await fs.mkdir(path.dirname(toPath), { recursive: true });
try {
await fs.copyFile(fromPath, toPath);
const stat = await fs.stat(toPath);
files.push({ file: relativeOutputPath, bytes: stat.size });
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
missingCount += 1;
continue;
}
throw error;
}
}
return {
files,
missingCount,
};
}