diff --git a/Dockerfile b/Dockerfile index c731410..16b4740 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,6 +56,7 @@ RUN apt-get update && apt-get install -y \ inkscape \ libheif-examples \ libjxl-tools \ + libreoffice \ libva2 \ libvips-tools \ lmodern \ @@ -81,4 +82,4 @@ EXPOSE 3000/tcp # used for calibre ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox" ENV NODE_ENV=production -ENTRYPOINT [ "bun", "run", "./src/index.tsx" ] \ No newline at end of file +ENTRYPOINT [ "bun", "run", "./src/index.tsx" ] diff --git a/src/converters/libreoffice.ts b/src/converters/libreoffice.ts new file mode 100644 index 0000000..d5c47af --- /dev/null +++ b/src/converters/libreoffice.ts @@ -0,0 +1,176 @@ +import { execFile } from "node:child_process"; + +export const properties = { + from: { + text: [ + "602", + "abw", + "csv", + "cwk", + "doc", + "docm", + "docx", + "dot", + "dotx", + "dotm", + "epub", + "fb2", + "fodt", + "htm", + "html", + "hwp", + "mcw", + "mw", + "mwd", + "lwp", + "lrf", + "odt", + "ott", + "pages", + "pdf", + "psw", + "rtf", + "sdw", + "stw", + "sxw", + "tab", + "tsv", + "txt", + "wn", + "wpd", + "wps", + "wpt", + "wri", + "xhtml", + "xml", + "zabw", + ], + }, + to: { + text: [ + "csv", + "doc", + "docm", + "docx", + "dot", + "dotx", + "dotm", + "epub", + "fodt", + "htm", + "html", + "odt", + "ott", + "pdf", + "rtf", + "tab", + "tsv", + "txt", + "wps", + "wpt", + "xhtml", + "xml", + ], + }, +}; + +type FileCategories = "text" | "calc"; + +const filters: Record> = { + text: { + "602": "T602Document", + abw: "AbiWord", + csv: "Text", + doc: "MS Word 97", + docm: "MS Word 2007 XML VBA", + docx: "MS Word 2007 XML", + dot: "MS Word 97 Vorlage", + dotx: "MS Word 2007 XML Template", + dotm: "MS Word 2007 XML Template", + epub: "EPUB", + fb2: "Fictionbook 2", + fodt: "OpenDocument Text Flat XML", + htm: "HTML (StarWriter)", + html: "HTML (StarWriter)", + hwp: "writer_MIZI_Hwp_97", + mcw: "MacWrite", + mw: "MacWrite", + mwd: "Mariner_Write", + lwp: "LotusWordPro", + lrf: "BroadBand eBook", + odt: "writer8", + ott: "writer8_template", + pages: "Apple Pages", + // pdf: "writer_pdf_import", + psw: "PocketWord File", + rtf: "Rich Text Format", + sdw: "StarOffice_Writer", + stw: "writer_StarOffice_XML_Writer_Template", + sxw: "StarOffice XML (Writer)", + tab: "Text", + tsv: "Text", + txt: "Text", + wn: "WriteNow", + wpd: "WordPerfect", + wps: "MS Word 97", + wpt: "MS Word 97 Vorlage", + wri: "MS_Write", + xhtml: "HTML (StarWriter)", + xml: "OpenDocument Text Flat XML", + zabw: "AbiWord", + }, + calc: {}, +}; + +const getFilters = (fileType: string, converto: string) => { + if (fileType in filters.text && converto in filters.text) { + return [filters.text[fileType], filters.text[converto]]; + } else if (fileType in filters.calc && converto in filters.calc) { + return [filters.calc[fileType], filters.calc[converto]]; + } + return [null, null]; +}; + +export function convert( + filePath: string, + fileType: string, + convertTo: string, + targetPath: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: unknown, +): Promise { + const outputPath = targetPath.split("/").slice(0, -1).join("/").replace("./", "") ?? targetPath; + + // Build arguments array + const args: string[] = []; + args.push("--headless"); + const [inFilter, outFilter] = getFilters(fileType, convertTo); + + if (inFilter) { + args.push(`--infilter="${inFilter}"`); + } + + if (outFilter) { + args.push("--convert-to", `${convertTo}:${outFilter}`, "--outdir", outputPath, filePath); + } else { + args.push("--convert-to", convertTo, "--outdir", outputPath, filePath); + } + + return new Promise((resolve, reject) => { + execFile("soffice", args, (error, stdout, stderr) => { + if (error) { + reject(`error: ${error}`); + } + + if (stdout) { + console.log(`stdout: ${stdout}`); + } + + if (stderr) { + console.error(`stderr: ${stderr}`); + } + + resolve("Done"); + }); + }); +} diff --git a/src/converters/main.ts b/src/converters/main.ts index 1726f44..0d08416 100644 --- a/src/converters/main.ts +++ b/src/converters/main.ts @@ -11,6 +11,7 @@ import { convert as convertImagemagick, properties as propertiesImagemagick } fr import { convert as convertInkscape, properties as propertiesInkscape } from "./inkscape"; import { convert as convertLibheif, properties as propertiesLibheif } from "./libheif"; import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libjxl"; +import { convert as convertLibreOffice, properties as propertiesLibreOffice } from "./libreoffice"; import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc"; import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace"; import { convert as convertresvg, properties as propertiesresvg } from "./resvg"; @@ -76,6 +77,10 @@ const properties: Record< properties: propertiesCalibre, converter: convertCalibre, }, + libreoffice: { + properties: propertiesLibreOffice, + converter: convertLibreOffice, + }, pandoc: { properties: propertiesPandoc, converter: convertPandoc, diff --git a/src/helpers/printVersions.ts b/src/helpers/printVersions.ts index 42044d2..68af2e0 100644 --- a/src/helpers/printVersions.ts +++ b/src/helpers/printVersions.ts @@ -144,6 +144,16 @@ if (process.env.NODE_ENV === "production") { } }); + exec("soffice --version", (error, stdout) => { + if (error) { + console.error("libreoffice is not installed"); + } + + if (stdout) { + console.log(stdout.split("\n")[0]); + } + }); + exec("bun -v", (error, stdout) => { if (error) { console.error("Bun is not installed. wait what");