import CoreMedia import DropTwoCore import Foundation // Prüfstein fürs Core-Framework (Schritt 3 der Umsetzungsreihenfolge): // echte Dateien durchjagen und die Ausgabequalität von CropEngine bewerten. // Nutzt dieselbe ConversionPipeline wie später die App, damit CLI und // Oberfläche garantiert dasselbe tun. let arguments = Array(CommandLine.arguments.dropFirst()) guard arguments.count >= 2 else { print("Usage: droptwo [ ...]") exit(0) } let outputDirectory = URL(fileURLWithPath: arguments[0], isDirectory: true) let sourcePaths = arguments.dropFirst() func describe(_ info: VideoInfo) -> String { let seconds = CMTimeGetSeconds(info.duration) return "\(Int(info.pixelSize.width))×\(Int(info.pixelSize.height)), \(info.codec), " + "\(String(format: "%.2f", info.frameRate)) fps, \(String(format: "%.2f", seconds))s, " + "Audio: \(info.hasAudioTrack ? "ja" : "nein")" } func fileSizeInMB(_ url: URL) -> Double? { guard let size = try? FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int else { return nil } return Double(size) / 1_000_000 } for sourcePath in sourcePaths { let sourceURL = URL(fileURLWithPath: sourcePath) let fileName = sourceURL.lastPathComponent let start = Date() let outcome = await ConversionPipeline.process(sourceURL: sourceURL, outputRootDirectory: outputDirectory) switch outcome { case .skipped(let fileName, let reason): print("\(fileName): übersprungen (\(reason))") case .rejected(let fileName, let reason): print("\(fileName): abgelehnt (\(reason))") case .failed(let fileName, let error): print("\(fileName): Fehler — \(error)") case .succeeded(let success): let elapsed = Date().timeIntervalSince(start) let sizeMB = fileSizeInMB(success.croppedDestination).map { String(format: "%.1f MB", $0) } ?? "?" print(fileName) print(" Quelle: \(describe(success.sourceInfo))") print(" -> \(success.croppedDestination.lastPathComponent): \(describe(success.croppedInfo)), \(sizeMB), \(String(format: "%.1f", elapsed))s Renderzeit") } }