Files
Recordly/electron/native/ScreenCaptureKitRecorder.swift
webadderall 5d040fbf2c refactor: split large files into focused modules
Split all source files exceeding 500 lines into smaller, focused modules:

- electron/main.ts → mainBootstrapHelpers, mainRuntimeState, mainUpdateIntegration, mainWindowControls
- electron/windows.ts → editorWindows, hudWindows, windowShared
- electron/updater.ts → updaterDialogs, updaterEventHandlers, updaterShared
- electron/preload.ts → preloadExtensionsBridge, preloadUpdateBridge
- electron/ipc/register/recording.ts → recording/ directory with focused handlers
- src/components/video-editor/VideoEditor.tsx → EditorContent, EditorHeader, EditorSidebar, EditorToolbar, hooks/
- src/components/video-editor/SettingsPanel.tsx → settings/ directory with per-section components
- src/components/video-editor/AnnotationSettingsPanel.tsx → tab components
- src/components/video-editor/ExtensionManager.tsx → extension-manager/ directory
- src/components/video-editor/VideoPlayback.tsx → videoPlaybackComponent/ directory
- src/components/video-editor/projectPersistence.ts → projectPersistence{Normalization,Paths,Regions,Shared}.ts
- src/components/video-editor/timeline/TimelineEditor.tsx → TimelineEditor/ directory
- src/components/video-editor/types.ts → focused type modules
- src/components/launch/LaunchWindow.tsx → LaunchWindow/ directory
- src/hooks/useScreenRecorder.ts → useScreenRecorder/ directory
- src/lib/exporter/audioEncoder.ts → audioEncoder/ directory
- src/lib/exporter/frameRenderer.ts → frameRenderer modules
- src/lib/exporter/modernFrameRenderer.ts → filters and lifecycle modules
- src/lib/exporter/modernVideoExporter.ts → modernVideoExporter/ directory
- src/lib/exporter/videoExporter.ts → video-exporter/ directory
- src/lib/exporter/streamingDecoder.ts → streamingDecoderHelpers.ts
- src/lib/extensions/extensionHost.ts → extensionHost{ApiFactory,QueryApi,RegistrationApi,Shared,State}.ts
- src/lib/extensions/types.ts → focused type modules
- electron/native/ScreenCaptureKitRecorder.swift → ScreenCaptureKitRecorder/ directory
- scripts/benchmark-export-queues.mjs → benchmark-export-queues/ directory
- .github/workflows/release.yml → extracted merge-macos-metadata composite action
- scripts/build-native-helpers.mjs → updated for multi-file Swift compilation

Also incorporates upstream default export quality change (good → source).
2026-04-20 20:41:42 +10:00

83 lines
1.9 KiB
Swift

import Foundation
import AVFoundation
import CoreGraphics
private func exitWithError(_ message: String) -> Never {
fputs("\(message)\n", stderr)
fflush(stderr)
exit(1)
}
private func requestScreenRecordingPermissionIfNeeded() {
if CGPreflightScreenCaptureAccess() {
return
}
let granted = CGRequestScreenCaptureAccess()
if !granted {
exitWithError("SCREEN_RECORDING_PERMISSION_DENIED")
}
}
private func requestMicrophonePermissionIfNeeded(configJSON: String) {
guard let configData = configJSON.data(using: .utf8),
let config = try? JSONDecoder().decode(CaptureConfig.self, from: configData),
config.capturesMicrophone == true else {
return
}
switch AVCaptureDevice.authorizationStatus(for: .audio) {
case .authorized:
break
case .notDetermined:
let semaphore = DispatchSemaphore(value: 0)
AVCaptureDevice.requestAccess(for: .audio) { _ in semaphore.signal() }
semaphore.wait()
if AVCaptureDevice.authorizationStatus(for: .audio) != .authorized {
exitWithError("MICROPHONE_PERMISSION_DENIED")
}
default:
exitWithError("MICROPHONE_PERMISSION_DENIED")
}
}
@main
struct ScreenCaptureKitRecorderMain {
static func main() {
guard CommandLine.arguments.count >= 2 else {
exitWithError("Missing config JSON")
}
let configJSON = CommandLine.arguments[1]
// Force CoreGraphics Services initialization on the main thread.
_ = CGMainDisplayID()
requestScreenRecordingPermissionIfNeeded()
requestMicrophonePermissionIfNeeded(configJSON: configJSON)
let service = RecorderService()
service.start(configJSON: configJSON)
DispatchQueue.global(qos: .utility).async {
while let input = readLine(strippingNewline: true)?.lowercased() {
if input == "pause" {
service.pause()
continue
}
if input == "resume" {
service.resume()
continue
}
if input == "stop" {
service.stop()
break
}
}
}
service.waitUntilFinished()
}
}