Files
nix/hosts/common/configs/user/gui/darktable/publish/src/index.ts
Nikolaos Karaolidis 2888bb8b72 Add treefmt
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
2025-02-16 18:53:11 +00:00

113 lines
3.3 KiB
TypeScript

import { Command } from "commander";
import { createFileNode, createImageNode, createHeadingNode } from "./lexical";
import { extractShootingConditions, createImageCaption } from "./exif";
import { uploadFile, uploadImage, uploadPost } from "./api";
import { getBasenameWithExtension, prepareFiles } from "./files";
new Command()
.name("darktable-publish")
.description("Publish files to GHOST CMS with optional metadata.")
.option("-t, --title [string]", "Specify the title")
.option("-s, --slug [string]", "Specify the slug")
.option("-k, --keywords [string...]", "Specify blog post keywords (tags)")
.argument("<files...>", "Files to process")
.action(async (files, options) => {
if (!options.title) {
throw new Error("Please specify a title.");
}
if (!options.slug) {
throw new Error("Please specify a slug.");
}
const parsedFiles = await prepareFiles(files);
const [
shootingConditions,
uploadedJpegImages,
uploadedJpegFiles,
uploadedRawFiles,
] = await Promise.all([
Promise.all(parsedFiles.map(extractShootingConditions)),
Promise.all(parsedFiles.map((f) => uploadImage(f.jpegPath))),
Promise.all(parsedFiles.map((f) => uploadFile(f.jpegPath))),
Promise.all(
parsedFiles.map((f) =>
f.rawPath ? uploadFile(f.rawPath) : Promise.resolve(undefined),
),
),
]);
const aggregatedFiles = parsedFiles.map((file, index) => ({
...file,
shootingConditions: shootingConditions[index],
uploadedJpegImage: uploadedJpegImages[index],
uploadedJpegFile: uploadedJpegFiles[index],
uploadedRawFile: uploadedRawFiles[index],
}));
const result: any = {
root: {
children: [],
direction: "ltr",
format: "",
indent: 0,
type: "root",
version: 1,
},
};
if (aggregatedFiles.length > 1) {
aggregatedFiles.slice(1).forEach((file) =>
result.root.children.push(
createImageNode({
src: file.uploadedJpegImage,
caption: createImageCaption(file.shootingConditions),
}),
),
);
}
result.root.children.push(createHeadingNode("Downloads", "h2"));
aggregatedFiles.forEach((file) => {
result.root.children.push(
createFileNode({
src: file.uploadedJpegFile,
name: getBasenameWithExtension(file.jpegPath),
size: file.jpegSize,
}),
);
if (file.uploadedRawFile && file.rawPath && file.rawSize) {
result.root.children.push(
createFileNode({
src: file.uploadedRawFile,
name: getBasenameWithExtension(file.rawPath),
size: file.rawSize,
}),
);
}
});
const post = {
title: options.title,
slug: options.slug,
lexical: JSON.stringify(result),
feature_image: aggregatedFiles[0].uploadedJpegImage,
feature_image_caption: createImageCaption(
aggregatedFiles[0].shootingConditions,
),
status: "published",
visibility: "public",
tags: options.keywords,
published_at: aggregatedFiles[0].shootingConditions.timestamp,
};
const url = await uploadPost(post);
console.log(url);
process.exit(0);
})
.parse();