 func usage() {
   print(
     """
-    usage: aperture <list-audio-devices | <destinationPath> <fps> <crop-rect-coordinates> <show-cursor> <highlight-clicks> <display-id> <audio-device-id>>
-    examples: aperture ./file.mp4 30 0:0:100:100 true false 1846519 'AppleHDAEngineInput:1B,0,1,0:1'
-              aperture ./file.mp4 30 none true false main none
-              aperture list-audio-devices
+    Usage:
+      aperture <options>
+      aperture list-audio-devices
     """
   )
 }
 
-let numberOfArgs = CommandLine.arguments.count
-
-if numberOfArgs == 8 {
-  try record()
+if arguments.first == "list-audio-devices" {
+  // Uses stderr because of unrelated stuff being outputted on stdout
+  printErr(try toJson(DeviceList.audio()))
   exit(0)
 }
 
-if numberOfArgs == 2 && CommandLine.arguments[1] == "list-audio-devices" {
-  // Use stderr because of unrelated stuff being outputted on stdout
-  printErr(try toJson(DeviceList.audio()))
+if arguments.first != nil {
+  try record()
   exit(0)
 }
 

import AVFoundation

var recorder: Recorder!

func quit(_: Int32) {
  recorder.stop()

  exit(0)
}

struct Options: Decodable {
  let destination: URL
  let fps: Int
  let cropRect: CGRect?
  let showCursor: Bool
  let highlightClicks: Bool
  let displayId: String
  let audioDeviceId: String?
}

func record() throws {
  let json = arguments.first!.data(using: .utf8)!
  let options = try JSONDecoder().decode(Options.self, from: json)

  recorder = try Recorder(
    destination: options.destination,
    fps: options.fps,
    cropRect: options.cropRect,
    showCursor: options.showCursor,
    highlightClicks: options.highlightClicks,
    displayId: options.displayId == "main" ? CGMainDisplayID() : CGDirectDisplayID(options.displayId)!,
    audioDevice: options.audioDeviceId != nil ? AVCaptureDevice(uniqueID: options.audioDeviceId!) : nil
  )

  recorder.onStart = {
