rtl-epub-maker/pages/api/book.ts

98 lines
2.8 KiB
TypeScript

import nextConnect from "next-connect";
import { NextApiResponse } from "next";
import writeYamlFile from "write-yaml-file";
import { statSync, createReadStream, writeFileSync, readFileSync } from "fs";
import { spawn } from "child_process";
import { join } from "path";
import { deleteFile } from "../../lib/backend-file-utils";
import multer from "multer";
const upload = multer({
storage: multer.diskStorage({
destination: './tmp',
filename: (req, file, cb) => {
cb(null, file.originalname);
},
}),
});
const route = nextConnect<any, NextApiResponse>({
onError(error, req, res) {
res.status(501).json({ error: `Sorry something Happened! ${error.message}` });
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
route.use(upload.any());
route.post((req, res) => {
const coverFile = (req.files[0] as Express.Multer.File);
const cover = coverFile ? join("tmp", coverFile.filename) : undefined;
const content = req.body.content as string;
const frontmatter = JSON.parse(req.body.frontmatter) as Frontmatter;
makeEpub(content, frontmatter, cover, (err, toDownload) => {
if (err || !toDownload) throw err;
const stat = statSync(toDownload);
// express res.download doesn't work with next-connect
res.writeHead(200, {
'Content-Type': 'application/epub+zip',
'Content-Length': stat.size,
'Content-Disposition': "attacment",
});
const readStream = createReadStream(toDownload);
readStream.pipe(res);
readStream.on("close", () => {
deleteFile(toDownload);
});
});
});
export default route;
export const config = {
api: {
bodyParser: false,
},
};
async function makeEpub(content: string, frontmatter: Frontmatter, cover: string | undefined, callback: (err: any, toDownload?: string) => void) {
const ts = new Date().getTime().toString();
const mdFile = join("tmp", `${ts}.md`);
const yamlFile = join("tmp", `${ts}.yaml`);
const epubFile = join("tmp", `${ts}.epub`);
if (cover) {
frontmatter["epub-cover-image"] = cover;
frontmatter["cover-image"] = cover;
}
writeFileSync(mdFile, content, "utf-8");
await writeYamlFile(yamlFile, frontmatter);
writeFileSync(yamlFile, `
---
${readFileSync(yamlFile, "utf-8")}
---
`, "utf8");
const pandoc = spawn("pandoc", [
"--table-of-contents",
"--css",
join("templates", "book.css"),
"-o",
epubFile,
yamlFile,
mdFile,
]);
pandoc.on("error", (err) => {
console.error("error converting word document");
console.error(err);
});
pandoc.stderr.on("data", data => {
console.error(data.toString());
});
pandoc.on("close", (code) => {
if (code === 0) {
callback(null, epubFile);
} else {
callback("error making epub with pandoc");
}
deleteFile(mdFile, yamlFile, cover);
});
}