pdflinux 0.1.1 → 0.1.2
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/README.md +96 -35
- package/bin/pdflinux +8 -6
- package/install.sh +28 -28
- package/package.json +2 -2
- package/uninstall.sh +12 -13
package/README.md
CHANGED
|
@@ -1,45 +1,39 @@
|
|
|
1
1
|
# PDFLinux
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/pdflinux)
|
|
4
|
+
[](https://www.npmjs.com/package/pdflinux)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](#install)
|
|
7
|
+
|
|
8
|
+
> **100% free. No subscription. No account. Your files never leave your computer.**
|
|
4
9
|
|
|
5
10
|
A fast, privacy-first desktop application for all your everyday PDF tasks. Built with Tauri + Rust on the backend and React + TypeScript on the frontend — runs entirely on your local machine, no internet connection required, no files uploaded anywhere.
|
|
6
11
|
|
|
7
12
|
---
|
|
8
13
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
### Option 1 — Git Clone (recommended)
|
|
14
|
+
## Table of Contents
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- Add a shortcut to your app menu and a `pdflinux` command in the terminal
|
|
16
|
+
- [Quick Install](#quick-install)
|
|
17
|
+
- [Why PDFLinux?](#why-pdflinux)
|
|
18
|
+
- [Features](#features)
|
|
19
|
+
- [Prerequisites](#prerequisites)
|
|
20
|
+
- [Installation](#installation)
|
|
21
|
+
- [Tech Stack](#tech-stack)
|
|
22
|
+
- [Development](#development)
|
|
23
|
+
- [Project Structure](#project-structure)
|
|
24
|
+
- [Contributing](#contributing)
|
|
25
|
+
- [License](#license)
|
|
26
|
+
- [Privacy](#privacy)
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
./uninstall.sh
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Option 2 — npx (via npm)
|
|
28
|
+
---
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
## Quick Install
|
|
34
31
|
|
|
35
32
|
```bash
|
|
36
33
|
npx pdflinux
|
|
37
34
|
```
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx pdflinux uninstall
|
|
42
|
-
```
|
|
36
|
+
That's it. The installer detects your distro, installs all dependencies, builds the app, and adds it to your application menu.
|
|
43
37
|
|
|
44
38
|
---
|
|
45
39
|
|
|
@@ -51,11 +45,14 @@ Most online PDF tools require you to upload your files to their servers. For sen
|
|
|
51
45
|
- **Privacy-first** — zero network requests, zero telemetry
|
|
52
46
|
- **Lightweight** — powered by Tauri (uses the OS native webview, not a bundled Chromium like Electron)
|
|
53
47
|
- **Linux-first** — primary target is Linux; Windows and macOS are also supported via Tauri
|
|
48
|
+
- **Open source** — auditable, forkable, yours
|
|
54
49
|
|
|
55
50
|
---
|
|
56
51
|
|
|
57
52
|
## Features
|
|
58
53
|
|
|
54
|
+
17 PDF tools, all running locally on your machine:
|
|
55
|
+
|
|
59
56
|
| Tool | Description |
|
|
60
57
|
|---|---|
|
|
61
58
|
| **Compress** | Reduce PDF file size using Ghostscript with quality presets |
|
|
@@ -78,6 +75,66 @@ Most online PDF tools require you to upload your files to their servers. For sen
|
|
|
78
75
|
|
|
79
76
|
---
|
|
80
77
|
|
|
78
|
+
## Prerequisites
|
|
79
|
+
|
|
80
|
+
PDFLinux requires a few native CLI utilities to do the heavy lifting. The installer will install these for you automatically, but here is the list for reference:
|
|
81
|
+
|
|
82
|
+
- **Ghostscript** — for compression and color operations
|
|
83
|
+
- **Poppler** — for PDF-to-image conversion and text extraction
|
|
84
|
+
- **QPDF** — for encryption, decryption, and page operations
|
|
85
|
+
- **Tesseract** — for OCR
|
|
86
|
+
|
|
87
|
+
The installer also requires:
|
|
88
|
+
- A supported Linux distro (Debian, Ubuntu, Fedora, RHEL, CentOS, Arch, openSUSE, or derivatives)
|
|
89
|
+
- `sudo` privileges (to install system packages)
|
|
90
|
+
- Internet access (during installation only)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Installation
|
|
95
|
+
|
|
96
|
+
### Option 1 — npx (easiest)
|
|
97
|
+
|
|
98
|
+
If you already have Node.js installed:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx pdflinux
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
To uninstall:
|
|
105
|
+
```bash
|
|
106
|
+
npx pdflinux uninstall
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Option 2 — Git Clone
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/saaandbite/pdflinux.git
|
|
113
|
+
cd pdflinux
|
|
114
|
+
./install.sh
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The `install.sh` script will automatically:
|
|
118
|
+
- Detect your distro (Debian/Ubuntu, Fedora/RHEL/CentOS, Arch, etc.)
|
|
119
|
+
- Install all required dependencies
|
|
120
|
+
- Build the application
|
|
121
|
+
- Install the appropriate package (`.deb` / `.rpm` / `AppImage`) for your distro
|
|
122
|
+
- Add a shortcut to your app menu and a `pdflinux` command in the terminal
|
|
123
|
+
|
|
124
|
+
To uninstall:
|
|
125
|
+
```bash
|
|
126
|
+
./uninstall.sh
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Launching the app
|
|
130
|
+
|
|
131
|
+
After installation you can launch PDFLinux in two ways:
|
|
132
|
+
|
|
133
|
+
- **Application menu** — search for "PDFLinux" in your desktop environment's app launcher
|
|
134
|
+
- **Terminal** — run `pdflinux` from anywhere
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
81
138
|
## Tech Stack
|
|
82
139
|
|
|
83
140
|
| Layer | Technology |
|
|
@@ -96,7 +153,7 @@ Tauri uses the operating system's native webview (WebKitGTK on Linux) instead of
|
|
|
96
153
|
|
|
97
154
|
## Development
|
|
98
155
|
|
|
99
|
-
To run from source:
|
|
156
|
+
To run from source for local development:
|
|
100
157
|
|
|
101
158
|
```bash
|
|
102
159
|
git clone https://github.com/saaandbite/pdflinux.git
|
|
@@ -131,12 +188,16 @@ pdflinux/
|
|
|
131
188
|
│ ├── App.tsx # Route definitions
|
|
132
189
|
│ └── main.tsx # React entry point
|
|
133
190
|
│
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
191
|
+
├── src-tauri/ # Rust backend (Tauri)
|
|
192
|
+
│ ├── src/
|
|
193
|
+
│ │ ├── main.rs # Tauri entry point
|
|
194
|
+
│ │ └── pdf_engine.rs # PDF processing logic (calls gs, qpdf, poppler)
|
|
195
|
+
│ ├── tauri.conf.json # App window and build configuration
|
|
196
|
+
│ └── Cargo.toml # Rust dependencies
|
|
197
|
+
│
|
|
198
|
+
├── bin/pdflinux # npm CLI wrapper
|
|
199
|
+
├── install.sh # Linux installer script
|
|
200
|
+
└── uninstall.sh # Linux uninstaller script
|
|
140
201
|
```
|
|
141
202
|
|
|
142
203
|
---
|
|
@@ -156,7 +217,7 @@ Please open an issue first for larger changes so we can discuss the approach.
|
|
|
156
217
|
|
|
157
218
|
## License
|
|
158
219
|
|
|
159
|
-
This project is open source
|
|
220
|
+
This project is open source under the [MIT License](./LICENSE).
|
|
160
221
|
|
|
161
222
|
---
|
|
162
223
|
|
package/bin/pdflinux
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { resolve, dirname } from 'node:path';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
3
6
|
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const { existsSync } = require('fs');
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
7
9
|
|
|
8
10
|
const root = resolve(__dirname, '..');
|
|
9
11
|
const installScript = resolve(root, 'install.sh');
|
|
@@ -14,7 +16,7 @@ const cmd = args[0];
|
|
|
14
16
|
|
|
15
17
|
if (cmd === 'uninstall') {
|
|
16
18
|
if (!existsSync(uninstallScript)) {
|
|
17
|
-
console.error('uninstall.sh
|
|
19
|
+
console.error('uninstall.sh not found.');
|
|
18
20
|
process.exit(1);
|
|
19
21
|
}
|
|
20
22
|
const result = spawnSync('bash', [uninstallScript], { stdio: 'inherit' });
|
|
@@ -23,7 +25,7 @@ if (cmd === 'uninstall') {
|
|
|
23
25
|
|
|
24
26
|
// Default: install
|
|
25
27
|
if (!existsSync(installScript)) {
|
|
26
|
-
console.error('install.sh
|
|
28
|
+
console.error('install.sh not found.');
|
|
27
29
|
process.exit(1);
|
|
28
30
|
}
|
|
29
31
|
|
package/install.sh
CHANGED
|
@@ -39,7 +39,7 @@ detect_pkg_manager() {
|
|
|
39
39
|
|
|
40
40
|
install_system_deps() {
|
|
41
41
|
local pm="$1"
|
|
42
|
-
info "
|
|
42
|
+
info "Installing PDF system dependencies (Ghostscript, Poppler, QPDF, Tesseract)..."
|
|
43
43
|
|
|
44
44
|
case "$pm" in
|
|
45
45
|
apt)
|
|
@@ -73,7 +73,7 @@ install_system_deps() {
|
|
|
73
73
|
pkg-config gcc curl wget
|
|
74
74
|
;;
|
|
75
75
|
*)
|
|
76
|
-
warn "Package manager
|
|
76
|
+
warn "Package manager not recognized. Make sure these are installed:"
|
|
77
77
|
warn " ghostscript, poppler-utils, qpdf, tesseract-ocr"
|
|
78
78
|
;;
|
|
79
79
|
esac
|
|
@@ -81,21 +81,21 @@ install_system_deps() {
|
|
|
81
81
|
|
|
82
82
|
install_rust() {
|
|
83
83
|
if command -v rustup &>/dev/null && rustup show active-toolchain &>/dev/null; then
|
|
84
|
-
success "Rust
|
|
84
|
+
success "Rust already installed: $(rustc --version)"
|
|
85
85
|
return
|
|
86
86
|
fi
|
|
87
|
-
info "
|
|
87
|
+
info "Installing Rust via rustup..."
|
|
88
88
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
|
89
89
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
90
|
-
success "Rust
|
|
90
|
+
success "Rust installed: $(rustc --version)"
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
install_node() {
|
|
94
94
|
if command -v node &>/dev/null; then
|
|
95
|
-
success "Node.js
|
|
95
|
+
success "Node.js already installed: $(node --version)"
|
|
96
96
|
return
|
|
97
97
|
fi
|
|
98
|
-
info "
|
|
98
|
+
info "Installing Node.js via NodeSource..."
|
|
99
99
|
local pm="$1"
|
|
100
100
|
case "$pm" in
|
|
101
101
|
apt)
|
|
@@ -113,21 +113,21 @@ install_node() {
|
|
|
113
113
|
sudo zypper install -y nodejs npm
|
|
114
114
|
;;
|
|
115
115
|
*)
|
|
116
|
-
error "
|
|
116
|
+
error "Please install Node.js LTS manually from https://nodejs.org/ then run this script again."
|
|
117
117
|
;;
|
|
118
118
|
esac
|
|
119
|
-
success "Node.js
|
|
119
|
+
success "Node.js installed: $(node --version)"
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
build_app() {
|
|
123
|
-
info "
|
|
123
|
+
info "Installing npm dependencies..."
|
|
124
124
|
npm ci --silent
|
|
125
125
|
|
|
126
|
-
info "
|
|
126
|
+
info "Building application (this may take a few minutes the first time)..."
|
|
127
127
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
128
128
|
npm run tauri build
|
|
129
129
|
|
|
130
|
-
success "Build
|
|
130
|
+
success "Build complete."
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
install_package() {
|
|
@@ -139,9 +139,9 @@ install_package() {
|
|
|
139
139
|
local deb
|
|
140
140
|
deb=$(find "$bundle_dir/deb" -name "*.deb" 2>/dev/null | head -1)
|
|
141
141
|
if [ -n "$deb" ]; then
|
|
142
|
-
info "
|
|
142
|
+
info "Installing .deb package: $deb"
|
|
143
143
|
sudo dpkg -i "$deb"
|
|
144
|
-
success "$DISPLAY_NAME
|
|
144
|
+
success "$DISPLAY_NAME installed successfully."
|
|
145
145
|
return
|
|
146
146
|
fi
|
|
147
147
|
;;
|
|
@@ -149,9 +149,9 @@ install_package() {
|
|
|
149
149
|
local rpm
|
|
150
150
|
rpm=$(find "$bundle_dir/rpm" -name "*.rpm" 2>/dev/null | head -1)
|
|
151
151
|
if [ -n "$rpm" ]; then
|
|
152
|
-
info "
|
|
152
|
+
info "Installing .rpm package: $rpm"
|
|
153
153
|
sudo "$pm" install -y "$rpm"
|
|
154
|
-
success "$DISPLAY_NAME
|
|
154
|
+
success "$DISPLAY_NAME installed successfully."
|
|
155
155
|
return
|
|
156
156
|
fi
|
|
157
157
|
;;
|
|
@@ -159,17 +159,17 @@ install_package() {
|
|
|
159
159
|
;;
|
|
160
160
|
esac
|
|
161
161
|
|
|
162
|
-
# Fallback
|
|
162
|
+
# Fallback to AppImage
|
|
163
163
|
local appimage
|
|
164
164
|
appimage=$(find "$bundle_dir/appimage" -name "*.AppImage" 2>/dev/null | head -1)
|
|
165
165
|
if [ -n "$appimage" ]; then
|
|
166
|
-
info "
|
|
166
|
+
info "Installing AppImage..."
|
|
167
167
|
local install_dir="$HOME/.local/bin"
|
|
168
168
|
mkdir -p "$install_dir"
|
|
169
169
|
cp "$appimage" "$install_dir/$APP_NAME"
|
|
170
170
|
chmod +x "$install_dir/$APP_NAME"
|
|
171
171
|
|
|
172
|
-
#
|
|
172
|
+
# Add to PATH if not already there
|
|
173
173
|
local shell_rc=""
|
|
174
174
|
case "$SHELL" in
|
|
175
175
|
*/bash) shell_rc="$HOME/.bashrc" ;;
|
|
@@ -178,15 +178,15 @@ install_package() {
|
|
|
178
178
|
esac
|
|
179
179
|
if [ -n "$shell_rc" ] && ! grep -q "$install_dir" "$shell_rc" 2>/dev/null; then
|
|
180
180
|
echo "export PATH=\"$install_dir:\$PATH\"" >> "$shell_rc"
|
|
181
|
-
warn "PATH
|
|
181
|
+
warn "PATH updated in $shell_rc. Run: source $shell_rc"
|
|
182
182
|
fi
|
|
183
183
|
|
|
184
184
|
install_desktop_file "$appimage"
|
|
185
|
-
success "$DISPLAY_NAME
|
|
185
|
+
success "$DISPLAY_NAME installed as AppImage."
|
|
186
186
|
return
|
|
187
187
|
fi
|
|
188
188
|
|
|
189
|
-
error "
|
|
189
|
+
error "No installer found in $bundle_dir"
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
install_desktop_file() {
|
|
@@ -205,7 +205,7 @@ install_desktop_file() {
|
|
|
205
205
|
[Desktop Entry]
|
|
206
206
|
Type=Application
|
|
207
207
|
Name=PDFLinux
|
|
208
|
-
Comment=Privacy-first PDF tools
|
|
208
|
+
Comment=Privacy-first PDF tools for Linux — runs 100% offline
|
|
209
209
|
Exec=$exec_path
|
|
210
210
|
Icon=$APP_NAME
|
|
211
211
|
Categories=Office;Utility;
|
|
@@ -219,7 +219,7 @@ EOF
|
|
|
219
219
|
if command -v gtk-update-icon-cache &>/dev/null; then
|
|
220
220
|
gtk-update-icon-cache -f "$HOME/.local/share/icons/hicolor" &>/dev/null || true
|
|
221
221
|
fi
|
|
222
|
-
success "
|
|
222
|
+
success "Application menu shortcut added."
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
# ── Main ────────────────────────────────────────────────────────────────────
|
|
@@ -236,7 +236,7 @@ cd "$SCRIPT_DIR"
|
|
|
236
236
|
DISTRO=$(detect_distro)
|
|
237
237
|
PKG_MANAGER=$(detect_pkg_manager)
|
|
238
238
|
|
|
239
|
-
info "
|
|
239
|
+
info "Detected distro: $DISTRO (package manager: $PKG_MANAGER)"
|
|
240
240
|
|
|
241
241
|
install_system_deps "$PKG_MANAGER"
|
|
242
242
|
install_rust
|
|
@@ -246,9 +246,9 @@ install_package "$PKG_MANAGER"
|
|
|
246
246
|
|
|
247
247
|
echo ""
|
|
248
248
|
echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
|
|
249
|
-
echo -e "${GREEN}║ ✓ PDFLinux
|
|
249
|
+
echo -e "${GREEN}║ ✓ PDFLinux installed successfully! ║${NC}"
|
|
250
250
|
echo -e "${GREEN}║ ║${NC}"
|
|
251
|
-
echo -e "${GREEN}║ •
|
|
252
|
-
echo -e "${GREEN}║ •
|
|
251
|
+
echo -e "${GREEN}║ • Launch from app menu: search for \"PDFLinux\" ║${NC}"
|
|
252
|
+
echo -e "${GREEN}║ • Or run from terminal: pdflinux ║${NC}"
|
|
253
253
|
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
|
|
254
254
|
echo ""
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdflinux",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Privacy-first PDF tools
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Privacy-first PDF tools for Linux — runs 100% offline",
|
|
5
5
|
"keywords": ["pdf", "linux", "tools", "privacy", "tauri", "desktop"],
|
|
6
6
|
"author": "saaandbite",
|
|
7
7
|
"license": "MIT",
|
package/uninstall.sh
CHANGED
|
@@ -11,7 +11,6 @@ NC='\033[0m'
|
|
|
11
11
|
|
|
12
12
|
info() { echo -e "${BLUE}[*]${NC} $*"; }
|
|
13
13
|
success() { echo -e "${GREEN}[✓]${NC} $*"; }
|
|
14
|
-
error() { echo -e "${RED}[✗]${NC} $*"; exit 1; }
|
|
15
14
|
|
|
16
15
|
detect_pkg_manager() {
|
|
17
16
|
if command -v apt &>/dev/null; then echo "apt"
|
|
@@ -30,30 +29,30 @@ echo -e "${RED}║ PDFLinux — Uninstall ║${NC}"
|
|
|
30
29
|
echo -e "${RED}╚══════════════════════════════════╝${NC}"
|
|
31
30
|
echo ""
|
|
32
31
|
|
|
33
|
-
#
|
|
32
|
+
# Remove package installed via package manager
|
|
34
33
|
case "$PM" in
|
|
35
34
|
apt)
|
|
36
|
-
if dpkg -l "
|
|
37
|
-
info "
|
|
38
|
-
sudo apt-get remove -y
|
|
35
|
+
if dpkg -l "pdflinux" &>/dev/null 2>&1; then
|
|
36
|
+
info "Removing .deb package..."
|
|
37
|
+
sudo apt-get remove -y pdflinux || true
|
|
39
38
|
fi
|
|
40
39
|
;;
|
|
41
40
|
dnf|yum)
|
|
42
|
-
if rpm -q "
|
|
43
|
-
info "
|
|
44
|
-
sudo "$PM" remove -y
|
|
41
|
+
if rpm -q "pdflinux" &>/dev/null 2>&1; then
|
|
42
|
+
info "Removing .rpm package..."
|
|
43
|
+
sudo "$PM" remove -y pdflinux || true
|
|
45
44
|
fi
|
|
46
45
|
;;
|
|
47
46
|
esac
|
|
48
47
|
|
|
49
|
-
#
|
|
48
|
+
# Remove AppImage
|
|
50
49
|
if [ -f "$HOME/.local/bin/$APP_NAME" ]; then
|
|
51
|
-
info "
|
|
50
|
+
info "Removing AppImage..."
|
|
52
51
|
rm -f "$HOME/.local/bin/$APP_NAME"
|
|
53
52
|
fi
|
|
54
53
|
|
|
55
|
-
#
|
|
56
|
-
info "
|
|
54
|
+
# Remove .desktop file and icon
|
|
55
|
+
info "Removing application menu shortcut..."
|
|
57
56
|
rm -f "$HOME/.local/share/applications/$APP_NAME.desktop"
|
|
58
57
|
rm -f "$HOME/.local/share/icons/hicolor/128x128/apps/$APP_NAME.png"
|
|
59
58
|
|
|
@@ -61,5 +60,5 @@ if command -v update-desktop-database &>/dev/null; then
|
|
|
61
60
|
update-desktop-database "$HOME/.local/share/applications" &>/dev/null || true
|
|
62
61
|
fi
|
|
63
62
|
|
|
64
|
-
success "$DISPLAY_NAME
|
|
63
|
+
success "$DISPLAY_NAME removed successfully."
|
|
65
64
|
echo ""
|