Photo: drop fileSize, exif() throws without a content cache
check / check (push) Successful in 1m58s

Remove fileSize from Photo, PhotoRecord, README and TODO.md: the server's
value is the size of the encrypted file, not the original's.

exif() now checks for the content cache before it returns {} for a video,
so it throws like original(), thumbnail() and content() when the library
has no content source. README names the methods that also serve an
original from the backup, since thumbnail() does not.

New tests: exif() on a JPEG whose EXIF block cannot be parsed returns {},
and exif() on a video throws without a content source.

Model: opus-5-5
This commit is contained in:
2026-10-01 15:23:05 +00:00
parent e7f75685e5
commit ead27ff419
7 changed files with 42 additions and 18 deletions
+31
View File
@@ -296,6 +296,16 @@ const JPEG_WITH_EXIF = new Uint8Array([
...[0xff, 0xda, 0x00, 0x02], // start of scan
]);
// A JPEG whose EXIF segment is laid out correctly but holds "XX" where the TIFF
// byte order belongs, so exif-reader cannot parse it.
const JPEG_WITH_BAD_EXIF = new Uint8Array([
...[0xff, 0xd8], // start of image
...[0xff, 0xe1, ...u16(2 + 6 + 2)], // APP1 and its length
...[...ascii("Exif"), 0], // "Exif\0\0"
...[0x58, 0x58], // "XX"
...[0xff, 0xda, 0x00, 0x02], // start of scan
]);
describe("Photo save path, local copy, content and EXIF", () => {
// The same account, with `files` in its album instead.
class FilesClient extends MockClient {
@@ -407,6 +417,27 @@ describe("Photo save path, local copy, content and EXIF", () => {
await lib.close();
});
it("returns no EXIF fields for a JPEG whose EXIF cannot be parsed", async () => {
const lib = await open({
contentSource: stubSource(JPEG_WITH_BAD_EXIF),
});
expect(await lib.photos.byID({ fileID: 1 })!.exif()).toStrictEqual({});
await lib.close();
});
it("throws from exif() on a video without a content source, as the other content methods do", async () => {
const video = file(1, 1);
video.metadata.fileType = "video";
const lib = await open({
client: new FilesClient([video]),
contentSource: undefined,
});
await expect(lib.photos.byID({ fileID: 1 })!.exif()).rejects.toThrow(
/content cache/i,
);
await lib.close();
});
it("returns no EXIF fields for a video, without fetching it", async () => {
const video = file(1, 1);
video.metadata.fileType = "video";