Add Konverter: a local-only menu bar file converter
Drag files in Finder, hold a modifier, and drop on a wheel of outputs. Conversions run entirely on-device through ImageIO, PDFKit, AVFoundation, the bundled CLI tools, and optional ffmpeg/LibreOffice. Includes a --self-test suite (41 checks) and a --convert CLI mode so the conversion matrix can be verified without the UI.
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# Konverter
|
||||
|
||||
A macOS menu bar file converter in the spirit of [Tangerine](https://tangerineformac.com):
|
||||
drag a file in Finder, hold a modifier key, get a wheel of outputs around the
|
||||
cursor, drop on one, and the converted file appears next to the original.
|
||||
Everything runs locally — no uploads, no accounts, no analytics.
|
||||
|
||||
<p align="center">
|
||||
<em>Shift = convert · Command (+Shift) = tools · Control = actions</em>
|
||||
</p>
|
||||
|
||||
## Using it
|
||||
|
||||
1. Launch Konverter. It lives in the menu bar (`LSUIElement`, no Dock icon).
|
||||
2. In Finder, drag one or more files (folders work for archives).
|
||||
3. **Hold a trigger key while dragging** — the wheel fades in under the pointer:
|
||||
- **Shift ⇧** — conversion targets (`PNG`, `JPG`, `PDF`, `MP4`, `ZIP`, …).
|
||||
- **Command ⌘ + Shift** — file tools (`Compress`, `Resize`, `Trim`,
|
||||
`Watermark`, `Merge`, `Extract`, …), each with its own small form.
|
||||
- **Control ⌃** — actions (`AirDrop`, `Float`, `Copy`, `Move`, `Copy Path`,
|
||||
`Terminal`, `Reveal`).
|
||||
4. Move the pointer onto a segment (or use ←/→ and Return) and **drop**.
|
||||
Dropping on the dead zone in the middle, pressing Escape, or dropping the
|
||||
file anywhere else cancels and lets Finder do its normal thing.
|
||||
|
||||
The wheel also works without dragging: the menu bar item and the Finder Quick
|
||||
Action **Convert with Konverter…** open the same options as a menu.
|
||||
|
||||
Keyboard/pointer alone is enough to use it. The optional keys (Escape, arrows,
|
||||
Return) come from a global key monitor, so they need Accessibility permission —
|
||||
without it the wheel still works by pointer, it just cannot read those keys.
|
||||
|
||||
### Preferences
|
||||
|
||||
Trigger keys (Shift/Command/Control/Option/fn), wheel style (radial/list),
|
||||
radius, labels, dimming, output folder (beside the original or a chosen
|
||||
folder), conflict policy (keep both / replace), progress window, reveal when
|
||||
finished, sound, use of external tools, and open at login. Stored in
|
||||
`UserDefaults` under the `konverter.` prefix.
|
||||
|
||||
## What it converts
|
||||
|
||||
94 input extensions are recognised. Outputs offered per kind of file:
|
||||
|
||||
| Input kind | Outputs |
|
||||
| --- | --- |
|
||||
| Image | PNG, JPG, HEIC, WebP, TIFF, BMP, GIF, AVIF, PDF |
|
||||
| Video | MP4, MOV, MKV, WebM, AVI, WMV, GIF, MP3, M4A, WAV |
|
||||
| Audio | MP3, M4A, WAV, FLAC, OGG, Opus, AIFF, WMA |
|
||||
| PDF | DOCX, PPTX, XLSX, JPG, PNG, EPUB, TXT, MD, HTML |
|
||||
| Document | DOCX, MD, TXT, RTF, HTML, EPUB, PDF |
|
||||
| Slides | PDF, JPG, PNG |
|
||||
| Spreadsheet | XLSX, ODS, CSV, TSV, PDF |
|
||||
| Ebook | TXT, HTML, MD, PDF |
|
||||
| Subtitle | SRT, VTT, TXT |
|
||||
| Archive / folder | ZIP, TAR, GZIP |
|
||||
|
||||
Plus 38 tools:
|
||||
|
||||
| Group | Tools |
|
||||
| --- | --- |
|
||||
| Image | Compress, Resize, Crop, Rotate, Flip, Grayscale, Strip Metadata, Watermark, Read QR |
|
||||
| Video | Compress, Trim, Mute, Speed, Snapshot, To GIF, Resize |
|
||||
| Audio | Trim, Normalize, Channels, Speed, Bleep, Compress |
|
||||
| PDF | Merge, Split, Rotate, Compress, Encrypt, Decrypt, Images to PDF, Collage, Extract Text |
|
||||
| Document | To PDF, Statistics |
|
||||
| Spreadsheet | To CSV |
|
||||
| Subtitle | Shift Time |
|
||||
| Archive | Extract, List Contents |
|
||||
| Any | Info |
|
||||
|
||||
### Engines and fallbacks
|
||||
|
||||
| Layer | Used for | Ships with macOS |
|
||||
| --- | --- | --- |
|
||||
| ImageIO / Core Graphics | raster image decode/encode | yes |
|
||||
| PDFKit / Core Text | PDF read/write, text extraction | yes |
|
||||
| AVFoundation | MP4/MOV/M4A/WAV/AIFF/GIF | yes |
|
||||
| `textutil`, `afconvert`, `ditto`, `tar`, `gzip`, `zip` | documents, audio, archives | yes |
|
||||
| Hand-written XLSX / EPUB / Markdown / CSV / TSV / SRT-VTT | office and ebook plumbing | yes |
|
||||
| ffmpeg / ffprobe | MKV, WebM, AVI, WMV, MP3, FLAC, OGG, Opus, WMA, bleep | optional |
|
||||
| LibreOffice | PAGES, KEY, NUMBERS, PPT, PPTX, XLS, ODS | optional |
|
||||
| `cwebp` | WebP encoding | optional |
|
||||
|
||||
Optional helpers are detected once at launch and are only ever *additive*: a
|
||||
format whose engine is missing shows as unavailable in the wheel (with the
|
||||
reason) instead of failing after you drop. Install them with:
|
||||
|
||||
```bash
|
||||
brew install ffmpeg webp # cwebp comes from the webp formula
|
||||
brew install --cask libreoffice
|
||||
```
|
||||
|
||||
Notes on specific formats:
|
||||
|
||||
- **WebP out** needs `cwebp` or an ffmpeg built with libwebp. ImageIO on macOS
|
||||
has no WebP encoder, and `sips` cannot write it either.
|
||||
- **SVG / PSD / RAW in** are rasterised through Quick Look (`qlmanage`) when
|
||||
ImageIO refuses them.
|
||||
- **PAGES / KEY / NUMBERS out** only exist through LibreOffice. In Safari-style
|
||||
document conversion, the Apple formats keep their layout via LibreOffice's
|
||||
filter, not a hand-rolled writer.
|
||||
- **Compressing a PNG** has no lossy quality knob, so the slider drives colour
|
||||
depth (posterisation) instead — a real size drop, at the cost of banding at
|
||||
low settings.
|
||||
|
||||
## Building
|
||||
|
||||
Requires Xcode (Swift 6 toolchain) and macOS 13+.
|
||||
|
||||
```bash
|
||||
swift build # debug binary
|
||||
swift build -c release
|
||||
|
||||
./.build/debug/Konverter --self-test # 41 checks over every engine
|
||||
./.build/debug/Konverter --convert photo.heic --to png
|
||||
./.build/debug/Konverter --convert clip.mov --tool trimVideo \
|
||||
--param start=0:02 --param end=0:05
|
||||
./.build/debug/Konverter --convert image.png --tool compressImage --param quality=50
|
||||
```
|
||||
|
||||
`--self-test` builds its own fixtures in a temp directory and asserts that each
|
||||
engine produces a non-empty, plausible file. Skips (printed as `SKIP`) mean an
|
||||
optional engine is absent on this machine.
|
||||
|
||||
Build the app bundle (ad-hoc signed when no Developer ID identity is present):
|
||||
|
||||
```bash
|
||||
./build-app.sh 0.1.0 # → Konverter.app, signed with Developer ID
|
||||
open Konverter.app
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
```bash
|
||||
./release.sh 0.1.0 # build → sign → notarize → staple → zip + sha256
|
||||
```
|
||||
|
||||
`release.sh` refuses to hand back a build that is not notarized and stapled;
|
||||
it also verifies `spctl -a -vv Konverter.app` reports
|
||||
`source=Notarized Developer ID` before printing the sha256. Notary credentials
|
||||
default to the shared App Store Connect key and can be overridden with
|
||||
`KONVERTER_NOTARY_API_KEY_PATH`, `KONVERTER_NOTARY_API_KEY_ID`, and
|
||||
`KONVERTER_NOTARY_API_ISSUER`.
|
||||
|
||||
Then tag, publish, and attach the zip:
|
||||
|
||||
```bash
|
||||
git tag v0.1.0 && git push origin v0.1.0
|
||||
tea releases create --tag v0.1.0 --title "Konverter 0.1.0" \
|
||||
--note "<what changed>" --asset dist/Konverter.zip \
|
||||
--repo TZGyn/konverter --login gitea.tzgyn.dev
|
||||
```
|
||||
|
||||
## Install (Homebrew)
|
||||
|
||||
```bash
|
||||
brew tap TZGyn/tap https://gitea.tzgyn.dev/TZGyn/homebrew-tap.git
|
||||
brew trust TZGyn/tap
|
||||
brew install --cask konverter
|
||||
```
|
||||
|
||||
Upgrade script:
|
||||
|
||||
```bash
|
||||
brew update
|
||||
brew upgrade --cask konverter
|
||||
```
|
||||
|
||||
## Privacy
|
||||
|
||||
Nothing leaves the machine. There is no networking code in the app, no
|
||||
telemetry, and no third-party dependencies in `Package.swift`. Conversions are
|
||||
performed by Apple frameworks, the bundled CLI tools, and (optionally) local
|
||||
`ffmpeg` / LibreOffice.
|
||||
|
||||
## Development docs
|
||||
|
||||
`AGENTS.md` covers the architecture, the drag/wheel mechanics, and the sharp
|
||||
edges worth knowing before changing the code.
|
||||
Reference in New Issue
Block a user