pdf2epub 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js DELETED
@@ -1,134 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const { spawnSync } = require('child_process');
5
-
6
- const paths = require('./paths');
7
- const setup = require('./setup');
8
- const { findPython, findUv } = require('./python');
9
-
10
- const WRAPPER_COMMANDS = new Set(['setup', 'info', 'clean', 'help', '--help', '-h', '--version', '-V']);
11
-
12
- function versionLine() {
13
- const up = setup.upstreamInfo();
14
- return `pdf2epub ${paths.pkg.version} (npm wrapper) / upstream ${up.repo}@${up.ref} ${String(up.commit).slice(0, 7)}`;
15
- }
16
-
17
- function usage() {
18
- return `${versionLine()}
19
-
20
- Convert PDF files to structured Markdown and EPUB (via marker-pdf).
21
-
22
- Usage:
23
- pdf2epub [input_path] [output_path] [options]
24
- pdf2epub <command>
25
-
26
- Upstream options (passed through to pdf2epub's main.py):
27
- input_path PDF file or directory (default: ./input/*.pdf)
28
- output_path Output directory (default: directory named after the PDF)
29
- --max-pages INT Maximum number of pages to process
30
- --start-page INT Page number to start from (requires --max-pages)
31
- --skip-epub Only create Markdown; no interactive EPUB prompts
32
- --skip-md Reuse existing Markdown, only build the EPUB
33
-
34
- Wrapper commands:
35
- setup [--force] Create (or recreate) the Python environment now
36
- info Show install location, Python, and upstream version
37
- clean Delete the Python environment (${paths.homeDir()})
38
- help, --help, -h Show this help
39
- --version, -V Show versions
40
-
41
- Use "pdf2epub -- <args>" to pass arguments straight to upstream, e.g.
42
- "pdf2epub -- --help" or when your input path is literally named "setup".
43
-
44
- Environment:
45
- PDF2EPUB_HOME Where the Python venv lives (default: ~/.pdf2epub)
46
- PDF2EPUB_PYTHON Python interpreter (or version for uv) to use
47
- PDF2EPUB_INSTALLER "auto" (default: uv if available, else pip) or "pip"
48
- HF_HOME Where marker-pdf caches its models (downloaded on first run)
49
-
50
- Notes:
51
- The first run installs PyTorch and marker-pdf into a private venv and marker
52
- downloads its models; both happen once. EPUB generation prompts for metadata
53
- interactively, so it needs a terminal; use --skip-epub for non-interactive use.
54
- `;
55
- }
56
-
57
- function info() {
58
- const up = setup.upstreamInfo();
59
- const state = setup.readState();
60
- const lines = [
61
- versionLine(),
62
- `home: ${paths.homeDir()}`,
63
- `venv: ${paths.venvDir()}${fs.existsSync(paths.venvPython()) ? '' : ' (not created)'}`,
64
- `installed: ${setup.isInstalled() ? 'yes' : state ? 'stale (run: pdf2epub setup)' : 'no (runs automatically on first use)'}`,
65
- `upstream: https://github.com/${up.repo}/tree/${up.commit || up.ref}`,
66
- `vendor: ${paths.vendorDir}`,
67
- ];
68
- if (state) {
69
- lines.push(`installer: ${state.installer}`, `installedAt: ${state.installedAt}`);
70
- } else {
71
- const uv = findUv();
72
- const py = findPython();
73
- lines.push(`uv: ${uv ? uv.version : 'not found'}`);
74
- lines.push(`python: ${py ? `${py.version} (${[py.cmd, ...py.args].join(' ')})` : 'no suitable interpreter found (need 3.10-3.13)'}`);
75
- }
76
- return lines.join('\n') + '\n';
77
- }
78
-
79
- function runUpstream(args) {
80
- const python = setup.ensureInstalled();
81
- const res = spawnSync(python, [paths.mainPy, ...args], {
82
- stdio: 'inherit',
83
- env: {
84
- ...process.env,
85
- PYTHONUNBUFFERED: process.env.PYTHONUNBUFFERED || '1',
86
- // The vendored source may live in a read-only global node_modules; keep it pristine.
87
- PYTHONDONTWRITEBYTECODE: process.env.PYTHONDONTWRITEBYTECODE || '1',
88
- },
89
- });
90
- if (res.error) throw res.error;
91
- if (res.signal) return 128 + (res.signal === 'SIGINT' ? 2 : 1);
92
- return res.status == null ? 1 : res.status;
93
- }
94
-
95
- async function main(argv) {
96
- const [first, ...rest] = argv;
97
-
98
- if (first === '--') return runUpstream(rest);
99
-
100
- if (!WRAPPER_COMMANDS.has(first)) return runUpstream(argv);
101
-
102
- switch (first) {
103
- case '--version':
104
- case '-V':
105
- process.stdout.write(versionLine() + '\n');
106
- return 0;
107
- case 'help':
108
- case '--help':
109
- case '-h':
110
- process.stdout.write(usage());
111
- return 0;
112
- case 'info':
113
- process.stdout.write(info());
114
- return 0;
115
- case 'setup': {
116
- const force = rest.includes('--force');
117
- if (!force && setup.isInstalled()) {
118
- setup.log(`Already set up in ${paths.homeDir()} (use --force to reinstall).`);
119
- return 0;
120
- }
121
- setup.ensureInstalled({ force });
122
- return 0;
123
- }
124
- case 'clean': {
125
- const removed = setup.clean();
126
- setup.log(removed ? `Removed ${paths.homeDir()}` : `Nothing to remove at ${paths.homeDir()}`);
127
- return 0;
128
- }
129
- default:
130
- return runUpstream(argv);
131
- }
132
- }
133
-
134
- module.exports = { main, usage, info, versionLine };
package/lib/paths.js DELETED
@@ -1,44 +0,0 @@
1
- 'use strict';
2
-
3
- const os = require('os');
4
- const path = require('path');
5
-
6
- const pkg = require('../package.json');
7
-
8
- const isWindows = process.platform === 'win32';
9
-
10
- function homeDir() {
11
- return process.env.PDF2EPUB_HOME || path.join(os.homedir(), '.pdf2epub');
12
- }
13
-
14
- function venvDir() {
15
- return path.join(homeDir(), 'venv');
16
- }
17
-
18
- function venvPython() {
19
- return isWindows
20
- ? path.join(venvDir(), 'Scripts', 'python.exe')
21
- : path.join(venvDir(), 'bin', 'python');
22
- }
23
-
24
- function stateFile() {
25
- return path.join(homeDir(), 'state.json');
26
- }
27
-
28
- const vendorDir = path.resolve(__dirname, '..', 'vendor', 'pdf2epub');
29
- const mainPy = path.join(vendorDir, 'main.py');
30
- const requirementsFile = path.join(vendorDir, 'requirements.txt');
31
- const upstreamFile = path.join(vendorDir, 'UPSTREAM.json');
32
-
33
- module.exports = {
34
- pkg,
35
- isWindows,
36
- homeDir,
37
- venvDir,
38
- venvPython,
39
- stateFile,
40
- vendorDir,
41
- mainPy,
42
- requirementsFile,
43
- upstreamFile,
44
- };
package/lib/python.js DELETED
@@ -1,76 +0,0 @@
1
- 'use strict';
2
-
3
- const { spawnSync } = require('child_process');
4
- const { isWindows } = require('./paths');
5
-
6
- // Upstream supports Python 3.10-3.14; 3.13 is recommended. On 3.14 Pillow has
7
- // to be built from source (marker-pdf pins Pillow<11), so treat it as a last
8
- // resort.
9
- const MIN = [3, 10];
10
- const PREFERRED_MAX = [3, 13];
11
- const HARD_MAX = [3, 14];
12
-
13
- function cmp(a, b) {
14
- return a[0] - b[0] || a[1] - b[1];
15
- }
16
-
17
- function probe(cmd, args) {
18
- const res = spawnSync(
19
- cmd,
20
- [...args, '-c', 'import sys; print("%d.%d.%d" % sys.version_info[:3])'],
21
- { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 15000 }
22
- );
23
- if (res.error || res.status !== 0) return null;
24
- const m = /^(\d+)\.(\d+)\.(\d+)/.exec((res.stdout || '').trim());
25
- if (!m) return null;
26
- return {
27
- cmd,
28
- args,
29
- version: m[0],
30
- tuple: [Number(m[1]), Number(m[2])],
31
- };
32
- }
33
-
34
- function candidates() {
35
- const list = [];
36
- if (process.env.PDF2EPUB_PYTHON) {
37
- list.push({ cmd: process.env.PDF2EPUB_PYTHON, args: [] });
38
- return list;
39
- }
40
- for (const v of ['3.13', '3.12', '3.11', '3.10', '3.14']) {
41
- list.push({ cmd: `python${v}`, args: [] });
42
- if (isWindows) list.push({ cmd: 'py', args: [`-${v}`] });
43
- }
44
- list.push({ cmd: 'python3', args: [] });
45
- list.push({ cmd: 'python', args: [] });
46
- if (isWindows) list.push({ cmd: 'py', args: ['-3'] });
47
- return list;
48
- }
49
-
50
- /**
51
- * Find a Python interpreter suitable for the upstream project.
52
- * Returns { cmd, args, version, tuple, fallback } or null.
53
- */
54
- function findPython() {
55
- let fallback = null;
56
- for (const c of candidates()) {
57
- const p = probe(c.cmd, c.args);
58
- if (!p) continue;
59
- if (cmp(p.tuple, MIN) < 0) continue;
60
- if (cmp(p.tuple, PREFERRED_MAX) <= 0) return { ...p, fallback: false };
61
- if (cmp(p.tuple, HARD_MAX) <= 0 && !fallback) fallback = { ...p, fallback: true };
62
- }
63
- return fallback;
64
- }
65
-
66
- function findUv() {
67
- const res = spawnSync('uv', ['--version'], {
68
- encoding: 'utf8',
69
- stdio: ['ignore', 'pipe', 'ignore'],
70
- timeout: 15000,
71
- });
72
- if (res.error || res.status !== 0) return null;
73
- return { cmd: 'uv', version: (res.stdout || '').trim() };
74
- }
75
-
76
- module.exports = { findPython, findUv, probe, MIN, PREFERRED_MAX, HARD_MAX };
package/lib/setup.js DELETED
@@ -1,152 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const crypto = require('crypto');
5
- const { spawnSync } = require('child_process');
6
-
7
- const paths = require('./paths');
8
- const { findPython, findUv } = require('./python');
9
-
10
- function log(msg) {
11
- process.stderr.write(`[pdf2epub] ${msg}\n`);
12
- }
13
-
14
- function readJson(file, fallback) {
15
- try {
16
- return JSON.parse(fs.readFileSync(file, 'utf8'));
17
- } catch {
18
- return fallback;
19
- }
20
- }
21
-
22
- function upstreamInfo() {
23
- return readJson(paths.upstreamFile, paths.pkg.pdf2epub.upstream);
24
- }
25
-
26
- /** Hash of everything that, when changed, requires reinstalling the venv. */
27
- function installHash() {
28
- const h = crypto.createHash('sha256');
29
- h.update(fs.readFileSync(paths.requirementsFile));
30
- h.update('\n');
31
- h.update(String(upstreamInfo().commit || ''));
32
- return h.digest('hex');
33
- }
34
-
35
- function readState() {
36
- return readJson(paths.stateFile(), null);
37
- }
38
-
39
- function isInstalled() {
40
- const state = readState();
41
- return Boolean(state && fs.existsSync(paths.venvPython()) && state.hash === installHash());
42
- }
43
-
44
- function run(cmd, args, opts = {}) {
45
- log(`$ ${[cmd, ...args].join(' ')}`);
46
- const res = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
47
- if (res.error) throw res.error;
48
- return res.status;
49
- }
50
-
51
- function installWithUv(uv) {
52
- const pyArg = process.env.PDF2EPUB_PYTHON || '3.13';
53
- if (run(uv.cmd, ['venv', '--python', pyArg, paths.venvDir()]) !== 0) return false;
54
- return (
55
- run(uv.cmd, [
56
- 'pip',
57
- 'install',
58
- '--python',
59
- paths.venvPython(),
60
- '-r',
61
- paths.requirementsFile,
62
- ]) === 0
63
- );
64
- }
65
-
66
- function installWithPip(python) {
67
- if (run(python.cmd, [...python.args, '-m', 'venv', paths.venvDir()]) !== 0) return false;
68
- const vp = paths.venvPython();
69
- // Failing to upgrade pip is not fatal.
70
- run(vp, ['-m', 'pip', 'install', '--upgrade', 'pip']);
71
- return run(vp, ['-m', 'pip', 'install', '-r', paths.requirementsFile]) === 0;
72
- }
73
-
74
- /**
75
- * Make sure the Python environment exists and matches the bundled upstream.
76
- * Returns the path to the venv's python executable.
77
- */
78
- function ensureInstalled({ force = false } = {}) {
79
- if (!force && isInstalled()) return paths.venvPython();
80
-
81
- const up = upstreamInfo();
82
- log(`Setting up Python environment in ${paths.homeDir()}`);
83
- log(`Upstream: ${up.repo}@${up.ref} (${String(up.commit).slice(0, 7)})`);
84
- log('This installs PyTorch and marker-pdf (several hundred MB); it only happens once.');
85
-
86
- if (fs.existsSync(paths.venvDir())) {
87
- log('Removing existing environment');
88
- fs.rmSync(paths.venvDir(), { recursive: true, force: true });
89
- }
90
- fs.mkdirSync(paths.homeDir(), { recursive: true });
91
-
92
- const installer = (process.env.PDF2EPUB_INSTALLER || 'auto').toLowerCase();
93
- let ok = false;
94
- let used = null;
95
-
96
- const uv = installer === 'pip' ? null : findUv();
97
- if (uv) {
98
- log(`Using ${uv.version}`);
99
- ok = installWithUv(uv);
100
- used = 'uv';
101
- if (!ok) {
102
- log('uv install failed; falling back to venv + pip');
103
- fs.rmSync(paths.venvDir(), { recursive: true, force: true });
104
- }
105
- }
106
-
107
- if (!ok) {
108
- const python = findPython();
109
- if (!python) {
110
- throw new Error(
111
- 'No suitable Python found. pdf2epub needs Python 3.10-3.13 (3.13 recommended).\n' +
112
- ' Install Python 3.13 (https://www.python.org/downloads/) or uv (https://docs.astral.sh/uv/),\n' +
113
- ' or point PDF2EPUB_PYTHON at an interpreter.'
114
- );
115
- }
116
- if (python.fallback) {
117
- log(
118
- `Warning: using Python ${python.version}; 3.13 is recommended. ` +
119
- 'Pillow will be built from source, which needs a C toolchain and image headers.'
120
- );
121
- }
122
- log(`Using Python ${python.version} (${[python.cmd, ...python.args].join(' ')})`);
123
- ok = installWithPip(python);
124
- used = 'pip';
125
- }
126
-
127
- if (!ok) {
128
- throw new Error(`Python dependency installation failed. See output above. Retry with: pdf2epub setup --force`);
129
- }
130
-
131
- const state = {
132
- hash: installHash(),
133
- upstream: up,
134
- wrapperVersion: paths.pkg.version,
135
- installer: used,
136
- python: paths.venvPython(),
137
- installedAt: new Date().toISOString(),
138
- };
139
- fs.writeFileSync(paths.stateFile(), JSON.stringify(state, null, 2) + '\n');
140
- log('Setup complete.');
141
- return paths.venvPython();
142
- }
143
-
144
- function clean() {
145
- if (fs.existsSync(paths.homeDir())) {
146
- fs.rmSync(paths.homeDir(), { recursive: true, force: true });
147
- return true;
148
- }
149
- return false;
150
- }
151
-
152
- module.exports = { ensureInstalled, isInstalled, installHash, readState, upstreamInfo, clean, log };
@@ -1,9 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 overcuriousity
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,217 +0,0 @@
1
- # PDF2EPUB 📚
2
-
3
- Convert PDF files to nicely structured Markdown and EPUB format with intelligent layout detection.
4
-
5
- ## ✨ Features
6
-
7
- - 📖 Smart layout detection for books and academic papers
8
- - 🔍 Advanced text extraction and OCR capabilities
9
- - 📊 Table detection and formatting
10
- - 🖼️ Image extraction and optimization
11
- - 📝 Clean markdown output with preserved structure
12
- - 📱 EPUB generation with customizable styling
13
- - 🌍 Multi-language support
14
- - 🚀 GPU acceleration support (NVIDIA & AMD)
15
- - 🍎 Apple Silicon support
16
-
17
- ## 🛠️ Dependencies
18
-
19
- - Python 3.10–3.14 (3.13 recommended, see below)
20
- - PyTorch (with CUDA/ROCm support for GPU acceleration)
21
- - marker-pdf==1.10.2
22
- - transformers==4.57.6
23
- - markdown==3.10.2
24
- - latex2mathml==3.81.0
25
-
26
- ### ⚠️ Python version
27
-
28
- Python 3.13 is recommended.
29
-
30
- `marker-pdf` constrains `Pillow<11.0.0`, and Pillow only ships Python 3.14
31
- wheels from 11.3.0 onward. On Python 3.10–3.13 every dependency installs as a
32
- prebuilt wheel. On 3.14, pip has to build Pillow from source instead: this
33
- works, but it is slower and requires a working C toolchain plus the image
34
- library headers Pillow links against. On Debian/Ubuntu install them first:
35
-
36
- ```bash
37
- sudo apt install libjpeg-dev zlib1g-dev libtiff-dev libfreetype6-dev libwebp-dev
38
- ```
39
-
40
- Without these headers the install fails with
41
- `RequiredDependencyException: The headers or library files could not be found for jpeg`.
42
-
43
- ## 💻 Installation
44
-
45
- 1. Create and activate a virtual environment.
46
-
47
- On Linux/Mac:
48
- ```bash
49
- python3.13 -m venv .venv
50
- source .venv/bin/activate
51
- ```
52
-
53
- On Windows:
54
- ```powershell
55
- py -3.13 -m venv .venv
56
- .venv\Scripts\activate
57
- ```
58
-
59
- 2. Install Python dependencies (this installs PyTorch as well):
60
- ```bash
61
- pip install -r requirements.txt
62
- ```
63
-
64
- 3. GPU acceleration (optional):
65
-
66
- PyTorch is installed as a dependency in step 2. On Apple Silicon that wheel
67
- already supports MPS, so no further action is needed. For a specific CUDA or
68
- ROCm build, reinstall PyTorch using the selector at
69
- [pytorch.org/get-started/locally](https://pytorch.org/get-started/locally/).
70
- For example, for AMD GPUs with ROCm:
71
- ```bash
72
- pip uninstall torch torchvision torchaudio
73
- pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.2
74
- ```
75
-
76
- 4. Verify GPU support:
77
- ```python
78
- import torch
79
- print(torch.__version__) # PyTorch version
80
- print(torch.cuda.is_available()) # Should return True for NVIDIA
81
- print(torch.backends.mps.is_available()) # Should return True for Apple Silicon
82
- print(torch.version.hip) # Should print ROCm version for AMD
83
- ```
84
-
85
- ### 🐳 Docker
86
-
87
- A CPU-only image can be built from the included `Dockerfile`:
88
-
89
- ```bash
90
- docker build -t pdf2epub .
91
- ```
92
-
93
- Run it with your PDFs mounted at `/data` and a model cache volume (marker-pdf
94
- downloads its models on first run):
95
-
96
- ```bash
97
- docker run -it --rm \
98
- -v "$(pwd)":/data \
99
- -v pdf2epub-models:/models \
100
- pdf2epub input.pdf
101
- ```
102
-
103
- `-it` is required for EPUB generation because metadata is prompted
104
- interactively; with `--skip-epub` it can run non-interactively.
105
-
106
- Tagged releases are also published to
107
- `ghcr.io/overcuriousity/pdf2epub` by the Docker workflow.
108
-
109
- ## 🚀 Usage
110
-
111
- ### Basic Usage
112
-
113
- Convert a single PDF file:
114
- ```bash
115
- python main.py input.pdf
116
- ```
117
-
118
- Convert all PDFs in a directory:
119
- ```bash
120
- python main.py input_directory/
121
- ```
122
-
123
- EPUB generation prompts interactively for metadata (title, author, language,
124
- and so on; press Enter to accept each default). It therefore needs a terminal —
125
- run it non-interactively and it will fail with `EOFError`. Use `--skip-epub` to
126
- produce only markdown without any prompts.
127
-
128
- ### Advanced Options
129
-
130
- ```bash
131
- python main.py [input_path] [output_path] [options]
132
-
133
- Options:
134
- --max-pages INT Maximum number of pages to process
135
- --start-page INT Page number to start from
136
- --skip-epub Skip EPUB generation, only create markdown
137
- --skip-md Skip markdown generation, use existing markdown files
138
- ```
139
-
140
- If `input_path` is omitted, all PDFs in `./input/` are processed.
141
-
142
- ### Examples
143
-
144
- Process a specific range of pages:
145
- ```bash
146
- python main.py book.pdf --start-page 10 --max-pages 50
147
- ```
148
-
149
- Convert to markdown only:
150
- ```bash
151
- python main.py thesis.pdf --skip-epub
152
- ```
153
-
154
- ### Output Structure
155
-
156
- ```
157
- output_directory/
158
- ├── document_name/
159
- │ ├── document_name.md
160
- │ ├── document_name.epub
161
- │ ├── document_name_metadata.json
162
- │ └── images/
163
- │ ├── image1.png
164
- │ ├── image2.jpg
165
- │ └── ...
166
- ```
167
-
168
- ## 🤝 Contributing
169
-
170
- Contributions are welcome! Here's how you can help:
171
-
172
- 1. Fork the repository
173
- 2. Create a new branch for your feature
174
- 3. Commit your changes
175
- 4. Push to your branch
176
- 5. Create a Pull Request
177
-
178
- Please ensure your code follows the existing style and includes appropriate tests.
179
-
180
- ### Development Setup
181
-
182
- 1. Clone the repository:
183
- ```bash
184
- git clone https://github.com/overcuriousity/pdf2epub.git
185
- cd pdf2epub
186
- ```
187
-
188
- 2. Create a virtual environment:
189
- ```bash
190
- python -m venv venv
191
- source venv/bin/activate # Linux/Mac
192
- venv\Scripts\activate # Windows
193
- ```
194
-
195
- 3. Install development dependencies:
196
- ```bash
197
- pip install -r requirements.txt
198
- ```
199
-
200
- ## 📄 License
201
-
202
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
203
-
204
- ## 🐛 Known Issues
205
-
206
- - Some image embedding might need manual adjustment
207
- - Some complex mathematical equations might not be perfectly converted
208
- - Certain PDF layouts with multiple columns may require manual adjustment
209
- - Font detection might be imperfect in some cases
210
-
211
- ## 🙏 Acknowledgments
212
-
213
- This project builds upon several excellent open-source libraries:
214
- - [marker-pdf](https://github.com/VikParuchuri/marker) for PDF processing
215
- - [mark2epub](https://github.com/AlexPof/mark2epub) for markdown conversion
216
- - [PyTorch](https://pytorch.org/) for GPU acceleration
217
- - [Transformers](https://huggingface.co/transformers) for advanced text processing
@@ -1,8 +0,0 @@
1
- {
2
- "repo": "overcuriousity/pdf2epub",
3
- "ref": "v1.1.0",
4
- "commit": "5eae669d1c897b4735f369fb2ff4086237db3a81",
5
- "commitDate": "2026-07-16T18:17:11Z",
6
- "url": "https://github.com/overcuriousity/pdf2epub/tree/5eae669d1c897b4735f369fb2ff4086237db3a81",
7
- "syncedAt": "2026-09-07T09:36:39.940Z"
8
- }