tv-anarchy/Sources/TVAnarchyCore/Display/AudioOutputInfo.swift
Natalie 4a2ceb9781 feat(offline): inline star-to-keep and trash-to-cull on cache rows
Surface the existing pin (keep-from-cull) and per-file delete actions as
visible inline buttons on each offline cache row instead of context-menu-only:
a star toggles protection from auto-cull (and restore-if-missing), a trash
culls that file early. Aligns wording/icons to the star metaphor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:12:41 -04:00

47 lines
No EOL
2 KiB
Swift

import Foundation
/// One macOS audio output endpoint the HDMI sink that pairs with an external
/// display, or the built-in speakers on the laptop.
public struct AudioOutputInfo: Identifiable, Sendable, Equatable, Codable {
public var id: UInt32 { deviceId }
/// CoreAudio `AudioDeviceID` persisted as VLC's `auhal-audio-device`.
public let deviceId: UInt32
public let name: String
public let isBuiltIn: Bool
public init(deviceId: UInt32, name: String, isBuiltIn: Bool) {
self.deviceId = deviceId
self.name = name
self.isBuiltIn = isBuiltIn
}
public var shortLabel: String {
if isBuiltIn { return "Built-in Speakers" }
return name.isEmpty ? "External Audio" : name
}
/// Heuristic: laptop speakers / built-in headphone jack vs HDMI/DisplayPort sinks.
public static func inferBuiltIn(name: String) -> Bool {
let n = name.lowercased()
return n.contains("built-in") || n.hasSuffix("speakers")
}
/// Pick the audio sink that belongs with `display`. External displays are
/// matched by name (e.g. SAMSUNG display SAMSUNG HDMI); built-in falls back
/// to the laptop speakers rather than the system-default output device.
public static func pick(for display: DisplayInfo, from devices: [AudioOutputInfo]) -> AudioOutputInfo? {
guard !devices.isEmpty else { return nil }
if display.isBuiltIn {
return devices.first(where: \.isBuiltIn) ?? devices.first
}
let dn = display.name.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if !dn.isEmpty {
if let exact = devices.first(where: { $0.name.lowercased() == dn }) { return exact }
if let partial = devices.first(where: {
let n = $0.name.lowercased()
return n.contains(dn) || dn.contains(n)
}) { return partial }
}
return devices.first(where: { !$0.isBuiltIn }) ?? devices.first
}
}