polytool 0.2.9__tar.gz → 0.2.11__tar.gz

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.
Files changed (38) hide show
  1. polytool-0.2.11/PKG-INFO +295 -0
  2. polytool-0.2.11/README.md +196 -0
  3. {polytool-0.2.9 → polytool-0.2.11}/docs/README.md +1 -1
  4. {polytool-0.2.9 → polytool-0.2.11}/pyproject.toml +3 -3
  5. polytool-0.2.11/src/polytool/__init__.py +4 -0
  6. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/__init__.py +6 -3
  7. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/dl.py +4 -16
  8. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/gen.py +3 -2
  9. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/img.py +8 -9
  10. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/pdf.py +12 -2
  11. polytool-0.2.9/PKG-INFO +0 -260
  12. polytool-0.2.9/README.md +0 -159
  13. polytool-0.2.9/src/polytool/__init__.py +0 -4
  14. {polytool-0.2.9 → polytool-0.2.11}/.gitignore +0 -0
  15. {polytool-0.2.9 → polytool-0.2.11}/LICENSE +0 -0
  16. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/__main__.py +0 -0
  17. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/clip.py +0 -0
  18. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/color.py +0 -0
  19. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/convert.py +0 -0
  20. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/cron.py +0 -0
  21. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/data.py +0 -0
  22. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/enc.py +0 -0
  23. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/file.py +0 -0
  24. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/net.py +0 -0
  25. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/qr.py +0 -0
  26. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/shot.py +0 -0
  27. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/text.py +0 -0
  28. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/cli/vid.py +0 -0
  29. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/__init__.py +0 -0
  30. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/browsers.py +0 -0
  31. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/config.py +0 -0
  32. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/console.py +0 -0
  33. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/errors.py +0 -0
  34. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/ffmpeg.py +0 -0
  35. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/io.py +0 -0
  36. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/lazy.py +0 -0
  37. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/progress.py +0 -0
  38. {polytool-0.2.9 → polytool-0.2.11}/src/polytool/core/runtime.py +0 -0
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.5
2
+ Name: polytool
3
+ Version: 0.2.11
4
+ Summary: One CLI with 60+ everyday commands — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more
5
+ Project-URL: Homepage, https://github.com/k6w/polytool
6
+ Project-URL: Repository, https://github.com/k6w/polytool
7
+ Project-URL: Issues, https://github.com/k6w/polytool/issues
8
+ Author: polytool contributors
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: background-removal,cli,convert,ffmpeg,image,ocr,pdf,qr,swiss-army-knife,utility,video,yt-dlp
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Multimedia :: Graphics
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.13
23
+ Requires-Dist: cron-descriptor>=1.4
24
+ Requires-Dist: croniter>=2
25
+ Requires-Dist: faker>=25
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: markdown-it-py>=3
28
+ Requires-Dist: pint>=0.24
29
+ Requires-Dist: pyjwt>=2.8
30
+ Requires-Dist: pyperclip>=1.8
31
+ Requires-Dist: python-dateutil>=2.9
32
+ Requires-Dist: python-slugify>=8
33
+ Requires-Dist: rich>=13
34
+ Requires-Dist: ruamel-yaml>=0.18
35
+ Requires-Dist: segno>=1.6
36
+ Requires-Dist: tomli-w>=1.0
37
+ Requires-Dist: typer>=0.12
38
+ Requires-Dist: xmltodict>=0.13
39
+ Requires-Dist: xxhash>=3.4
40
+ Provides-Extra: ai
41
+ Requires-Dist: rembg[cpu]>=2.0; extra == 'ai'
42
+ Provides-Extra: archive
43
+ Requires-Dist: py7zr>=0.21; extra == 'archive'
44
+ Provides-Extra: dev
45
+ Requires-Dist: basedpyright>=1.13; extra == 'dev'
46
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
47
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
48
+ Requires-Dist: pytest>=8; extra == 'dev'
49
+ Requires-Dist: ruff>=0.5; extra == 'dev'
50
+ Provides-Extra: dl
51
+ Requires-Dist: yt-dlp[default]>=2026.8.19; extra == 'dl'
52
+ Provides-Extra: full
53
+ Requires-Dist: ascii-magic>=2; extra == 'full'
54
+ Requires-Dist: colorthief>=0.2; extra == 'full'
55
+ Requires-Dist: easyocr>=1.7; extra == 'full'
56
+ Requires-Dist: ffmpeg-python>=0.2; extra == 'full'
57
+ Requires-Dist: imageio-ffmpeg>=0.5; extra == 'full'
58
+ Requires-Dist: mss>=9; extra == 'full'
59
+ Requires-Dist: pdfplumber>=0.11; extra == 'full'
60
+ Requires-Dist: piexif>=1.1; extra == 'full'
61
+ Requires-Dist: pikepdf>=8; extra == 'full'
62
+ Requires-Dist: pillow-avif-plugin>=1.4; extra == 'full'
63
+ Requires-Dist: pillow-heif>=0.18; extra == 'full'
64
+ Requires-Dist: pillow>=10; extra == 'full'
65
+ Requires-Dist: playwright>=1.44; extra == 'full'
66
+ Requires-Dist: py7zr>=0.21; extra == 'full'
67
+ Requires-Dist: pymupdf>=1.24; extra == 'full'
68
+ Requires-Dist: pypdf>=4; extra == 'full'
69
+ Requires-Dist: pytesseract>=0.3; extra == 'full'
70
+ Requires-Dist: pyzbar>=0.1; extra == 'full'
71
+ Requires-Dist: rembg[cpu]>=2.0; extra == 'full'
72
+ Requires-Dist: resvg-py>=0.1; extra == 'full'
73
+ Requires-Dist: yt-dlp[default]>=2026.8.19; extra == 'full'
74
+ Provides-Extra: img
75
+ Requires-Dist: ascii-magic>=2; extra == 'img'
76
+ Requires-Dist: colorthief>=0.2; extra == 'img'
77
+ Requires-Dist: piexif>=1.1; extra == 'img'
78
+ Requires-Dist: pillow-avif-plugin>=1.4; extra == 'img'
79
+ Requires-Dist: pillow-heif>=0.18; extra == 'img'
80
+ Requires-Dist: pillow>=10; extra == 'img'
81
+ Requires-Dist: resvg-py>=0.1; extra == 'img'
82
+ Provides-Extra: ocr
83
+ Requires-Dist: easyocr>=1.7; extra == 'ocr'
84
+ Requires-Dist: pytesseract>=0.3; extra == 'ocr'
85
+ Provides-Extra: pdf
86
+ Requires-Dist: pdfplumber>=0.11; extra == 'pdf'
87
+ Requires-Dist: pikepdf>=8; extra == 'pdf'
88
+ Requires-Dist: pymupdf>=1.24; extra == 'pdf'
89
+ Requires-Dist: pypdf>=4; extra == 'pdf'
90
+ Provides-Extra: qr-decode
91
+ Requires-Dist: pyzbar>=0.1; extra == 'qr-decode'
92
+ Provides-Extra: shot
93
+ Requires-Dist: mss>=9; extra == 'shot'
94
+ Requires-Dist: playwright>=1.44; extra == 'shot'
95
+ Provides-Extra: vid
96
+ Requires-Dist: ffmpeg-python>=0.2; extra == 'vid'
97
+ Requires-Dist: imageio-ffmpeg>=0.5; extra == 'vid'
98
+ Description-Content-Type: text/markdown
99
+
100
+ # polytool
101
+
102
+ **The command line toolbox for everything that is not worth installing another app for.**
103
+
104
+ `polytool` puts 60+ practical commands behind one memorable interface: `pt`. Convert
105
+ images, trim video, clean PDFs, remove backgrounds, run OCR, generate QR codes,
106
+ download media, transform data, hash files, inspect networks, and automate the
107
+ small tasks that normally turn into a tab-hunting expedition.
108
+
109
+ [![CI](https://github.com/k6w/polytool/actions/workflows/ci.yml/badge.svg)](https://github.com/k6w/polytool/actions/workflows/ci.yml)
110
+ [![PyPI](https://img.shields.io/pypi/v/polytool.svg)](https://pypi.org/project/polytool/)
111
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
112
+
113
+ ## See the real thing
114
+
115
+ These are direct captures from the installed CLI and its generated artifacts—not
116
+ mockups or a web demo.
117
+
118
+ ![The full command surface](docs/screenshots/terminal-overview.png)
119
+
120
+ One Terminal window can handle text, color, units, data, security, generators,
121
+ images, QR, OCR, audio, and PDF work:
122
+
123
+ ![Many polytool commands in one Terminal session](docs/screenshots/terminal-toolbox.png)
124
+
125
+ Real AI background removal, with the original and transparent result shown in Preview:
126
+
127
+ ![Background removal before and after](docs/screenshots/background-removal-preview.png)
128
+
129
+ Live YouTube metadata and download through the `pt` wrapper:
130
+
131
+ ![Live YouTube download](docs/screenshots/terminal-youtube.png)
132
+
133
+ ## Why people reach for `pt`
134
+
135
+ - **One install, a broad surface.** Stop collecting tiny single-purpose utilities.
136
+ - **Discoverable by design.** Every command has focused help and runnable examples.
137
+ - **Pipelines-first.** Text commands use stdout; file commands choose sensible output names.
138
+ - **Fast startup.** Heavy dependencies load only when the relevant command runs.
139
+ - **Helpful failure modes.** Missing optional tools produce an actionable install hint.
140
+ - **Local by default.** Media, documents, data, hashes, and OCR stay on your machine unless a command explicitly accesses a network service.
141
+ - **Flexible footprint.** Install the lightweight core or opt into only the extras you need.
142
+
143
+ ## Install in seconds
144
+
145
+ `uv` is the recommended installer because it manages Python and keeps the command isolated:
146
+
147
+ ```bash
148
+ # macOS / Linux
149
+ curl -LsSf https://astral.sh/uv/install.sh | sh
150
+ uv tool install polytool
151
+
152
+ # Windows PowerShell
153
+ irm https://astral.sh/uv/install.ps1 | iex
154
+ uv tool install polytool
155
+ ```
156
+
157
+ That gives you the fast core: data, encoding, generators, color, units, text,
158
+ QR generation, cron, networking, clipboard, and file operations.
159
+
160
+ For the complete toolbox:
161
+
162
+ ```bash
163
+ uv tool install 'polytool[full]'
164
+ pt setup -y # install Deno and Chromium for external integrations
165
+ ```
166
+
167
+ Both `polytool` and the shorter `pt` command are installed. PowerShell users
168
+ should keep the quotes around extras because brackets are shell glob characters.
169
+
170
+ ## A five-minute tour
171
+
172
+ ```bash
173
+ # Make a shareable QR code
174
+ pt qr gen "https://github.com/k6w/polytool" -o qr.png
175
+
176
+ # Prepare an image for the web
177
+ pt img convert photo.heic -o photo.jpg
178
+ pt img resize photo.jpg --width 1600
179
+ pt img compress photo.jpg --quality 75
180
+
181
+ # Turn media into something useful
182
+ pt vid gif clip.mp4 --width 480
183
+ pt vid extract-audio recording.mp4 -o recording.mp3
184
+
185
+ # Clean up documents
186
+ pt pdf merge cover.pdf report.pdf -o release.pdf
187
+ pt pdf to-images release.pdf --dpi 200
188
+
189
+ # Download public media and inspect it first
190
+ pt dl info 'https://www.youtube.com/watch?v=...'
191
+ pt dl get 'https://www.youtube.com/watch?v=...'
192
+
193
+ # Make data and developer chores boring
194
+ pt data convert config.yaml --to json
195
+ pt enc hash sha256 release.zip
196
+ pt enc base64 encode README.md
197
+ pt gen password --length 32
198
+ pt gen uuid v7
199
+ pt color convert '#3366ff'
200
+ pt convert unit '100 km' --to mi
201
+ pt text slugify 'Hello, World!'
202
+ pt cron explain '0 9 * * MON-FRI'
203
+ pt file dedupe ./Downloads
204
+ ```
205
+
206
+ Run `pt --help`, then `pt <group> --help`. You can also pipe text into commands
207
+ that accept stdin and compose them with standard Unix tools.
208
+
209
+ ## Everything inside
210
+
211
+ | Group | What it unlocks |
212
+ |---|---|
213
+ | `pt img` | Convert, resize, compress, watermark, palette, EXIF, ASCII, background removal, OCR |
214
+ | `pt vid` | Convert, trim, extract audio, animated GIF |
215
+ | `pt pdf` | Merge, split, compress, extract text, render, build from images, OCR |
216
+ | `pt dl` | YouTube and 1000+ site downloads, metadata, audio-only mode, browser cookies |
217
+ | `pt data` | JSON, YAML, TOML, CSV, XML conversion, pretty-printing, validation |
218
+ | `pt enc` | SHA/Blake2/xxhash, Base64, URL/HTML escaping, JWT decode and verify |
219
+ | `pt qr` | PNG, SVG, PDF, EPS, terminal, Wi-Fi QR generation, decode |
220
+ | `pt gen` | Passwords, UUID v1/v3/v4/v5/v7, lorem ipsum |
221
+ | `pt file` | Batch rename, duplicate detection, largest files, organizing, archives |
222
+ | `pt net` | Port checks, IP information, HTTP requests |
223
+ | `pt text` | Diff, word counts, case conversion, slugify, Markdown HTML/preview |
224
+ | `pt convert` | Units, timestamps, number bases |
225
+ | `pt color` | Hex, RGB, HSL, HSV, CMYK conversion |
226
+ | `pt cron` | Human explanations and next firing times |
227
+ | `pt clip` / `pt shot` | Clipboard operations and screen/web screenshots |
228
+
229
+ ## Install only what you need
230
+
231
+ The base package stays intentionally small. Add capabilities à la carte:
232
+
233
+ ```bash
234
+ uv tool install 'polytool[img]' # Pillow, HEIC/AVIF/SVG, palette, ASCII
235
+ uv tool install 'polytool[vid]' # ffmpeg-backed media conversion
236
+ uv tool install 'polytool[pdf]' # PDF manipulation and rendering
237
+ uv tool install 'polytool[dl]' # yt-dlp and matched EJS scripts
238
+ uv tool install 'polytool[shot]' # mss and Playwright
239
+ uv tool install 'polytool[ai]' # rembg background removal
240
+ uv tool install 'polytool[ocr]' # Tesseract wrapper and EasyOCR
241
+ uv tool install 'polytool[qr-decode]' # QR decoding (also needs native zbar)
242
+ uv tool install 'polytool[archive]' # 7z support
243
+ ```
244
+
245
+ `[full]` combines every extra. The first use of some commands also downloads
246
+ runtime assets: Deno for YouTube challenge solving, Chromium for web captures,
247
+ the U2-Net model for background removal, or language/model data for OCR.
248
+
249
+ Platform notes:
250
+
251
+ - macOS QR decoding: `brew install zbar`
252
+ - Debian/Ubuntu QR decoding: `sudo apt install libzbar0`
253
+ - macOS OCR: `brew install tesseract`
254
+ - Windows OCR: install Tesseract from UB Mannheim
255
+ - Video commands use a system `ffmpeg` when available and otherwise fall back to the bundled binary
256
+
257
+ If an optional dependency is missing, `pt` explains the exact extra to install.
258
+
259
+ ## Trust the plumbing
260
+
261
+ The project is tested as a CLI, not only as a collection of importable functions:
262
+
263
+ - 143 automated tests covering happy paths, invalid input, integrations, and file outputs
264
+ - Ruff lint and formatting checks
265
+ - basedpyright static analysis
266
+ - Cross-platform CI configuration for macOS, Linux, and Windows
267
+ - Lazy imports so `pt --help` remains quick
268
+ - MIT licensed and straightforward to extend
269
+
270
+ ## Documentation
271
+
272
+ Start with the [full command index](docs/README.md), or jump directly to:
273
+
274
+ [Install](docs/install.md) · [Images](docs/img.md) · [Video](docs/vid.md) ·
275
+ [PDF](docs/pdf.md) · [Downloads](docs/dl.md) · [Data](docs/data.md) ·
276
+ [Encoding](docs/enc.md) · [QR](docs/qr.md) · [Files](docs/file.md) ·
277
+ [Text](docs/text.md) · [Troubleshooting](docs/troubleshooting.md)
278
+
279
+ ## Build from source
280
+
281
+ ```bash
282
+ git clone https://github.com/k6w/polytool
283
+ cd polytool
284
+ uv sync --extra dev --extra img --extra vid --extra pdf --extra dl --extra shot --extra archive --extra qr-decode
285
+ uv run pytest
286
+ uv run ruff check .
287
+ ```
288
+
289
+ Contributions use conventional commits (`feat:`, `fix:`, `docs:`, `test:`, and so on).
290
+ Every user-facing command should ship help examples, a happy-path test, and an
291
+ error-path test. See [architecture.md](docs/architecture.md) before adding a new group.
292
+
293
+ ## License
294
+
295
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,196 @@
1
+ # polytool
2
+
3
+ **The command line toolbox for everything that is not worth installing another app for.**
4
+
5
+ `polytool` puts 60+ practical commands behind one memorable interface: `pt`. Convert
6
+ images, trim video, clean PDFs, remove backgrounds, run OCR, generate QR codes,
7
+ download media, transform data, hash files, inspect networks, and automate the
8
+ small tasks that normally turn into a tab-hunting expedition.
9
+
10
+ [![CI](https://github.com/k6w/polytool/actions/workflows/ci.yml/badge.svg)](https://github.com/k6w/polytool/actions/workflows/ci.yml)
11
+ [![PyPI](https://img.shields.io/pypi/v/polytool.svg)](https://pypi.org/project/polytool/)
12
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
+
14
+ ## See the real thing
15
+
16
+ These are direct captures from the installed CLI and its generated artifacts—not
17
+ mockups or a web demo.
18
+
19
+ ![The full command surface](docs/screenshots/terminal-overview.png)
20
+
21
+ One Terminal window can handle text, color, units, data, security, generators,
22
+ images, QR, OCR, audio, and PDF work:
23
+
24
+ ![Many polytool commands in one Terminal session](docs/screenshots/terminal-toolbox.png)
25
+
26
+ Real AI background removal, with the original and transparent result shown in Preview:
27
+
28
+ ![Background removal before and after](docs/screenshots/background-removal-preview.png)
29
+
30
+ Live YouTube metadata and download through the `pt` wrapper:
31
+
32
+ ![Live YouTube download](docs/screenshots/terminal-youtube.png)
33
+
34
+ ## Why people reach for `pt`
35
+
36
+ - **One install, a broad surface.** Stop collecting tiny single-purpose utilities.
37
+ - **Discoverable by design.** Every command has focused help and runnable examples.
38
+ - **Pipelines-first.** Text commands use stdout; file commands choose sensible output names.
39
+ - **Fast startup.** Heavy dependencies load only when the relevant command runs.
40
+ - **Helpful failure modes.** Missing optional tools produce an actionable install hint.
41
+ - **Local by default.** Media, documents, data, hashes, and OCR stay on your machine unless a command explicitly accesses a network service.
42
+ - **Flexible footprint.** Install the lightweight core or opt into only the extras you need.
43
+
44
+ ## Install in seconds
45
+
46
+ `uv` is the recommended installer because it manages Python and keeps the command isolated:
47
+
48
+ ```bash
49
+ # macOS / Linux
50
+ curl -LsSf https://astral.sh/uv/install.sh | sh
51
+ uv tool install polytool
52
+
53
+ # Windows PowerShell
54
+ irm https://astral.sh/uv/install.ps1 | iex
55
+ uv tool install polytool
56
+ ```
57
+
58
+ That gives you the fast core: data, encoding, generators, color, units, text,
59
+ QR generation, cron, networking, clipboard, and file operations.
60
+
61
+ For the complete toolbox:
62
+
63
+ ```bash
64
+ uv tool install 'polytool[full]'
65
+ pt setup -y # install Deno and Chromium for external integrations
66
+ ```
67
+
68
+ Both `polytool` and the shorter `pt` command are installed. PowerShell users
69
+ should keep the quotes around extras because brackets are shell glob characters.
70
+
71
+ ## A five-minute tour
72
+
73
+ ```bash
74
+ # Make a shareable QR code
75
+ pt qr gen "https://github.com/k6w/polytool" -o qr.png
76
+
77
+ # Prepare an image for the web
78
+ pt img convert photo.heic -o photo.jpg
79
+ pt img resize photo.jpg --width 1600
80
+ pt img compress photo.jpg --quality 75
81
+
82
+ # Turn media into something useful
83
+ pt vid gif clip.mp4 --width 480
84
+ pt vid extract-audio recording.mp4 -o recording.mp3
85
+
86
+ # Clean up documents
87
+ pt pdf merge cover.pdf report.pdf -o release.pdf
88
+ pt pdf to-images release.pdf --dpi 200
89
+
90
+ # Download public media and inspect it first
91
+ pt dl info 'https://www.youtube.com/watch?v=...'
92
+ pt dl get 'https://www.youtube.com/watch?v=...'
93
+
94
+ # Make data and developer chores boring
95
+ pt data convert config.yaml --to json
96
+ pt enc hash sha256 release.zip
97
+ pt enc base64 encode README.md
98
+ pt gen password --length 32
99
+ pt gen uuid v7
100
+ pt color convert '#3366ff'
101
+ pt convert unit '100 km' --to mi
102
+ pt text slugify 'Hello, World!'
103
+ pt cron explain '0 9 * * MON-FRI'
104
+ pt file dedupe ./Downloads
105
+ ```
106
+
107
+ Run `pt --help`, then `pt <group> --help`. You can also pipe text into commands
108
+ that accept stdin and compose them with standard Unix tools.
109
+
110
+ ## Everything inside
111
+
112
+ | Group | What it unlocks |
113
+ |---|---|
114
+ | `pt img` | Convert, resize, compress, watermark, palette, EXIF, ASCII, background removal, OCR |
115
+ | `pt vid` | Convert, trim, extract audio, animated GIF |
116
+ | `pt pdf` | Merge, split, compress, extract text, render, build from images, OCR |
117
+ | `pt dl` | YouTube and 1000+ site downloads, metadata, audio-only mode, browser cookies |
118
+ | `pt data` | JSON, YAML, TOML, CSV, XML conversion, pretty-printing, validation |
119
+ | `pt enc` | SHA/Blake2/xxhash, Base64, URL/HTML escaping, JWT decode and verify |
120
+ | `pt qr` | PNG, SVG, PDF, EPS, terminal, Wi-Fi QR generation, decode |
121
+ | `pt gen` | Passwords, UUID v1/v3/v4/v5/v7, lorem ipsum |
122
+ | `pt file` | Batch rename, duplicate detection, largest files, organizing, archives |
123
+ | `pt net` | Port checks, IP information, HTTP requests |
124
+ | `pt text` | Diff, word counts, case conversion, slugify, Markdown HTML/preview |
125
+ | `pt convert` | Units, timestamps, number bases |
126
+ | `pt color` | Hex, RGB, HSL, HSV, CMYK conversion |
127
+ | `pt cron` | Human explanations and next firing times |
128
+ | `pt clip` / `pt shot` | Clipboard operations and screen/web screenshots |
129
+
130
+ ## Install only what you need
131
+
132
+ The base package stays intentionally small. Add capabilities à la carte:
133
+
134
+ ```bash
135
+ uv tool install 'polytool[img]' # Pillow, HEIC/AVIF/SVG, palette, ASCII
136
+ uv tool install 'polytool[vid]' # ffmpeg-backed media conversion
137
+ uv tool install 'polytool[pdf]' # PDF manipulation and rendering
138
+ uv tool install 'polytool[dl]' # yt-dlp and matched EJS scripts
139
+ uv tool install 'polytool[shot]' # mss and Playwright
140
+ uv tool install 'polytool[ai]' # rembg background removal
141
+ uv tool install 'polytool[ocr]' # Tesseract wrapper and EasyOCR
142
+ uv tool install 'polytool[qr-decode]' # QR decoding (also needs native zbar)
143
+ uv tool install 'polytool[archive]' # 7z support
144
+ ```
145
+
146
+ `[full]` combines every extra. The first use of some commands also downloads
147
+ runtime assets: Deno for YouTube challenge solving, Chromium for web captures,
148
+ the U2-Net model for background removal, or language/model data for OCR.
149
+
150
+ Platform notes:
151
+
152
+ - macOS QR decoding: `brew install zbar`
153
+ - Debian/Ubuntu QR decoding: `sudo apt install libzbar0`
154
+ - macOS OCR: `brew install tesseract`
155
+ - Windows OCR: install Tesseract from UB Mannheim
156
+ - Video commands use a system `ffmpeg` when available and otherwise fall back to the bundled binary
157
+
158
+ If an optional dependency is missing, `pt` explains the exact extra to install.
159
+
160
+ ## Trust the plumbing
161
+
162
+ The project is tested as a CLI, not only as a collection of importable functions:
163
+
164
+ - 143 automated tests covering happy paths, invalid input, integrations, and file outputs
165
+ - Ruff lint and formatting checks
166
+ - basedpyright static analysis
167
+ - Cross-platform CI configuration for macOS, Linux, and Windows
168
+ - Lazy imports so `pt --help` remains quick
169
+ - MIT licensed and straightforward to extend
170
+
171
+ ## Documentation
172
+
173
+ Start with the [full command index](docs/README.md), or jump directly to:
174
+
175
+ [Install](docs/install.md) · [Images](docs/img.md) · [Video](docs/vid.md) ·
176
+ [PDF](docs/pdf.md) · [Downloads](docs/dl.md) · [Data](docs/data.md) ·
177
+ [Encoding](docs/enc.md) · [QR](docs/qr.md) · [Files](docs/file.md) ·
178
+ [Text](docs/text.md) · [Troubleshooting](docs/troubleshooting.md)
179
+
180
+ ## Build from source
181
+
182
+ ```bash
183
+ git clone https://github.com/k6w/polytool
184
+ cd polytool
185
+ uv sync --extra dev --extra img --extra vid --extra pdf --extra dl --extra shot --extra archive --extra qr-decode
186
+ uv run pytest
187
+ uv run ruff check .
188
+ ```
189
+
190
+ Contributions use conventional commits (`feat:`, `fix:`, `docs:`, `test:`, and so on).
191
+ Every user-facing command should ship help examples, a happy-path test, and an
192
+ error-path test. See [architecture.md](docs/architecture.md) before adding a new group.
193
+
194
+ ## License
195
+
196
+ MIT — see [LICENSE](LICENSE).
@@ -2,7 +2,7 @@
2
2
 
3
3
  Detailed reference for every command in `polytool` (binary `pt`).
4
4
 
5
- `pt` is built around 16 subcommand groups, each with one or more verbs (26 verbs in total). Every verb has its own page below — argument types, defaults, all flags, exit codes, and runnable examples.
5
+ `pt` is built around 16 subcommand groups with more than 60 commands. Every command is documented below with argument types, defaults, flags, exit behavior, and runnable examples.
6
6
 
7
7
  ## Quick links
8
8
 
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "polytool"
7
- version = "0.2.9"
8
- description = "One-binary CLI bundling 26 everyday utilities — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more"
7
+ version = "0.2.11"
8
+ description = "One CLI with 60+ everyday commands — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
11
11
  license = { text = "MIT" }
@@ -58,7 +58,7 @@ img = [
58
58
  ]
59
59
  vid = ["ffmpeg-python>=0.2", "imageio-ffmpeg>=0.5"]
60
60
  pdf = ["pypdf>=4", "pikepdf>=8", "pdfplumber>=0.11", "pymupdf>=1.24"]
61
- dl = ["yt-dlp>=2024.5", "yt-dlp-ejs>=0.8"]
61
+ dl = ["yt-dlp[default]>=2026.8.19"]
62
62
  ocr = ["pytesseract>=0.3", "easyocr>=1.7"]
63
63
  ai = ["rembg[cpu]>=2.0"]
64
64
  qr-decode = ["pyzbar>=0.1"]
@@ -0,0 +1,4 @@
1
+ """polytool — one CLI with 60+ everyday commands."""
2
+
3
+ __version__ = "0.2.11"
4
+ __all__ = ["__version__"]
@@ -9,6 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import subprocess
11
11
  import sys
12
+ from io import TextIOWrapper
12
13
  from typing import Annotated
13
14
 
14
15
  import typer
@@ -38,7 +39,7 @@ from polytool.core.errors import PolytoolError, render_panel
38
39
 
39
40
  app = typer.Typer(
40
41
  name="polytool",
41
- help="polytool — one-binary CLI bundling 26 everyday utilities (pt for short).",
42
+ help="polytool — one CLI with 60+ everyday commands (pt for short).",
42
43
  no_args_is_help=True,
43
44
  add_completion=False,
44
45
  rich_markup_mode="rich",
@@ -56,7 +57,9 @@ def _force_utf8_io() -> None:
56
57
  import contextlib
57
58
 
58
59
  for stream in (sys.stdout, sys.stderr):
59
- with contextlib.suppress(AttributeError, OSError):
60
+ if not isinstance(stream, TextIOWrapper):
61
+ continue
62
+ with contextlib.suppress(OSError):
60
63
  stream.reconfigure(encoding="utf-8", errors="replace")
61
64
 
62
65
 
@@ -91,7 +94,7 @@ def main(
91
94
  help="Show version and exit.",
92
95
  ),
93
96
  ) -> None:
94
- """polytool — one-binary CLI bundling 26 everyday utilities."""
97
+ """polytool — one CLI with 60+ everyday commands."""
95
98
 
96
99
 
97
100
  @app.command("setup")
@@ -653,14 +653,9 @@ def cmd_get(
653
653
  "noprogress": True, # we render a Rich progress bar
654
654
  "logger": logger,
655
655
  "progress_hooks": [_make_progress_hook(progress, state)],
656
- # Try multiple YouTube clients — `tv` alone often fails the n-challenge
657
- # while web/android/ios still return usable formats. yt-dlp aggregates
658
- # formats across all clients before selecting.
659
- "extractor_args": {
660
- "youtube": {
661
- "player_client": ["web", "web_safari", "mweb", "android", "ios", "tv"],
662
- }
663
- },
656
+ # Let current yt-dlp select the appropriate YouTube client. Forcing a
657
+ # broad client list causes duplicate requests and noisy SABR warnings,
658
+ # and tends to age badly as YouTube changes its APIs.
664
659
  }
665
660
  if audio_only:
666
661
  opts["format"] = "bestaudio/best"
@@ -716,9 +711,7 @@ def cmd_get(
716
711
  f"({_human_size(size)} in {_human_duration(elapsed)})[/dim]"
717
712
  )
718
713
  else:
719
- console.print(
720
- f" [dim]({_human_size(size)} in {_human_duration(elapsed)})[/dim]"
721
- )
714
+ console.print(f" [dim]({_human_size(size)} in {_human_duration(elapsed)})[/dim]")
722
715
 
723
716
 
724
717
  @app.command("info")
@@ -775,11 +768,6 @@ def cmd_info(
775
768
  "quiet": True,
776
769
  "no_warnings": True,
777
770
  "logger": logger,
778
- "extractor_args": {
779
- "youtube": {
780
- "player_client": ["web", "web_safari", "mweb", "android", "ios", "tv"],
781
- }
782
- },
783
771
  }
784
772
  _apply_cookie_opts(opts, cookies_from_browser, cookies_file)
785
773
  if username is not None:
@@ -76,8 +76,9 @@ def cmd_uuid(
76
76
  typer.echo(str(_uuid.uuid4()))
77
77
  elif v == "7":
78
78
  # Python 3.13 added uuid.uuid7
79
- if hasattr(_uuid, "uuid7"):
80
- typer.echo(str(_uuid.uuid7()))
79
+ uuid7 = getattr(_uuid, "uuid7", None)
80
+ if uuid7 is not None:
81
+ typer.echo(str(uuid7()))
81
82
  else:
82
83
  # Manual v7 fallback (won't be hit on 3.13+, but defensive)
83
84
  import os
@@ -246,11 +246,9 @@ def cmd_exif(
246
246
  # Fallback: re-encode without EXIF via Pillow
247
247
  from PIL import Image
248
248
 
249
- img = Image.open(source)
250
- data = list(img.getdata())
251
- clean = Image.new(img.mode, img.size)
252
- clean.putdata(data)
253
- clean.save(out)
249
+ with Image.open(source) as img:
250
+ clean = img.copy()
251
+ clean.save(out, exif=b"")
254
252
  console.print(f"[green]Stripped[/green] EXIF -> {out}")
255
253
 
256
254
 
@@ -293,7 +291,7 @@ def cmd_watermark(
293
291
  str,
294
292
  typer.Option(
295
293
  "--position",
296
- help="topleft | topright | bottomleft | bottomright | center",
294
+ help="top-left | top-right | bottom-left | bottom-right | center",
297
295
  ),
298
296
  ] = "bottomright",
299
297
  size: Annotated[int, typer.Option("--size", help="Font size (px)")] = 48,
@@ -328,12 +326,13 @@ def cmd_watermark(
328
326
  "bottomright": (w - tw - pad, h - th - pad),
329
327
  "center": ((w - tw) // 2, (h - th) // 2),
330
328
  }
331
- if position not in positions:
329
+ position_key = position.lower().replace("-", "").replace("_", "")
330
+ if position_key not in positions:
332
331
  raise PolytoolError(
333
332
  f"Unknown position {position!r}",
334
- hint=f"One of: {', '.join(positions)}",
333
+ hint="One of: top-left, top-right, bottom-left, bottom-right, center",
335
334
  )
336
- x, y = positions[position]
335
+ x, y = positions[position_key]
337
336
  alpha = int(255 * max(0.0, min(1.0, opacity)))
338
337
  draw.text((x, y), text, font=font, fill=(255, 255, 255, alpha))
339
338
  out_img = Image.alpha_composite(img, overlay)
@@ -229,12 +229,22 @@ def cmd_from_images(
229
229
  from polytool.core.lazy import require_extra
230
230
 
231
231
  PIL_Image = require_extra("PIL.Image", extra="img")
232
+ # Pillow loads encoders lazily. A fresh CLI process that opens only PNGs
233
+ # has not registered JPEG yet, but Pillow's PDF writer uses it internally.
234
+ require_extra("PIL.JpegImagePlugin", extra="img")
232
235
 
233
236
  if not inputs:
234
237
  raise PolytoolError("No input images")
235
- imgs = [PIL_Image.open(p).convert("RGB") for p in inputs]
238
+ imgs = []
239
+ for path in inputs:
240
+ with PIL_Image.open(path) as image:
241
+ imgs.append(image.convert("RGB"))
236
242
  head, *rest = imgs
237
- head.save(output, save_all=True, append_images=rest)
243
+ try:
244
+ head.save(output, save_all=True, append_images=rest)
245
+ finally:
246
+ for image in imgs:
247
+ image.close()
238
248
  console.print(f"[green]Wrote[/green] {output} ({len(inputs)} pages)")
239
249
 
240
250
 
polytool-0.2.9/PKG-INFO DELETED
@@ -1,260 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: polytool
3
- Version: 0.2.9
4
- Summary: One-binary CLI bundling 26 everyday utilities — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more
5
- Project-URL: Homepage, https://github.com/k6w/polytool
6
- Project-URL: Repository, https://github.com/k6w/polytool
7
- Project-URL: Issues, https://github.com/k6w/polytool/issues
8
- Author: polytool contributors
9
- License: MIT
10
- License-File: LICENSE
11
- Keywords: background-removal,cli,convert,ffmpeg,image,ocr,pdf,qr,swiss-army-knife,utility,video,yt-dlp
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Environment :: Console
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: End Users/Desktop
16
- Classifier: License :: OSI Approved :: MIT License
17
- Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.13
20
- Classifier: Topic :: Multimedia :: Graphics
21
- Classifier: Topic :: Utilities
22
- Requires-Python: >=3.13
23
- Requires-Dist: cron-descriptor>=1.4
24
- Requires-Dist: croniter>=2
25
- Requires-Dist: faker>=25
26
- Requires-Dist: httpx>=0.27
27
- Requires-Dist: markdown-it-py>=3
28
- Requires-Dist: pint>=0.24
29
- Requires-Dist: pyjwt>=2.8
30
- Requires-Dist: pyperclip>=1.8
31
- Requires-Dist: python-dateutil>=2.9
32
- Requires-Dist: python-slugify>=8
33
- Requires-Dist: rich>=13
34
- Requires-Dist: ruamel-yaml>=0.18
35
- Requires-Dist: segno>=1.6
36
- Requires-Dist: tomli-w>=1.0
37
- Requires-Dist: typer>=0.12
38
- Requires-Dist: xmltodict>=0.13
39
- Requires-Dist: xxhash>=3.4
40
- Provides-Extra: ai
41
- Requires-Dist: rembg[cpu]>=2.0; extra == 'ai'
42
- Provides-Extra: archive
43
- Requires-Dist: py7zr>=0.21; extra == 'archive'
44
- Provides-Extra: dev
45
- Requires-Dist: basedpyright>=1.13; extra == 'dev'
46
- Requires-Dist: pre-commit>=3.7; extra == 'dev'
47
- Requires-Dist: pytest-cov>=5; extra == 'dev'
48
- Requires-Dist: pytest>=8; extra == 'dev'
49
- Requires-Dist: ruff>=0.5; extra == 'dev'
50
- Provides-Extra: dl
51
- Requires-Dist: yt-dlp-ejs>=0.8; extra == 'dl'
52
- Requires-Dist: yt-dlp>=2024.5; extra == 'dl'
53
- Provides-Extra: full
54
- Requires-Dist: ascii-magic>=2; extra == 'full'
55
- Requires-Dist: colorthief>=0.2; extra == 'full'
56
- Requires-Dist: easyocr>=1.7; extra == 'full'
57
- Requires-Dist: ffmpeg-python>=0.2; extra == 'full'
58
- Requires-Dist: imageio-ffmpeg>=0.5; extra == 'full'
59
- Requires-Dist: mss>=9; extra == 'full'
60
- Requires-Dist: pdfplumber>=0.11; extra == 'full'
61
- Requires-Dist: piexif>=1.1; extra == 'full'
62
- Requires-Dist: pikepdf>=8; extra == 'full'
63
- Requires-Dist: pillow-avif-plugin>=1.4; extra == 'full'
64
- Requires-Dist: pillow-heif>=0.18; extra == 'full'
65
- Requires-Dist: pillow>=10; extra == 'full'
66
- Requires-Dist: playwright>=1.44; extra == 'full'
67
- Requires-Dist: py7zr>=0.21; extra == 'full'
68
- Requires-Dist: pymupdf>=1.24; extra == 'full'
69
- Requires-Dist: pypdf>=4; extra == 'full'
70
- Requires-Dist: pytesseract>=0.3; extra == 'full'
71
- Requires-Dist: pyzbar>=0.1; extra == 'full'
72
- Requires-Dist: rembg[cpu]>=2.0; extra == 'full'
73
- Requires-Dist: resvg-py>=0.1; extra == 'full'
74
- Requires-Dist: yt-dlp-ejs>=0.8; extra == 'full'
75
- Requires-Dist: yt-dlp>=2024.5; extra == 'full'
76
- Provides-Extra: img
77
- Requires-Dist: ascii-magic>=2; extra == 'img'
78
- Requires-Dist: colorthief>=0.2; extra == 'img'
79
- Requires-Dist: piexif>=1.1; extra == 'img'
80
- Requires-Dist: pillow-avif-plugin>=1.4; extra == 'img'
81
- Requires-Dist: pillow-heif>=0.18; extra == 'img'
82
- Requires-Dist: pillow>=10; extra == 'img'
83
- Requires-Dist: resvg-py>=0.1; extra == 'img'
84
- Provides-Extra: ocr
85
- Requires-Dist: easyocr>=1.7; extra == 'ocr'
86
- Requires-Dist: pytesseract>=0.3; extra == 'ocr'
87
- Provides-Extra: pdf
88
- Requires-Dist: pdfplumber>=0.11; extra == 'pdf'
89
- Requires-Dist: pikepdf>=8; extra == 'pdf'
90
- Requires-Dist: pymupdf>=1.24; extra == 'pdf'
91
- Requires-Dist: pypdf>=4; extra == 'pdf'
92
- Provides-Extra: qr-decode
93
- Requires-Dist: pyzbar>=0.1; extra == 'qr-decode'
94
- Provides-Extra: shot
95
- Requires-Dist: mss>=9; extra == 'shot'
96
- Requires-Dist: playwright>=1.44; extra == 'shot'
97
- Provides-Extra: vid
98
- Requires-Dist: ffmpeg-python>=0.2; extra == 'vid'
99
- Requires-Dist: imageio-ffmpeg>=0.5; extra == 'vid'
100
- Description-Content-Type: text/markdown
101
-
102
- # polytool
103
-
104
- > One CLI, 26 everyday utilities. Image format conversion, background removal, video/audio conversion, PDF tooling, OCR, QR codes, hashing, downloads, and more — all behind one binary called `pt`.
105
-
106
- [![CI](https://github.com/k6w/polytool/actions/workflows/ci.yml/badge.svg)](https://github.com/k6w/polytool/actions/workflows/ci.yml)
107
-
108
- ## Install
109
-
110
- The fastest way (no Python prerequisite — `uv` brings its own):
111
-
112
- ```powershell
113
- # 1. install uv (Windows PowerShell)
114
- irm https://astral.sh/uv/install.ps1 | iex
115
-
116
- # 2. install polytool (slim — fast, ~80 MB)
117
- uv tool install polytool
118
-
119
- # or, install everything (image/video/PDF/yt-dlp/screenshots/AI background removal)
120
- uv tool install 'polytool[full]'
121
- ```
122
-
123
- ```bash
124
- # macOS / Linux
125
- curl -LsSf https://astral.sh/uv/install.sh | sh
126
- uv tool install 'polytool[full]'
127
- ```
128
-
129
- > **Note for PowerShell users:** quote `'polytool[full]'` — the brackets are shell glob characters.
130
-
131
- After install, both `polytool` and the short alias `pt` are on your PATH.
132
-
133
- ## Quick start
134
-
135
- ```bash
136
- pt qr gen "https://github.com/k6w/polytool" -o qr.png
137
- pt img convert photo.heic -o photo.jpg
138
- pt img bg-remove portrait.jpg # transparent PNG
139
- pt vid gif clip.mp4 # animated gif
140
- pt vid extract-audio movie.mp4 # mp3
141
- pt pdf merge a.pdf b.pdf -o merged.pdf
142
- pt pdf to-images doc.pdf --dpi 200
143
- pt dl get 'https://www.youtube.com/watch?v=...'
144
- pt enc hash sha256 release.zip
145
- pt enc base64 encode README.md
146
- pt data convert config.yaml --to json
147
- pt gen password --length 32
148
- pt gen uuid v7
149
- pt color convert "#3366ff"
150
- pt convert unit "100 km" --to mi
151
- pt convert timestamp 1715200000
152
- pt text slugify "Hello, World!"
153
- pt cron explain "0 9 * * MON"
154
- pt net http GET https://api.github.com
155
- pt file dedupe ./Downloads
156
- pt file archive ./project -o project.7z
157
- ```
158
-
159
- Run `pt --help` to see all groups, or `pt <group> --help` for any group's verbs (each verb's help has runnable Examples).
160
-
161
- ## Documentation
162
-
163
- Full reference for every verb, argument, and option lives in **[docs/](docs/README.md)**:
164
-
165
- - **[Install guide](docs/install.md)** — slim vs full, all extras, Windows quoting
166
- - **Per-group reference** — [img](docs/img.md) · [vid](docs/vid.md) · [pdf](docs/pdf.md) · [dl](docs/dl.md) · [shot](docs/shot.md) · [qr](docs/qr.md) · [data](docs/data.md) · [enc](docs/enc.md) · [text](docs/text.md) · [convert](docs/convert.md) · [color](docs/color.md) · [cron](docs/cron.md) · [file](docs/file.md) · [gen](docs/gen.md) · [net](docs/net.md) · [clip](docs/clip.md)
167
- - **[Architecture](docs/architecture.md)** — package layout, lazy imports, error model, how to add a verb
168
- - **[Troubleshooting](docs/troubleshooting.md)** — every common error with a fix
169
-
170
- ## Feature reference (all 26 verbs)
171
-
172
- | Group | Verbs |
173
- |---|---|
174
- | `pt img` | `convert` (png/jpg/webp/avif/heic/svg/bmp/tiff), `resize`, `compress`, `bg-remove`, `watermark`, `ascii`, `exif`, `palette`, `ocr` |
175
- | `pt vid` | `convert`, `trim`, `extract-audio`, `gif` |
176
- | `pt pdf` | `merge`, `split`, `compress`, `extract-text`, `to-images`, `from-images`, `ocr` |
177
- | `pt dl` | `get` (yt-dlp wrapper, audio-only mode), `info` |
178
- | `pt data` | `convert` (json↔yaml↔toml↔csv↔xml), `pretty`, `validate` |
179
- | `pt enc` | `hash` (md5/sha1/sha256/sha512/blake2b/xxhash), `base64`, `url`, `html`, `jwt-decode`, `jwt-verify` |
180
- | `pt qr` | `gen` (png/svg/pdf/eps/terminal), `wifi` (Wi-Fi join code), `decode` |
181
- | `pt gen` | `password`, `uuid` (v1/v3/v4/v5/v7), `lorem` |
182
- | `pt file` | `rename`, `dedupe`, `bigfiles`, `organize`, `archive` (zip/tar/tar.gz/7z) |
183
- | `pt net` | `port-check`, `ip-info`, `http` |
184
- | `pt clip` | `copy`, `paste` |
185
- | `pt shot` | `screen`, `web` (Playwright), `install` |
186
- | `pt color` | `convert` (hex/rgb/hsl/hsv/cmyk) |
187
- | `pt convert` | `unit`, `timestamp`, `base` |
188
- | `pt text` | `diff`, `wc`, `case` (snake/kebab/camel/pascal/...), `slugify`, `md-to-html`, `md-preview` |
189
- | `pt cron` | `explain`, `next` |
190
-
191
- ## Slim vs full install
192
-
193
- The default install ships only lightweight utilities (data, enc, gen, color, convert, text, qr-gen, cron, net, clip, file). Heavy/optional features are grouped behind extras so you only pull what you need:
194
-
195
- | Extra | Adds | Approx. size |
196
- |---|---|---|
197
- | `[img]` | Pillow + HEIC/AVIF/SVG plugins, EXIF, palette, ASCII, watermark | ~50 MB |
198
- | `[vid]` | `ffmpeg-python` + bundled `ffmpeg` (auto-downloaded) | ~70 MB on first use |
199
- | `[pdf]` | pypdf, pikepdf, pdfplumber, PyMuPDF | ~80 MB |
200
- | `[dl]` | yt-dlp | ~10 MB |
201
- | `[shot]` | mss, Playwright (Chromium installed via `pt shot install`) | ~150 MB |
202
- | `[ai]` | rembg + ONNX runtime (170 MB U2-Net model on first run) | ~250 MB |
203
- | `[ocr]` | pytesseract / easyocr (PyTorch) | ~1 GB if easyocr |
204
- | `[qr-decode]` | pyzbar (system `libzbar` on Linux) | ~5 MB |
205
- | `[archive]` | py7zr | ~5 MB |
206
- | `[full]` | all of the above | ~1.5 GB |
207
-
208
- Verbs that need an extra you haven't installed print a friendly hint:
209
-
210
- ```
211
- This command needs the 'ai' extra.
212
- Install with: uv tool install 'polytool[ai]'
213
- ```
214
-
215
- ## Troubleshooting
216
-
217
- ### `pt img convert *.svg` fails on Windows
218
- We use `resvg-py` (a pre-built Rust wheel) instead of `cairosvg` precisely to avoid the Cairo DLL pain. Reinstall the `[img]` extra to pull it in.
219
-
220
- ### `pt vid` wants ffmpeg
221
- We prefer a system `ffmpeg` if it's on PATH, and fall back to `imageio-ffmpeg`'s bundled binary (auto-downloads ~70 MB on first call). Install ffmpeg system-wide with [`winget install ffmpeg`](https://learn.microsoft.com/windows/package-manager/) / `brew install ffmpeg` / `apt install ffmpeg` to skip the bundled download.
222
-
223
- ### `pt img bg-remove` is downloading something
224
- First run pulls the U2-Net ONNX model (~170 MB) into `~/.u2net/`. Set `U2NET_HOME` to relocate.
225
-
226
- ### `pt qr decode` says pyzbar missing
227
- On Linux, install the system library: `sudo apt-get install libzbar0` (Debian/Ubuntu) or `sudo dnf install zbar` (Fedora). Then reinstall `[qr-decode]`.
228
-
229
- ### `pt shot web` fails on first run
230
- Chromium isn't installed yet. Run `pt shot install` (which is shorthand for `python -m playwright install chromium`).
231
-
232
- ### `pt img ocr` says Tesseract not found
233
- The default `tesseract` engine needs the system Tesseract binary. Either install it (`winget install --id UB-Mannheim.TesseractOCR` on Windows, `brew install tesseract`, `apt install tesseract-ocr`) or pass `--engine easyocr` to use a self-contained PyTorch OCR.
234
-
235
- ### Brackets in `uv tool install 'polytool[full]'`
236
- PowerShell parses unquoted brackets — always wrap the spec in single quotes.
237
-
238
- ## Contributing
239
-
240
- ```bash
241
- git clone https://github.com/k6w/polytool
242
- cd polytool
243
- uv sync --extra dev --extra img --extra vid --extra pdf --extra dl --extra shot --extra archive --extra qr-decode
244
- uv run pre-commit install
245
- uv run pytest
246
- uv run ruff check .
247
- ```
248
-
249
- Conventional Commits required (`feat:`, `fix:`, `chore:`, `docs:`, `test:`, `ci:`, `build:`).
250
-
251
- Each user-facing verb must:
252
- - Include a runnable `Examples:` block in its `--help`.
253
- - Read from path or stdin (`-`) where it's semantic.
254
- - Default `--output` to next-to-source for files, stdout for text.
255
- - Raise `PolytoolError(msg, hint=...)` on user errors (rendered as a red panel).
256
- - Ship at least one happy-path and one error-path test.
257
-
258
- ## License
259
-
260
- MIT — see [LICENSE](LICENSE).
polytool-0.2.9/README.md DELETED
@@ -1,159 +0,0 @@
1
- # polytool
2
-
3
- > One CLI, 26 everyday utilities. Image format conversion, background removal, video/audio conversion, PDF tooling, OCR, QR codes, hashing, downloads, and more — all behind one binary called `pt`.
4
-
5
- [![CI](https://github.com/k6w/polytool/actions/workflows/ci.yml/badge.svg)](https://github.com/k6w/polytool/actions/workflows/ci.yml)
6
-
7
- ## Install
8
-
9
- The fastest way (no Python prerequisite — `uv` brings its own):
10
-
11
- ```powershell
12
- # 1. install uv (Windows PowerShell)
13
- irm https://astral.sh/uv/install.ps1 | iex
14
-
15
- # 2. install polytool (slim — fast, ~80 MB)
16
- uv tool install polytool
17
-
18
- # or, install everything (image/video/PDF/yt-dlp/screenshots/AI background removal)
19
- uv tool install 'polytool[full]'
20
- ```
21
-
22
- ```bash
23
- # macOS / Linux
24
- curl -LsSf https://astral.sh/uv/install.sh | sh
25
- uv tool install 'polytool[full]'
26
- ```
27
-
28
- > **Note for PowerShell users:** quote `'polytool[full]'` — the brackets are shell glob characters.
29
-
30
- After install, both `polytool` and the short alias `pt` are on your PATH.
31
-
32
- ## Quick start
33
-
34
- ```bash
35
- pt qr gen "https://github.com/k6w/polytool" -o qr.png
36
- pt img convert photo.heic -o photo.jpg
37
- pt img bg-remove portrait.jpg # transparent PNG
38
- pt vid gif clip.mp4 # animated gif
39
- pt vid extract-audio movie.mp4 # mp3
40
- pt pdf merge a.pdf b.pdf -o merged.pdf
41
- pt pdf to-images doc.pdf --dpi 200
42
- pt dl get 'https://www.youtube.com/watch?v=...'
43
- pt enc hash sha256 release.zip
44
- pt enc base64 encode README.md
45
- pt data convert config.yaml --to json
46
- pt gen password --length 32
47
- pt gen uuid v7
48
- pt color convert "#3366ff"
49
- pt convert unit "100 km" --to mi
50
- pt convert timestamp 1715200000
51
- pt text slugify "Hello, World!"
52
- pt cron explain "0 9 * * MON"
53
- pt net http GET https://api.github.com
54
- pt file dedupe ./Downloads
55
- pt file archive ./project -o project.7z
56
- ```
57
-
58
- Run `pt --help` to see all groups, or `pt <group> --help` for any group's verbs (each verb's help has runnable Examples).
59
-
60
- ## Documentation
61
-
62
- Full reference for every verb, argument, and option lives in **[docs/](docs/README.md)**:
63
-
64
- - **[Install guide](docs/install.md)** — slim vs full, all extras, Windows quoting
65
- - **Per-group reference** — [img](docs/img.md) · [vid](docs/vid.md) · [pdf](docs/pdf.md) · [dl](docs/dl.md) · [shot](docs/shot.md) · [qr](docs/qr.md) · [data](docs/data.md) · [enc](docs/enc.md) · [text](docs/text.md) · [convert](docs/convert.md) · [color](docs/color.md) · [cron](docs/cron.md) · [file](docs/file.md) · [gen](docs/gen.md) · [net](docs/net.md) · [clip](docs/clip.md)
66
- - **[Architecture](docs/architecture.md)** — package layout, lazy imports, error model, how to add a verb
67
- - **[Troubleshooting](docs/troubleshooting.md)** — every common error with a fix
68
-
69
- ## Feature reference (all 26 verbs)
70
-
71
- | Group | Verbs |
72
- |---|---|
73
- | `pt img` | `convert` (png/jpg/webp/avif/heic/svg/bmp/tiff), `resize`, `compress`, `bg-remove`, `watermark`, `ascii`, `exif`, `palette`, `ocr` |
74
- | `pt vid` | `convert`, `trim`, `extract-audio`, `gif` |
75
- | `pt pdf` | `merge`, `split`, `compress`, `extract-text`, `to-images`, `from-images`, `ocr` |
76
- | `pt dl` | `get` (yt-dlp wrapper, audio-only mode), `info` |
77
- | `pt data` | `convert` (json↔yaml↔toml↔csv↔xml), `pretty`, `validate` |
78
- | `pt enc` | `hash` (md5/sha1/sha256/sha512/blake2b/xxhash), `base64`, `url`, `html`, `jwt-decode`, `jwt-verify` |
79
- | `pt qr` | `gen` (png/svg/pdf/eps/terminal), `wifi` (Wi-Fi join code), `decode` |
80
- | `pt gen` | `password`, `uuid` (v1/v3/v4/v5/v7), `lorem` |
81
- | `pt file` | `rename`, `dedupe`, `bigfiles`, `organize`, `archive` (zip/tar/tar.gz/7z) |
82
- | `pt net` | `port-check`, `ip-info`, `http` |
83
- | `pt clip` | `copy`, `paste` |
84
- | `pt shot` | `screen`, `web` (Playwright), `install` |
85
- | `pt color` | `convert` (hex/rgb/hsl/hsv/cmyk) |
86
- | `pt convert` | `unit`, `timestamp`, `base` |
87
- | `pt text` | `diff`, `wc`, `case` (snake/kebab/camel/pascal/...), `slugify`, `md-to-html`, `md-preview` |
88
- | `pt cron` | `explain`, `next` |
89
-
90
- ## Slim vs full install
91
-
92
- The default install ships only lightweight utilities (data, enc, gen, color, convert, text, qr-gen, cron, net, clip, file). Heavy/optional features are grouped behind extras so you only pull what you need:
93
-
94
- | Extra | Adds | Approx. size |
95
- |---|---|---|
96
- | `[img]` | Pillow + HEIC/AVIF/SVG plugins, EXIF, palette, ASCII, watermark | ~50 MB |
97
- | `[vid]` | `ffmpeg-python` + bundled `ffmpeg` (auto-downloaded) | ~70 MB on first use |
98
- | `[pdf]` | pypdf, pikepdf, pdfplumber, PyMuPDF | ~80 MB |
99
- | `[dl]` | yt-dlp | ~10 MB |
100
- | `[shot]` | mss, Playwright (Chromium installed via `pt shot install`) | ~150 MB |
101
- | `[ai]` | rembg + ONNX runtime (170 MB U2-Net model on first run) | ~250 MB |
102
- | `[ocr]` | pytesseract / easyocr (PyTorch) | ~1 GB if easyocr |
103
- | `[qr-decode]` | pyzbar (system `libzbar` on Linux) | ~5 MB |
104
- | `[archive]` | py7zr | ~5 MB |
105
- | `[full]` | all of the above | ~1.5 GB |
106
-
107
- Verbs that need an extra you haven't installed print a friendly hint:
108
-
109
- ```
110
- This command needs the 'ai' extra.
111
- Install with: uv tool install 'polytool[ai]'
112
- ```
113
-
114
- ## Troubleshooting
115
-
116
- ### `pt img convert *.svg` fails on Windows
117
- We use `resvg-py` (a pre-built Rust wheel) instead of `cairosvg` precisely to avoid the Cairo DLL pain. Reinstall the `[img]` extra to pull it in.
118
-
119
- ### `pt vid` wants ffmpeg
120
- We prefer a system `ffmpeg` if it's on PATH, and fall back to `imageio-ffmpeg`'s bundled binary (auto-downloads ~70 MB on first call). Install ffmpeg system-wide with [`winget install ffmpeg`](https://learn.microsoft.com/windows/package-manager/) / `brew install ffmpeg` / `apt install ffmpeg` to skip the bundled download.
121
-
122
- ### `pt img bg-remove` is downloading something
123
- First run pulls the U2-Net ONNX model (~170 MB) into `~/.u2net/`. Set `U2NET_HOME` to relocate.
124
-
125
- ### `pt qr decode` says pyzbar missing
126
- On Linux, install the system library: `sudo apt-get install libzbar0` (Debian/Ubuntu) or `sudo dnf install zbar` (Fedora). Then reinstall `[qr-decode]`.
127
-
128
- ### `pt shot web` fails on first run
129
- Chromium isn't installed yet. Run `pt shot install` (which is shorthand for `python -m playwright install chromium`).
130
-
131
- ### `pt img ocr` says Tesseract not found
132
- The default `tesseract` engine needs the system Tesseract binary. Either install it (`winget install --id UB-Mannheim.TesseractOCR` on Windows, `brew install tesseract`, `apt install tesseract-ocr`) or pass `--engine easyocr` to use a self-contained PyTorch OCR.
133
-
134
- ### Brackets in `uv tool install 'polytool[full]'`
135
- PowerShell parses unquoted brackets — always wrap the spec in single quotes.
136
-
137
- ## Contributing
138
-
139
- ```bash
140
- git clone https://github.com/k6w/polytool
141
- cd polytool
142
- uv sync --extra dev --extra img --extra vid --extra pdf --extra dl --extra shot --extra archive --extra qr-decode
143
- uv run pre-commit install
144
- uv run pytest
145
- uv run ruff check .
146
- ```
147
-
148
- Conventional Commits required (`feat:`, `fix:`, `chore:`, `docs:`, `test:`, `ci:`, `build:`).
149
-
150
- Each user-facing verb must:
151
- - Include a runnable `Examples:` block in its `--help`.
152
- - Read from path or stdin (`-`) where it's semantic.
153
- - Default `--output` to next-to-source for files, stdout for text.
154
- - Raise `PolytoolError(msg, hint=...)` on user errors (rendered as a red panel).
155
- - Ship at least one happy-path and one error-path test.
156
-
157
- ## License
158
-
159
- MIT — see [LICENSE](LICENSE).
@@ -1,4 +0,0 @@
1
- """polytool — one-binary CLI bundling 26 everyday utilities."""
2
-
3
- __version__ = "0.2.9"
4
- __all__ = ["__version__"]
File without changes
File without changes