Skip to content

Latest commit

 

History

History
210 lines (161 loc) · 10.3 KB

File metadata and controls

210 lines (161 loc) · 10.3 KB

iPhoneCopy — Product Requirements Document

Purpose

iPhoneCopy is a command-line utility for Windows that copies photos and videos from an iPhone connected via USB cable to a local folder on the PC. It is designed to run unattended overnight across libraries of 20,000+ files, behaving like robocopy: incremental copies, fault-tolerant, resumable after interruption, with detailed logging.


Problem

Windows has no built-in tool to reliably sync photos/videos from an iPhone in bulk. The Photos app and iCloud are not suitable for users who want a local, scripted, or automated copy workflow. iTunes/Finder sync is overkill and not scriptable. Robocopy works great for local/network paths but cannot reach the iPhone's file system.


Goals

  • Copy all photos and videos from the iPhone's DCIM folder to a local destination path
  • Skip files that already exist at the destination (incremental copy)
  • Resume a previous run after interruption without re-copying already-transferred files
  • Survive individual file errors without aborting the entire run
  • Display clear progress: files copied, skipped, failed, bytes transferred, ETA
  • Produce a single standalone .exe — no installer, no dependencies to manage
  • Work without jailbreaking the iPhone
  • Work on Windows 10/11

Non-Goals

  • Syncing back to the phone
  • Deleting files from the phone after copy
  • Managing Apple Music, contacts, or app data
  • Cross-platform support (macOS/Linux) in v1
  • GUI interface in v1

Requirements

Functional

# Requirement
F1 Detect iPhone(s) connected via USB and list them if multiple are present
F2 Enumerate all photo/video files in the DCIM folder lazily (streaming, not loading all into memory at once)
F3 Copy files to a user-specified local destination directory, preserving DCIM subfolder structure by default
F4 Skip files that already exist at the destination with the same name and size
F5 Support --overwrite flag to force re-copy of all existing files
F6 Support --dry-run flag to preview what would be copied without copying
F7 Display a live progress line: current filename, N/Total, MB transferred, elapsed time, ETA
F8 Write a final summary: files copied, skipped, failed, total bytes, elapsed time
F9 On per-file error: log the error, skip that file, and continue — never abort the run
F10 Always write a timestamped log file alongside the destination (default: iPhoneCopy_<timestamp>.log)
F11 Support --since <YYYY-MM-DD> to copy only files modified on or after the given date
F12 Support --flat to copy all files into destination root with no subfolder structure
F13 Handle duplicate filenames (same name in different DCIM subfolders) without silently overwriting — append a counter suffix if needed

Robustness (Overnight / Unattended Operation)

# Requirement
R1 Resume/checkpoint: Maintain a state file (.iPhoneCopy_state.json) in the destination recording every successfully completed file. On restart, skip files already recorded in the state file, regardless of --overwrite.
R2 Atomic writes: Copy each file to a .tmp temp file first; rename to final name only on successful completion. A partial file from a crash will never silently masquerade as a good copy.
R3 Retry with backoff: On transient USB/WPD errors for a single file, retry up to 3 times with 5-second delays before recording it as failed and moving on.
R4 Post-copy size verification: After each file is copied, verify the destination file size matches the source size. On mismatch, delete the bad copy, record as failed, and continue.
R5 Graceful Ctrl+C handling: On SIGINT/cancel, finish the file currently in progress, flush the state file, write a partial summary, and exit cleanly. The next run will resume from where it stopped.
R6 Streaming transfer: Copy file data in chunks (e.g., 4 MB buffers) — never load an entire file into memory. Essential for large video files.
R7 Memory-bounded enumeration: Do not build a list of all 23,000+ file objects in memory before starting. Enumerate and copy in a pipeline/streaming fashion, or enumerate in batches.
R8 Stale temp file cleanup: On startup, scan the destination for any leftover .tmp files from a previous aborted run and delete them before starting.
R9 USB disconnect detection: If the device disappears mid-run (cable pulled, phone locked, screen timeout), detect the error immediately, log it clearly ("Device disconnected — reconnect and re-run to resume"), and exit with a non-zero code. Do not loop indefinitely.
R10 Screen timeout warning: At startup, remind the user to disable iPhone auto-lock (Settings → Display & Brightness → Auto-Lock → Never) for unattended overnight runs.

Non-Functional

# Requirement
N1 Standalone .exe — no .NET runtime or other dependencies required on the target machine
N2 Must not require jailbreak
N3 Requires Apple Mobile Device Support drivers (bundled with iTunes or the Apple Devices app from the Microsoft Store)
N4 Must handle 23,000+ files without memory growth or degradation over time
N5 Executable size < 100 MB
N6 Exit code 0 = all files copied/skipped successfully; 1 = completed with some errors; 2 = fatal error (device not found, destination not writable, etc.)

Command-Line Interface

Usage:
  iPhoneCopy <destination> [options]

Arguments:
  destination     Local folder to copy files into (created if it does not exist)

Options:
  --device <name>    Select a specific device by name (if multiple are connected)
  --overwrite        Re-copy files that already exist at destination (still honors resume state)
  --dry-run          Preview what would be copied; do not copy or modify anything
  --since <date>     Only copy files modified on or after <date> (YYYY-MM-DD)
  --flat             Copy all files into destination root; no DCIM subfolder structure
  --log <file>       Override the default log file path
  --no-resume        Ignore the state file and treat this as a fresh run
  --retries <n>      Number of per-file retries on error (default: 3)
  --help             Show help
  --version          Show version

Examples:
  iPhoneCopy D:\Photos
  iPhoneCopy D:\Photos --since 2025-01-01
  iPhoneCopy D:\Photos --dry-run
  iPhoneCopy D:\Photos --no-resume --overwrite

State File Format

The state file <destination>\.iPhoneCopy_state.json is written incrementally after each successful file copy. Format:

{
  "device": "iPhone (Alfred's iPhone)",
  "started": "2026-03-22T22:00:00Z",
  "last_updated": "2026-03-22T23:45:12Z",
  "completed": [
    { "src": "DCIM/100APPLE/IMG_0001.HEIC", "dest": "100APPLE\\IMG_0001.HEIC", "size": 3145728, "copied_at": "2026-03-22T22:00:05Z" },
    ...
  ]
}

On resume, the completed list is loaded into a HashSet<string> keyed on src path for O(1) lookup.


Log File Format

Tab-separated, one line per file, appended in real time:

2026-03-22T22:00:05Z  COPIED   DCIM/100APPLE/IMG_0001.HEIC  ->  D:\Photos\100APPLE\IMG_0001.HEIC  3145728 bytes
2026-03-22T22:00:06Z  SKIPPED  DCIM/100APPLE/IMG_0002.HEIC  (already exists, same size)
2026-03-22T22:00:07Z  FAILED   DCIM/100APPLE/IMG_0003.MOV   WPD error after 3 retries: 0x800700AA
2026-03-22T23:45:12Z  SUMMARY  Copied: 18432  Skipped: 4521  Failed: 12  Bytes: 187,432,904,192  Elapsed: 1h45m12s

Technology Decision

Recommended: C# / .NET 8 with Windows Portable Devices (WPD) API

Rationale:

  • Windows natively exposes the iPhone as a WPD/MTP device when Apple Mobile Device Support drivers are installed (iTunes or the free "Apple Devices" app from the Microsoft Store)
  • The WPD COM API (PortableDeviceApi.dll) is built into Windows — no third-party libraries needed
  • .NET 8 dotnet publish --self-contained --single-file produces a true single .exe with no runtime needed
  • C# async/await and Stream-based I/O handle large file streaming cleanly
  • Strong exception handling model suits the fault-tolerant design

Alternative considered: Python + pymobiledevice3

  • AFC protocol, doesn't require iTunes
  • Good fallback if WPD proves unreliable for specific iOS versions
  • Harder to produce a clean single-file exe on Windows

Prerequisites on the User's PC

One of:

  • iTunes for Windows (Microsoft Store or apple.com) — installs Apple Mobile Device Support
  • Apple Devices app (Microsoft Store) — lightweight, installs the same USB drivers

When the iPhone is first connected, unlock the phone and tap Trust on the "Trust This Computer?" prompt.

Important for overnight runs: Set iPhone → Settings → Display & Brightness → Auto-Lock → Never before starting. Re-enable afterward.


Suggested Source Structure

iPhoneCopy/
  src/
    iPhoneCopy/
      Program.cs            # Entry point, argument parsing, startup checks
      DeviceScanner.cs      # WPD device enumeration and selection
      FileBrowser.cs        # Lazy/streaming DCIM traversal
      FileCopier.cs         # Atomic copy, retry, size verification
      StateFile.cs          # Resume checkpoint read/write
      ProgressReporter.cs   # Live console progress line + ETA
      Logger.cs             # Append-mode structured log file
      ConflictResolver.cs   # Duplicate filename handling
  iPhoneCopy.sln
  PRD.md
  README.md

Milestones

Milestone Scope
M1 — Device Discovery Detect and list connected iPhones via WPD; print device name, storage info
M2 — DCIM Enumeration Lazily enumerate all files in DCIM; print names, sizes, dates
M3 — Atomic Copy Copy files with temp-file-then-rename; size verification; error logging
M4 — Incremental Skip Skip by name+size; --overwrite flag; duplicate filename resolution
M5 — Resume/Checkpoint State file: write after each success; resume on restart; --no-resume flag
M6 — Retry & Disconnect Per-file retry with backoff; USB disconnect detection and clean exit
M7 — Progress & Logging Live progress line with ETA; structured log file; final summary
M8 — Filtering & Flags --since, --flat, --dry-run, --device, --log flags
M9 — Packaging Single-file self-contained .exe; exit codes; startup warning for Auto-Lock