|
|
|
@@ -5,8 +5,10 @@
|
|
|
|
|
* The account has two albums sharing one photo, and one of its photos is a
|
|
|
|
|
* live photo whose image is a HEIC with EXIF. The first run puts every
|
|
|
|
|
* original at its save path, writes each photo's metadata beside it and each
|
|
|
|
|
* album's photos under `albums/`. The second run fetches nothing and changes
|
|
|
|
|
* no file.
|
|
|
|
|
* album's photos under `albums/`. Before the second run the account gains an
|
|
|
|
|
* album holding a new photo. The second run downloads that photo and writes
|
|
|
|
|
* its files and the new album's, and fetches nothing else and changes no
|
|
|
|
|
* other file.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
|
|
@@ -101,7 +103,7 @@ const readJSON = (path: string): unknown =>
|
|
|
|
|
JSON.parse(readFileSync(path, "utf-8"));
|
|
|
|
|
|
|
|
|
|
describe("examples/download-albums.ts", () => {
|
|
|
|
|
it("downloads every album's photos with their metadata, and nothing on a second run", async () => {
|
|
|
|
|
it("downloads every album's photos with their metadata, and on a second run only what the account gained", async () => {
|
|
|
|
|
// Album 1, "Trip", holds photos 1 and 2. Album 2, "Family", holds
|
|
|
|
|
// photo 2 and photo 3, a live photo.
|
|
|
|
|
const live = await asLivePhoto(
|
|
|
|
@@ -109,20 +111,22 @@ describe("examples/download-albums.ts", () => {
|
|
|
|
|
livePhotoZip({ "image.heic": HEIC_WITH_EXIF, "video.mov": VIDEO }),
|
|
|
|
|
livePhotoHash(HEIC_WITH_EXIF, VIDEO),
|
|
|
|
|
);
|
|
|
|
|
const collections = [collection(1, "Trip"), collection(2, "Family")];
|
|
|
|
|
const filesByAlbum = new Map<number, EnteFile[]>([
|
|
|
|
|
[1, [file(1, 1), file(2, 1)]],
|
|
|
|
|
[2, [file(2, 2), live.file]],
|
|
|
|
|
]);
|
|
|
|
|
const client = {
|
|
|
|
|
whoami: () => ({ email: "u@example.com", userID: USER_ID }),
|
|
|
|
|
collectionsSince: async (): Promise<CollectionsPage> => ({
|
|
|
|
|
collections: [collection(1, "Trip"), collection(2, "Family")],
|
|
|
|
|
collections: [...collections],
|
|
|
|
|
deleted: [],
|
|
|
|
|
cursor: 1,
|
|
|
|
|
}),
|
|
|
|
|
filesSince: async (args: {
|
|
|
|
|
collectionID: number;
|
|
|
|
|
}): Promise<FilesPage> => ({
|
|
|
|
|
files:
|
|
|
|
|
args.collectionID === 1
|
|
|
|
|
? [file(1, 1), file(2, 1)]
|
|
|
|
|
: [file(2, 2), live.file],
|
|
|
|
|
files: filesByAlbum.get(args.collectionID) ?? [],
|
|
|
|
|
deleted: [],
|
|
|
|
|
cursor: 1,
|
|
|
|
|
}),
|
|
|
|
@@ -270,18 +274,44 @@ describe("examples/download-albums.ts", () => {
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// The second run, with a newly opened library, finds every photo
|
|
|
|
|
// already local, fetches nothing, and writes, renames or adds no
|
|
|
|
|
// file.
|
|
|
|
|
// Before the second run the account gains album 3, "Garden", holding
|
|
|
|
|
// a new photo 4. The second run, with a newly opened library, opens
|
|
|
|
|
// the cache written by the first and still downloads photo 4. It finds
|
|
|
|
|
// the other photos already local and fetches nothing else.
|
|
|
|
|
collections.push(collection(3, "Garden"));
|
|
|
|
|
filesByAlbum.set(3, [file(4, 3)]);
|
|
|
|
|
backdate(dir);
|
|
|
|
|
const before = mtimes(dir);
|
|
|
|
|
const second = await open();
|
|
|
|
|
expect(await downloadAlbums(second, dir)).toEqual({
|
|
|
|
|
downloaded: 0,
|
|
|
|
|
downloaded: 1,
|
|
|
|
|
alreadyLocal: 3,
|
|
|
|
|
});
|
|
|
|
|
await second.close();
|
|
|
|
|
expect(calls).toBe(3);
|
|
|
|
|
expect(mtimes(dir)).toEqual(before);
|
|
|
|
|
expect(calls).toBe(4);
|
|
|
|
|
expect(readFileSync(join(day, "2026-03-01.4.jpg"), "utf-8")).toBe(
|
|
|
|
|
"original-4",
|
|
|
|
|
);
|
|
|
|
|
expect(readJSON(join(dir, "albums", "3.json"))).toEqual({
|
|
|
|
|
collectionID: 3,
|
|
|
|
|
name: "Garden",
|
|
|
|
|
savePaths: [join(DAY, "2026-03-01.4.jpg")],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// The second run adds only photo 4's files and album 3's, and
|
|
|
|
|
// rewrites, renames or removes no file from the first run. The two
|
|
|
|
|
// directories that gain a file are the only other changes.
|
|
|
|
|
const after = mtimes(dir);
|
|
|
|
|
expect(
|
|
|
|
|
[...after.keys()].filter((name) => !before.has(name)).sort(),
|
|
|
|
|
).toEqual([
|
|
|
|
|
join(DAY, "2026-03-01.4.jpg"),
|
|
|
|
|
join(DAY, "2026-03-01.4.jpg.json"),
|
|
|
|
|
join("albums", "3.json"),
|
|
|
|
|
]);
|
|
|
|
|
for (const [name, mtime] of before) {
|
|
|
|
|
if (name === DAY || name === "albums") continue;
|
|
|
|
|
expect(after.get(name), name).toBe(mtime);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|