import AppKit import Darwin import TerebiConfiguration @main @MainActor enum TerebiCLI { static func main() async { let command: PlayerCommand do { command = try PlayerCommand.parse(Array(CommandLine.arguments.dropFirst())) } catch { fail(error.localizedDescription, code: 64) } switch command { case .help: print(PlayerCommand.usage) case .printDefaultConfig: print(PlayerConfiguration.defaultTOML, terminator: "") case .launch(let url, let newInstance, let noConfig, let progressFile): if let progressFile { var existing = stat() guard lstat(progressFile.path, &existing) != 0 else { fail("Progress file already exists: \(progressFile.path). Supply a nonexistent destination.", code: 73) } guard errno == ENOENT else { fail("Could not inspect progress file \(progressFile.path): \(String(cString: strerror(errno))).", code: 73) } } let configURL = PlayerConfiguration.fileURL(environment: ProcessInfo.processInfo.environment, homeDirectory: FileManager.default.homeDirectoryForCurrentUser) if !noConfig { do { _ = try PlayerConfiguration.load(from: configURL) } catch { fail(error.localizedDescription, code: 78) } } guard let executable = Bundle.main.executableURL else { fail("Could not locate the CLI executable.", code: 69) } let app = executable.resolvingSymlinksInPath().deletingLastPathComponent() .appendingPathComponent("terebi.app", isDirectory: true) if let error = FFmpegRuntime.error(for: app) { fail(error, code: 69) } let configuration = NSWorkspace.OpenConfiguration() configuration.createsNewApplicationInstance = newInstance // LaunchServices does not inherit the invoking shell's XDG environment. configuration.arguments = noConfig ? ["--no-config"] : ["--config-file", configURL.absoluteString] if let progressFile { configuration.arguments += ["--progress-file", progressFile.path] } if newInstance, let url { configuration.arguments += ["--open-media", url.absoluteString] } do { // Launch an application, not a document, so SwiftUI creates its singleton window. _ = try await NSWorkspace.shared.openApplication(at: app, configuration: configuration) if !newInstance, let url { _ = try await NSWorkspace.shared.open([url], withApplicationAt: app, configuration: configuration) } } catch { fail("Could not launch the player: \(error.localizedDescription)", code: 69) } } } private static func fail(_ message: String, code: Int32) -> Never { FileHandle.standardError.write(Data("terebi: \(message)\n".utf8)) exit(code) } }