import AppKit import MediaPlayer @_cdecl("terebi_app_main") @MainActor public func checkAppStartup() { AppStartupCheck.run() } @MainActor private enum AppStartupCheck { static var model: PlayerModel? static var timer: Timer? static let deadline = ContinuousClock.now.advanced(by: .seconds(15)) static let historyDomain = Bundle.main.bundleIdentifier! + ".history" static func run() { _ = NSApplication.shared NSApp.setActivationPolicy(.regular) let defaults = UserDefaults(suiteName: historyDomain)! model = PlayerModel(defaults: defaults) model!.setVolume(0) model!.open(URL(fileURLWithPath: CommandLine.arguments[2]).appendingPathComponent("av.mp4")) timer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { _ in MainActor.assumeIsolated { finishWhenReady() } } NSApp.run() } static func finishWhenReady() { guard let model else { return } let ready = model.canTogglePlayback && model.state.status == PLAYER_PLAYING guard ready || model.state.status == PLAYER_ERROR || ContinuousClock.now >= deadline else { return } timer?.invalidate() let pid = ProcessInfo.processInfo.processIdentifier let application = NSRunningApplication.current let recognized = application.processIdentifier == pid && NSWorkspace.shared.runningApplications.contains { $0.processIdentifier == pid && $0.bundleURL == Bundle.main.bundleURL } let result: [String: Any] = [ "passed": ready && recognized && MPNowPlayingInfoCenter.default().playbackState == .playing, "pid": pid, "registeredPID": application.processIdentifier, "bundleIdentifier": application.bundleIdentifier ?? "nil", "playing": ready, ] do { let pipe = try FileHandle(forWritingTo: URL(fileURLWithPath: CommandLine.arguments[1])) try pipe.write(contentsOf: JSONSerialization.data(withJSONObject: result)) try pipe.write(contentsOf: Data([10])) try pipe.close() } catch { FileHandle.standardError.write(Data("Startup check could not report: \(error)\n".utf8)) } model.shutdown() UserDefaults(suiteName: historyDomain)!.removePersistentDomain(forName: historyDomain) self.model = nil NSApp.terminate(nil) } }