Skip to content

Commit

Permalink
feat: change description in image files
Browse files Browse the repository at this point in the history
  • Loading branch information
bensandee committed Feb 20, 2024
1 parent ae3ff11 commit 7123fc2
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = {
],
eqeqeq: ["warn", "smart"],
"func-style": ["warn"],
"require-await": ["error"],
"require-await": ["warn"],
"@typescript-eslint/no-floating-promises": "error",
"import/no-default-export": 2,
"@typescript-eslint/strict-boolean-expressions": "warn",
Expand Down
33 changes: 18 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@
"pino": "^8.17.2",
"pino-pretty": "^10.3.1",
"pm2": "^5.3.1",
"promisify-child-process": "^4.1.2",
"readline-sync": "^1.4.10",
"redis": "^4.6.12",
"reflect-metadata": "^0.2.1",
"sharp": "^0.33.2",
"superagent": "^8.1.2",
"tempy": "^3.1.0",
"ts-node": "^10.9.2",
"tsyringe": "^4.8.0",
"twitter-api-client": "^1.6.1",
Expand Down
6 changes: 6 additions & 0 deletions src/fs_repository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fs from "fs/promises";
import path from "path";
import { injectable } from "tsyringe";
import sharp from "sharp";
import { updateImageDescription } from "../utils/exiftool";

@injectable()
export class FilesystemRepository {
Expand Down Expand Up @@ -55,4 +56,9 @@ export class FilesystemRepository {
return Promise.resolve();
}
}

async updateImageDescription(baseFilename: string, description: string) {
const originalFile = this.photoPath(baseFilename);
await updateImageDescription(originalFile, description);
}
}
14 changes: 6 additions & 8 deletions src/routes/images/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ import { asyncWrapper } from "../async";
import { ImageGet } from "./get";
import { SingleImageDelete } from "./delete";
import { Cache } from "../cache";
import {
handler as singleImagePutHandler,
bodySchema as singleImagePutSchema,
} from "./put";
import { ImagePut, bodySchema as singleImagePutSchema } from "./put";

@injectable()
export class ImageRouter {
constructor(
private cache: Cache,
private imageGet: ImageGet,
private singleDelete: SingleImageDelete
private singleDelete: SingleImageDelete,
private imagePut: ImagePut,
) {}

readonly routes = express
Expand All @@ -37,7 +35,7 @@ export class ImageRouter {
validateBodySchema({ schema: singleImagePutSchema }),
validateRole({ role: Roles.EDITOR }),
validateId(),
asyncWrapper(singleImagePutHandler)
asyncWrapper(this.imagePut.handler),
)

// single image metadata
Expand All @@ -47,7 +45,7 @@ export class ImageRouter {
"/:id",
validateAdmin(),
validateId(),
asyncWrapper(this.singleDelete.handler)
asyncWrapper(this.singleDelete.handler),
)

// single image, cached
Expand All @@ -56,6 +54,6 @@ export class ImageRouter {
this.cache.middleware({ callNextWhenCacheable: false }),
validateId(),
validateQuerySchema({ schema: this.imageGet.querySchema }),
asyncWrapper(this.imageGet.binary)
asyncWrapper(this.imageGet.binary),
);
}
49 changes: 33 additions & 16 deletions src/routes/images/put.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,42 @@ import { Image, ImageDocument } from "../../database";
import { logger } from "../../utils";
import { PutImageBody, putImageBodySchema } from "../contract";
import { lenientImageSchema } from "./localTypes";
import { FilesystemRepository } from "../../fs_repository";
import { injectable } from "tsyringe";

export const bodySchema = putImageBodySchema;

export const handler = async (req: Request, res: Response) => {
const body = req.validated as PutImageBody;
@injectable()
export class ImagePut {
constructor(private fsRepository: FilesystemRepository) {}

const { id } = req.params;
logger.trace({ id, body }, "put single image");
handler = async (req: Request, res: Response) => {
const body = req.validated as PutImageBody;

const modified: Partial<ImageDocument> = { ...body };
if (modified.description != null) {
modified.description_from_exif = false;
}
const { id } = req.params;
logger.trace({ id, body }, "put single image");

const result = await Image.findByIdAndUpdate(id, modified, { new: true });
if (result != null) {
res.send(lenientImageSchema.parse(result));
} else {
// not found
res.sendStatus(404);
}
};
const modified: Partial<ImageDocument> = { ...body };
if (modified.description != null) {
modified.description_from_exif = false;
}

const oldValue = await Image.findByIdAndUpdate(id, modified);
if (oldValue != null) {
const newValue = await Image.findById(id);
if (
oldValue.description !== newValue?.description &&
newValue?.description != null
) {
await this.fsRepository.updateImageDescription(
id,
newValue?.description,
);
}
res.send(lenientImageSchema.parse(newValue));
} else {
// not found
res.sendStatus(404);
}
};
}
28 changes: 28 additions & 0 deletions src/utils/exiftool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fs from "fs/promises";
import path from "path";
import { updateImageDescription } from "./exiftool";
import { load } from "exifreader";

describe("exiftool", () => {
const imageFile = path.resolve(
__dirname,
"../../test_resources/test_DSC07588_with_description.jpg",
);
let tempFile: string;

beforeEach(async () => {
const { temporaryFile } = await import("tempy");
tempFile = temporaryFile({ name: "exiftool_test" });
await fs.copyFile(imageFile, tempFile);
});

it("behaves", async () => {
await updateImageDescription(tempFile, "new description");
const tags = await load(tempFile, { expanded: true });
expect(tags.exif?.ImageDescription).toEqual("new description");
});

afterEach(async () => {
await fs.unlink(tempFile);
});
});
20 changes: 20 additions & 0 deletions src/utils/exiftool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { execFile } from "promisify-child-process";
import fs from "fs/promises";

export const updateImageDescription = async (
file: string,
description: string,
) => {
const { temporaryWrite, temporaryFile } = await import("tempy");
const argFile = await temporaryWrite(description, { name: "args" });
const newFile = temporaryFile({ name: "newFile" });
await execFile("exiftool", [
`-mwg:Description<${argFile}`,
file,
"-o",
newFile,
]);
await fs.unlink(argFile);
await fs.copyFile(newFile, file);
await fs.unlink(newFile);
};

0 comments on commit 7123fc2

Please sign in to comment.