mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 23:05:49 +00:00
- Swift helper: filter out untitled auxiliary windows from multi-window apps (e.g. Arc sidebar/tab-bar chrome) - Swift helper: increase minimum window size from 1x1 to 50x50 - Remove .filter(source => Boolean(source.thumbnail)) that hid valid sources - Remove hasUsableSourceThumbnail filter in fallback path - Recompile prebundled openscreen-window-list binary
156 lines
4.0 KiB
Swift
156 lines
4.0 KiB
Swift
import Foundation
|
|
import CoreGraphics
|
|
import ScreenCaptureKit
|
|
|
|
struct WindowListEntry: Codable {
|
|
let id: String
|
|
let name: String
|
|
let display_id: String
|
|
let appName: String?
|
|
let windowTitle: String?
|
|
let bundleId: String?
|
|
let x: Double
|
|
let y: Double
|
|
let width: Double
|
|
let height: Double
|
|
}
|
|
|
|
func normalize(_ value: String?) -> String? {
|
|
guard let rawValue = value?.trimmingCharacters(in: .whitespacesAndNewlines), !rawValue.isEmpty else {
|
|
return nil
|
|
}
|
|
|
|
return rawValue
|
|
}
|
|
|
|
let excludedBundleIds: Set<String> = [
|
|
"com.apple.controlcenter",
|
|
"com.apple.dock",
|
|
"com.apple.WindowManager",
|
|
"com.apple.wallpaper.agent",
|
|
]
|
|
|
|
let excludedWindowTitles: Set<String> = [
|
|
"Display 1 Backstop",
|
|
"Event Shield Window",
|
|
"Menubar",
|
|
"Offscreen Wallpaper Window",
|
|
"Wallpaper-",
|
|
]
|
|
|
|
// Force CoreGraphics Services initialization before asking ScreenCaptureKit for
|
|
// shareable content. Without this, the helper can stall sporadically when run
|
|
// as a standalone CLI process from Electron.
|
|
let _ = CGMainDisplayID()
|
|
|
|
let group = DispatchGroup()
|
|
group.enter()
|
|
|
|
Task {
|
|
do {
|
|
let shareableContent = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true)
|
|
|
|
struct RawWindowEntry {
|
|
let entry: WindowListEntry
|
|
let hasRawTitle: Bool
|
|
let bundleId: String?
|
|
}
|
|
|
|
let rawEntries = shareableContent.windows.compactMap { window -> RawWindowEntry? in
|
|
let appName = normalize(window.owningApplication?.applicationName)
|
|
let windowTitle = normalize(window.title)
|
|
let bundleId = normalize(window.owningApplication?.bundleIdentifier)
|
|
let frame = window.frame
|
|
|
|
guard window.windowLayer == 0 else {
|
|
return nil
|
|
}
|
|
|
|
guard frame.width >= 50, frame.height >= 50 else {
|
|
return nil
|
|
}
|
|
|
|
guard appName != nil || windowTitle != nil else {
|
|
return nil
|
|
}
|
|
|
|
if let bundleId, excludedBundleIds.contains(bundleId) {
|
|
return nil
|
|
}
|
|
|
|
if let windowTitle, excludedWindowTitles.contains(windowTitle) {
|
|
return nil
|
|
}
|
|
|
|
let matchedDisplay = shareableContent.displays.first(where: { display in
|
|
display.frame.intersects(frame) || display.frame.contains(CGPoint(x: frame.midX, y: frame.midY))
|
|
})
|
|
|
|
let resolvedWindowTitle = windowTitle ?? appName ?? "Window"
|
|
let resolvedName: String
|
|
if let appName, let windowTitle {
|
|
resolvedName = "\(appName) — \(windowTitle)"
|
|
} else {
|
|
resolvedName = resolvedWindowTitle
|
|
}
|
|
|
|
let entry = WindowListEntry(
|
|
id: "window:\(window.windowID):0",
|
|
name: resolvedName,
|
|
display_id: matchedDisplay.map { String($0.displayID) } ?? "",
|
|
appName: appName,
|
|
windowTitle: resolvedWindowTitle,
|
|
bundleId: bundleId,
|
|
x: Double(frame.origin.x),
|
|
y: Double(frame.origin.y),
|
|
width: Double(frame.width),
|
|
height: Double(frame.height)
|
|
)
|
|
|
|
return RawWindowEntry(entry: entry, hasRawTitle: windowTitle != nil, bundleId: bundleId)
|
|
}
|
|
|
|
// For apps with multiple windows, drop auxiliary windows that lack a
|
|
// distinct title (e.g. Arc's sidebar/tab-bar chrome). If ALL windows
|
|
// from an app lack titles, keep them all.
|
|
var titledCountByBundle: [String: Int] = [:]
|
|
for raw in rawEntries {
|
|
if let bid = raw.bundleId, raw.hasRawTitle {
|
|
titledCountByBundle[bid, default: 0] += 1
|
|
}
|
|
}
|
|
|
|
let entries = rawEntries
|
|
.filter { raw in
|
|
guard let bid = raw.bundleId else { return true }
|
|
if let titled = titledCountByBundle[bid], titled > 0 {
|
|
return raw.hasRawTitle
|
|
}
|
|
return true
|
|
}
|
|
.map { $0.entry }
|
|
.sorted { lhs, rhs in
|
|
let lhsApp = lhs.appName ?? lhs.name
|
|
let rhsApp = rhs.appName ?? rhs.name
|
|
if lhsApp != rhsApp {
|
|
return lhsApp.localizedCaseInsensitiveCompare(rhsApp) == .orderedAscending
|
|
}
|
|
|
|
return (lhs.windowTitle ?? lhs.name).localizedCaseInsensitiveCompare(rhs.windowTitle ?? rhs.name) == .orderedAscending
|
|
}
|
|
|
|
let encoder = JSONEncoder()
|
|
encoder.outputFormatting = [.sortedKeys]
|
|
let data = try encoder.encode(entries)
|
|
FileHandle.standardOutput.write(data)
|
|
} catch {
|
|
fputs("Error listing windows: \(error.localizedDescription)\n", stderr)
|
|
fflush(stderr)
|
|
exit(1)
|
|
}
|
|
|
|
group.leave()
|
|
}
|
|
|
|
group.wait()
|