浏览代码

feat: add calibre

issue #191
C4illin 7 月之前
父节点
当前提交
03d3edfff6
共有 6 个文件被更改,包括 123 次插入22 次删除
  1. 4 1
      Dockerfile
  2. 16 16
      compose.yaml
  3. 2 5
      src/converters/assimp.ts
  4. 86 0
      src/converters/calibre.ts
  5. 5 0
      src/converters/main.ts
  6. 10 0
      src/helpers/printVersions.ts

+ 4 - 1
Dockerfile

@@ -51,7 +51,10 @@ RUN apk --no-cache add  \
   vips-jxl \
   libjxl-tools \
   assimp \
-  inkscape
+  inkscape \
+  poppler-utils
+
+RUN apk --no-cache add calibre --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/
 
 # this might be needed for some latex use cases, will add it if needed.
 #   texmf-dist-fontsextra \

+ 16 - 16
compose.yaml

@@ -1,16 +1,16 @@
-services:
-  convertx:
-    build:
-      context: .
-      # dockerfile: Debian.Dockerfile
-    volumes:
-      - ./data:/app/data
-    environment: # Defaults are listed below. All are optional.
-      - ACCOUNT_REGISTRATION=true # true or false, doesn't matter for the first account (e.g. keep this to false if you only want one account)
-      - JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() by default
-      - HTTP_ALLOWED=true # setting this to true is unsafe, only set this to true locally
-      - ALLOW_UNAUTHENTICATED=true # allows anyone to use the service without logging in, only set this to true locally
-      - AUTO_DELETE_EVERY_N_HOURS=1 # checks every n hours for files older then n hours and deletes them, set to 0 to disable
-      - WEBROOT=/convertx # the root path of the web interface, leave empty to disable
-    ports:
-      - 3000:3000
+services:
+  convertx:
+    build:
+      context: .
+      # dockerfile: Debian.Dockerfile
+    volumes:
+      - ./data:/app/data
+    environment: # Defaults are listed below. All are optional.
+      - ACCOUNT_REGISTRATION=true # true or false, doesn't matter for the first account (e.g. keep this to false if you only want one account)
+      - JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() by default
+      - HTTP_ALLOWED=true # setting this to true is unsafe, only set this to true locally
+      - ALLOW_UNAUTHENTICATED=true # allows anyone to use the service without logging in, only set this to true locally
+      - AUTO_DELETE_EVERY_N_HOURS=1 # checks every n hours for files older then n hours and deletes them, set to 0 to disable
+      # - WEBROOT=/convertx # the root path of the web interface, leave empty to disable
+    ports:
+      - 3000:3000

+ 2 - 5
src/converters/assimp.ts

@@ -1,9 +1,8 @@
 import { exec } from "node:child_process";
 
-// This could be done dynamically by running `ffmpeg -formats` and parsing the output
 export const properties = {
   from: {
-    muxer: [
+    object: [
       "3d",
       "3ds",
       "3mf",
@@ -84,7 +83,7 @@ export const properties = {
     ],
   },
   to: {
-    muxer: [
+    object: [
       "3ds",
       "3mf",
       "assbin",
@@ -120,8 +119,6 @@ export async function convert(
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   options?: unknown,
 ): Promise<string> {
-  // let command = "ffmpeg";
-
   const command = `assimp export "${filePath}" "${targetPath}"`;
 
   return new Promise((resolve, reject) => {

+ 86 - 0
src/converters/calibre.ts

@@ -0,0 +1,86 @@
+import { exec } from "node:child_process";
+
+export const properties = {
+  from: {
+    document: [
+      "azw4",
+      "chm",
+      "cbr",
+      "cbz",
+      "cbt",
+      "cba",
+      "cb7",
+      "djvu",
+      "docx",
+      "epub",
+      "fb2",
+      "htlz",
+      "html",
+      "lit",
+      "lrf",
+      "mobi",
+      "odt",
+      "pdb",
+      "pdf",
+      "pml",
+      "rb",
+      "rtf",
+      "recipe",
+      "snb",
+      "tcr",
+      "txt",
+    ],
+  },
+  to: {
+    document: [
+      "azw3",
+      "docx",
+      "epub",
+      "fb2",
+      "html",
+      "htmlz",
+      "lit",
+      "lrf",
+      "mobi",
+      "oeb",
+      "pdb",
+      "pdf",
+      "pml",
+      "rb",
+      "rtf",
+      "snb",
+      "tcr",
+      "txt",
+      "txtz",
+    ],
+  },
+};
+
+export async function convert(
+  filePath: string,
+  fileType: string,
+  convertTo: string,
+  targetPath: string,
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  options?: unknown,
+): Promise<string> {
+  const command = `ebook-convert "${filePath}" "${targetPath}"`;
+
+  return new Promise((resolve, reject) => {
+    exec(command, (error, stdout, stderr) => {
+      if (error) {
+        reject(`error: ${error}`);
+      }
+
+      if (stdout) {
+        console.log(`stdout: ${stdout}`);
+      }
+
+      if (stderr) {
+        console.error(`stderr: ${stderr}`);
+      }
+
+      resolve("Done");
+    });
+  });
+}

+ 5 - 0
src/converters/main.ts

@@ -8,6 +8,7 @@ import { convert as convertPandoc, properties as propertiesPandoc } from "./pand
 import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
 import { convert as convertImage, properties as propertiesImage } from "./vips";
 import { convert as convertxelatex, properties as propertiesxelatex } from "./xelatex";
+import { convert as convertCalibre, properties as propertiesCalibre } from "./calibre";
 
 
 // This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular
@@ -56,6 +57,10 @@ const properties: Record<
     properties: propertiesxelatex,
     converter: convertxelatex,
   },
+  calibre: {
+    properties: propertiesCalibre,
+    converter: convertCalibre,
+  },
   pandoc: {
     properties: propertiesPandoc,
     converter: convertPandoc,

+ 10 - 0
src/helpers/printVersions.ts

@@ -103,6 +103,16 @@ if (process.env.NODE_ENV === "production") {
     }
   });
 
+  exec("ebook-convert --version", (error, stdout) => {
+    if (error) {
+      console.error("ebook-convert (calibre) 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");