Add darktable ghost publish plugin

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-12-22 21:39:55 +02:00
parent 98ce774210
commit f44dac4158
17 changed files with 2624 additions and 19 deletions

View File

@@ -0,0 +1,115 @@
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();