morphconv 1.0.2__tar.gz → 1.0.4__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.
- {morphconv-1.0.2 → morphconv-1.0.4}/LICENSE +1 -1
- morphconv-1.0.4/PKG-INFO +350 -0
- morphconv-1.0.4/README.md +292 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/cli.py +328 -7
- morphconv-1.0.4/morph/converters/archives.py +188 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/images.py +71 -0
- morphconv-1.0.4/morph/converters/legacy_office.py +153 -0
- morphconv-1.0.4/morph/converters/notebooks.py +165 -0
- morphconv-1.0.4/morph/converters/pdf.py +576 -0
- morphconv-1.0.4/morph/converters/qrcode.py +172 -0
- morphconv-1.0.4/morph/converters/raw_photo.py +145 -0
- morphconv-1.0.4/morph/converters/subtitles.py +145 -0
- morphconv-1.0.4/morph/converters/toml.py +72 -0
- morphconv-1.0.4/morph/converters/weasyprint_pdf.py +92 -0
- morphconv-1.0.4/morph/converters/web.py +153 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/deps.py +29 -9
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/history.py +60 -0
- morphconv-1.0.4/morphconv.egg-info/PKG-INFO +350 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morphconv.egg-info/SOURCES.txt +8 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morphconv.egg-info/requires.txt +25 -3
- {morphconv-1.0.2 → morphconv-1.0.4}/pyproject.toml +26 -4
- morphconv-1.0.2/PKG-INFO +0 -396
- morphconv-1.0.2/README.md +0 -357
- morphconv-1.0.2/morph/converters/archives.py +0 -85
- morphconv-1.0.2/morph/converters/web.py +0 -92
- morphconv-1.0.2/morphconv.egg-info/PKG-INFO +0 -396
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/__init__.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/batch.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/__init__.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/audio.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/csv_json.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/csv_to_xlsx.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/documents.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/ebooks.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/fonts.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/json_yaml.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/models_3d.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/ocr.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/pandas_extra.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/svg.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/video.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/vtracer_converter.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/converters/xlsx_to_csv.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/ffmpeg_utils.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/progress.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/registry.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morph/tui.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morphconv.egg-info/dependency_links.txt +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morphconv.egg-info/entry_points.txt +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/morphconv.egg-info/top_level.txt +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/setup.cfg +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/tests/test_cli.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/tests/test_converters.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/tests/test_registry.py +0 -0
- {morphconv-1.0.2 → morphconv-1.0.4}/tests/test_web.py +0 -0
morphconv-1.0.4/PKG-INFO
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: morphconv
|
|
3
|
+
Version: 1.0.4
|
|
4
|
+
Summary: morph — convert anything to anything, from the CLI
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: pandas>=2.2.0
|
|
10
|
+
Requires-Dist: openpyxl>=3.1.2
|
|
11
|
+
Requires-Dist: xlsxwriter>=3.2.0
|
|
12
|
+
Requires-Dist: xlrd>=2.0.1
|
|
13
|
+
Requires-Dist: pyarrow>=15.0.0
|
|
14
|
+
Requires-Dist: odfpy>=1.4.1
|
|
15
|
+
Requires-Dist: lxml>=5.1.0
|
|
16
|
+
Requires-Dist: SQLAlchemy>=2.0.0
|
|
17
|
+
Requires-Dist: rich>=13.7.0
|
|
18
|
+
Requires-Dist: typer>=0.12.0
|
|
19
|
+
Requires-Dist: chardet>=5.2.0
|
|
20
|
+
Requires-Dist: python-dateutil>=2.9.0
|
|
21
|
+
Requires-Dist: click>=8.1.7
|
|
22
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
23
|
+
Requires-Dist: textual>=0.60.0
|
|
24
|
+
Requires-Dist: Pillow>=10.0.0
|
|
25
|
+
Requires-Dist: pillow-heif>=0.15.0
|
|
26
|
+
Requires-Dist: pillow-avif-plugin>=1.4.3
|
|
27
|
+
Requires-Dist: cairosvg>=2.7.1
|
|
28
|
+
Requires-Dist: fonttools[woff]>=4.50.0
|
|
29
|
+
Requires-Dist: pytesseract>=0.3.10
|
|
30
|
+
Requires-Dist: trafilatura>=1.8.0
|
|
31
|
+
Requires-Dist: vtracer>=0.6.0
|
|
32
|
+
Requires-Dist: yt-dlp>=2024.03.10
|
|
33
|
+
Requires-Dist: pymupdf>=1.24.0
|
|
34
|
+
Requires-Dist: pdfplumber>=0.11.0
|
|
35
|
+
Requires-Dist: pdf2docx>=0.5.8
|
|
36
|
+
Requires-Dist: py7zr>=0.21.0
|
|
37
|
+
Requires-Dist: rarfile>=4.1
|
|
38
|
+
Requires-Dist: pysubs2>=1.6.0
|
|
39
|
+
Requires-Dist: tomlkit>=0.12.0
|
|
40
|
+
Requires-Dist: nbconvert>=7.0.0
|
|
41
|
+
Requires-Dist: img2pdf>=0.5.0
|
|
42
|
+
Requires-Dist: rawpy>=0.19.0
|
|
43
|
+
Requires-Dist: qrcode[pil]>=7.4.0
|
|
44
|
+
Requires-Dist: pyzbar>=0.1.9
|
|
45
|
+
Requires-Dist: markdownify>=0.13.0
|
|
46
|
+
Requires-Dist: weasyprint>=62.0
|
|
47
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
|
|
50
|
+
Provides-Extra: 3d
|
|
51
|
+
Requires-Dist: bpy>=5.0.0; python_version < "3.13" and extra == "3d"
|
|
52
|
+
Provides-Extra: web
|
|
53
|
+
Requires-Dist: crawl4ai>=0.4.0; extra == "web"
|
|
54
|
+
Requires-Dist: playwright>=1.40.0; extra == "web"
|
|
55
|
+
Provides-Extra: all
|
|
56
|
+
Requires-Dist: morphconv[3d,web]; extra == "all"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
<div align="center">
|
|
60
|
+
|
|
61
|
+
# 🦋 MORPH
|
|
62
|
+
|
|
63
|
+
**The Universal File Converter for the Command Line.**
|
|
64
|
+
|
|
65
|
+
*One command. No format-specific tools to remember. No cloud upload. No API keys.*
|
|
66
|
+
*Convert anything, to anything.*
|
|
67
|
+
|
|
68
|
+
[](LICENSE)
|
|
69
|
+
[](https://www.python.org/downloads/)
|
|
70
|
+
[](https://typer.tiangolo.com/)
|
|
71
|
+
[](https://github.com/Textualize/rich)
|
|
72
|
+
[](https://textual.textualize.io/)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
morph report.docx report.pdf
|
|
76
|
+
morph data.csv data.xlsx --table-style TableStyleMedium2 --header-bg 2E7D32
|
|
77
|
+
morph logo.png logo.svg --mode spline
|
|
78
|
+
morph batch '*.mp4' mp3 --workers 4
|
|
79
|
+
morph pack '*.png' photos/ doc.pdf archive.zip
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## ⚡ Why `morph` exists
|
|
87
|
+
|
|
88
|
+
`ffmpeg` converts media. `pandoc` converts documents. `ImageMagick` converts images. Each is an incredible piece of software, but using them together is a nightmare of different flag dialects, mental models, and obscure syntax errors.
|
|
89
|
+
|
|
90
|
+
**`morph` doesn't reinvent codecs or file formats — it orchestrates the best tool for each job behind a single, predictable, and beautiful interface.**
|
|
91
|
+
|
|
92
|
+
Whether you are rendering a 3D `.blend` file to a `.png`, scraping a Wikipedia article into a Markdown file, vectorizing a `.jpg` into an `.svg`, or converting a batch of `.csv` files to `.parquet`, `morph` calculates the route, fetches the dependencies, and executes the job.
|
|
93
|
+
|
|
94
|
+
## ✨ Features
|
|
95
|
+
|
|
96
|
+
- **One Universal Verb.** `morph <input> <output>`. That's it. Omit the output, and `morph` acts as a wizard, presenting you with an interactive menu of all possible destination formats.
|
|
97
|
+
- **Undo.** Made a mistake? Convert a massive 1,000-file directory by accident? Just type `morph undo` and watch it instantly delete the generated files and revert your history.
|
|
98
|
+
- **Smart Multi-Hop Graph Routing.** No direct `csv → yaml` converter? `morph` automatically finds the `csv → json → yaml` route. When crossing wild paradigms (e.g. Markdown → SQLite), `morph` explicitly hints its logic (like `extracts tabular data only`).
|
|
99
|
+
- **Contextual Intelligence.** Run `morph data.csv data.xlsx --help` and you'll *only* see flags relevant to that specific pair (like `--table-style` or `--freeze-cols`). Run it on a video file, and you'll see bitrate and framerate controls instead.
|
|
100
|
+
- **Output Verification.** Pass the `--verify` flag to calculate and display the exact SHA-256 checksum of the resulting file right alongside the success message.
|
|
101
|
+
- **Transparent Remote Downloads.** Pass any `http://` link and `morph` handles the rest. It uses `trafilatura` to scrape web articles into clean Markdown, or `yt-dlp` to natively download high-quality media (`morph <url> --audio`).
|
|
102
|
+
- **Batch Processing Engine.** `morph batch '*.mp4' mp3` converts files concurrently with a live progress table, smart skip logic (`--newer-only`, `--skip-existing`), and output structure mirroring.
|
|
103
|
+
- **Pack Command.** Run `morph pack *.png output.zip` to collect any number of files, globs, or directories into a single archive (zip/7z/tar.gz), with auto-stripped common paths.
|
|
104
|
+
- **Interactive TUI.** Type `morph` with no arguments to launch a stunning, keyboard-driven Textual UI. Navigate your filesystem, preview conversion options, and watch live progress bars without touching your mouse.
|
|
105
|
+
- **Automated Dependency Management.** Missing `ffmpeg` or `pandoc`? `morph` detects your OS and package manager (brew/apt/winget/etc.), shows you the exact install command, and asks before running it. Massive dependencies (like 3D rendering engines) are cleanly isolated as optional extras!
|
|
106
|
+
- **Pluggable Architecture.** Drop a Python script in `morph/converters/`, add a `@register` decorator, and it's instantly live in the routing graph.
|
|
107
|
+
- **Local-First & Private.** No cloud uploads. No API keys. Everything runs on your machine.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 📦 Installation
|
|
112
|
+
|
|
113
|
+
`morph` is natively distributed across all major operating systems. You do not need Python installed to use the standalone binaries!
|
|
114
|
+
|
|
115
|
+
### Windows
|
|
116
|
+
```powershell
|
|
117
|
+
# via Winget (Recommended)
|
|
118
|
+
winget install hariharen.morph
|
|
119
|
+
|
|
120
|
+
# via Scoop
|
|
121
|
+
scoop bucket add morph https://github.com/hariharen9/scoop-bucket.git
|
|
122
|
+
scoop install morph
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### macOS & Linux
|
|
126
|
+
```bash
|
|
127
|
+
# via Homebrew
|
|
128
|
+
brew tap hariharen9/homebrew-tap
|
|
129
|
+
brew install morph
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Python Ecosystem (PyPI)
|
|
133
|
+
If you prefer managing via `pip` (or `pipx`), install it globally:
|
|
134
|
+
```bash
|
|
135
|
+
pipx install morphconv
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Development (Source)
|
|
139
|
+
```bash
|
|
140
|
+
git clone https://github.com/hariharen9/morph.git
|
|
141
|
+
cd morph
|
|
142
|
+
pip install -e .
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`morph` relies on native Python libraries for data, web, and archives. For massive specialized packages, `morph` uses optional extras to keep your base installation blazing fast. If you need them, simply install them:
|
|
146
|
+
```bash
|
|
147
|
+
pip install -e ".[3d]" # Installs bpy (Blender) for 3D conversions
|
|
148
|
+
pip install -e ".[web]" # Installs crawl4ai and playwright for heavy JS rendering
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
For domain-specific external binaries (e.g., `ffmpeg`, `pandoc`), you don't need to install these upfront — `morph` will intelligently prompt you to install them the first time they are needed.
|
|
152
|
+
|
|
153
|
+
To see your current system dependencies at any time:
|
|
154
|
+
```bash
|
|
155
|
+
morph deps
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 🚀 Quickstart & Real-World Examples
|
|
161
|
+
|
|
162
|
+
### 📊 Data Processing
|
|
163
|
+
Switch between analytical formats effortlessly.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
morph data.csv data.xlsx
|
|
167
|
+
morph data.json data.yaml
|
|
168
|
+
morph database.sqlite data.csv
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 📄 Documents & Ebooks
|
|
172
|
+
```bash
|
|
173
|
+
morph notes.md notes.docx
|
|
174
|
+
morph report.docx report.pdf
|
|
175
|
+
morph book.epub book.mobi
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 🖼️ Images & Vectorization
|
|
179
|
+
Raster conversions, plus advanced raster-to-vector tracing.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Standard image processing
|
|
183
|
+
morph photo.png photo.webp --quality 80 --resize 1200x
|
|
184
|
+
morph icon.png icon.ico
|
|
185
|
+
|
|
186
|
+
# Raster to Vector (via vtracer)
|
|
187
|
+
morph logo.png logo.svg --mode spline --hierarchical stacked
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 🎬 Audio & Video (via `ffmpeg`)
|
|
191
|
+
Media manipulation with real-time progress bars parsed directly from ffmpeg.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
morph song.wav song.mp3 --bitrate 192k
|
|
195
|
+
morph clip.mp4 clip.gif --fps 10 --width 480
|
|
196
|
+
morph clip.mkv clip.mp3 # Extract audio
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 🌐 Web & Remote Files
|
|
200
|
+
Fetch data directly from the internet and transform it locally in one step. `morph` natively embeds `yt-dlp` to download almost any media from the web.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Natively download video from YouTube, Twitter, etc.
|
|
204
|
+
morph https://youtube.com/watch?v=... video.mp4
|
|
205
|
+
|
|
206
|
+
# Extract audio only from a remote video with metadata embedded
|
|
207
|
+
morph https://youtube.com/watch?v=... audio.mp3 --audio
|
|
208
|
+
|
|
209
|
+
# Scrape an article into clean Markdown (via trafilatura)
|
|
210
|
+
morph https://en.wikipedia.org/wiki/Graph_theory graph_theory.md
|
|
211
|
+
|
|
212
|
+
# Download a remote CSV and style it as an Excel workbook natively
|
|
213
|
+
morph https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/latest/owid-covid-latest.csv covid.xlsx --table-style TableStyleMedium2
|
|
214
|
+
|
|
215
|
+
# Scrape a JavaScript-heavy page (requires morphconv[web])
|
|
216
|
+
morph https://example.com/dynamic-article doc.pdf --js
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 🧊 3D Models & Rendering (Powered by Blender/`bpy`)
|
|
220
|
+
Seamlessly convert between 3D formats, or utilize headless rendering to generate images of your models.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Format conversion
|
|
224
|
+
morph character.fbx character.glb
|
|
225
|
+
morph scene.obj scene.blend
|
|
226
|
+
|
|
227
|
+
# Headless 3D rendering (automatically places lights and cameras)
|
|
228
|
+
morph character.gltf character.png
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 🏎️ Batch Operations
|
|
234
|
+
|
|
235
|
+
Convert hundreds of files concurrently with a beautiful terminal dashboard.
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# All MP4s to MP3 using 4 parallel workers
|
|
239
|
+
morph batch '*.mp4' mp3 --workers 4
|
|
240
|
+
|
|
241
|
+
# Recursively convert a whole directory and mirror its structure in an output folder
|
|
242
|
+
morph batch ./raw_footage/ mp3 --recursive --out-dir ./audio_only/ --mirror
|
|
243
|
+
|
|
244
|
+
# Skip files that have already been converted
|
|
245
|
+
morph batch '*.flac' mp3 --skip-existing
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
During batch conversions, `morph` displays a live status table:
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
╭─ morph batch — 8 files → mp3 ─────────────────────────────────────╮
|
|
252
|
+
│ Status File Time Size │
|
|
253
|
+
│ ✓ done concert_01.flac 0:00:04 8.3MB → 4.1MB │
|
|
254
|
+
│ ✓ done concert_02.flac 0:00:03 7.9MB → 3.8MB │
|
|
255
|
+
│ ▶ converting… concert_03.flac 0:00:01 │
|
|
256
|
+
│ · waiting concert_04.wav │
|
|
257
|
+
│ │
|
|
258
|
+
│ Overall ████████░░░░░░░░ 2/8 [0:00:07] │
|
|
259
|
+
╰──────────────────────────────────────────────────────────────────────╯
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 🗂️ Supported Formats
|
|
265
|
+
|
|
266
|
+
| Domain | Formats | Backend |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| **Data** | `csv`, `xlsx`, `json`, `yaml`, `toml`, `parquet`, `feather`, `ods`, `xml`, `html`, `sqlite` | Native (`pandas` / `tomlkit`) |
|
|
269
|
+
| **Documents** | `md`, `html`, `docx`, `odt`, `rtf`, `epub`, `latex`, `rst`, `txt`, `pptx`, `adoc`, `org`, `opml`, `man` | `pandoc` |
|
|
270
|
+
| **Legacy Office** | `doc`, `xls`, `ppt` | `LibreOffice (soffice)` |
|
|
271
|
+
| **Notebooks** | `ipynb` | `nbconvert` (executes & renders outputs) |
|
|
272
|
+
| **PDF** | `pdf` (real text, layout, tables, generation) | `pymupdf` / `pdfplumber` / `pdf2docx` |
|
|
273
|
+
| **Images (Raster)** | `png`, `jpg/jpeg`, `webp`, `bmp`, `gif`, `tiff`, `ico`, `heic`, `avif`, `icns` | `Pillow` / `cairosvg` |
|
|
274
|
+
| **Vectorization** | `png`/`jpg`/etc. → `svg` | `vtracer` |
|
|
275
|
+
| **3D Models** | `obj`, `stl`, `fbx`, `gltf`, `glb`, `blend`, `any → png` (Render) | `bpy` (Blender) |
|
|
276
|
+
| **Web Extraction** | `url` → `md`, `txt`, `xml`, `html` | `trafilatura` / `crawl4ai` |
|
|
277
|
+
| **Audio** | `mp3`, `wav`, `flac`, `ogg`, `aac`, `m4a`, `opus`, `wma` | `ffmpeg` |
|
|
278
|
+
| **Video** | `mp4`, `mkv`, `mov`, `webm`, `avi`, `flv`, `wmv`, `mpeg` | `ffmpeg` |
|
|
279
|
+
| **Subtitles** | `srt`, `vtt`, `ass`, `ssa`, `sub`, `sami` | `pysubs2` |
|
|
280
|
+
| **Ebooks** | `epub`, `mobi`, `azw3` | `ebook-convert` |
|
|
281
|
+
| **Fonts** | `ttf`, `otf`, `woff`, `woff2` | `fontTools` |
|
|
282
|
+
| **OCR** | `png`, `jpg`, `webp`, `pdf`, etc. → `txt` | `tesseract` |
|
|
283
|
+
| **Archives** | `zip`, `7z`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`, `rar`* | Python stdlib / `py7zr` / `rarfile` |
|
|
284
|
+
|
|
285
|
+
*\* Note: RAR is an extract-only format (RAR creation requires proprietary tools).*
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 🛠️ Architecture & Under the Hood
|
|
290
|
+
|
|
291
|
+
The magic of `morph` lies in its modular graph architecture.
|
|
292
|
+
|
|
293
|
+
```text
|
|
294
|
+
morph/
|
|
295
|
+
├── cli.py # Command dispatch (run, batch, formats, history, deps)
|
|
296
|
+
├── registry.py # BFS Routing graph & registration logic
|
|
297
|
+
├── tui.py # Textual keyboard-driven TUI
|
|
298
|
+
└── converters/
|
|
299
|
+
├── __init__.py # Auto-discovers all modules
|
|
300
|
+
├── documents.py # pandoc engine
|
|
301
|
+
├── images.py # Pillow engine
|
|
302
|
+
├── models_3d.py # Blender/bpy engine
|
|
303
|
+
├── web.py # trafilatura / crawl4ai engine
|
|
304
|
+
└── vtracer_converter.py # Raster-to-SVG vectorization
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Adding a new conversion is trivial
|
|
308
|
+
|
|
309
|
+
Drop a file in `morph/converters/` and use the `@register` decorator. No central registry, no CLI parsers to update.
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from pathlib import Path
|
|
313
|
+
from ..registry import ConversionResult, OptionSpec, register
|
|
314
|
+
|
|
315
|
+
@register("foo", "bar", backend="mytool", family="image")
|
|
316
|
+
def foo_to_bar(input_path: Path, output_path: Path, **kwargs) -> ConversionResult:
|
|
317
|
+
# Do the conversion...
|
|
318
|
+
return ConversionResult(output=output_path)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Because of `morph`'s graph routing, once `foo → bar` is registered, if a path exists from `bar → baz`, `morph` immediately knows how to convert `foo → baz`.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 📜 History & Transparency
|
|
326
|
+
|
|
327
|
+
Every conversion is automatically logged. You can review your execution history at any time.
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
morph history
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
┌──────────┬──────┬──────┬────────────────┬────────┬────────────┐
|
|
335
|
+
│ When │ From │ To │ File │ Mode │ Status │
|
|
336
|
+
├──────────┼──────┼──────┼────────────────┼────────┼────────────┤
|
|
337
|
+
│ 2m ago │ md │ docx │ README.md │ single │ ✓ 1.8s │
|
|
338
|
+
│ 1h ago │ mp4 │ mp3 │ intro.mp4 │ batch │ ✓ 4.2s │
|
|
339
|
+
└──────────┴──────┴──────┴────────────────┴────────┴────────────┘
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## 🤝 Contributing
|
|
345
|
+
|
|
346
|
+
PRs are highly encouraged! If you are adding a new conversion, simply add the file in the `converters/` directory.
|
|
347
|
+
|
|
348
|
+
## ⚖️ License
|
|
349
|
+
|
|
350
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🦋 MORPH
|
|
4
|
+
|
|
5
|
+
**The Universal File Converter for the Command Line.**
|
|
6
|
+
|
|
7
|
+
*One command. No format-specific tools to remember. No cloud upload. No API keys.*
|
|
8
|
+
*Convert anything, to anything.*
|
|
9
|
+
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://www.python.org/downloads/)
|
|
12
|
+
[](https://typer.tiangolo.com/)
|
|
13
|
+
[](https://github.com/Textualize/rich)
|
|
14
|
+
[](https://textual.textualize.io/)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
morph report.docx report.pdf
|
|
18
|
+
morph data.csv data.xlsx --table-style TableStyleMedium2 --header-bg 2E7D32
|
|
19
|
+
morph logo.png logo.svg --mode spline
|
|
20
|
+
morph batch '*.mp4' mp3 --workers 4
|
|
21
|
+
morph pack '*.png' photos/ doc.pdf archive.zip
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ Why `morph` exists
|
|
29
|
+
|
|
30
|
+
`ffmpeg` converts media. `pandoc` converts documents. `ImageMagick` converts images. Each is an incredible piece of software, but using them together is a nightmare of different flag dialects, mental models, and obscure syntax errors.
|
|
31
|
+
|
|
32
|
+
**`morph` doesn't reinvent codecs or file formats — it orchestrates the best tool for each job behind a single, predictable, and beautiful interface.**
|
|
33
|
+
|
|
34
|
+
Whether you are rendering a 3D `.blend` file to a `.png`, scraping a Wikipedia article into a Markdown file, vectorizing a `.jpg` into an `.svg`, or converting a batch of `.csv` files to `.parquet`, `morph` calculates the route, fetches the dependencies, and executes the job.
|
|
35
|
+
|
|
36
|
+
## ✨ Features
|
|
37
|
+
|
|
38
|
+
- **One Universal Verb.** `morph <input> <output>`. That's it. Omit the output, and `morph` acts as a wizard, presenting you with an interactive menu of all possible destination formats.
|
|
39
|
+
- **Undo.** Made a mistake? Convert a massive 1,000-file directory by accident? Just type `morph undo` and watch it instantly delete the generated files and revert your history.
|
|
40
|
+
- **Smart Multi-Hop Graph Routing.** No direct `csv → yaml` converter? `morph` automatically finds the `csv → json → yaml` route. When crossing wild paradigms (e.g. Markdown → SQLite), `morph` explicitly hints its logic (like `extracts tabular data only`).
|
|
41
|
+
- **Contextual Intelligence.** Run `morph data.csv data.xlsx --help` and you'll *only* see flags relevant to that specific pair (like `--table-style` or `--freeze-cols`). Run it on a video file, and you'll see bitrate and framerate controls instead.
|
|
42
|
+
- **Output Verification.** Pass the `--verify` flag to calculate and display the exact SHA-256 checksum of the resulting file right alongside the success message.
|
|
43
|
+
- **Transparent Remote Downloads.** Pass any `http://` link and `morph` handles the rest. It uses `trafilatura` to scrape web articles into clean Markdown, or `yt-dlp` to natively download high-quality media (`morph <url> --audio`).
|
|
44
|
+
- **Batch Processing Engine.** `morph batch '*.mp4' mp3` converts files concurrently with a live progress table, smart skip logic (`--newer-only`, `--skip-existing`), and output structure mirroring.
|
|
45
|
+
- **Pack Command.** Run `morph pack *.png output.zip` to collect any number of files, globs, or directories into a single archive (zip/7z/tar.gz), with auto-stripped common paths.
|
|
46
|
+
- **Interactive TUI.** Type `morph` with no arguments to launch a stunning, keyboard-driven Textual UI. Navigate your filesystem, preview conversion options, and watch live progress bars without touching your mouse.
|
|
47
|
+
- **Automated Dependency Management.** Missing `ffmpeg` or `pandoc`? `morph` detects your OS and package manager (brew/apt/winget/etc.), shows you the exact install command, and asks before running it. Massive dependencies (like 3D rendering engines) are cleanly isolated as optional extras!
|
|
48
|
+
- **Pluggable Architecture.** Drop a Python script in `morph/converters/`, add a `@register` decorator, and it's instantly live in the routing graph.
|
|
49
|
+
- **Local-First & Private.** No cloud uploads. No API keys. Everything runs on your machine.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 📦 Installation
|
|
54
|
+
|
|
55
|
+
`morph` is natively distributed across all major operating systems. You do not need Python installed to use the standalone binaries!
|
|
56
|
+
|
|
57
|
+
### Windows
|
|
58
|
+
```powershell
|
|
59
|
+
# via Winget (Recommended)
|
|
60
|
+
winget install hariharen.morph
|
|
61
|
+
|
|
62
|
+
# via Scoop
|
|
63
|
+
scoop bucket add morph https://github.com/hariharen9/scoop-bucket.git
|
|
64
|
+
scoop install morph
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### macOS & Linux
|
|
68
|
+
```bash
|
|
69
|
+
# via Homebrew
|
|
70
|
+
brew tap hariharen9/homebrew-tap
|
|
71
|
+
brew install morph
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Python Ecosystem (PyPI)
|
|
75
|
+
If you prefer managing via `pip` (or `pipx`), install it globally:
|
|
76
|
+
```bash
|
|
77
|
+
pipx install morphconv
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Development (Source)
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/hariharen9/morph.git
|
|
83
|
+
cd morph
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`morph` relies on native Python libraries for data, web, and archives. For massive specialized packages, `morph` uses optional extras to keep your base installation blazing fast. If you need them, simply install them:
|
|
88
|
+
```bash
|
|
89
|
+
pip install -e ".[3d]" # Installs bpy (Blender) for 3D conversions
|
|
90
|
+
pip install -e ".[web]" # Installs crawl4ai and playwright for heavy JS rendering
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For domain-specific external binaries (e.g., `ffmpeg`, `pandoc`), you don't need to install these upfront — `morph` will intelligently prompt you to install them the first time they are needed.
|
|
94
|
+
|
|
95
|
+
To see your current system dependencies at any time:
|
|
96
|
+
```bash
|
|
97
|
+
morph deps
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🚀 Quickstart & Real-World Examples
|
|
103
|
+
|
|
104
|
+
### 📊 Data Processing
|
|
105
|
+
Switch between analytical formats effortlessly.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
morph data.csv data.xlsx
|
|
109
|
+
morph data.json data.yaml
|
|
110
|
+
morph database.sqlite data.csv
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 📄 Documents & Ebooks
|
|
114
|
+
```bash
|
|
115
|
+
morph notes.md notes.docx
|
|
116
|
+
morph report.docx report.pdf
|
|
117
|
+
morph book.epub book.mobi
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 🖼️ Images & Vectorization
|
|
121
|
+
Raster conversions, plus advanced raster-to-vector tracing.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Standard image processing
|
|
125
|
+
morph photo.png photo.webp --quality 80 --resize 1200x
|
|
126
|
+
morph icon.png icon.ico
|
|
127
|
+
|
|
128
|
+
# Raster to Vector (via vtracer)
|
|
129
|
+
morph logo.png logo.svg --mode spline --hierarchical stacked
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 🎬 Audio & Video (via `ffmpeg`)
|
|
133
|
+
Media manipulation with real-time progress bars parsed directly from ffmpeg.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
morph song.wav song.mp3 --bitrate 192k
|
|
137
|
+
morph clip.mp4 clip.gif --fps 10 --width 480
|
|
138
|
+
morph clip.mkv clip.mp3 # Extract audio
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 🌐 Web & Remote Files
|
|
142
|
+
Fetch data directly from the internet and transform it locally in one step. `morph` natively embeds `yt-dlp` to download almost any media from the web.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Natively download video from YouTube, Twitter, etc.
|
|
146
|
+
morph https://youtube.com/watch?v=... video.mp4
|
|
147
|
+
|
|
148
|
+
# Extract audio only from a remote video with metadata embedded
|
|
149
|
+
morph https://youtube.com/watch?v=... audio.mp3 --audio
|
|
150
|
+
|
|
151
|
+
# Scrape an article into clean Markdown (via trafilatura)
|
|
152
|
+
morph https://en.wikipedia.org/wiki/Graph_theory graph_theory.md
|
|
153
|
+
|
|
154
|
+
# Download a remote CSV and style it as an Excel workbook natively
|
|
155
|
+
morph https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/latest/owid-covid-latest.csv covid.xlsx --table-style TableStyleMedium2
|
|
156
|
+
|
|
157
|
+
# Scrape a JavaScript-heavy page (requires morphconv[web])
|
|
158
|
+
morph https://example.com/dynamic-article doc.pdf --js
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 🧊 3D Models & Rendering (Powered by Blender/`bpy`)
|
|
162
|
+
Seamlessly convert between 3D formats, or utilize headless rendering to generate images of your models.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Format conversion
|
|
166
|
+
morph character.fbx character.glb
|
|
167
|
+
morph scene.obj scene.blend
|
|
168
|
+
|
|
169
|
+
# Headless 3D rendering (automatically places lights and cameras)
|
|
170
|
+
morph character.gltf character.png
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 🏎️ Batch Operations
|
|
176
|
+
|
|
177
|
+
Convert hundreds of files concurrently with a beautiful terminal dashboard.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# All MP4s to MP3 using 4 parallel workers
|
|
181
|
+
morph batch '*.mp4' mp3 --workers 4
|
|
182
|
+
|
|
183
|
+
# Recursively convert a whole directory and mirror its structure in an output folder
|
|
184
|
+
morph batch ./raw_footage/ mp3 --recursive --out-dir ./audio_only/ --mirror
|
|
185
|
+
|
|
186
|
+
# Skip files that have already been converted
|
|
187
|
+
morph batch '*.flac' mp3 --skip-existing
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
During batch conversions, `morph` displays a live status table:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
╭─ morph batch — 8 files → mp3 ─────────────────────────────────────╮
|
|
194
|
+
│ Status File Time Size │
|
|
195
|
+
│ ✓ done concert_01.flac 0:00:04 8.3MB → 4.1MB │
|
|
196
|
+
│ ✓ done concert_02.flac 0:00:03 7.9MB → 3.8MB │
|
|
197
|
+
│ ▶ converting… concert_03.flac 0:00:01 │
|
|
198
|
+
│ · waiting concert_04.wav │
|
|
199
|
+
│ │
|
|
200
|
+
│ Overall ████████░░░░░░░░ 2/8 [0:00:07] │
|
|
201
|
+
╰──────────────────────────────────────────────────────────────────────╯
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 🗂️ Supported Formats
|
|
207
|
+
|
|
208
|
+
| Domain | Formats | Backend |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| **Data** | `csv`, `xlsx`, `json`, `yaml`, `toml`, `parquet`, `feather`, `ods`, `xml`, `html`, `sqlite` | Native (`pandas` / `tomlkit`) |
|
|
211
|
+
| **Documents** | `md`, `html`, `docx`, `odt`, `rtf`, `epub`, `latex`, `rst`, `txt`, `pptx`, `adoc`, `org`, `opml`, `man` | `pandoc` |
|
|
212
|
+
| **Legacy Office** | `doc`, `xls`, `ppt` | `LibreOffice (soffice)` |
|
|
213
|
+
| **Notebooks** | `ipynb` | `nbconvert` (executes & renders outputs) |
|
|
214
|
+
| **PDF** | `pdf` (real text, layout, tables, generation) | `pymupdf` / `pdfplumber` / `pdf2docx` |
|
|
215
|
+
| **Images (Raster)** | `png`, `jpg/jpeg`, `webp`, `bmp`, `gif`, `tiff`, `ico`, `heic`, `avif`, `icns` | `Pillow` / `cairosvg` |
|
|
216
|
+
| **Vectorization** | `png`/`jpg`/etc. → `svg` | `vtracer` |
|
|
217
|
+
| **3D Models** | `obj`, `stl`, `fbx`, `gltf`, `glb`, `blend`, `any → png` (Render) | `bpy` (Blender) |
|
|
218
|
+
| **Web Extraction** | `url` → `md`, `txt`, `xml`, `html` | `trafilatura` / `crawl4ai` |
|
|
219
|
+
| **Audio** | `mp3`, `wav`, `flac`, `ogg`, `aac`, `m4a`, `opus`, `wma` | `ffmpeg` |
|
|
220
|
+
| **Video** | `mp4`, `mkv`, `mov`, `webm`, `avi`, `flv`, `wmv`, `mpeg` | `ffmpeg` |
|
|
221
|
+
| **Subtitles** | `srt`, `vtt`, `ass`, `ssa`, `sub`, `sami` | `pysubs2` |
|
|
222
|
+
| **Ebooks** | `epub`, `mobi`, `azw3` | `ebook-convert` |
|
|
223
|
+
| **Fonts** | `ttf`, `otf`, `woff`, `woff2` | `fontTools` |
|
|
224
|
+
| **OCR** | `png`, `jpg`, `webp`, `pdf`, etc. → `txt` | `tesseract` |
|
|
225
|
+
| **Archives** | `zip`, `7z`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`, `rar`* | Python stdlib / `py7zr` / `rarfile` |
|
|
226
|
+
|
|
227
|
+
*\* Note: RAR is an extract-only format (RAR creation requires proprietary tools).*
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 🛠️ Architecture & Under the Hood
|
|
232
|
+
|
|
233
|
+
The magic of `morph` lies in its modular graph architecture.
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
morph/
|
|
237
|
+
├── cli.py # Command dispatch (run, batch, formats, history, deps)
|
|
238
|
+
├── registry.py # BFS Routing graph & registration logic
|
|
239
|
+
├── tui.py # Textual keyboard-driven TUI
|
|
240
|
+
└── converters/
|
|
241
|
+
├── __init__.py # Auto-discovers all modules
|
|
242
|
+
├── documents.py # pandoc engine
|
|
243
|
+
├── images.py # Pillow engine
|
|
244
|
+
├── models_3d.py # Blender/bpy engine
|
|
245
|
+
├── web.py # trafilatura / crawl4ai engine
|
|
246
|
+
└── vtracer_converter.py # Raster-to-SVG vectorization
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Adding a new conversion is trivial
|
|
250
|
+
|
|
251
|
+
Drop a file in `morph/converters/` and use the `@register` decorator. No central registry, no CLI parsers to update.
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from pathlib import Path
|
|
255
|
+
from ..registry import ConversionResult, OptionSpec, register
|
|
256
|
+
|
|
257
|
+
@register("foo", "bar", backend="mytool", family="image")
|
|
258
|
+
def foo_to_bar(input_path: Path, output_path: Path, **kwargs) -> ConversionResult:
|
|
259
|
+
# Do the conversion...
|
|
260
|
+
return ConversionResult(output=output_path)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Because of `morph`'s graph routing, once `foo → bar` is registered, if a path exists from `bar → baz`, `morph` immediately knows how to convert `foo → baz`.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 📜 History & Transparency
|
|
268
|
+
|
|
269
|
+
Every conversion is automatically logged. You can review your execution history at any time.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
morph history
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
┌──────────┬──────┬──────┬────────────────┬────────┬────────────┐
|
|
277
|
+
│ When │ From │ To │ File │ Mode │ Status │
|
|
278
|
+
├──────────┼──────┼──────┼────────────────┼────────┼────────────┤
|
|
279
|
+
│ 2m ago │ md │ docx │ README.md │ single │ ✓ 1.8s │
|
|
280
|
+
│ 1h ago │ mp4 │ mp3 │ intro.mp4 │ batch │ ✓ 4.2s │
|
|
281
|
+
└──────────┴──────┴──────┴────────────────┴────────┴────────────┘
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 🤝 Contributing
|
|
287
|
+
|
|
288
|
+
PRs are highly encouraged! If you are adding a new conversion, simply add the file in the `converters/` directory.
|
|
289
|
+
|
|
290
|
+
## ⚖️ License
|
|
291
|
+
|
|
292
|
+
Released under the [MIT License](LICENSE).
|