ML data included by default, --exif is the opt-in, --all aliases --exif
ML data (face detections, CLIP embeddings) is now fetched by default in backup-metadata. Use --no-ml to skip it. EXIF extraction (which requires downloading every file) remains opt-in via --exif. --all is an alias for --exif.
This commit is contained in:
29
bin/quak.ts
29
bin/quak.ts
@@ -340,23 +340,26 @@ program
|
||||
"Dump all decrypted account metadata to a directory of JSON files",
|
||||
)
|
||||
.argument("<dir>", "Output directory")
|
||||
.option(
|
||||
"--ml",
|
||||
"Include ML data (face detections, CLIP embeddings) from the Ente server",
|
||||
)
|
||||
.option("--no-ml", "Skip ML data (face detections, CLIP embeddings)")
|
||||
.option(
|
||||
"--exif",
|
||||
"Download each file and extract full EXIF/IPTC/XMP metadata (slow)",
|
||||
)
|
||||
.action(async (dir: string, opts: { ml?: boolean; exif?: boolean }) => {
|
||||
await init();
|
||||
const client = requireSession();
|
||||
await runMetadataBackup(client, dir, {
|
||||
mlData: opts.ml,
|
||||
exif: opts.exif,
|
||||
onProgress: (msg) => stderr.write(msg + "\n"),
|
||||
});
|
||||
});
|
||||
.option("--all", "Alias for --exif")
|
||||
.action(
|
||||
async (
|
||||
dir: string,
|
||||
opts: { ml?: boolean; exif?: boolean; all?: boolean },
|
||||
) => {
|
||||
await init();
|
||||
const client = requireSession();
|
||||
await runMetadataBackup(client, dir, {
|
||||
mlData: opts.ml,
|
||||
exif: opts.exif || opts.all,
|
||||
onProgress: (msg) => stderr.write(msg + "\n"),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
program
|
||||
.command("backup")
|
||||
|
||||
@@ -120,7 +120,7 @@ export const runMetadataBackup = async (
|
||||
opts?: MetadataBackupOptions,
|
||||
): Promise<void> => {
|
||||
const log = opts?.onProgress ?? (() => {});
|
||||
const wantML = opts?.mlData ?? false;
|
||||
const wantML = opts?.mlData ?? true;
|
||||
const wantExif = opts?.exif ?? false;
|
||||
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
|
||||
@@ -587,8 +587,8 @@ describe("quak backup-metadata", () => {
|
||||
expect(fileMeta.mlData.clip.embedding).toEqual([0.5, 0.6, 0.7]);
|
||||
});
|
||||
|
||||
it("does not include ML data when --ml is not set", async () => {
|
||||
const outDir = join(testDir, "no-ml");
|
||||
it("includes ML data by default", async () => {
|
||||
const outDir = join(testDir, "ml-default");
|
||||
const client = await Client.login({
|
||||
email: TEST_EMAIL,
|
||||
password: TEST_PASSWORD,
|
||||
@@ -597,6 +597,28 @@ describe("quak backup-metadata", () => {
|
||||
|
||||
await runMetadataBackup(client, outDir);
|
||||
|
||||
const collDirs = readdirSync(join(outDir, "collections"));
|
||||
const vacDir = collDirs.find((d) => d.includes("Vacation"))!;
|
||||
const fileMeta = JSON.parse(
|
||||
readFileSync(
|
||||
join(outDir, "collections", vacDir, "100.json"),
|
||||
"utf-8",
|
||||
),
|
||||
);
|
||||
expect(fileMeta.mlData).toBeDefined();
|
||||
expect(fileMeta.mlData.face.faces[0].faceID).toBe("face-abc");
|
||||
});
|
||||
|
||||
it("excludes ML data when mlData: false", async () => {
|
||||
const outDir = join(testDir, "no-ml");
|
||||
const client = await Client.login({
|
||||
email: TEST_EMAIL,
|
||||
password: TEST_PASSWORD,
|
||||
apiOptions: { fetch: buildMetaFetch(mock) },
|
||||
});
|
||||
|
||||
await runMetadataBackup(client, outDir, { mlData: false });
|
||||
|
||||
const collDirs = readdirSync(join(outDir, "collections"));
|
||||
const vacDir = collDirs.find((d) => d.includes("Vacation"))!;
|
||||
const fileMeta = JSON.parse(
|
||||
|
||||
Reference in New Issue
Block a user