Files
photophetch/README.md
Kyle Bolen 145b7bc955 Initial commit: PhotoPhetch v1.0.0
Kotlin/Compose Multiplatform desktop app for importing photos from
phones into PhotoPhile staging directory.

Features:
- Android support via ADB subprocess
- iPhone support via gphoto2 subprocess
- Smart filtering: excludes screenshots, received images, Live Photo MOVs
- HEIC -> JPEG conversion via macOS sips (built-in)
- SHA-256 verification of every copied file
- Safe delete with explicit confirmation
- Staging path convention: _staging/{date}_{device}/
- Config persistence at ~/.photophetch/config.json
2026-07-28 03:04:05 +00:00

4.0 KiB

PhotoPhetch

A macOS desktop app for importing photos from phones into PhotoPhile's staging directory.

Solves the "messy phone import" problem: only grabs camera-roll originals, filters out screenshots and received images, optionally converts HEIC → JPEG, and SHA-256 verifies every file before optionally deleting it from the phone.

Features

  • Android support via ADB (adb pull)
  • iPhone support via gphoto2 (PTP over USB)
  • Smart filtering: excludes screenshots, WhatsApp/Telegram received images, and Live Photo motion clips
  • HEIC → JPEG conversion via macOS sips (built-in, no install needed)
  • SHA-256 verification of every copied file
  • Safe delete: explicit confirmation screen before removing files from the phone
  • Staging path convention: writes to _staging/<YYYY-MM-DD>_<DeviceName>/
  • Persists settings to ~/.photophetch/config.json

Requirements

  • macOS (primary target)
  • Java 21+
  • Homebrew for dependencies

Install dependencies

# For iPhone support
brew install gphoto2

# For Android support
brew install android-platform-tools

Running

From source (development)

cd photophetch
./gradlew run

Build a fat JAR

./gradlew packageUberJarForCurrentOS
# Output: build/compose/jars/photophetch-macos-*.jar
java -jar build/compose/jars/photophetch-macos-*.jar

Build a macOS .app bundle

./gradlew packageDmg
# Output: build/compose/binaries/main/dmg/PhotoPhetch-1.0.0.dmg

First-time setup

  1. Launch the app
  2. Go to Settings and set your staging root (e.g. /Volumes/delphi/_staging)
  3. Make sure your NAS is mounted at that path
  4. Connect your phone via USB
  5. Click Scan for Devices on the Connect screen

iPhone notes

When you plug in an iPhone, macOS's built-in PTPCamera daemon may grab the device before gphoto2 can. If PhotoPhetch finds the device but shows no photos:

killall PTPCamera

Then rescan in the app.

HEIC settings

If your iPhone is shooting in HEIC (the default), PhotoPhetch will warn you and convert to JPEG during import. To stop shooting HEIC:

Settings → Camera → Formats → Most Compatible

Android notes

Enable USB debugging:

Settings → About Phone → tap Build Number 7 times → Developer Options → USB Debugging

Accept the "Trust this computer?" prompt on the phone when connecting.

Project structure

src/main/kotlin/com/bolenpad/photophetch/
├── Main.kt                    # Entry point
├── device/
│   ├── DeviceConnector.kt     # Interface
│   ├── AndroidConnector.kt    # ADB implementation
│   └── IosConnector.kt        # gphoto2 implementation
├── model/
│   ├── PhonePhoto.kt          # Photo metadata
│   ├── ImportJob.kt           # Import batch + results
│   ├── DeviceInfo.kt          # Connected device info
│   └── AppConfig.kt           # Persisted preferences
├── transfer/
│   └── Copier.kt              # Copy + SHA-256 verify + HEIC conversion
├── ui/
│   ├── App.kt                 # Root composable + navigation
│   ├── AppState.kt            # StateFlow ViewModel
│   ├── ConnectScreen.kt       # Device detection
│   ├── BrowseScreen.kt        # Photo grid + filters
│   ├── ImportScreen.kt        # Import configuration
│   ├── VerifyScreen.kt        # Progress + results + delete confirmation
│   └── SettingsScreen.kt      # Staging path + preferences
└── util/
    ├── ConfigStore.kt          # Config persistence
    ├── ExifFilter.kt           # Screenshot/noise filtering
    └── StagingPath.kt          # Staging directory path resolution

PhotoPhile integration

PhotoPhetch writes directly to the mounted NAS path — no API calls. After import, PhotoPhile picks up the new folder in _staging/ and runs it through its normal pipeline: configure → normalize → publish.