Skip to content

Commit

Permalink
Minor tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 19, 2021
1 parent 19b54f0 commit 0fed237
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 189 deletions.
218 changes: 109 additions & 109 deletions Sources/ApertureCLI/notifications.swift
Original file line number Diff line number Diff line change
@@ -1,125 +1,125 @@
import Foundation

final class ApertureNotification {
static func notificationName(forEvent event: String, processId: String) -> String {
"aperture.\(processId).\(event)"
}
static func notificationName(forEvent event: String, processId: String) -> String {
"aperture.\(processId).\(event)"
}

private var notification: Notification
var isAnswered = false
private var notification: Notification
var isAnswered = false

init(_ notification: Notification) {
self.notification = notification
}
init(_ notification: Notification) {
self.notification = notification
}

func getField<T>(_ name: String) -> T? {
notification.userInfo?[name] as? T
}
func getField<T>(_ name: String) -> T? {
notification.userInfo?[name] as? T
}

var data: String? { getField("data") }
var data: String? { getField("data") }

func answer(_ data: Any? = nil) {
isAnswered = true
func answer(_ data: Any? = nil) {
isAnswered = true

guard
let responseIdentifier: String = getField("responseIdentifier")
guard
let responseIdentifier: String = getField("responseIdentifier")
else {
return
}

var payload = [AnyHashable: Any]()

if let payloadData = data {
payload["data"] = "\(payloadData)"
}

DistributedNotificationCenter.default().postNotificationName(
.init(responseIdentifier),
object: nil,
userInfo: payload,
deliverImmediately: true
)
}
return
}

var payload = [AnyHashable: Any]()

if let payloadData = data {
payload["data"] = "\(payloadData)"
}

DistributedNotificationCenter.default().postNotificationName(
.init(responseIdentifier),
object: nil,
userInfo: payload,
deliverImmediately: true
)
}
}

enum ApertureEvents {
static func answerEvent(
processId: String,
event: String,
using handler: @escaping (ApertureNotification) -> Void
) -> NSObjectProtocol {
static func answerEvent(
processId: String,
event: String,
using handler: @escaping (ApertureNotification) -> Void
) -> NSObjectProtocol {
DistributedNotificationCenter.default().addObserver(
forName: .init(ApertureNotification.notificationName(forEvent: event, processId: processId)),
object: nil,
queue: nil
) { notification in
let apertureNotification = ApertureNotification(notification)
handler(apertureNotification)

if !apertureNotification.isAnswered {
apertureNotification.answer()
}
forName: .init(ApertureNotification.notificationName(forEvent: event, processId: processId)),
object: nil,
queue: nil
) { notification in
let apertureNotification = ApertureNotification(notification)
handler(apertureNotification)

if !apertureNotification.isAnswered {
apertureNotification.answer()
}
}
}

static func sendEvent(
processId: String,
event: String,
data: Any?,
using callback: @escaping (ApertureNotification) -> Void
) {
let notificationName = ApertureNotification.notificationName(forEvent: event, processId: processId)
let responseIdentifier = "\(notificationName).response.\(UUID().uuidString)"

var payload: [AnyHashable: Any] = ["responseIdentifier": responseIdentifier]

if let payloadData = data {
payload["data"] = "\(payloadData)"
}

var observer: AnyObject?

observer = DistributedNotificationCenter.default().addObserver(
forName: .init(responseIdentifier),
object: nil,
queue: nil
) { notification in
DistributedNotificationCenter.default().removeObserver(observer!)
callback(ApertureNotification(notification))
}

DistributedNotificationCenter.default().postNotificationName(
.init(
ApertureNotification.notificationName(forEvent: event, processId: processId)
),
object: nil,
userInfo: payload,
deliverImmediately: true
)
}

static func sendEvent(
processId: String,
event: String,
using callback: @escaping (ApertureNotification) -> Void
) {
sendEvent(
processId: processId,
event: event,
data: nil,
using: callback
)
}

static func sendEvent(
processId: String,
event: String,
data: Any? = nil
) {
sendEvent(
processId: processId,
event: event,
data: data
) { _ in }
}
}

static func sendEvent(
processId: String,
event: String,
data: Any?,
using callback: @escaping (ApertureNotification) -> Void
) {
let notificationName = ApertureNotification.notificationName(forEvent: event, processId: processId)
let responseIdentifier = "\(notificationName).response.\(UUID().uuidString)"

var payload: [AnyHashable: Any] = ["responseIdentifier": responseIdentifier]

if let payloadData = data {
payload["data"] = "\(payloadData)"
}

var observer: AnyObject?

observer = DistributedNotificationCenter.default().addObserver(
forName: .init(responseIdentifier),
object: nil,
queue: nil
) { notification in
DistributedNotificationCenter.default().removeObserver(observer!)
callback(ApertureNotification(notification))
}

DistributedNotificationCenter.default().postNotificationName(
.init(
ApertureNotification.notificationName(forEvent: event, processId: processId)
),
object: nil,
userInfo: payload,
deliverImmediately: true
)
}

static func sendEvent(
processId: String,
event: String,
using callback: @escaping (ApertureNotification) -> Void
) {
sendEvent(
processId: processId,
event: event,
data: nil,
using: callback
)
}

static func sendEvent(
processId: String,
event: String,
data: Any? = nil
) {
sendEvent(
processId: processId,
event: event,
data: data
) { _ in }
}
}
156 changes: 78 additions & 78 deletions Sources/ApertureCLI/record.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,85 @@ import AVFoundation
import Aperture

struct Options: Decodable {
let destination: URL
let framesPerSecond: Int
let cropRect: CGRect?
let showCursor: Bool
let highlightClicks: Bool
let screenId: CGDirectDisplayID
let audioDeviceId: String?
let videoCodec: String?
let destination: URL
let framesPerSecond: Int
let cropRect: CGRect?
let showCursor: Bool
let highlightClicks: Bool
let screenId: CGDirectDisplayID
let audioDeviceId: String?
let videoCodec: String?
}

func record(_ optionsString: String, processId: String) throws {
setbuf(__stdoutp, nil)
let options: Options = try optionsString.jsonDecoded()
var observers = [Any]()

let recorder = try Aperture(
destination: options.destination,
framesPerSecond: options.framesPerSecond,
cropRect: options.cropRect,
showCursor: options.showCursor,
highlightClicks: options.highlightClicks,
screenId: options.screenId == 0 ? .main : options.screenId,
audioDevice: options.audioDeviceId != nil ? AVCaptureDevice(uniqueID: options.audioDeviceId!) : nil,
videoCodec: options.videoCodec != nil ? AVVideoCodecType(rawValue: options.videoCodec!) : nil
)

recorder.onStart = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onFileReady.rawValue)
}

recorder.onPause = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onPause.rawValue)
}

recorder.onResume = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onResume.rawValue)
}

recorder.onFinish = { error in
if let error = error {
print(error, to: .standardError)
exit(1)
}

ApertureEvents.sendEvent(processId: processId, event: OutEvent.onFinish.rawValue)

for observer in observers {
DistributedNotificationCenter.default().removeObserver(observer)
}

exit(0)
}

CLI.onExit = {
recorder.stop()
// Do not call `exit()` here as the video is not always done
// saving at this point and will be corrupted randomly
}

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.pause.rawValue) { _ in
recorder.pause()
}
)

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.resume.rawValue) { _ in
recorder.resume()
}
)

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.isPaused.rawValue) { notification in
notification.answer(recorder.isPaused)
}
)

recorder.start()
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onStart.rawValue)

RunLoop.main.run()
setbuf(__stdoutp, nil)
let options: Options = try optionsString.jsonDecoded()
var observers = [Any]()

let recorder = try Aperture(
destination: options.destination,
framesPerSecond: options.framesPerSecond,
cropRect: options.cropRect,
showCursor: options.showCursor,
highlightClicks: options.highlightClicks,
screenId: options.screenId == 0 ? .main : options.screenId,
audioDevice: options.audioDeviceId != nil ? AVCaptureDevice(uniqueID: options.audioDeviceId!) : nil,
videoCodec: options.videoCodec != nil ? AVVideoCodecType(rawValue: options.videoCodec!) : nil
)

recorder.onStart = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onFileReady.rawValue)
}

recorder.onPause = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onPause.rawValue)
}

recorder.onResume = {
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onResume.rawValue)
}

recorder.onFinish = { error in
if let error = error {
print(error, to: .standardError)
exit(1)
}

ApertureEvents.sendEvent(processId: processId, event: OutEvent.onFinish.rawValue)

for observer in observers {
DistributedNotificationCenter.default().removeObserver(observer)
}

exit(0)
}

CLI.onExit = {
recorder.stop()
// Do not call `exit()` here as the video is not always done
// saving at this point and will be corrupted randomly
}

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.pause.rawValue) { _ in
recorder.pause()
}
)

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.resume.rawValue) { _ in
recorder.resume()
}
)

observers.append(
ApertureEvents.answerEvent(processId: processId, event: InEvent.isPaused.rawValue) { notification in
notification.answer(recorder.isPaused)
}
)

recorder.start()
ApertureEvents.sendEvent(processId: processId, event: OutEvent.onStart.rawValue)

RunLoop.main.run()
}
Loading

0 comments on commit 0fed237

Please sign in to comment.