mirror of
https://github.com/C4illin/ConvertX.git
synced 2025-11-04 14:03:32 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
961a55cbe5 | ||
|
|
cdf9bad903 | ||
|
|
6769fa2f83 | ||
|
|
3b7ea88b73 | ||
|
|
59310c095d | ||
|
|
c47f0c12fe | ||
|
|
ca71a40485 | ||
|
|
d4e8f376c1 | ||
|
|
14c6ea1e6b | ||
|
|
d6e4d8fbd6 | ||
|
|
460bda62d5 | ||
|
|
d2702ab673 | ||
|
|
e2581f42f5 | ||
|
|
f0fcfc159f | ||
|
|
538c5b60c9 | ||
|
|
2fabb7bbb2 | ||
|
|
e7c34a9c94 | ||
|
|
618f9fce5a | ||
|
|
95dbc9f678 | ||
|
|
aa87bc5c51 | ||
|
|
815de531ed | ||
|
|
cf2b026dc4 | ||
|
|
9ce46aefba | ||
|
|
98b2db7818 | ||
|
|
0229851bf9 | ||
|
|
9e15114fe8 | ||
|
|
7f66a76bb0 | ||
|
|
e9cc8392bb | ||
|
|
d0b89ce74f | ||
|
|
f537c81db7 | ||
|
|
03d3edfff6 | ||
|
|
447b4c5e5c | ||
|
|
cb143209ae | ||
|
|
9c24fe73b5 | ||
|
|
19ae85424b | ||
|
|
22fad99552 | ||
|
|
8144bbef74 | ||
|
|
aad6da0ae8 | ||
|
|
c5f8162a22 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.10.1](https://github.com/C4illin/ConvertX/compare/v0.10.0...v0.10.1) (2025-01-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ffmpeg works without ffmpeg_args ([3b7ea88](https://github.com/C4illin/ConvertX/commit/3b7ea88b7382f7c21b120bdc9bda5bb10547f55d)), closes [#212](https://github.com/C4illin/ConvertX/issues/212)
|
||||||
|
|
||||||
|
## [0.10.0](https://github.com/C4illin/ConvertX/compare/v0.9.0...v0.10.0) (2025-01-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add calibre ([03d3edf](https://github.com/C4illin/ConvertX/commit/03d3edfff65c252dd4b8922fc98257c089c1ff74)), closes [#191](https://github.com/C4illin/ConvertX/issues/191)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add FFMPEG_ARGS env variable ([f537c81](https://github.com/C4illin/ConvertX/commit/f537c81db7815df8017f834e3162291197e1c40f)), closes [#190](https://github.com/C4illin/ConvertX/issues/190)
|
||||||
|
* add qt6-qtbase-private-dev from community repo ([95dbc9f](https://github.com/C4illin/ConvertX/commit/95dbc9f678bec7e6e2c03587e1473fb8ff708ea3))
|
||||||
|
* skip account setup when ALLOW_UNAUTHENTICATED is true ([538c5b6](https://github.com/C4illin/ConvertX/commit/538c5b60c9e27a8184740305475245da79bae143))
|
||||||
|
|
||||||
## [0.9.0](https://github.com/C4illin/ConvertX/compare/v0.8.1...v0.9.0) (2024-11-21)
|
## [0.9.0](https://github.com/C4illin/ConvertX/compare/v0.8.1...v0.9.0) (2024-11-21)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM oven/bun:1.1.36-alpine AS base
|
FROM oven/bun:1.1.45-alpine AS base
|
||||||
LABEL org.opencontainers.image.source="https://github.com/C4illin/ConvertX"
|
LABEL org.opencontainers.image.source="https://github.com/C4illin/ConvertX"
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -51,7 +51,12 @@ RUN apk --no-cache add \
|
|||||||
vips-jxl \
|
vips-jxl \
|
||||||
libjxl-tools \
|
libjxl-tools \
|
||||||
assimp \
|
assimp \
|
||||||
inkscape
|
inkscape \
|
||||||
|
poppler-utils
|
||||||
|
|
||||||
|
RUN apk --no-cache add qt6-qtbase-private-dev --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/
|
||||||
|
|
||||||
|
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.
|
# this might be needed for some latex use cases, will add it if needed.
|
||||||
# texmf-dist-fontsextra \
|
# texmf-dist-fontsextra \
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
[](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml)
|
[](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml)
|
||||||
[](https://github.com/C4illin/ConvertX/pkgs/container/ConvertX)
|
[](https://github.com/C4illin/ConvertX/pkgs/container/ConvertX)
|
||||||
|
[](https://hub.docker.com/r/c4illin/convertx)
|
||||||
[](https://github.com/C4illin/ConvertX/pkgs/container/convertx)
|
[](https://github.com/C4illin/ConvertX/pkgs/container/convertx)
|
||||||

|

|
||||||

|

|
||||||
@@ -26,12 +27,13 @@ A self-hosted online file converter. Supports over a thousand different formats.
|
|||||||
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
|
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
|
||||||
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
|
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
|
||||||
| [Vips](https://github.com/libvips/libvips) | Images | 45 | 23 |
|
| [Vips](https://github.com/libvips/libvips) | Images | 45 | 23 |
|
||||||
| [Assimp](https://github.com/assimp/assimp) | 3D Assets | 70 | 24 |
|
|
||||||
| [XeLaTeX](https://tug.org/xetex/) | LaTeX | 1 | 1 |
|
| [XeLaTeX](https://tug.org/xetex/) | LaTeX | 1 | 1 |
|
||||||
|
| [Calibre](https://calibre-ebook.com/) | E-books | 26 | 19 |
|
||||||
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
|
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
|
||||||
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 166 | 133 |
|
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 167 | 130 |
|
||||||
| [Inkscape](https://inkscape.org/) | Vector images | 7 | 17 |
|
| [Inkscape](https://inkscape.org/) | Vector images | 7 | 17 |
|
||||||
| [FFmpeg](https://ffmpeg.org/) | Video | ~473 | ~280 |
|
| [Assimp](https://github.com/assimp/assimp) | 3D Assets | 77 | 23 |
|
||||||
|
| [FFmpeg](https://ffmpeg.org/) | Video | ~472 | ~199 |
|
||||||
|
|
||||||
<!-- many ffmpeg fileformats are duplicates -->
|
<!-- many ffmpeg fileformats are duplicates -->
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() if unset
|
- JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() if unset
|
||||||
volumes:
|
volumes:
|
||||||
- convertx:/app/data
|
- ./data:/app/data
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
@@ -75,11 +77,27 @@ All are optional, JWT_SECRET is recommended to be set.
|
|||||||
| HTTP_ALLOWED | false | Allow HTTP connections, only set this to true locally |
|
| HTTP_ALLOWED | false | Allow HTTP connections, only set this to true locally |
|
||||||
| ALLOW_UNAUTHENTICATED | false | Allow unauthenticated users to use the service, only set this to true locally |
|
| ALLOW_UNAUTHENTICATED | false | Allow unauthenticated users to use the service, only set this to true locally |
|
||||||
| AUTO_DELETE_EVERY_N_HOURS | 24 | Checks every n hours for files older then n hours and deletes them, set to 0 to disable |
|
| AUTO_DELETE_EVERY_N_HOURS | 24 | Checks every n hours for files older then n hours and deletes them, set to 0 to disable |
|
||||||
| WEBROOT | "" | The address to the root path setting this to "/convert" will serve the website on "example.com/convert/" |
|
| WEBROOT | | The address to the root path setting this to "/convert" will serve the website on "example.com/convert/" |
|
||||||
|
| FFMPEG_ARGS | | Arguments to pass to ffmpeg, e.g. `-preset veryfast` |
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> If you can't login, make sure you are accessing the service over https or set HTTP_ALLOWED=true
|
> If you can't login, make sure you are accessing the service over https or set HTTP_ALLOWED=true
|
||||||
|
|
||||||
|
### Docker images
|
||||||
|
|
||||||
|
There is a `:latest` tag that is updated with every release and a `:main` tag that is updated with every push to the main branch. `:latest` is recommended for normal use.
|
||||||
|
|
||||||
|
The image is available on [GitHub Container Registry](https://github.com/C4illin/ConvertX/pkgs/container/ConvertX) and [Docker Hub](https://hub.docker.com/r/c4illin/convertx).
|
||||||
|
|
||||||
|
| Image | What it is |
|
||||||
|
|-------|------------|
|
||||||
|
| `image: ghcr.io/c4illin/convertx` | The latest release on ghcr |
|
||||||
|
| `image: ghcr.io/c4illin/convertx:main` | The latest commit on ghcr |
|
||||||
|
| `image: c4illin/convertx` | The latest release on docker hub |
|
||||||
|
| `image: c4illin/convertx:main` | The latest commit on docker hub |
|
||||||
|
|
||||||
|
<!-- Dockerhub was introduced in 0.9.0 and older releases -->
|
||||||
|
|
||||||
### Tutorial
|
### Tutorial
|
||||||
|
|
||||||
Tutorial in french: <https://belginux.com/installer-convertx-avec-docker/>
|
Tutorial in french: <https://belginux.com/installer-convertx-avec-docker/>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ services:
|
|||||||
- HTTP_ALLOWED=true # setting this to true is unsafe, only set this to true locally
|
- 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
|
- 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
|
- 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
|
# - FFMPEG_ARGS=-hwaccel vulkan # additional arguments to pass to ffmpeg
|
||||||
|
# - WEBROOT=/convertx # the root path of the web interface, leave empty to disable
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
|
|||||||
42
package.json
42
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "convertx-frontend",
|
"name": "convertx-frontend",
|
||||||
"version": "0.9.0",
|
"version": "0.10.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --watch src/index.tsx",
|
"dev": "bun run --watch src/index.tsx",
|
||||||
"hot": "bun run --hot src/index.tsx",
|
"hot": "bun run --hot src/index.tsx",
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elysiajs/cookie": "^0.8.0",
|
"@elysiajs/cookie": "^0.8.0",
|
||||||
"@elysiajs/html": "^1.1.1",
|
"@elysiajs/html": "^1.2.0",
|
||||||
"@elysiajs/jwt": "^1.1.1",
|
"@elysiajs/jwt": "^1.2.0",
|
||||||
"@elysiajs/static": "^1.1.1",
|
"@elysiajs/static": "^1.2.0",
|
||||||
"@kitajs/html": "^4.2.4",
|
"@kitajs/html": "^4.2.7",
|
||||||
"elysia": "^1.1.25"
|
"elysia": "^1.2.10"
|
||||||
},
|
},
|
||||||
"module": "src/index.tsx",
|
"module": "src/index.tsx",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -25,31 +25,31 @@
|
|||||||
"start": "bun run src/index.tsx"
|
"start": "bun run src/index.tsx"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/compat": "^1.2.3",
|
"@eslint/compat": "^1.2.5",
|
||||||
"@eslint/js": "^9.15.0",
|
"@eslint/js": "^9.18.0",
|
||||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
|
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||||
"@kitajs/ts-html-plugin": "^4.1.0",
|
"@kitajs/ts-html-plugin": "^4.1.1",
|
||||||
"@total-typescript/ts-reset": "^0.6.1",
|
"@total-typescript/ts-reset": "^0.6.1",
|
||||||
"@types/bun": "^1.1.13",
|
"@types/bun": "^1.1.16",
|
||||||
"@types/eslint-plugin-tailwindcss": "^3.17.0",
|
"@types/eslint-plugin-tailwindcss": "^3.17.0",
|
||||||
"@types/eslint__js": "^8.42.3",
|
"@types/eslint__js": "^8.42.3",
|
||||||
"@types/node": "^22.9.1",
|
"@types/node": "^22.10.7",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"cssnano": "^7.0.6",
|
"cssnano": "^7.0.6",
|
||||||
"eslint": "^9.15.0",
|
"eslint": "^9.18.0",
|
||||||
"eslint-plugin-deprecation": "^3.0.0",
|
"eslint-plugin-deprecation": "^3.0.0",
|
||||||
"eslint-plugin-readable-tailwind": "^1.8.2",
|
"eslint-plugin-readable-tailwind": "^1.8.2",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-tailwindcss": "^3.17.5",
|
"eslint-plugin-tailwindcss": "^3.17.5",
|
||||||
"globals": "^15.12.0",
|
"globals": "^15.14.0",
|
||||||
"knip": "^5.37.1",
|
"knip": "^5.42.1",
|
||||||
"npm-run-all2": "^7.0.1",
|
"npm-run-all2": "^7.0.2",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.5.1",
|
||||||
"postcss-cli": "^11.0.0",
|
"postcss-cli": "^11.0.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.4.2",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "^3.4.15",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.7.3",
|
||||||
"typescript-eslint": "^8.15.0"
|
"typescript-eslint": "^8.20.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,12 @@ import { Html } from "@kitajs/html";
|
|||||||
export const Header = ({
|
export const Header = ({
|
||||||
loggedIn,
|
loggedIn,
|
||||||
accountRegistration,
|
accountRegistration,
|
||||||
|
allowUnauthenticated,
|
||||||
webroot = "",
|
webroot = "",
|
||||||
}: {
|
}: {
|
||||||
loggedIn?: boolean;
|
loggedIn?: boolean;
|
||||||
accountRegistration?: boolean;
|
accountRegistration?: boolean;
|
||||||
|
allowUnauthenticated?: boolean;
|
||||||
webroot?: string;
|
webroot?: string;
|
||||||
}) => {
|
}) => {
|
||||||
let rightNav: JSX.Element;
|
let rightNav: JSX.Element;
|
||||||
@@ -24,6 +26,7 @@ export const Header = ({
|
|||||||
History
|
History
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{!allowUnauthenticated ? (
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class={`
|
class={`
|
||||||
@@ -35,6 +38,7 @@ export const Header = ({
|
|||||||
Logout
|
Logout
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
) : null}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { exec } from "node:child_process";
|
import { exec } from "node:child_process";
|
||||||
|
|
||||||
// This could be done dynamically by running `ffmpeg -formats` and parsing the output
|
|
||||||
export const properties = {
|
export const properties = {
|
||||||
from: {
|
from: {
|
||||||
muxer: [
|
object: [
|
||||||
"3d",
|
"3d",
|
||||||
"3ds",
|
"3ds",
|
||||||
"3mf",
|
"3mf",
|
||||||
@@ -84,7 +83,7 @@ export const properties = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
muxer: [
|
object: [
|
||||||
"3ds",
|
"3ds",
|
||||||
"3mf",
|
"3mf",
|
||||||
"assbin",
|
"assbin",
|
||||||
@@ -120,8 +119,6 @@ export async function convert(
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: unknown,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// let command = "ffmpeg";
|
|
||||||
|
|
||||||
const command = `assimp export "${filePath}" "${targetPath}"`;
|
const command = `assimp export "${filePath}" "${targetPath}"`;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
86
src/converters/calibre.ts
Normal file
86
src/converters/calibre.ts
Normal file
@@ -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");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -700,7 +700,7 @@ export async function convert(
|
|||||||
message = "Done: resized to 256x256";
|
message = "Done: resized to 256x256";
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = `ffmpeg -i "${filePath}" ${extra} "${targetPath}"`;
|
const command = `ffmpeg ${process.env.FFMPEG_ARGS || ""} -i "${filePath}" ${extra} "${targetPath}"`;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(command, (error, stdout, stderr) => {
|
exec(command, (error, stdout, stderr) => {
|
||||||
|
|||||||
@@ -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 convertresvg, properties as propertiesresvg } from "./resvg";
|
||||||
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
||||||
import { convert as convertxelatex, properties as propertiesxelatex } from "./xelatex";
|
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
|
// 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,
|
properties: propertiesxelatex,
|
||||||
converter: convertxelatex,
|
converter: convertxelatex,
|
||||||
},
|
},
|
||||||
|
calibre: {
|
||||||
|
properties: propertiesCalibre,
|
||||||
|
converter: convertCalibre,
|
||||||
|
},
|
||||||
pandoc: {
|
pandoc: {
|
||||||
properties: propertiesPandoc,
|
properties: propertiesPandoc,
|
||||||
converter: convertPandoc,
|
converter: convertPandoc,
|
||||||
|
|||||||
@@ -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) => {
|
exec("bun -v", (error, stdout) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Bun is not installed. wait what");
|
console.error("Bun is not installed. wait what");
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ const app = new Elysia({
|
|||||||
<Header
|
<Header
|
||||||
webroot={WEBROOT}
|
webroot={WEBROOT}
|
||||||
accountRegistration={ACCOUNT_REGISTRATION}
|
accountRegistration={ACCOUNT_REGISTRATION}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
/>
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
@@ -340,6 +341,7 @@ const app = new Elysia({
|
|||||||
<Header
|
<Header
|
||||||
webroot={WEBROOT}
|
webroot={WEBROOT}
|
||||||
accountRegistration={ACCOUNT_REGISTRATION}
|
accountRegistration={ACCOUNT_REGISTRATION}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
/>
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
@@ -457,36 +459,19 @@ const app = new Elysia({
|
|||||||
return redirect(`${WEBROOT}/login`, 302);
|
return redirect(`${WEBROOT}/login`, 302);
|
||||||
})
|
})
|
||||||
.get("/", async ({ jwt, redirect, cookie: { auth, jobId } }) => {
|
.get("/", async ({ jwt, redirect, cookie: { auth, jobId } }) => {
|
||||||
|
if (!ALLOW_UNAUTHENTICATED) {
|
||||||
if (FIRST_RUN) {
|
if (FIRST_RUN) {
|
||||||
return redirect(`${WEBROOT}/setup`, 302);
|
return redirect(`${WEBROOT}/setup`, 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!auth?.value && !ALLOW_UNAUTHENTICATED) {
|
if (!auth?.value) {
|
||||||
return redirect(`${WEBROOT}/login`, 302);
|
return redirect(`${WEBROOT}/login`, 302);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validate jwt
|
// validate jwt
|
||||||
let user: ({ id: string } & JWTPayloadSpec) | false = false;
|
let user: ({ id: string } & JWTPayloadSpec) | false = false;
|
||||||
if (auth?.value) {
|
if (ALLOW_UNAUTHENTICATED) {
|
||||||
user = await jwt.verify(auth.value);
|
|
||||||
|
|
||||||
if (user !== false && user.id) {
|
|
||||||
if (Number.parseInt(user.id) < 2 ** 24 || !ALLOW_UNAUTHENTICATED) {
|
|
||||||
// make sure user exists in db
|
|
||||||
const existingUser = db
|
|
||||||
.query("SELECT * FROM users WHERE id = ?")
|
|
||||||
.as(User)
|
|
||||||
.get(user.id);
|
|
||||||
|
|
||||||
if (!existingUser) {
|
|
||||||
if (auth?.value) {
|
|
||||||
auth.remove();
|
|
||||||
}
|
|
||||||
return redirect(`${WEBROOT}/login`, 302);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ALLOW_UNAUTHENTICATED) {
|
|
||||||
const newUserId = String(
|
const newUserId = String(
|
||||||
randomInt(
|
randomInt(
|
||||||
2 ** 24,
|
2 ** 24,
|
||||||
@@ -512,6 +497,25 @@ const app = new Elysia({
|
|||||||
maxAge: 24 * 60 * 60,
|
maxAge: 24 * 60 * 60,
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
});
|
});
|
||||||
|
} else if (auth?.value) {
|
||||||
|
user = await jwt.verify(auth.value);
|
||||||
|
|
||||||
|
if (user !== false && user.id) {
|
||||||
|
if (Number.parseInt(user.id) < 2 ** 24 || !ALLOW_UNAUTHENTICATED) {
|
||||||
|
// make sure user exists in db
|
||||||
|
const existingUser = db
|
||||||
|
.query("SELECT * FROM users WHERE id = ?")
|
||||||
|
.as(User)
|
||||||
|
.get(user.id);
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
if (auth?.value) {
|
||||||
|
auth.remove();
|
||||||
|
}
|
||||||
|
return redirect(`${WEBROOT}/login`, 302);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
@@ -547,7 +551,11 @@ const app = new Elysia({
|
|||||||
return (
|
return (
|
||||||
<BaseHtml webroot={WEBROOT}>
|
<BaseHtml webroot={WEBROOT}>
|
||||||
<>
|
<>
|
||||||
<Header webroot={WEBROOT} loggedIn />
|
<Header
|
||||||
|
webroot={WEBROOT}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
|
loggedIn
|
||||||
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
<h1 class="mb-4 text-xl">Convert</h1>
|
<h1 class="mb-4 text-xl">Convert</h1>
|
||||||
@@ -951,7 +959,11 @@ const app = new Elysia({
|
|||||||
return (
|
return (
|
||||||
<BaseHtml webroot={WEBROOT} title="ConvertX | Results">
|
<BaseHtml webroot={WEBROOT} title="ConvertX | Results">
|
||||||
<>
|
<>
|
||||||
<Header webroot={WEBROOT} loggedIn />
|
<Header
|
||||||
|
webroot={WEBROOT}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
|
loggedIn
|
||||||
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
<h1 class="mb-4 text-xl">Results</h1>
|
<h1 class="mb-4 text-xl">Results</h1>
|
||||||
@@ -1038,7 +1050,11 @@ const app = new Elysia({
|
|||||||
return (
|
return (
|
||||||
<BaseHtml webroot={WEBROOT} title="ConvertX | Result">
|
<BaseHtml webroot={WEBROOT} title="ConvertX | Result">
|
||||||
<>
|
<>
|
||||||
<Header webroot={WEBROOT} loggedIn />
|
<Header
|
||||||
|
webroot={WEBROOT}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
|
loggedIn
|
||||||
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
@@ -1284,7 +1300,11 @@ const app = new Elysia({
|
|||||||
return (
|
return (
|
||||||
<BaseHtml webroot={WEBROOT} title="ConvertX | Converters">
|
<BaseHtml webroot={WEBROOT} title="ConvertX | Converters">
|
||||||
<>
|
<>
|
||||||
<Header webroot={WEBROOT} loggedIn />
|
<Header
|
||||||
|
webroot={WEBROOT}
|
||||||
|
allowUnauthenticated={ALLOW_UNAUTHENTICATED}
|
||||||
|
loggedIn
|
||||||
|
/>
|
||||||
<main class="w-full px-4">
|
<main class="w-full px-4">
|
||||||
<article class="article">
|
<article class="article">
|
||||||
<h1 class="mb-4 text-xl">Converters</h1>
|
<h1 class="mb-4 text-xl">Converters</h1>
|
||||||
|
|||||||
Reference in New Issue
Block a user