Compare commits

...

217 Commits

Author SHA1 Message Date
C4illin bba420386f chore: flake wip 2025-05-15 22:11:30 +02:00
C4illin 74df47531c chore: nix doesn't like dirty git trees 2025-05-15 21:09:04 +02:00
C4illin 1adac8c31c chore: start on flake 2025-05-15 21:08:20 +02:00
Emrik Östling 0579f1852b chore: add potrace to readme 2025-05-14 13:14:55 +02:00
Emrik Östling 52d4cc0d03 chore: remove calibre from README.md 2025-05-14 13:10:57 +02:00
Emrik Östling 2c68016ca6 chore: remove duplicates 2025-05-14 13:09:06 +02:00
Emrik Östling 7914194856 Merge pull request #255 from C4illin/release-please--branches--main--components--convertx-frontend 2025-05-14 13:07:23 +02:00
Emrik Östling 2dac7f1362 chore: downgrade bun to 1.2.2 2025-05-14 12:19:40 +02:00
Emrik Östling a17e5fd614 chore(main): release 0.13.0 2025-05-14 08:55:39 +02:00
Emrik Östling 21994fb6a2 Merge pull request #282 from aidanjacobson/main
Added support for drag/drop of images
2025-05-14 08:54:10 +02:00
Emrik Östling a5eaaa422a Merge pull request #284 from frederickjansen/hif
feat: Add support for .HIF files
2025-05-14 08:02:28 +02:00
aidanjacobson ff2ef74135 feat: add support for drag/drop of images 2025-05-13 19:19:57 -07:00
Frederick Jansen 70705c1850 feat: Add support for .HIF files 2025-05-13 12:22:08 -04:00
C4illin fd9c151e01 chore: update deps 2025-05-12 09:24:36 +02:00
Emrik Östling 4f0573963f Merge pull request #283 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.13
2025-05-10 18:11:06 +02:00
renovate[bot] 6bb6bce8a4 chore(deps): update oven/bun docker tag to v1.2.13 2025-05-10 14:45:25 +00:00
Emrik Östling 448557bece Merge pull request #278 from atfox98/main 2025-05-07 10:11:44 +02:00
A Fox bdbd4a122c feat: add potrace converter 2025-05-06 12:46:05 -05:00
Emrik Östling cb9d0ec680 Merge pull request #275 from C4illin/renovate/oven-bun-1.x 2025-05-04 23:04:38 +02:00
renovate[bot] fb60ef66f5 chore(deps): update oven/bun docker tag to v1.2.12 2025-05-04 10:08:16 +00:00
Emrik Östling c1ae43075f Merge pull request #274 from C4illin/renovate/npm-run-all2-8.x
chore(deps): update dependency npm-run-all2 to v8
2025-05-02 21:30:55 +02:00
renovate[bot] 377f69ae8d chore(deps): update dependency npm-run-all2 to v8 2025-05-02 18:38:15 +00:00
Emrik Östling cb131cd0a0 Merge pull request #270 from C4illin/renovate/oven-bun-1.x 2025-04-29 10:46:38 +02:00
renovate[bot] fcc83c5ea8 chore(deps): update oven/bun docker tag to v1.2.11 2025-04-29 08:11:10 +00:00
Emrik Östling 96d4717d13 chore: create FUNDING.yml 2025-04-24 18:17:24 +02:00
Emrik Östling 4d73bf9760 chore: add tutorial disclaimer 2025-04-24 18:06:57 +02:00
Emrik Östling 725a94bc95 chore: move http warning 2025-04-24 18:03:21 +02:00
Emrik Östling 0a366b447a chore: add dev image size 2025-04-24 18:01:47 +02:00
Emrik Östling 4a27a7bc03 Merge pull request #264 from C4illin/renovate/oven-bun-1.x 2025-04-17 13:45:47 +02:00
renovate[bot] 3ca5803bda chore(deps): update oven/bun docker tag to v1.2.10 2025-04-17 10:54:10 +00:00
Emrik Östling 239041294c Merge pull request #260 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.9
2025-04-16 12:46:11 +02:00
renovate[bot] 31fdd8f214 chore(deps): update oven/bun docker tag to v1.2.9 2025-04-16 10:08:31 +00:00
C4illin c3319c09eb chore: remove calibre dependency 2025-04-16 11:23:44 +02:00
C4illin d460e94d52 chore: disable calibre due to conflict with other packages 2025-04-16 11:21:40 +02:00
C4illin 4b5c732380 fix: add timezone support
issue #258
2025-04-12 10:24:08 +02:00
C4illin f42665ca40 chore: update deps 2025-04-12 10:18:44 +02:00
Emrik Östling bed52cef17 Merge pull request #254 from kek-Sec/feat/hide-history
feat: add HIDE_HISTORY option to control visibility of history page
2025-04-02 14:26:35 +02:00
g.petrakis 9d1c93155c feat: add HIDE_HISTORY option to control visibility of history page 2025-04-02 15:02:56 +03:00
C4illin 794cc7c474 chore: update deps 2025-04-01 18:09:56 +02:00
C4illin d7d584e497 chore: format 2025-04-01 14:50:15 +02:00
Emrik Östling f5320df86e Merge pull request #241 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.8
2025-04-01 14:19:48 +02:00
C4illin 056fd4ba93 change to bun 1.2.2 2025-04-01 14:19:00 +02:00
Emrik Östling 5b6e70eb3a Merge pull request #246 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.12.1
2025-04-01 14:15:28 +02:00
renovate[bot] f437a8e7e2 chore(deps): update oven/bun docker tag to v1.2.8 2025-03-31 19:37:32 +00:00
Emrik Östling cdae798fcf chore: rollback to 1.2.2
issue: #235
2025-03-20 11:05:24 +01:00
Emrik Östling bcc827a81b chore(main): release 0.12.1 2025-03-20 09:40:15 +01:00
Emrik Östling 84274b9c55 chore: revert to bun 1.2.3
issue: #235
2025-03-20 09:39:36 +01:00
Emrik Östling 20c6f8249e Merge pull request #245 from C4illin/fix/#235/change-to-canary-bun
fix: change to canary bun
2025-03-19 21:19:45 +01:00
C4illin 8f0ea2a592 fix: change to canary bun
issue: #235
2025-03-19 20:30:50 +01:00
Emrik Östling a29e4a930a Merge pull request #242 from C4illin/downgrade-bun-to-1.2.2
chore: downgrade bun to 1.2.2
2025-03-10 13:12:31 +01:00
Emrik Östling 4549c96ae3 chore: remove old labels 2025-03-10 12:38:17 +01:00
Emrik Östling bc64094c04 chore: downgrade bun to 1.2.2
issue: #235
2025-03-10 12:34:47 +01:00
Emrik Östling fa58827ad5 Merge pull request #240 from C4illin/donwgrade-bun-to-1.2.3
chore: downgrade bun to 1.2.3
2025-03-09 22:43:02 +01:00
C4illin 8f27be0e3d chore: downgrade bun 2025-03-09 21:10:59 +01:00
C4illin df43df1178 Merge branch 'main' of https://github.com/C4illin/ConvertX 2025-03-09 21:09:58 +01:00
C4illin c2beb4a227 chore: add default full opacity 2025-03-09 21:09:53 +01:00
Emrik Östling 9277c27a50 chore: change security url 2025-03-09 21:07:04 +01:00
Emrik Östling 171ecd6884 chore: Create SECURITY.md 2025-03-09 21:04:18 +01:00
Emrik Östling dca29f7e5a Merge pull request #239 from C4illin/remove-slim
build: remove slim for tailwind
2025-03-09 16:40:20 +01:00
C4illin 318acc20bd build: remove slim for tailwind 2025-03-08 01:08:00 +01:00
C4illin f433493d57 chore: remove @elysiajs/cookie 2025-03-08 00:28:27 +01:00
C4illin 19970fc132 chore: fix lint 2025-03-06 21:09:02 +01:00
Emrik Östling 24394ca3c5 Merge pull request #226 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.12.0
2025-03-06 18:47:25 +01:00
Emrik Östling 10ff0b464a chore(main): release 0.12.0 2025-03-06 18:17:28 +01:00
C4illin 9263d17609 feat: replace exec with execFile 2025-03-06 18:16:51 +01:00
Emrik Östling c1b75a13fd chore: sanitize filename 2025-03-04 09:23:06 +01:00
Emrik Östling a8ed60d48f Merge pull request #233 from Lacni135/feature-progress
Added progress bar for file upload
2025-02-28 09:57:39 +01:00
lacni dc82a438d4 fix: refactored uploadFile to only accept a single file instead of multiple 2025-02-27 21:11:52 -05:00
lacni cc54bdcbe7 feat: made every upload file independent 2025-02-27 19:18:13 -05:00
lacni ae4bbc8baa fix: added onerror log 2025-02-27 19:15:58 -05:00
C4illin ad98499da0 chore: move libheif below vips 2025-02-27 22:17:02 +01:00
lacni db60f355b2 feat: added progress bar for file upload 2025-02-26 23:31:31 -05:00
Emrik Östling eb91d8b298 Merge pull request #232 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.4
2025-02-26 16:07:27 +01:00
renovate[bot] b8312be4b7 chore(deps): update oven/bun docker tag to v1.2.4 2025-02-26 14:32:53 +00:00
Emrik Östling 326a8e3404 Merge pull request #230 from C4illin/renovate/oven-bun-1.x 2025-02-23 12:45:09 +01:00
renovate[bot] f017e13ac1 chore(deps): update oven/bun docker tag to v1.2.3 2025-02-23 01:15:18 +00:00
Emrik Östling 67a5fe353e Merge pull request #229 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.3
2025-02-22 11:47:50 +01:00
renovate[bot] 51d49d7ff3 chore(deps): update oven/bun docker tag to v1.2.3 2025-02-22 10:05:09 +00:00
Emrik Östling d42b820b36 Merge pull request #227 from C4illin/renovate/eslint__js-9.x
chore(deps): update dependency @types/eslint__js to v9
2025-02-22 11:04:42 +01:00
renovate[bot] 07d32776d3 chore(deps): update dependency @types/eslint__js to v9 2025-02-21 23:05:04 +00:00
Emrik Östling ef027e81b5 Merge pull request #228 from C4illin/renovate/globals-16.x
chore(deps): update dependency globals to v16
2025-02-22 00:04:37 +01:00
renovate[bot] a75e4b495d chore(deps): update dependency globals to v16 2025-02-21 20:05:07 +00:00
C4illin fba5e212e8 fix: update libheif to 1.19.5
issue: #202
2025-02-18 21:24:54 +01:00
C4illin 62f44fb052 chore: print libheif version 2025-02-18 20:05:46 +01:00
Emrik Östling 6b9254047c Merge pull request #225 from C4illin/fix/#202/add-libheif
fix: add libheif
2025-02-16 23:04:35 +01:00
C4illin decfea5dc9 fix: add libheif
issue #202
2025-02-16 21:18:33 +01:00
Emrik Östling eacded6848 Merge pull request #224 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.11.1
2025-02-07 22:52:29 +01:00
Emrik Östling 279ca72c64 chore(main): release 0.11.1 2025-02-07 16:15:21 +01:00
C4illin b8fc9383ca chore: update deps 2025-02-07 16:14:46 +01:00
C4illin bec58ac59f fix: mobile view overflow 2025-02-06 19:57:07 +01:00
Emrik Östling 83d7126820 Merge pull request #216 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.11.0
2025-02-05 15:23:43 +01:00
Emrik Östling f0e9c6d794 chore(main): release 0.11.0 2025-02-05 14:18:31 +01:00
Emrik Östling 0e61051fc6 fix: install numpy for inkscape 2025-02-05 14:17:55 +01:00
C4illin 480ba77ebe chore: fix eslint config 2025-02-01 21:46:15 +01:00
C4illin 16f27c13bb fix: don't crash if file is not found 2025-02-01 21:09:48 +01:00
C4illin afe5c50d66 chore: fix tailwind v4 docker 2025-02-01 21:09:12 +01:00
C4illin 72ea859ebb chore: switch to new lockfile format 2025-02-01 21:08:38 +01:00
C4illin 8edf3834c4 chore: print correct version 2025-02-01 21:08:04 +01:00
C4illin e595014fcd refactor: update Tailwind to v4 2025-02-01 20:15:50 +01:00
Emrik Östling 8bebf7e569 Merge pull request #220 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.2
2025-02-01 10:05:04 +01:00
renovate[bot] c825ec06e2 chore(deps): update oven/bun docker tag to v1.2.2 2025-02-01 08:31:38 +00:00
Emrik Östling 8c75f273fb Merge pull request #217 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.1
2025-01-28 07:13:26 +01:00
renovate[bot] 0ba776c129 chore(deps): update oven/bun docker tag to v1.2.1 2025-01-28 01:48:23 +00:00
C4illin 2bbbd03554 feat: add deps for vaapi
issue #192
2025-01-23 22:00:19 +01:00
C4illin 0a5d0487b1 chore: update deps 2025-01-23 21:59:24 +01:00
Emrik Östling 583cd2dd3b Merge pull request #214 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.2.0
2025-01-22 23:11:45 +01:00
renovate[bot] e1f7fc1ecb chore(deps): update oven/bun docker tag to v1.2.0 2025-01-22 18:46:19 +00:00
Emrik Östling 961a55cbe5 Merge pull request #213 from C4illin/release-please--branches--main--components--convertx-frontend 2025-01-21 23:28:20 +01:00
Emrik Östling cdf9bad903 chore(main): release 0.10.1 2025-01-21 23:25:50 +01:00
C4illin 6769fa2f83 chore: update deps 2025-01-21 23:25:11 +01:00
C4illin 3b7ea88b73 fix: ffmpeg works without ffmpeg_args
issue #212
2025-01-21 23:24:53 +01:00
Emrik Östling 59310c095d Merge pull request #192 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.10.0
2025-01-18 12:46:01 +01:00
Emrik Östling c47f0c12fe chore(main): release 0.10.0 2025-01-18 12:01:01 +01:00
Emrik Östling ca71a40485 Merge pull request #211 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.45
2025-01-18 12:00:28 +01:00
renovate[bot] d4e8f376c1 chore(deps): update oven/bun docker tag to v1.1.45 2025-01-17 17:41:37 +00:00
Emrik Östling 14c6ea1e6b Merge pull request #210 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.44
2025-01-17 11:14:27 +01:00
renovate[bot] d6e4d8fbd6 chore(deps): update oven/bun docker tag to v1.1.44 2025-01-17 09:03:11 +00:00
C4illin 460bda62d5 chore: update deps 2025-01-16 21:30:10 +01:00
Emrik Östling d2702ab673 Merge pull request #208 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.43
2025-01-08 23:35:11 +01:00
renovate[bot] e2581f42f5 chore(deps): update oven/bun docker tag to v1.1.43 2025-01-08 19:03:18 +00:00
Emrik Östling f0fcfc159f Merge pull request #203 from tejashah88/fix-unauthed-users-1
Fix: skip account setup when ALLOW_UNAUTHENTICATED is true
2025-01-04 17:36:04 +01:00
Tejas Shah 538c5b60c9 fix: skip account setup when ALLOW_UNAUTHENTICATED is true 2025-01-04 17:05:03 +01:00
Emrik Östling 2fabb7bbb2 Merge pull request #197 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.42
2025-01-04 14:27:59 +01:00
renovate[bot] e7c34a9c94 chore(deps): update oven/bun docker tag to v1.1.42 2025-01-04 12:43:57 +00:00
Emrik Östling 618f9fce5a Merge pull request #204 from C4illin/fix-calibre-build-error
fix: add qt6-qtbase-private-dev from community repo
2025-01-04 13:43:30 +01:00
C4illin 95dbc9f678 fix: add qt6-qtbase-private-dev from community repo 2025-01-04 12:54:22 +01:00
Emrik Östling aa87bc5c51 Merge pull request #200 from tejashah88/main
Fixed example docker-compose.yml file
2024-12-27 03:34:01 +01:00
Tejas Shah 815de531ed Fixed example docker-compose.yml file 2024-12-26 07:04:26 -08:00
Emrik Östling cf2b026dc4 Merge pull request #196 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.41
2024-12-20 16:44:02 +01:00
renovate[bot] 9ce46aefba chore(deps): update oven/bun docker tag to v1.1.41 2024-12-20 15:33:31 +00:00
Emrik Östling 98b2db7818 Merge pull request #195 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.40
2024-12-18 13:20:35 +01:00
renovate[bot] 0229851bf9 chore(deps): update oven/bun docker tag to v1.1.40 2024-12-18 09:07:21 +00:00
C4illin 9e15114fe8 chore: update deps 2024-12-17 21:56:24 +01:00
Emrik Östling 7f66a76bb0 Merge pull request #194 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.39
2024-12-17 18:04:50 +01:00
renovate[bot] e9cc8392bb chore(deps): update oven/bun docker tag to v1.1.39 2024-12-17 16:08:25 +00:00
C4illin d0b89ce74f chore: add ffmpeg args and calibre to readme 2024-12-11 11:09:03 +01:00
C4illin f537c81db7 fix: add FFMPEG_ARGS env variable
issue #190
2024-12-11 11:01:39 +01:00
C4illin 03d3edfff6 feat: add calibre
issue #191
2024-12-07 02:38:30 +01:00
Emrik Östling 447b4c5e5c Merge pull request #189 from C4illin/renovate/oven-bun-1.x 2024-12-01 12:22:47 +01:00
renovate[bot] cb143209ae chore(deps): update oven/bun docker tag to v1.1.38 2024-11-29 14:10:18 +00:00
C4illin 9c24fe73b5 chore: add table overview for images 2024-11-27 17:06:35 +01:00
C4illin 19ae85424b chore: add dockerhub pulls badge 2024-11-27 16:51:31 +01:00
C4illin 22fad99552 chore: update converter count 2024-11-26 17:18:48 +01:00
Emrik Östling 8144bbef74 Merge pull request #188 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.37
2024-11-26 09:31:12 +01:00
renovate[bot] aad6da0ae8 chore(deps): update oven/bun docker tag to v1.1.37 2024-11-26 04:13:39 +00:00
C4illin c5f8162a22 chore: update deps 2024-11-25 23:22:18 +01:00
Emrik Östling f0f30224b5 Merge pull request #183 from C4illin/release-please--branches--main--components--convertx-frontend
chore(main): release 0.9.0
2024-11-24 14:47:34 +01:00
C4illin d0d888e356 chore: update postcss to ejs 2024-11-21 23:08:30 +01:00
C4illin 2c64122224 chore: update deps 2024-11-21 23:08:16 +01:00
C4illin 3b2eee96a9 chore: update deps 2024-11-21 22:50:45 +01:00
C4illin 465aacbf9b chore: update formats 2024-11-21 22:50:38 +01:00
Emrik Östling d1a2a66170 chore(main): release 0.9.0 2024-11-21 22:44:51 +01:00
C4illin 4c05fd72bb fix: wait for both upload and selection
issue #177
2024-11-21 22:44:13 +01:00
Emrik Östling f04fe760e3 Merge pull request #187 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.36
2024-11-20 10:12:40 +01:00
renovate[bot] 834d19bcc6 chore(deps): update oven/bun docker tag to v1.1.36 2024-11-20 02:03:06 +00:00
Emrik Östling 6808c4642c Update README.md 2024-11-18 17:00:04 +01:00
Emrik Östling d0ce307f94 Merge pull request #186 from C10udburst/main
feat: add inkscape for vector images
2024-11-16 14:13:43 +01:00
Cloudburst f3740e9ded feat: add inkscape for vector images 2024-11-16 11:34:47 +01:00
C4illin b485bc9445 chore: add download stats 2024-11-14 11:26:24 +01:00
Emrik Östling 2d14c1bb26 Merge pull request #184 from C4illin/feature/#177/disable-convert-when-uploading 2024-11-13 14:59:31 +01:00
C4illin 1a442d6e69 fix: treat unknown as m4a
issue #178
2024-11-13 13:08:40 +01:00
C4illin 2386543e5c chore: update deps 2024-11-13 13:08:00 +01:00
C4illin 58e220e82d feat: disable convert when uploading
issue #177
2024-11-12 22:30:16 +01:00
C4illin 24bea6e4d2 chore: add tutorial link 2024-11-12 22:20:32 +01:00
C4illin 43497ad8d1 ci: split docker hub description to separate workflow 2024-11-12 12:35:05 +01:00
C4illin f22b61fe4c ci: sync docker hub description with readme 2024-11-12 12:27:39 +01:00
C4illin 5b08f4cd19 ci: support dockerhub 2024-11-12 12:17:45 +01:00
Emrik Östling 1589f8d24e Merge pull request #182 from C4illin/feature/#180/add-webroot-env-variable 2024-11-06 22:56:00 +01:00
C4illin 7d1db72cf5 chore: fix default value for webroot 2024-11-06 14:14:11 +01:00
C4illin 53a8f66414 chore: update deps 2024-11-06 14:04:57 +01:00
C4illin 36cb6cc589 feat: Allow to chose webroot
issue #180
2024-11-06 08:49:53 +01:00
Emrik Östling f3a4aece46 Merge pull request #181 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.34
2024-11-04 11:21:48 +01:00
renovate[bot] 580a6a869a chore(deps): update oven/bun docker tag to v1.1.34 2024-11-02 06:59:17 +00:00
Emrik Östling 008eaac493 Merge pull request #176 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.33
2024-10-28 22:56:14 +01:00
renovate[bot] b450623bb4 chore(deps): update oven/bun docker tag to v1.1.33 2024-10-24 10:42:28 +00:00
Emrik Östling 8ac2ecb673 Merge pull request #175 from C4illin/renovate/npm-run-all2-7.x
chore(deps): update dependency npm-run-all2 to v7
2024-10-22 09:04:39 +02:00
Emrik Östling 0a10a56ae3 Merge pull request #174 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.32
2024-10-22 09:04:14 +02:00
renovate[bot] 9378ba9208 chore(deps): update dependency npm-run-all2 to v7 2024-10-22 01:09:18 +00:00
renovate[bot] 0c586e324b chore(deps): update oven/bun docker tag to v1.1.32 2024-10-21 23:14:26 +00:00
Emrik Östling 91c4a64284 chore: add dev image size 2024-10-18 20:07:44 +02:00
C4illin c599e98d9d chore: ignore more files 2024-10-18 20:03:19 +02:00
C4illin d2cd6706c9 chore: update @elysiajs/static 2024-10-18 19:32:42 +02:00
C4illin e8ed10dde8 chore(deps): update @elysiajs/html to version 1.1.1 2024-10-18 18:53:45 +02:00
C4illin 5fe0b79802 chore(deps): update dependencies to latest versions 2024-10-18 18:43:51 +02:00
Emrik Östling 34a6722a68 Merge pull request #172 from C4illin/renovate/oven-bun-1.x 2024-10-18 11:52:36 +02:00
renovate[bot] 5b0d769c63 chore(deps): update oven/bun docker tag to v1.1.31 2024-10-18 07:56:43 +00:00
Emrik Östling 718401a28b Merge pull request #169 from C4illin/renovate/oven-bun-1.x
chore(deps): update oven/bun docker tag to v1.1.30
2024-10-08 18:09:13 +02:00
renovate[bot] 3112cd57f6 chore(deps): update oven/bun docker tag to v1.1.30 2024-10-08 14:13:13 +00:00
C4illin 410fc777a7 Merge branch 'main' of https://github.com/C4illin/ConvertX 2024-10-07 10:47:40 +02:00
C4illin 8eed99e732 chore: fix drop done style 2024-10-07 10:47:37 +02:00
Emrik Östling 663b1d4171 Merge pull request #167 from C4illin/release-please--branches--main--components--convertx-frontend 2024-10-06 23:36:13 +02:00
Emrik Östling c3067ca12d chore(main): release 0.8.1 2024-10-06 00:49:06 +02:00
Emrik Östling 4561ca3760 Merge pull request #164 from C4illin/fix/#163/add-jfif-support 2024-10-06 00:48:46 +02:00
Emrik Östling 698cce58ce Merge pull request #165 from C4illin/fix/#157/resize-when-converting-to-ico 2024-10-06 00:46:22 +02:00
C4illin 339b79f786 fix: treat jfif as jpeg
issue #163
2024-10-06 00:45:08 +02:00
C4illin 4f98f778f0 chore: add message when resizing image 2024-10-06 00:40:34 +02:00
Emrik Östling 8479b33a47 Merge pull request #166 from C4illin/fix/#151/disable-convert-button 2024-10-05 23:29:39 +02:00
C4illin 78844d7bd5 fix: disable convert button when input is empty
issue #151
2024-10-05 01:20:23 +02:00
Emrik Östling 64e4a271e1 Merge branch 'main' into fix/#157/resize-when-converting-to-ico 2024-10-05 01:02:48 +02:00
C4illin 5fb8c3575b chore: add eslint-plugin-readable-tailwind 2024-10-05 01:01:00 +02:00
C4illin a6b8bcecae chore: disable dependency dashboard in Renovate configuration 2024-10-05 00:47:34 +02:00
C4illin bc9c820820 chore: remove DeepSource configuration file 2024-10-05 00:45:34 +02:00
C4illin ee9207a7f4 chore: fix eslint rules 2024-10-05 00:43:24 +02:00
C4illin a34e215202 chore: remove biome 2024-10-05 00:01:39 +02:00
C4illin b4e53dbb8e fix: resize to fit for ico
issue #157
2024-10-04 23:55:39 +02:00
C4illin b5e8d82bfa chore(eslint): add browser globals to ESLint configuration 2024-10-04 23:44:18 +02:00
Emrik Östling 5d9000bb33 Merge pull request #162 from C4illin/renovate/biomejs-biome-1.x
chore(deps): update dependency @biomejs/biome to v1.9.3
2024-10-01 22:01:56 +02:00
renovate[bot] ccb065ef0f chore(deps): update dependency @biomejs/biome to v1.9.3 2024-10-01 15:11:07 +00:00
Emrik Östling 883fad806b Merge pull request #155 from C4illin/release-please--branches--main--components--convertx-frontend 2024-10-01 14:17:30 +02:00
Emrik Östling feacd1b816 chore(main): release 0.8.0 2024-09-30 22:01:44 +02:00
Emrik Östling 094e7a0d1c Merge pull request #160 from C4illin/feature-light-theme
feat: add light theme
2024-09-30 22:01:19 +02:00
C4illin 72636c5059 feat: add light theme, fixes #156 2024-09-30 17:14:44 +02:00
C4illin 291cfc80c6 chore: update deps 2024-09-30 15:56:33 +02:00
C4illin ae1dfafc9d fix: cleanup formats and add opus, fixes #159 2024-09-30 15:51:11 +02:00
Emrik Östling 6caa583c35 Merge pull request #154 from C4illin/fix/#153/clean-up-ffmpeg-formats
fix: support .awb and clean up, fixes #153, #92
2024-09-28 13:36:46 +02:00
C4illin 2057167576 fix: add support for usd for assimp, #144 2024-09-28 13:13:48 +02:00
C4illin 1c9e67fc32 fix: support .awb and clean up, fixes #153, #92 2024-09-28 13:02:17 +02:00
53 changed files with 4629 additions and 2502 deletions
-7
View File
@@ -1,7 +0,0 @@
version = 1
[[analyzers]]
name = "javascript"
[analyzers.meta]
environment = ["nodejs"]
+19 -16
View File
@@ -1,16 +1,19 @@
node_modules
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
Makefile
helm-charts
.env
.editorconfig
.idea
coverage*
data
.dockerignore
.editorconfig
.env
.git
.idea
.vscode
CHANGELOG.md
coverage*
data
docker-compose*
Dockerfile*
eslint.config.js
helm-charts
LICENSE
Makefile
node_modules
prettier.config.js
README.md
renovate.json
+15
View File
@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: [C4illin] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+80 -69
View File
@@ -1,69 +1,80 @@
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
push:
branches: [ "main" ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
push:
branches: [ "main" ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
DOCKERHUB_USERNAME: c4illin
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
@@ -0,0 +1,27 @@
name: Update Docker Hub Description
env:
IMAGE_NAME: ${{ github.repository }}
DOCKERHUB_USERNAME: c4illin
on:
push:
branches:
- main
paths:
- README.md
- .github/workflows/dockerhub-description.yml
jobs:
dockerHubDescription:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ env.IMAGE_NAME }}
short-description: ${{ github.event.repository.description }}
enable-url-completion: true
+1 -1
View File
@@ -48,4 +48,4 @@ package-lock.json
/data
/Bruno
/tsconfig.tsbuildinfo
/src/public/generated.css
/public/generated.css
+119
View File
@@ -1,5 +1,124 @@
# Changelog
## [0.13.0](https://github.com/C4illin/ConvertX/compare/v0.12.1...v0.13.0) (2025-05-14)
### Features
* add HIDE_HISTORY option to control visibility of history page ([9d1c931](https://github.com/C4illin/ConvertX/commit/9d1c93155cc33ed6c83f9e5122afff8f28d0e4bf))
* add potrace converter ([bdbd4a1](https://github.com/C4illin/ConvertX/commit/bdbd4a122c09559b089b985ea12c5f3e085107da))
* Add support for .HIF files ([70705c1](https://github.com/C4illin/ConvertX/commit/70705c1850d470296df85958c02a01fb5bc3a25f))
* add support for drag/drop of images ([ff2ef74](https://github.com/C4illin/ConvertX/commit/ff2ef7413542cf10ba7a6e246763bcecd6829ec1))
### Bug Fixes
* add timezone support ([4b5c732](https://github.com/C4illin/ConvertX/commit/4b5c732380bc844dccf340ea1eb4f8bfe3bb44a5)), closes [#258](https://github.com/C4illin/ConvertX/issues/258)
## [0.12.1](https://github.com/C4illin/ConvertX/compare/v0.12.0...v0.12.1) (2025-03-20)
### Bug Fixes
* rollback to bun 1.2.2 ([cdae798](https://github.com/C4illin/ConvertX/commit/cdae798fcf5879e4adea87386a38748b9a1e1ddc))
## [0.12.0](https://github.com/C4illin/ConvertX/compare/v0.11.1...v0.12.0) (2025-03-06)
### Features
* added progress bar for file upload ([db60f35](https://github.com/C4illin/ConvertX/commit/db60f355b2973f43f8e5990e6fe4e351b959b659))
* made every upload file independent ([cc54bdc](https://github.com/C4illin/ConvertX/commit/cc54bdcbe764c41cc3273485d072fd3178ad2dca))
* replace exec with execFile ([9263d17](https://github.com/C4illin/ConvertX/commit/9263d17609dc4b2b367eb7fee67b3182e283b3a3))
### Bug Fixes
* add libheif ([6b92540](https://github.com/C4illin/ConvertX/commit/6b9254047c0598963aee1d99e20ba1650a0368bf))
* add libheif ([decfea5](https://github.com/C4illin/ConvertX/commit/decfea5dc9627b216bb276a9e1578c32cfa1deb6)), closes [#202](https://github.com/C4illin/ConvertX/issues/202)
* added onerror log ([ae4bbc8](https://github.com/C4illin/ConvertX/commit/ae4bbc8baacbaf67763c62ea44140bb21cc17230))
* refactored uploadFile to only accept a single file instead of multiple ([dc82a43](https://github.com/C4illin/ConvertX/commit/dc82a438d4104b79ff423d502a6779a43928968a))
* update libheif to 1.19.5 ([fba5e21](https://github.com/C4illin/ConvertX/commit/fba5e212e8d0eaba8971e239e35aeb521f3cd813)), closes [#202](https://github.com/C4illin/ConvertX/issues/202)
## [0.11.1](https://github.com/C4illin/ConvertX/compare/v0.11.0...v0.11.1) (2025-02-07)
### Bug Fixes
* mobile view overflow ([bec58ac](https://github.com/C4illin/ConvertX/commit/bec58ac59f9600e35385b9e21d174f3ab1b42b1d))
## [0.11.0](https://github.com/C4illin/ConvertX/compare/v0.10.1...v0.11.0) (2025-02-05)
### Features
* add deps for vaapi ([2bbbd03](https://github.com/C4illin/ConvertX/commit/2bbbd03554d384a4488143f29e5fc863cfdf333b)), closes [#192](https://github.com/C4illin/ConvertX/issues/192)
### Bug Fixes
* don't crash if file is not found ([16f27c1](https://github.com/C4illin/ConvertX/commit/16f27c13bbc1c0e5fa2316f3db11d0918524053b))
* install numpy for inkscape ([0e61051](https://github.com/C4illin/ConvertX/commit/0e61051fc6be188164c3865b4fb579c140859fdc))
## [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)
### Features
* add inkscape for vector images ([f3740e9](https://github.com/C4illin/ConvertX/commit/f3740e9ded100b8500f3613517960248bbd3c210))
* Allow to chose webroot ([36cb6cc](https://github.com/C4illin/ConvertX/commit/36cb6cc589d80d0a87fa8dbe605db71a9a2570f9)), closes [#180](https://github.com/C4illin/ConvertX/issues/180)
* disable convert when uploading ([58e220e](https://github.com/C4illin/ConvertX/commit/58e220e82d7f9c163d6ea4dc31092c08a3e254f4)), closes [#177](https://github.com/C4illin/ConvertX/issues/177)
### Bug Fixes
* treat unknown as m4a ([1a442d6](https://github.com/C4illin/ConvertX/commit/1a442d6e69606afef63b1e7df36aa83d111fa23d)), closes [#178](https://github.com/C4illin/ConvertX/issues/178)
* wait for both upload and selection ([4c05fd7](https://github.com/C4illin/ConvertX/commit/4c05fd72bbbf91ee02327f6fcbf749b78272376b)), closes [#177](https://github.com/C4illin/ConvertX/issues/177)
## [0.8.1](https://github.com/C4illin/ConvertX/compare/v0.8.0...v0.8.1) (2024-10-05)
### Bug Fixes
* disable convert button when input is empty ([78844d7](https://github.com/C4illin/ConvertX/commit/78844d7bd55990789ed07c81e49043e688cbe656)), closes [#151](https://github.com/C4illin/ConvertX/issues/151)
* resize to fit for ico ([b4e53db](https://github.com/C4illin/ConvertX/commit/b4e53dbb8e70b3a95b44e5b756759d16117a87e1)), closes [#157](https://github.com/C4illin/ConvertX/issues/157)
* treat jfif as jpeg ([339b79f](https://github.com/C4illin/ConvertX/commit/339b79f786131deb93f0d5683e03178fdcab1ef5)), closes [#163](https://github.com/C4illin/ConvertX/issues/163)
## [0.8.0](https://github.com/C4illin/ConvertX/compare/v0.7.0...v0.8.0) (2024-09-30)
### Features
* add light theme, fixes [#156](https://github.com/C4illin/ConvertX/issues/156) ([72636c5](https://github.com/C4illin/ConvertX/commit/72636c5059ebf09c8fece2e268293650b2f8ccf6))
### Bug Fixes
* add support for usd for assimp, [#144](https://github.com/C4illin/ConvertX/issues/144) ([2057167](https://github.com/C4illin/ConvertX/commit/20571675766209ad1251f07e687d29a6791afc8b))
* cleanup formats and add opus, fixes [#159](https://github.com/C4illin/ConvertX/issues/159) ([ae1dfaf](https://github.com/C4illin/ConvertX/commit/ae1dfafc9d9116a57b08c2f7fc326990e00824b0))
* support .awb and clean up, fixes [#153](https://github.com/C4illin/ConvertX/issues/153), [#92](https://github.com/C4illin/ConvertX/issues/92) ([1c9e67f](https://github.com/C4illin/ConvertX/commit/1c9e67fc3201e0e5dee91e8981adf34daaabf33a))
## [0.7.0](https://github.com/C4illin/ConvertX/compare/v0.6.0...v0.7.0) (2024-09-26)
+19 -15
View File
@@ -1,4 +1,4 @@
FROM oven/bun:1.1.29-alpine AS base
FROM oven/bun:1.2.2-alpine AS base
LABEL org.opencontainers.image.source="https://github.com/C4illin/ConvertX"
WORKDIR /app
@@ -6,12 +6,12 @@ WORKDIR /app
# this will cache them and speed up future builds
FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
COPY package.json bun.lock /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile
# install with --production (exclude devDependencies)
RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/
COPY package.json bun.lock /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production
FROM base AS builder
@@ -20,22 +20,18 @@ ENV PATH=/root/.cargo/bin:$PATH
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
RUN cargo install resvg
# copy node_modules from temp directory
# then copy all (non-ignored) project files into the image
FROM base AS prerelease
WORKDIR /app
COPY --from=install /temp/dev/node_modules node_modules
COPY . .
# # [optional] tests & build
ENV NODE_ENV=production
# RUN bun test
# ENV NODE_ENV=production
RUN bun run build
# copy production dependencies and source code into final image
FROM base AS release
LABEL maintainer="Emrik Östling (C4illin)"
LABEL description="ConvertX: self-hosted online file converter supporting 700+ file formats."
LABEL repo="https://github.com/C4illin/ConvertX"
RUN apk --no-cache add libheif-tools --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community/
# install additional dependencies
RUN apk --no-cache add \
@@ -49,17 +45,25 @@ RUN apk --no-cache add \
vips-tools \
vips-poppler \
vips-jxl \
vips-heif \
vips-magick \
libjxl-tools \
assimp
assimp \
inkscape \
poppler-utils \
gcompat \
libva-utils \
py3-numpy \
potrace
# RUN apk --no-cache add calibre@testing --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main/
# this might be needed for some latex use cases, will add it if needed.
# texmf-dist-fontsextra \
COPY --from=install /temp/prod/node_modules node_modules
COPY --from=builder /root/.cargo/bin/resvg /usr/local/bin/resvg
COPY --from=prerelease /app/src/public/generated.css /app/src/public/
# COPY --from=prerelease /app/src/index.tsx /app/src/
# COPY --from=prerelease /app/package.json .
COPY --from=prerelease /app/public/generated.css /app/public/
COPY . .
EXPOSE 3000/tcp
+157 -111
View File
@@ -1,111 +1,157 @@
![ConvertX](images/logo.png)
# ConvertX
[![Docker](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml/badge.svg?branch=main)](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml)
[![GitHub Release](https://img.shields.io/github/v/release/C4illin/ConvertX)](https://github.com/C4illin/ConvertX/pkgs/container/convertx)
![GitHub commits since latest release](https://img.shields.io/github/commits-since/C4illin/ConvertX/latest)
![GitHub repo size](https://img.shields.io/github/repo-size/C4illin/ConvertX)
![Docker container size](https://ghcr-badge.egpl.dev/c4illin/convertx/size?color=%230375b6&tag=latest&label=image+size&trim=)
![GitHub top language](https://img.shields.io/github/languages/top/C4illin/ConvertX)
A self-hosted online file converter. Supports over a thousand different formats. Written with TypeScript, Bun and Elysia.
## Features
- Convert files to different formats
- Process multiple files at once
- Password protection
- Multiple accounts
## Converters supported
| Converter | Use case | Converts from | Converts to |
|------------------------------------------------------------------------------|---------------|---------------|-------------|
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
| [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 |
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 166 | 133 |
| [FFmpeg](https://ffmpeg.org/) | Video | ~473 | ~280 |
<!-- many ffmpeg fileformats are duplicates -->
Any missing converter? Open an issue or pull request!
## Deployment
```yml
# docker-compose.yml
services:
convertx:
image: ghcr.io/c4illin/convertx
container_name: convertx
restart: unless-stopped
ports:
- "3000:3000"
environment: # Defaults are listed below. All are optional.
- ACCOUNT_REGISTRATION=false # 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=false # setting this to true is unsafe, only set this to true locally
- ALLOW_UNAUTHENTICATED=false # allows anyone to use the service without logging in, 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
volumes:
- convertx:/app/data
```
or
```bash
docker run -p 3000:3000 -v ./data:/app/data ghcr.io/c4illin/convertx
```
Then visit `http://localhost:3000` in your browser and create your account. Don't leave it unconfigured and open, as anyone can register the first account.
If you get unable to open database file run `chown -R $USER:$USER path` on the path you choose.
### Tutorial
Tutorial in french: https://belginux.com/installer-convertx-avec-docker/
## Screenshots
![ConvertX Preview](images/preview.png)
## Development
0. Install [Bun](https://bun.sh/) and Git
1. Clone the repository
2. `bun install`
3. `bun run dev`
Pull requests are welcome! See below and open issues for the list of todos.
## Todo
- [x] Add messages for errors in converters
- [x] Add searchable list of formats
- [ ] Add options for converters
- [ ] Divide index.tsx into smaller components
- [ ] Add tests
- [ ] Make the upload button nicer and more easy to drop files on. Support copy paste as well if possible.
- [ ] Make errors logs visible from the web ui
- [ ] Add more converters:
- [ ] [deark](https://github.com/jsummers/deark)
- [ ] LibreOffice
- [ ] [dvisvgm](https://github.com/mgieseki/dvisvgm)
## Contributors
<a href="https://github.com/C4illin/ConvertX/graphs/contributors">
<img src="https://contrib.rocks/image?repo=C4illin/ConvertX" />
</a>
## Star History
<a href="https://github.com/C4illin/ConvertX/stargazers">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date" />
</picture>
</a>
![ConvertX](images/logo.png)
# ConvertX
[![Docker](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml/badge.svg?branch=main)](https://github.com/C4illin/ConvertX/actions/workflows/docker-publish.yml)
[![ghcr.io Pulls](https://img.shields.io/badge/dynamic/json?logo=github&url=https%3A%2F%2Fipitio.github.io%2Fbackage%2FC4illin%2FConvertX%2Fconvertx.json&query=%24.downloads&label=ghcr.io%20pulls&cacheSeconds=14400)](https://github.com/C4illin/ConvertX/pkgs/container/ConvertX)
[![Docker Pulls](https://img.shields.io/docker/pulls/c4illin/convertx?style=flat&logo=docker&label=dockerhub%20pulls&link=https%3A%2F%2Fhub.docker.com%2Frepository%2Fdocker%2Fc4illin%2Fconvertx%2Fgeneral)](https://hub.docker.com/r/c4illin/convertx)
[![GitHub Release](https://img.shields.io/github/v/release/C4illin/ConvertX)](https://github.com/C4illin/ConvertX/pkgs/container/convertx)
![GitHub commits since latest release](https://img.shields.io/github/commits-since/C4illin/ConvertX/latest)
![GitHub repo size](https://img.shields.io/github/repo-size/C4illin/ConvertX)
![Docker container size](https://ghcr-badge.egpl.dev/c4illin/convertx/size?color=%230375b6&tag=latest&label=image+size&trim=)
<!-- ![Dev image size](https://ghcr-badge.egpl.dev/c4illin/convertx/size?color=%230375b6&tag=main&label=dev+image&trim=) -->
A self-hosted online file converter. Supports over a thousand different formats. Written with TypeScript, Bun and Elysia.
## Features
- Convert files to different formats
- Process multiple files at once
- Password protection
- Multiple accounts
## Converters supported
| Converter | Use case | Converts from | Converts to |
|------------------------------------------------------------------------------|---------------|---------------|-------------|
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
| [Vips](https://github.com/libvips/libvips) | Images | 45 | 23 |
| [libheif](https://github.com/strukturag/libheif) | HEIF | 2 | 4 |
| [XeLaTeX](https://tug.org/xetex/) | LaTeX | 1 | 1 |
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 167 | 130 |
| [Inkscape](https://inkscape.org/) | Vector images | 7 | 17 |
| [Assimp](https://github.com/assimp/assimp) | 3D Assets | 77 | 23 |
| [FFmpeg](https://ffmpeg.org/) | Video | ~472 | ~199 |
| [Potrace](https://potrace.sourceforge.net/) | Raster to vector | 4 | 11 |
<!-- | [Calibre](https://calibre-ebook.com/) | E-books | 26 | 19 | -->
<!-- many ffmpeg fileformats are duplicates -->
Any missing converter? Open an issue or pull request!
## Deployment
> [!WARNING]
> If you can't login, make sure you are accessing the service over localhost or https otherwise set HTTP_ALLOWED=true
```yml
# docker-compose.yml
services:
convertx:
image: ghcr.io/c4illin/convertx
container_name: convertx
restart: unless-stopped
ports:
- "3000:3000"
environment:
- JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() if unset
volumes:
- ./data:/app/data
```
or
```bash
docker run -p 3000:3000 -v ./data:/app/data ghcr.io/c4illin/convertx
```
Then visit `http://localhost:3000` in your browser and create your account. Don't leave it unconfigured and open, as anyone can register the first account.
If you get unable to open database file run `chown -R $USER:$USER path` on the path you choose.
### Environment variables
All are optional, JWT_SECRET is recommended to be set.
| Name | Default | Description |
|---------------------------|---------|-------------|
| JWT_SECRET | when unset it will use the value from randomUUID() | A long and secret string used to sign the JSON Web Token |
| ACCOUNT_REGISTRATION | false | Allow users to register accounts |
| 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 |
| 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/" |
| FFMPEG_ARGS | | Arguments to pass to ffmpeg, e.g. `-preset veryfast` |
| HIDE_HISTORY | false | Hide the history page |
### 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 |
![Release image size](https://ghcr-badge.egpl.dev/c4illin/convertx/size?color=%230375b6&tag=latest&label=release+image&trim=)
![Dev image size](https://ghcr-badge.egpl.dev/c4illin/convertx/size?color=%230375b6&tag=main&label=dev+image&trim=)
<!-- Dockerhub was introduced in 0.9.0 and older releases -->
### Tutorial
> [!NOTE]
> These are written by other people, and may be outdated, incorrect or wrong.
Tutorial in french: <https://belginux.com/installer-convertx-avec-docker/>
Tutorial in chinese: <https://xzllll.com/24092901/>
## Screenshots
![ConvertX Preview](images/preview.png)
## Development
0. Install [Bun](https://bun.sh/) and Git
1. Clone the repository
2. `bun install`
3. `bun run dev`
Pull requests are welcome! See below and open issues for the list of todos.
## Todo
- [x] Add messages for errors in converters
- [x] Add searchable list of formats
- [ ] Add options for converters
- [ ] Divide index.tsx into smaller components
- [ ] Add tests
- [ ] Make the upload button nicer and more easy to drop files on. Support copy paste as well if possible.
- [ ] Make errors logs visible from the web ui
- [ ] Add more converters:
- [ ] [deark](https://github.com/jsummers/deark)
- [ ] LibreOffice
- [ ] [dvisvgm](https://github.com/mgieseki/dvisvgm)
## Contributors
<a href="https://github.com/C4illin/ConvertX/graphs/contributors">
<img src="https://contrib.rocks/image?repo=C4illin/ConvertX" alt="Image with all contributors"/>
</a>
## Star History
<a href="https://github.com/C4illin/ConvertX/stargazers">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=C4illin/ConvertX&type=Date" />
</picture>
</a>
+9
View File
@@ -0,0 +1,9 @@
# Security Policy
## Supported Versions
Only the latest release is supported
## Reporting a Vulnerability
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/C4illin/ConvertX/security/advisories/new) tab.
+1164
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+18 -15
View File
@@ -1,15 +1,18 @@
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
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
# - FFMPEG_ARGS=-hwaccel vulkan # additional arguments to pass to ffmpeg
# - WEBROOT=/convertx # the root path of the web interface, leave empty to disable
# - HIDE_HISTORY=true # hides the history tab in the web interface, defaults to false
ports:
- 3000:3000
-55
View File
@@ -1,55 +0,0 @@
import comments from "@eslint-community/eslint-plugin-eslint-comments/configs";
import { fixupPluginRules } from "@eslint/compat";
import js from "@eslint/js";
import deprecationPlugin from "eslint-plugin-deprecation";
import importPlugin from "eslint-plugin-import";
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
import tailwind from "eslint-plugin-tailwindcss";
import globals from "globals";
import tseslint from "typescript-eslint";
export default tseslint.config(
js.configs.recommended,
importPlugin.flatConfigs.recommended,
comments.recommended,
...tseslint.configs.recommended,
...tailwind.configs["flat/recommended"],
{
plugins: {
"@typescript-eslint": tseslint.plugin,
deprecation: fixupPluginRules(deprecationPlugin),
import: fixupPluginRules(importPlugin),
"simple-import-sort": simpleImportSortPlugin,
},
ignores: ["**/node_modules/**", "**/public/**"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
ecmaVersion: "latest",
sourceType: "module",
project: ["./tsconfig.json"],
},
globals: {
...globals.node,
},
},
files: ["**/*.{js,mjs,cjs}"],
rules: {
"tailwindcss/no-custom-classname": [
"error",
{
config: "./tailwind.config.js",
whitelist: [
"select_container",
"convert_to_popup",
"convert_to_group",
"target",
"convert_to_target",
],
},
],
"import/no-named-as-default": "off",
},
},
);
+57
View File
@@ -0,0 +1,57 @@
import js from "@eslint/js";
import eslintParserTypeScript from "@typescript-eslint/parser";
import type { Linter } from "eslint";
import eslintPluginReadableTailwind from "eslint-plugin-readable-tailwind";
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
import globals from "globals";
import tseslint from "typescript-eslint";
export default [
js.configs.recommended,
...tseslint.configs.recommended,
// ...tailwind.configs["flat/recommended"],
{
plugins: {
"simple-import-sort": simpleImportSortPlugin,
"readable-tailwind": eslintPluginReadableTailwind,
},
ignores: ["**/node_modules/**"],
languageOptions: {
parser: eslintParserTypeScript,
parserOptions: {
project: true,
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.node,
...globals.browser,
},
},
files: ["**/*.{js,mjs,cjs,jsx,tsx,ts}"],
rules: {
...eslintPluginReadableTailwind.configs.warning.rules,
// "tailwindcss/classnames-order": "off",
"readable-tailwind/multiline": [
"warn",
{
group: "newLine",
printWidth: 100,
},
],
// "tailwindcss/no-custom-classname": [
// "warn",
// {
// whitelist: [
// "select_container",
// "convert_to_popup",
// "convert_to_group",
// "target",
// "convert_to_target",
// ],
// },
// ],
},
},
] as Linter.Config[];
Generated
+61
View File
@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1747179050,
"narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+60
View File
@@ -0,0 +1,60 @@
{
description = "ConvertX";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system; };
appSrc = ./.;
app = pkgs.dockerTools.buildLayeredImage {
name = "convertx";
tag = "latest";
contents = [
pkgs.bun
pkgs.resvg
pkgs.ffmpeg
pkgs.graphicsmagick
pkgs.ghostscript
pkgs.vips
pkgs.pandoc
pkgs.texlive.combined.scheme-full
pkgs.calibre
pkgs.inkscape
pkgs.poppler_utils
pkgs.assimp
pkgs.jxrlib
pkgs.libheif
pkgs.libjxl
pkgs.python3Packages.numpy
];
config = {
Env = [
"NODE_ENV=production"
"PATH=/bin:/usr/bin"
];
WorkingDir = "/app";
Cmd = [ "bun" "run" "./src/index.tsx" ];
ExposedPorts = {
"3000/tcp" = {};
};
};
extraCommands = ''
export PATH=${pkgs.bun}/bin:$PATH
mkdir -p /app
cp -r ${./dist}/* /app/
'';
};
in {
packages.default = app;
}
);
}
+35 -47
View File
@@ -1,22 +1,24 @@
{
"name": "convertx-frontend",
"version": "0.7.0",
"version": "0.13.0",
"scripts": {
"dev": "bun run --watch src/index.tsx",
"hot": "bun run --hot src/index.tsx",
"format": "biome format --write ./src",
"build": "postcss ./src/main.css -o ./src/public/generated.css",
"start": "bun run src/index.tsx",
"format": "eslint --fix .",
"build": "bunx @tailwindcss/cli -i ./src/main.css -o ./public/generated.css",
"lint": "run-p 'lint:*'",
"lint:tsc": "tsc --noEmit",
"lint:knip": "knip",
"lint:biome": "biome lint --error-on-warnings ./src"
"lint:eslint": "eslint ."
},
"dependencies": {
"@elysiajs/cookie": "^0.8.0",
"@elysiajs/html": "1.0.2",
"@elysiajs/jwt": "^1.1.1",
"@elysiajs/static": "1.0.3",
"elysia": "^1.1.16"
"@elysiajs/html": "^1.3.0",
"@elysiajs/jwt": "^1.3.0",
"@elysiajs/static": "^1.3.0",
"@kitajs/html": "^4.2.9",
"elysia": "^1.3.1",
"sanitize-filename": "^1.6.3"
},
"module": "src/index.tsx",
"type": "module",
@@ -24,44 +26,30 @@
"start": "bun run src/index.tsx"
},
"devDependencies": {
"@biomejs/biome": "1.9.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
"@eslint/compat": "^1.1.1",
"@eslint/js": "^9.11.1",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@kitajs/ts-html-plugin": "^4.1.0",
"@picocss/pico": "^2.0.6",
"@eslint/js": "^9.26.0",
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
"@kitajs/ts-html-plugin": "^4.1.1",
"@tailwindcss/cli": "^4.1.6",
"@tailwindcss/postcss": "^4.1.6",
"@total-typescript/ts-reset": "^0.6.1",
"@types/bun": "^1.1.10",
"@types/eslint": "^9.6.1",
"@types/bun": "^1.2.13",
"@types/eslint-plugin-tailwindcss": "^3.17.0",
"@types/eslint__js": "^8.42.3",
"@types/node": "^22.6.1",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"autoprefixer": "^10.4.20",
"cssnano": "^7.0.6",
"eslint": "^9.11.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-isaacscript": "^4.0.0",
"eslint-plugin-prettier": "^5.2.1",
"@types/node": "^22.15.17",
"autoprefixer": "^10.4.21",
"cssnano": "^7.0.7",
"eslint": "^9.26.0",
"eslint-plugin-readable-tailwind": "^2.1.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tailwindcss": "^3.17.4",
"globals": "^15.9.0",
"knip": "^5.30.5",
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.47",
"postcss-cli": "^11.0.0",
"postcss-lightningcss": "^1.0.1",
"prettier": "^3.3.3",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.13",
"typescript": "^5.6.2",
"typescript-eslint": "^8.7.0"
},
"trustedDependencies": [
"@biomejs/biome"
]
}
"eslint-plugin-tailwindcss": "4.0.0-alpha.0",
"globals": "^16.1.0",
"knip": "^5.55.1",
"npm-run-all2": "^8.0.1",
"postcss": "^8.5.3",
"postcss-cli": "^11.0.1",
"prettier": "^3.5.3",
"tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.6",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.0"
}
}
-9
View File
@@ -1,9 +0,0 @@
// eslint-disable-next-line no-undef
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
// eslint-disable-next-line no-undef
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
}
}
+5
View File
@@ -0,0 +1,5 @@
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 476 B

Before

Width:  |  Height:  |  Size: 960 B

After

Width:  |  Height:  |  Size: 960 B

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+3 -1
View File
@@ -1,3 +1,5 @@
const webroot = document.querySelector("meta[name='webroot']").content;
window.downloadAll = function () {
// Get all download links
const downloadLinks = document.querySelectorAll("a[download]");
@@ -18,7 +20,7 @@ let progressElem = document.querySelector("progress");
const refreshData = () => {
// console.log("Refreshing data...", progressElem.value, progressElem.max);
if (progressElem.value !== progressElem.max) {
fetch(`/progress/${jobId}`, {
fetch(`${webroot}/progress/${jobId}`, {
method: "POST",
})
.then((res) => res.text())
+118 -75
View File
@@ -1,17 +1,74 @@
// Select the file input element
const webroot = document.querySelector("meta[name='webroot']").content;
const fileInput = document.querySelector('input[type="file"]');
const dropZone = document.getElementById("dropzone");
const convertButton = document.querySelector("input[type='submit']");
const fileNames = [];
let fileType;
let pendingFiles = 0;
let formatSelected = false;
dropZone.addEventListener("dragover", (e) => {
e.preventDefault();
dropZone.classList.add("dragover");
});
dropZone.addEventListener("dragleave", (e) => {
dropZone.addEventListener("dragleave", () => {
dropZone.classList.remove("dragover");
});
dropZone.addEventListener("drop", (e) => {
e.preventDefault();
dropZone.classList.remove("dragover");
const files = e.dataTransfer.files;
if (files.length === 0) {
console.warn("No files dropped — likely a URL or unsupported source.");
return;
}
for (const file of files) {
console.log("Handling dropped file:", file.name);
handleFile(file);
}
});
// Extracted handleFile function for reusability in drag-and-drop and file input
function handleFile(file) {
const fileList = document.querySelector("#file-list");
const row = document.createElement("tr");
row.innerHTML = `
<td>${file.name}</td>
<td><progress max="100"></progress></td>
<td>${(file.size / 1024).toFixed(2)} kB</td>
<td><a onclick="deleteRow(this)">Remove</a></td>
`;
if (!fileType) {
fileType = file.name.split(".").pop();
fileInput.setAttribute("accept", `.${fileType}`);
setTitle();
fetch(`${webroot}/conversions`, {
method: "POST",
body: JSON.stringify({ fileType }),
headers: { "Content-Type": "application/json" },
})
.then((res) => res.text())
.then((html) => {
selectContainer.innerHTML = html;
updateSearchBar();
})
.catch(console.error);
}
fileList.appendChild(row);
file.htmlRow = row;
fileNames.push(file.name);
uploadFile(file);
}
const selectContainer = document.querySelector("form .select_container");
const updateSearchBar = () => {
@@ -57,6 +114,10 @@ const updateSearchBar = () => {
target.onmousedown = () => {
convertToElement.value = target.dataset.value;
convertToInput.value = `${target.dataset.target} using ${target.dataset.converter}`;
formatSelected = true;
if (pendingFiles === 0 && fileNames.length > 0) {
convertButton.disabled = false;
}
showMatching("");
};
}
@@ -68,6 +129,12 @@ const updateSearchBar = () => {
showMatching(e.target.value.toLowerCase());
});
convertToInput.addEventListener("search", () => {
// when the user clears the search bar using the 'x' button
convertButton.disabled = true;
formatSelected = false;
});
convertToInput.addEventListener("blur", (e) => {
// Keep the popup open even when clicking on a target button
// for a split second to allow the click to go through
@@ -87,64 +154,12 @@ const updateSearchBar = () => {
});
};
// const convertFromSelect = document.querySelector("select[name='convert_from']");
// Add a 'change' event listener to the file input element
fileInput.addEventListener("change", (e) => {
// console.log(e.target.files);
// Get the selected files from the event target
const files = e.target.files;
// Select the file-list table
const fileList = document.querySelector("#file-list");
// Loop through the selected files
for (const file of files) {
// Create a new table row for each file
const row = document.createElement("tr");
row.innerHTML = `
<td>${file.name}</td>
<td>${(file.size / 1024).toFixed(2)} kB</td>
<td><a class="secondary" onclick="deleteRow(this)" style="cursor: pointer">Remove</a></td>
`;
if (!fileType) {
fileType = file.name.split(".").pop();
console.log("fileType", fileType);
fileInput.setAttribute("accept", `.${fileType}`);
setTitle();
// choose the option that matches the file type
// for (const option of convertFromSelect.children) {
// console.log(option.value);
// if (option.value === fileType) {
// option.selected = true;
// }
// }
fetch("/conversions", {
method: "POST",
body: JSON.stringify({ fileType: fileType }),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.text())
.then((html) => {
selectContainer.innerHTML = html;
updateSearchBar();
})
.catch((err) => console.log(err));
}
// Append the row to the file-list table
fileList.appendChild(row);
// Append the file to the hidden input
fileNames.push(file.name);
handleFile(file);
}
uploadFiles(files);
});
const setTitle = () => {
@@ -153,6 +168,7 @@ const setTitle = () => {
};
// Add a onclick for the delete button
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const deleteRow = (target) => {
const filename = target.parentElement.parentElement.children[0].textContent;
const row = target.parentElement.parentElement;
@@ -162,48 +178,75 @@ const deleteRow = (target) => {
const index = fileNames.indexOf(filename);
fileNames.splice(index, 1);
// reset fileInput
fileInput.value = "";
// if fileNames is empty, reset fileType
if (fileNames.length === 0) {
fileType = null;
fileInput.removeAttribute("accept");
convertButton.disabled = true;
setTitle();
}
fetch("/delete", {
fetch(`${webroot}/delete`, {
method: "POST",
body: JSON.stringify({ filename: filename }),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data) => {
console.log(data);
})
.catch((err) => console.log(err));
};
const uploadFiles = (files) => {
const uploadFile = (file) => {
convertButton.disabled = true;
convertButton.textContent = "Uploading...";
pendingFiles += 1;
const formData = new FormData();
formData.append("file", file, file.name);
for (const file of files) {
formData.append("file", file, file.name);
}
let xhr = new XMLHttpRequest();
fetch("/upload", {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
console.log(data);
})
.catch((err) => console.log(err));
xhr.open("POST", `${webroot}/upload`, true);
xhr.onload = () => {
let data = JSON.parse(xhr.responseText);
pendingFiles -= 1;
if (pendingFiles === 0) {
if (formatSelected) {
convertButton.disabled = false;
}
convertButton.textContent = "Convert";
}
//Remove the progress bar when upload is done
let progressbar = file.htmlRow.getElementsByTagName("progress");
progressbar[0].parentElement.remove();
console.log(data);
};
xhr.upload.onprogress = (e) => {
let sent = e.loaded;
let total = e.total;
console.log(`upload progress (${file.name}):`, (100 * sent) / total);
let progressbar = file.htmlRow.getElementsByTagName("progress");
progressbar[0].value = ((100 * sent) / total);
};
xhr.onerror = (e) => {
console.log(e);
};
xhr.send(formData);
};
const formConvert = document.querySelector("form[action='/convert']");
const formConvert = document.querySelector(`form[action='${webroot}/convert']`);
formConvert.addEventListener("submit", (e) => {
formConvert.addEventListener("submit", () => {
const hiddenInput = document.querySelector("input[name='file_names']");
hiddenInput.value = JSON.stringify(fileNames);
});
+8 -3
View File
@@ -1,6 +1,11 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}
"config:recommended",
":disableDependencyDashboard"
],
"lockFileMaintenance": {
"enabled": true,
"automerge": true
}
}
+40 -32
View File
@@ -1,32 +1,40 @@
export const BaseHtml = ({
children,
title = "ConvertX",
}: { children: JSX.Element; title?: string }) => (
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title safe>{title}</title>
<link rel="stylesheet" href="/generated.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon-16x16.png"
/>
<link rel="manifest" href="/site.webmanifest" />
</head>
<body class="w-full bg-gray-900 text-gray-200">{children}</body>
</html>
);
import { Html } from "@elysiajs/html";
export const BaseHtml = ({
children,
title = "ConvertX",
webroot = "",
}: {
children: JSX.Element;
title?: string;
webroot?: string;
}) => (
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="webroot" content={webroot} />
<title safe>{title}</title>
<link rel="stylesheet" href={`${webroot}/generated.css`} />
<link
rel="apple-touch-icon"
sizes="180x180"
href={`${webroot}/apple-touch-icon.png`}
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href={`${webroot}/favicon-32x32.png`}
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href={`${webroot}/favicon-16x16.png`}
/>
<link rel="manifest" href={`${webroot}/site.webmanifest`} />
</head>
<body class="w-full bg-neutral-900 text-neutral-200">{children}</body>
</html>
);
+53 -22
View File
@@ -1,25 +1,48 @@
import { Html } from "@kitajs/html";
export const Header = ({
loggedIn,
accountRegistration,
}: { loggedIn?: boolean; accountRegistration?: boolean }) => {
allowUnauthenticated,
hideHistory,
webroot = "",
}: {
loggedIn?: boolean;
accountRegistration?: boolean;
allowUnauthenticated?: boolean;
hideHistory?: boolean;
webroot?: string;
}) => {
let rightNav: JSX.Element;
if (loggedIn) {
rightNav = (
<ul class="flex gap-4 ">
<li>
<a
class="text-lime-600 transition-all hover:text-lime-500 hover:underline"
href="/history">
History
</a>
</li>
<li>
<a
class="text-lime-600 transition-all hover:text-lime-500 hover:underline"
href="/logoff">
Logout
</a>
</li>
<ul class="flex gap-4">
{!hideHistory && (
<li>
<a
class={`
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href={`${webroot}/history`}
>
History
</a>
</li>
)}
{!allowUnauthenticated ? (
<li>
<a
class={`
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href={`${webroot}/logoff`}
>
Logout
</a>
</li>
) : null}
</ul>
);
} else {
@@ -27,16 +50,24 @@ export const Header = ({
<ul class="flex gap-4">
<li>
<a
class="text-lime-600 transition-all hover:text-lime-500 hover:underline"
href="/login">
class={`
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href={`${webroot}/login`}
>
Login
</a>
</li>
{accountRegistration ? (
<li>
<a
class="text-lime-600 transition-all hover:text-lime-500 hover:underline"
href="/register">
class={`
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href={`${webroot}/register`}
>
Register
</a>
</li>
@@ -47,11 +78,11 @@ export const Header = ({
return (
<header class="w-full p-4">
<nav class="mx-auto flex max-w-4xl justify-between rounded bg-gray-900 p-4">
<nav class="mx-auto flex max-w-4xl justify-between rounded-sm bg-neutral-900 p-4">
<ul>
<li>
<strong>
<a href="/">ConvertX</a>
<a href={`${webroot}/`}>ConvertX</a>
</strong>
</li>
</ul>
+139 -139
View File
@@ -1,139 +1,139 @@
import { exec } from "node:child_process";
// This could be done dynamically by running `ffmpeg -formats` and parsing the output
export const properties = {
from: {
muxer: [
"3d",
"3ds",
"3mf",
"ac",
"ac3d",
"acc",
"amf",
"ase",
"ask",
"assbin",
"b3d",
"blend",
"bsp",
"bvh",
"cob",
"csm",
"dae",
"dxf",
"enff",
"fbx",
"glb",
"gltf",
"hmp",
"ifc",
"ifczip",
"iqm",
"irr",
"irrmesh",
"lwo",
"lws",
"lxo",
"md2",
"md3",
"md5anim",
"md5camera",
"md5mesh",
"mdc",
"mdl",
"mesh",
"mesh.xml",
"mot",
"ms3d",
"ndo",
"nff",
"obj",
"off",
"ogex",
"pk3",
"ply",
"pmx",
"prj",
"q3o",
"q3s",
"raw",
"scn",
"sib",
"smd",
"step",
"stl",
"stp",
"ter",
"uc",
"vta",
"x",
"x3d",
"x3db",
"xgl",
"xml",
"zae",
"zgl",
],
},
to: {
muxer: [
"collada",
"x",
"stp",
"obj",
"objnomtl",
"stl",
"stlb",
"ply",
"plyb",
"3ds",
"gltf2",
"glb2",
"gltf",
"glb",
"assbin",
"assxml",
"x3d",
"fbx",
"fbxa",
"m3d",
"m3da",
"3mf",
"pbrt",
"assjson",
],
},
};
export async function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
// let command = "ffmpeg";
const command = `assimp export "${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("success");
});
});
}
import { execFile } from "node:child_process";
export const properties = {
from: {
object: [
"3d",
"3ds",
"3mf",
"ac",
"ac3d",
"acc",
"amf",
"amj",
"ase",
"ask",
"assbin",
"b3d",
"blend",
"bsp",
"bvh",
"cob",
"csm",
"dae",
"dxf",
"enff",
"fbx",
"glb",
"gltf",
"hmb",
"hmp",
"ifc",
"ifczip",
"iqm",
"irr",
"irrmesh",
"lwo",
"lws",
"lxo",
"m3d",
"md2",
"md3",
"md5anim",
"md5camera",
"md5mesh",
"mdc",
"mdl",
"mesh.xml",
"mesh",
"mot",
"ms3d",
"ndo",
"nff",
"obj",
"off",
"ogex",
"pk3",
"ply",
"pmx",
"prj",
"q3o",
"q3s",
"raw",
"scn",
"sib",
"smd",
"step",
"stl",
"stp",
"ter",
"uc",
"usd",
"usda",
"usdc",
"usdz",
"vta",
"x",
"x3d",
"x3db",
"xgl",
"xml",
"zae",
"zgl",
],
},
to: {
object: [
"3ds",
"3mf",
"assbin",
"assjson",
"assxml",
"collada",
"dae",
"fbx",
"fbxa",
"glb",
"glb2",
"gltf",
"gltf2",
"json",
"obj",
"objnomtl",
"pbrt",
"ply",
"plyb",
"stl",
"stlb",
"stp",
"x",
],
},
};
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> {
return new Promise((resolve, reject) => {
execFile("assimp", ["export", filePath, targetPath], (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+84
View File
@@ -0,0 +1,84 @@
import { execFile } 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> {
return new Promise((resolve, reject) => {
execFile("ebook-convert", [filePath, targetPath], (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+731 -828
View File
File diff suppressed because it is too large Load Diff
+340 -339
View File
@@ -1,339 +1,340 @@
import { exec } from "node:child_process";
export const properties = {
from: {
image: [
"3fr",
"8bim",
"8bimtext",
"8bimwtext",
"app1",
"app1jpeg",
"art",
"arw",
"avs",
"b",
"bie",
"bigtiff",
"bmp",
"c",
"cals",
"caption",
"cin",
"cmyk",
"cmyka",
"cr2",
"crw",
"cur",
"cut",
"dcm",
"dcr",
"dcx",
"dng",
"dpx",
"epdf",
"epi",
"eps",
"epsf",
"epsi",
"ept",
"ept2",
"ept3",
"erf",
"exif",
"fax",
"file",
"fits",
"fractal",
"ftp",
"g",
"gif",
"gif87",
"gradient",
"gray",
"graya",
"heic",
"heif",
"hrz",
"http",
"icb",
"icc",
"icm",
"ico",
"icon",
"identity",
"image",
"iptc",
"iptctext",
"iptcwtext",
"jbg",
"jbig",
"jng",
"jnx",
"jpeg",
"jpg",
"k",
"k25",
"kdc",
"label",
"m",
"mac",
"map",
"mat",
"mef",
"miff",
"mng",
"mono",
"mpc",
"mrw",
"msl",
"mtv",
"mvg",
"nef",
"null",
"o",
"orf",
"otb",
"p7",
"pal",
"palm",
"pam",
"pbm",
"pcd",
"pcds",
"pct",
"pcx",
"pdb",
"pdf",
"pef",
"pfa",
"pfb",
"pgm",
"picon",
"pict",
"pix",
"plasma",
"png",
"png00",
"png24",
"png32",
"png48",
"png64",
"png8",
"pnm",
"ppm",
"ps",
"ptif",
"pwp",
"r",
"raf",
"ras",
"rgb",
"rgba",
"rla",
"rle",
"sct",
"sfw",
"sgi",
"sr2",
"srf",
"stegano",
"sun",
"svg",
"svgz",
"text",
"tga",
"tif",
"tiff",
"tile",
"tim",
"topol",
"ttf",
"txt",
"uyvy",
"vda",
"vicar",
"vid",
"viff",
"vst",
"wbmp",
"webp",
"wmf",
"wpg",
"x3f",
"xbm",
"xc",
"xcf",
"xmp",
"xpm",
"xv",
"xwd",
"y",
"yuv",
],
},
to: {
image: [
"8bim",
"8bimtext",
"8bimwtext",
"app1",
"app1jpeg",
"art",
"avs",
"b",
"bie",
"bigtiff",
"bmp",
"bmp2",
"bmp3",
"brf",
"c",
"cals",
"cin",
"cmyk",
"cmyka",
"dcx",
"dpx",
"epdf",
"epi",
"eps",
"eps2",
"eps3",
"epsf",
"epsi",
"ept",
"ept2",
"ept3",
"exif",
"fax",
"fits",
"g",
"gif",
"gif87",
"gray",
"graya",
"histogram",
"html",
"icb",
"icc",
"icm",
"info",
"iptc",
"iptctext",
"iptcwtext",
"isobrl",
"isobrl6",
"jbg",
"jbig",
"jng",
"jpeg",
"k",
"m",
"m2v",
"map",
"mat",
"matte",
"miff",
"mng",
"mono",
"mpc",
"mpeg",
"mpg",
"msl",
"mtv",
"mvg",
"null",
"o",
"otb",
"p7",
"pal",
"pam",
"pbm",
"pcd",
"pcds",
"pcl",
"pct",
"pcx",
"pdb",
"pdf",
"pgm",
"picon",
"pict",
"png",
"png00",
"png24",
"png32",
"png48",
"png64",
"png8",
"pnm",
"ppm",
"preview",
"ps",
"ps2",
"ps3",
"ptif",
"r",
"ras",
"rgb",
"rgba",
"sgi",
"shtml",
"sun",
"text",
"tga",
"tiff",
"txt",
"ubrl",
"ubrl6",
"uil",
"uyvy",
"vda",
"vicar",
"vid",
"viff",
"vst",
"wbmp",
"webp",
"x",
"xbm",
"xmp",
"xpm",
"xv",
"xwd",
"y",
"yuv",
],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
return new Promise((resolve, reject) => {
exec(
`gm convert "${filePath}" "${targetPath}"`,
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
},
);
});
}
import { execFile } from "node:child_process";
export const properties = {
from: {
image: [
"3fr",
"8bim",
"8bimtext",
"8bimwtext",
"app1",
"app1jpeg",
"art",
"arw",
"avs",
"b",
"bie",
"bigtiff",
"bmp",
"c",
"cals",
"caption",
"cin",
"cmyk",
"cmyka",
"cr2",
"crw",
"cur",
"cut",
"dcm",
"dcr",
"dcx",
"dng",
"dpx",
"epdf",
"epi",
"eps",
"epsf",
"epsi",
"ept",
"ept2",
"ept3",
"erf",
"exif",
"fax",
"file",
"fits",
"fractal",
"ftp",
"g",
"gif",
"gif87",
"gradient",
"gray",
"graya",
"heic",
"heif",
"hrz",
"http",
"icb",
"icc",
"icm",
"ico",
"icon",
"identity",
"image",
"iptc",
"iptctext",
"iptcwtext",
"jbg",
"jbig",
"jng",
"jnx",
"jpeg",
"jpg",
"k",
"k25",
"kdc",
"label",
"m",
"mac",
"map",
"mat",
"mef",
"miff",
"mng",
"mono",
"mpc",
"mrw",
"msl",
"mtv",
"mvg",
"nef",
"null",
"o",
"orf",
"otb",
"p7",
"pal",
"palm",
"pam",
"pbm",
"pcd",
"pcds",
"pct",
"pcx",
"pdb",
"pdf",
"pef",
"pfa",
"pfb",
"pgm",
"picon",
"pict",
"pix",
"plasma",
"png",
"png00",
"png24",
"png32",
"png48",
"png64",
"png8",
"pnm",
"ppm",
"ps",
"ptif",
"pwp",
"r",
"raf",
"ras",
"rgb",
"rgba",
"rla",
"rle",
"sct",
"sfw",
"sgi",
"sr2",
"srf",
"stegano",
"sun",
"svg",
"svgz",
"text",
"tga",
"tif",
"tiff",
"tile",
"tim",
"topol",
"ttf",
"txt",
"uyvy",
"vda",
"vicar",
"vid",
"viff",
"vst",
"wbmp",
"webp",
"wmf",
"wpg",
"x3f",
"xbm",
"xc",
"xcf",
"xmp",
"xpm",
"xv",
"xwd",
"y",
"yuv",
],
},
to: {
image: [
"8bim",
"8bimtext",
"8bimwtext",
"app1",
"app1jpeg",
"art",
"avs",
"b",
"bie",
"bigtiff",
"bmp",
"bmp2",
"bmp3",
"brf",
"c",
"cals",
"cin",
"cmyk",
"cmyka",
"dcx",
"dpx",
"epdf",
"epi",
"eps",
"eps2",
"eps3",
"epsf",
"epsi",
"ept",
"ept2",
"ept3",
"exif",
"fax",
"fits",
"g",
"gif",
"gif87",
"gray",
"graya",
"histogram",
"html",
"icb",
"icc",
"icm",
"info",
"iptc",
"iptctext",
"iptcwtext",
"isobrl",
"isobrl6",
"jbg",
"jbig",
"jng",
"jpeg",
"k",
"m",
"m2v",
"map",
"mat",
"matte",
"miff",
"mng",
"mono",
"mpc",
"mpeg",
"mpg",
"msl",
"mtv",
"mvg",
"null",
"o",
"otb",
"p7",
"pal",
"pam",
"pbm",
"pcd",
"pcds",
"pcl",
"pct",
"pcx",
"pdb",
"pdf",
"pgm",
"picon",
"pict",
"png",
"png00",
"png24",
"png32",
"png48",
"png64",
"png8",
"pnm",
"ppm",
"preview",
"ps",
"ps2",
"ps3",
"ptif",
"r",
"ras",
"rgb",
"rgba",
"sgi",
"shtml",
"sun",
"text",
"tga",
"tiff",
"txt",
"ubrl",
"ubrl6",
"uil",
"uyvy",
"vda",
"vicar",
"vid",
"viff",
"vst",
"wbmp",
"webp",
"x",
"xbm",
"xmp",
"xpm",
"xv",
"xwd",
"y",
"yuv",
],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
execFile(
"gm",
["convert", filePath, targetPath],
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
},
);
});
}
+59
View File
@@ -0,0 +1,59 @@
import { execFile } from "node:child_process";
export const properties = {
from: {
images: ["svg", "pdf", "eps", "ps", "wmf", "emf", "png"],
},
to: {
images: [
"dxf",
"emf",
"eps",
"fxg",
"gpl",
"hpgl",
"html",
"odg",
"pdf",
"png",
"pov",
"ps",
"sif",
"svg",
"svgz",
"tex",
"wmf",
],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
execFile(
"inkscape",
[filePath, "-o", targetPath],
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
},
);
});
}
+53
View File
@@ -0,0 +1,53 @@
import { execFile } from "child_process";
export const properties = {
from: {
images: [
"avci",
"avcs",
"avif",
"h264",
"heic",
"heics",
"heif",
"heifs",
"hif",
"mkv",
"mp4",
],
},
to: {
images: ["jpeg", "png", "y4m"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
execFile(
"heif-convert",
[filePath, targetPath],
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
},
);
});
}
+71 -71
View File
@@ -1,71 +1,71 @@
import { exec } from "node:child_process";
// declare possible conversions
export const properties = {
from: {
jxl: ["jxl"],
images: [
"apng",
"exr",
"gif",
"jpeg",
"pam",
"pfm",
"pgm",
"pgx",
"png",
"ppm",
],
},
to: {
jxl: [
"apng",
"exr",
"gif",
"jpeg",
"pam",
"pfm",
"pgm",
"pgx",
"png",
"ppm",
],
images: ["jxl"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
let tool = "";
if (fileType === "jxl") {
tool = "djxl";
}
if (convertTo === "jxl") {
tool = "cjxl";
}
return new Promise((resolve, reject) => {
exec(`${tool} "${filePath}" "${targetPath}"`, (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
});
});
}
import { execFile } from "node:child_process";
// declare possible conversions
export const properties = {
from: {
jxl: ["jxl"],
images: [
"apng",
"exr",
"gif",
"jpeg",
"pam",
"pfm",
"pgm",
"pgx",
"png",
"ppm",
],
},
to: {
jxl: [
"apng",
"exr",
"gif",
"jpeg",
"pam",
"pfm",
"pgm",
"pgx",
"png",
"ppm",
],
images: ["jxl"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
let tool = "";
if (fileType === "jxl") {
tool = "djxl";
}
if (convertTo === "jxl") {
tool = "cjxl";
}
return new Promise((resolve, reject) => {
execFile(tool, [filePath, targetPath], (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+58 -61
View File
@@ -1,67 +1,48 @@
import {
convert as convertImage,
properties as propertiesImage
} from "./vips";
import {
convert as convertPandoc,
properties as propertiesPandoc,
} from "./pandoc";
import {
convert as convertFFmpeg,
properties as propertiesFFmpeg,
} from "./ffmpeg";
import {
convert as convertGraphicsmagick,
properties as propertiesGraphicsmagick,
} from "./graphicsmagick";
import {
convert as convertxelatex,
properties as propertiesxelatex,
} from "./xelatex";
import {
convert as convertLibjxl,
properties as propertiesLibjxl,
} from "./libjxl";
import {
convert as convertresvg,
properties as propertiesresvg,
} from "./resvg";
import {
convert as convertassimp,
properties as propertiesassimp,
} from "./assimp";
import { normalizeFiletype } from "../helpers/normalizeFiletype";
import { convert as convertassimp, properties as propertiesassimp } from "./assimp";
import { convert as convertFFmpeg, properties as propertiesFFmpeg } from "./ffmpeg";
import { convert as convertGraphicsmagick, properties as propertiesGraphicsmagick } from "./graphicsmagick";
import { convert as convertInkscape, properties as propertiesInkscape } from "./inkscape";
import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libjxl";
import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc";
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";
import { convert as convertLibheif, properties as propertiesLibheif } from "./libheif";
import { convert as convertpotrace, properties as propertiespotrace } from "./potrace";
// This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular
const properties: Record<string, {
const properties: Record<
string,
{
properties: {
from: Record<string, string[]>;
to: Record<string, string[]>;
options?: Record<string, Record<string, {
options?: Record<
string,
Record<
string,
{
description: string;
type: string;
default: number;
}>>;
}
>
>;
};
converter: (
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
) => any;
}> = {
options?: unknown,
) => unknown;
}
> = {
libjxl: {
properties: propertiesLibjxl,
converter: convertLibjxl,
@@ -74,10 +55,18 @@ const properties: Record<string, {
properties: propertiesImage,
converter: convertImage,
},
libheif: {
properties: propertiesLibheif,
converter: convertLibheif,
},
xelatex: {
properties: propertiesxelatex,
converter: convertxelatex,
},
// calibre: {
// properties: propertiesCalibre,
// converter: convertCalibre,
// },
pandoc: {
properties: propertiesPandoc,
converter: convertPandoc,
@@ -86,6 +75,10 @@ const properties: Record<string, {
properties: propertiesGraphicsmagick,
converter: convertGraphicsmagick,
},
inkscape: {
properties: propertiesInkscape,
converter: convertInkscape,
},
assimp: {
properties: propertiesassimp,
converter: convertassimp,
@@ -94,29 +87,28 @@ const properties: Record<string, {
properties: propertiesFFmpeg,
converter: convertFFmpeg,
},
potrace: {
properties: propertiespotrace,
converter: convertpotrace,
},
};
export async function mainConverter(
inputFilePath: string,
fileTypeOriginal: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
convertTo: any,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
options?: unknown,
converterName?: string,
) {
const fileType = normalizeFiletype(fileTypeOriginal);
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
let converterFunc: any;
// let converterName = converterName;
let converterFunc: typeof properties["libjxl"]["converter"] | undefined;
if (converterName) {
converterFunc = properties[converterName]?.converter;
} else {
// Iterate over each converter in properties
// biome-ignore lint/style/noParameterAssign: <explanation>
for (converterName in properties) {
const converterObj = properties[converterName];
@@ -144,7 +136,7 @@ export async function mainConverter(
}
try {
await converterFunc(
const result = await converterFunc(
inputFilePath,
fileType,
convertTo,
@@ -154,7 +146,13 @@ export async function mainConverter(
console.log(
`Converted ${inputFilePath} from ${fileType} to ${convertTo} successfully using ${converterName}.`,
result,
);
if (typeof result === "string") {
return result;
}
return "Done";
} catch (error) {
console.error(
@@ -190,9 +188,7 @@ for (const converterName in properties) {
}
}
export const getPossibleTargets = (
from: string,
): Record<string, string[]> => {
export const getPossibleTargets = (from: string): Record<string, string[]> => {
const fromClean = normalizeFiletype(from);
return possibleTargets[fromClean] || {};
@@ -216,6 +212,7 @@ for (const converterName in properties) {
}
possibleInputs.sort();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const getPossibleInputs = () => {
return possibleInputs;
};
@@ -287,4 +284,4 @@ export const getAllInputs = (converter: string) => {
// }
// // print the number of unique Inputs and Outputs
// console.log(`Unique Formats: ${uniqueFormats.size}`);
// console.log(`Unique Formats: ${uniqueFormats.size}`);
+162 -156
View File
@@ -1,156 +1,162 @@
import { exec } from "node:child_process";
export const properties = {
from: {
text: [
"textile",
"tikiwiki",
"tsv",
"twiki",
"typst",
"vimwiki",
"biblatex",
"bibtex",
"bits",
"commonmark",
"commonmark_x",
"creole",
"csljson",
"csv",
"djot",
"docbook",
"docx",
"dokuwiki",
"endnotexml",
"epub",
"fb2",
"gfm",
"haddock",
"html",
"ipynb",
"jats",
"jira",
"json",
"latex",
"man",
"markdown",
"markdown_mmd",
"markdown_phpextra",
"markdown_strict",
"mediawiki",
"muse",
"pandoc native",
"opml",
"org",
"ris",
"rst",
"rtf",
"t2t",
],
},
to: {
text: [
"tei",
"texinfo",
"textile",
"typst",
"xwiki",
"zimwiki",
"asciidoc",
"asciidoc_legacy",
"asciidoctor",
"beamer",
"biblatex",
"bibtex",
"chunkedhtml",
"commonmark",
"commonmark_x",
"context",
"csljson",
"djot",
"docbook",
"docbook4",
"docbook5",
"docx",
"dokuwiki",
"dzslides",
"epub",
"epub2",
"epub3",
"fb2",
"gfm",
"haddock",
"html",
"html4",
"html5",
"icml",
"ipynb",
"jats",
"jats_archiving",
"jats_articleauthoring",
"jats_publishing",
"jira",
"json",
"latex",
"man",
"markdown",
"markdown_mmd",
"markdown_phpextra",
"markdown_strict",
"markua",
"mediawiki",
"ms",
"muse",
"pandoc native",
"odt",
"opendocument",
"opml",
"org",
"pdf",
"plain",
"pptx",
"revealjs",
"rst",
"rtf",
"s5",
"slideous",
"slidy",
],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
// set xelatex here
const xelatex = ["pdf", "latex"];
let option = "";
if (xelatex.includes(convertTo)) {
option = "--pdf-engine=xelatex";
}
return new Promise((resolve, reject) => {
exec(
`pandoc ${option} "${filePath}" -f ${fileType} -t ${convertTo} -o "${targetPath}"`,
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
},
);
});
}
import { execFile } from "node:child_process";
export const properties = {
from: {
text: [
"textile",
"tikiwiki",
"tsv",
"twiki",
"typst",
"vimwiki",
"biblatex",
"bibtex",
"bits",
"commonmark",
"commonmark_x",
"creole",
"csljson",
"csv",
"djot",
"docbook",
"docx",
"dokuwiki",
"endnotexml",
"epub",
"fb2",
"gfm",
"haddock",
"html",
"ipynb",
"jats",
"jira",
"json",
"latex",
"man",
"markdown",
"markdown_mmd",
"markdown_phpextra",
"markdown_strict",
"mediawiki",
"muse",
"pandoc native",
"opml",
"org",
"ris",
"rst",
"rtf",
"t2t",
],
},
to: {
text: [
"tei",
"texinfo",
"textile",
"typst",
"xwiki",
"zimwiki",
"asciidoc",
"asciidoc_legacy",
"asciidoctor",
"beamer",
"biblatex",
"bibtex",
"chunkedhtml",
"commonmark",
"commonmark_x",
"context",
"csljson",
"djot",
"docbook",
"docbook4",
"docbook5",
"docx",
"dokuwiki",
"dzslides",
"epub",
"epub2",
"epub3",
"fb2",
"gfm",
"haddock",
"html",
"html4",
"html5",
"icml",
"ipynb",
"jats",
"jats_archiving",
"jats_articleauthoring",
"jats_publishing",
"jira",
"json",
"latex",
"man",
"markdown",
"markdown_mmd",
"markdown_phpextra",
"markdown_strict",
"markua",
"mediawiki",
"ms",
"muse",
"pandoc native",
"odt",
"opendocument",
"opml",
"org",
"pdf",
"plain",
"pptx",
"revealjs",
"rst",
"rtf",
"s5",
"slideous",
"slidy",
],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
// set xelatex here
const xelatex = ["pdf", "latex"];
// Build arguments array
const args: string[] = [];
if (xelatex.includes(convertTo)) {
args.push("--pdf-engine=xelatex");
}
args.push(filePath);
args.push("-f", fileType);
args.push("-t", convertTo);
args.push("-o", targetPath);
return new Promise((resolve, reject) => {
execFile("pandoc", args, (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+37
View File
@@ -0,0 +1,37 @@
import { execFile } from "node:child_process";
export const properties = {
from: {
images: ["pnm", "pbm", "pgm", "bmp"],
},
to: {
images: ["svg", "pdf", "pdfpage", "eps", "postscript", "ps", "dxf", "geojson", "pgm", "gimppath", "xfig"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
execFile("potrace", [filePath, "-o", targetPath, "-b", convertTo], (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+37 -37
View File
@@ -1,37 +1,37 @@
import { exec } from "node:child_process";
export const properties = {
from: {
images: ["svg"],
},
to: {
images: ["png"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
return new Promise((resolve, reject) => {
exec(`resvg "${filePath}" "${targetPath}"`, (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
});
});
}
import { execFile } from "node:child_process";
export const properties = {
from: {
images: ["svg"],
},
to: {
images: ["png"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
execFile("resvg", [filePath, targetPath], (error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
});
});
}
+142 -141
View File
@@ -1,141 +1,142 @@
import { exec } from "node:child_process";
// declare possible conversions
export const properties = {
from: {
images: [
"avif",
"bif",
"csv",
"exr",
"fits",
"gif",
"hdr.gz",
"hdr",
"heic",
"heif",
"img.gz",
"img",
"j2c",
"j2k",
"jp2",
"jpeg",
"jpx",
"jxl",
"mat",
"mrxs",
"ndpi",
"nia.gz",
"nia",
"nii.gz",
"nii",
"pdf",
"pfm",
"pgm",
"pic",
"png",
"ppm",
"raw",
"scn",
"svg",
"svs",
"svslide",
"szi",
"tif",
"tiff",
"v",
"vips",
"vms",
"vmu",
"webp",
"zip",
],
},
to: {
images: [
"avif",
"dzi",
"fits",
"gif",
"hdr.gz",
"heic",
"heif",
"img.gz",
"j2c",
"j2k",
"jp2",
"jpeg",
"jpx",
"jxl",
"mat",
"nia.gz",
"nia",
"nii.gz",
"nii",
"png",
"tiff",
"vips",
"webp",
],
},
options: {
svg: {
scale: {
description: "Scale the image up or down",
type: "number",
default: 1,
},
},
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
// if (fileType === "svg") {
// const scale = options.scale || 1;
// const metadata = await sharp(filePath).metadata();
// if (!metadata || !metadata.width || !metadata.height) {
// throw new Error("Could not get metadata from image");
// }
// const newWidth = Math.round(metadata.width * scale);
// const newHeight = Math.round(metadata.height * scale);
// return await sharp(filePath)
// .resize(newWidth, newHeight)
// .toFormat(convertTo)
// .toFile(targetPath);
// }
let action = "copy";
if (fileType === "pdf") {
action = "pdfload";
}
return new Promise((resolve, reject) => {
exec(
`vips ${action} "${filePath}" "${targetPath}"`,
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
},
);
});
}
import { execFile } from "node:child_process";
// declare possible conversions
export const properties = {
from: {
images: [
"avif",
"bif",
"csv",
"exr",
"fits",
"gif",
"hdr.gz",
"hdr",
"heic",
"heif",
"img.gz",
"img",
"j2c",
"j2k",
"jp2",
"jpeg",
"jpx",
"jxl",
"mat",
"mrxs",
"ndpi",
"nia.gz",
"nia",
"nii.gz",
"nii",
"pdf",
"pfm",
"pgm",
"pic",
"png",
"ppm",
"raw",
"scn",
"svg",
"svs",
"svslide",
"szi",
"tif",
"tiff",
"v",
"vips",
"vms",
"vmu",
"webp",
"zip",
],
},
to: {
images: [
"avif",
"dzi",
"fits",
"gif",
"hdr.gz",
"heic",
"heif",
"img.gz",
"j2c",
"j2k",
"jp2",
"jpeg",
"jpx",
"jxl",
"mat",
"nia.gz",
"nia",
"nii.gz",
"nii",
"png",
"tiff",
"vips",
"webp",
],
},
options: {
svg: {
scale: {
description: "Scale the image up or down",
type: "number",
default: 1,
},
},
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
// if (fileType === "svg") {
// const scale = options.scale || 1;
// const metadata = await sharp(filePath).metadata();
// if (!metadata || !metadata.width || !metadata.height) {
// throw new Error("Could not get metadata from image");
// }
// const newWidth = Math.round(metadata.width * scale);
// const newHeight = Math.round(metadata.height * scale);
// return await sharp(filePath)
// .resize(newWidth, newHeight)
// .toFormat(convertTo)
// .toFile(targetPath);
// }
let action = "copy";
if (fileType === "pdf") {
action = "pdfload";
}
return new Promise((resolve, reject) => {
execFile(
"vips",
[action, filePath, targetPath],
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
},
);
});
}
+53 -46
View File
@@ -1,46 +1,53 @@
import { exec } from "node:child_process";
export const properties = {
from: {
text: ["tex", "latex"],
},
to: {
text: ["pdf"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
options?: any,
): Promise<string> {
return new Promise((resolve, reject) => {
// const fileName: string = (targetPath.split("/").pop() as string).replace(".pdf", "")
const outputPath = targetPath
.split("/")
.slice(0, -1)
.join("/")
.replace("./", "");
exec(
`latexmk -xelatex -interaction=nonstopmode -output-directory="${outputPath}" "${filePath}"`,
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("success");
},
);
});
}
import { execFile } from "node:child_process";
export const properties = {
from: {
text: ["tex", "latex"],
},
to: {
text: ["pdf"],
},
};
export function convert(
filePath: string,
fileType: string,
convertTo: string,
targetPath: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options?: unknown,
): Promise<string> {
return new Promise((resolve, reject) => {
// const fileName: string = (targetPath.split("/").pop() as string).replace(".pdf", "")
const outputPath = targetPath
.split("/")
.slice(0, -1)
.join("/")
.replace("./", "");
execFile(
"latexmk",
[
"-xelatex",
"-interaction=nonstopmode",
`-output-directory=${outputPath}`,
filePath,
],
(error, stdout, stderr) => {
if (error) {
reject(`error: ${error}`);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
resolve("Done");
},
);
});
}
+37 -31
View File
@@ -1,31 +1,37 @@
export const normalizeFiletype = (filetype: string): string => {
const lowercaseFiletype = filetype.toLowerCase();
switch (lowercaseFiletype) {
case "jpg":
return "jpeg";
case "htm":
return "html";
case "tex":
return "latex";
case "md":
return "markdown";
default:
return lowercaseFiletype;
}
};
export const normalizeOutputFiletype = (filetype: string): string => {
const lowercaseFiletype = filetype.toLowerCase();
switch (lowercaseFiletype) {
case "jpeg":
return "jpg";
case "latex":
return "tex";
case "markdown":
return "md";
default:
return lowercaseFiletype;
}
};
export const normalizeFiletype = (filetype: string): string => {
const lowercaseFiletype = filetype.toLowerCase();
switch (lowercaseFiletype) {
case "jfif":
case "jpg":
return "jpeg";
case "htm":
return "html";
case "tex":
return "latex";
case "md":
return "markdown";
case "unknown":
return "m4a";
default:
return lowercaseFiletype;
}
};
export const normalizeOutputFiletype = (filetype: string): string => {
const lowercaseFiletype = filetype.toLowerCase();
switch (lowercaseFiletype) {
case "jpeg":
return "jpg";
case "latex":
return "tex";
case "markdown_phpextra":
case "markdown_strict":
case "markdown_mmd":
case "markdown":
return "md";
default:
return lowercaseFiletype;
}
};
+42 -1
View File
@@ -1,5 +1,6 @@
import { exec } from "node:child_process";
import { version } from "../../package.json";
console.log(`ConvertX v${version}`);
if (process.env.NODE_ENV === "production") {
@@ -53,6 +54,16 @@ if (process.env.NODE_ENV === "production") {
}
});
exec("inkscape --version", (error, stdout) => {
if (error) {
console.error("Inkscape is not installed.");
}
if (stdout) {
console.log(stdout.split("\n")[0]);
}
});
exec("djxl --version", (error, stdout) => {
if (error) {
console.error("libjxl-tools is not installed.");
@@ -89,7 +100,37 @@ if (process.env.NODE_ENV === "production") {
}
if (stdout) {
console.log(`assimp v${stdout.split("\n")[5]}`);
console.log(`assimp ${stdout.split("\n")[5]}`);
}
});
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("heif-info -v", (error, stdout) => {
if (error) {
console.error("libheif is not installed");
}
if (stdout) {
console.log(`libheif v${stdout.split("\n")[0]}`);
}
});
exec("potrace -v", (error, stdout) => {
if (error) {
console.error("potrace is not installed");
}
if (stdout) {
console.log(stdout.split("\n")[0]);
}
});
+2 -4
View File
@@ -1,13 +1,11 @@
import tw from "tailwindcss";
import tailwind from "@tailwindcss/postcss";
import postcss from "postcss";
export const generateTailwind = async () => {
const result = await Bun.file("./src/main.css")
.text()
.then((sourceText) => {
const config = "./tailwind.config.js";
return postcss([tw(config)]).process(sourceText, {
return postcss([tailwind]).process(sourceText, {
from: "./src/main.css",
to: "./public/generated.css",
});
+438 -151
View File
File diff suppressed because it is too large Load Diff
+75 -9
View File
@@ -1,12 +1,78 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@layer components {
.article {
@apply p-4 mb-4 bg-gray-800/40 w-full mx-auto max-w-4xl rounded;
}
.btn-primary {
@apply bg-lime-500 text-black rounded p-4 hover:bg-lime-400 cursor-pointer;
@plugin 'tailwind-scrollbar';
@theme {
--color-contrast: rgba(var(--contrast));
--color-neutral-900: rgba(var(--neutral-900));
--color-neutral-800: rgba(var(--neutral-800));
--color-neutral-700: rgba(var(--neutral-700));
--color-neutral-600: rgba(var(--neutral-600));
--color-neutral-500: rgba(var(--neutral-500));
--color-neutral-400: rgba(var(--neutral-400));
--color-neutral-300: rgba(var(--neutral-300));
--color-neutral-200: rgba(var(--neutral-200));
--color-neutral-100: rgba(var(--neutral-100));
--color-accent-600: rgba(var(--accent-600));
--color-accent-500: rgba(var(--accent-500));
--color-accent-400: rgba(var(--accent-400));
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
@utility article {
@apply px-2 sm:px-4 py-4 mb-4 bg-neutral-800/40 w-full mx-auto max-w-4xl rounded-sm;
}
@utility btn-primary {
@apply bg-accent-500 text-contrast rounded-sm p-2 sm:p-4 hover:bg-accent-400 cursor-pointer transition-colors;
}
:root {
--contrast: 255, 255, 255;
--neutral-900: 243, 244, 246;
--neutral-800: 229, 231, 235;
--neutral-700: 209, 213, 219;
--neutral-600: 156, 163, 175;
--neutral-500: 180, 180, 180;
--neutral-400: 75, 85, 99;
--neutral-300: 55, 65, 81;
--neutral-200: 31, 41, 55;
--neutral-100: 17, 24, 39;
--accent-400: 132, 204, 22;
--accent-500: 101, 163, 13;
--accent-600: 77, 124, 15;
}
@media (prefers-color-scheme: dark) {
:root {
--contrast: 0, 0, 0;
--neutral-900: 17, 24, 39;
--neutral-800: 31, 41, 55;
--neutral-700: 55, 65, 81;
--neutral-600: 75, 85, 99;
--neutral-500: 107, 114, 128;
--neutral-300: 209, 213, 219;
--neutral-400: 156, 163, 175;
--neutral-200: 229, 231, 235;
--accent-600: 101, 163, 13;
--accent-500: 132, 204, 22;
--accent-400: 163, 230, 53;
}
}
-9
View File
@@ -1,9 +0,0 @@
/** @type {import('tailwindcss').Config} */
// eslint-disable-next-line no-undef
module.exports = {
content: ['./src/**/*.{html,js,tsx,jsx,cjs,mjs}'],
theme: {
extend: {},
},
plugins: [require('tailwind-scrollbar')],
}
+1 -1
View File
@@ -27,4 +27,4 @@
"noImplicitOverride": true
// "noImplicitReturns": true
}
}
}