vOOice/VoiceInk/Services/BrowserURLService.swift
2025-02-22 11:52:41 +05:45

123 lines
3.6 KiB
Swift

import Foundation
import AppKit
enum BrowserType {
case safari
case arc
case chrome
case edge
case firefox
case brave
case opera
case vivaldi
case orion
case zen
var scriptName: String {
switch self {
case .safari: return "safariURL"
case .arc: return "arcURL"
case .chrome: return "chromeURL"
case .edge: return "edgeURL"
case .firefox: return "firefoxURL"
case .brave: return "braveURL"
case .opera: return "operaURL"
case .vivaldi: return "vivaldiURL"
case .orion: return "orionURL"
case .zen: return "zenURL"
}
}
var bundleIdentifier: String {
switch self {
case .safari: return "com.apple.Safari"
case .arc: return "company.thebrowser.Browser"
case .chrome: return "com.google.Chrome"
case .edge: return "com.microsoft.edgemac"
case .firefox: return "org.mozilla.firefox"
case .brave: return "com.brave.Browser"
case .opera: return "com.operasoftware.Opera"
case .vivaldi: return "com.vivaldi.Vivaldi"
case .orion: return "com.kagi.kagimacOS"
case .zen: return "app.zen-browser.zen"
}
}
var displayName: String {
switch self {
case .safari: return "Safari"
case .arc: return "Arc"
case .chrome: return "Google Chrome"
case .edge: return "Microsoft Edge"
case .firefox: return "Firefox"
case .brave: return "Brave"
case .opera: return "Opera"
case .vivaldi: return "Vivaldi"
case .orion: return "Orion"
case .zen: return "Zen Browser"
}
}
static var allCases: [BrowserType] {
[.safari, .arc, .chrome, .edge, .firefox, .brave, .opera, .vivaldi, .orion, .zen]
}
static var installedBrowsers: [BrowserType] {
allCases.filter { browser in
let workspace = NSWorkspace.shared
return workspace.urlForApplication(withBundleIdentifier: browser.bundleIdentifier) != nil
}
}
}
enum BrowserURLError: Error {
case scriptNotFound
case executionFailed
case browserNotRunning
case noActiveWindow
case noActiveTab
}
class BrowserURLService {
static let shared = BrowserURLService()
private init() {}
func getCurrentURL(from browser: BrowserType) async throws -> String {
guard let scriptURL = Bundle.main.url(forResource: browser.scriptName, withExtension: "scpt") else {
throw BrowserURLError.scriptNotFound
}
let task = Process()
task.launchPath = "/usr/bin/osascript"
task.arguments = [scriptURL.path]
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
do {
try task.run()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) {
if output.isEmpty {
throw BrowserURLError.noActiveTab
}
return output
} else {
throw BrowserURLError.executionFailed
}
} catch {
throw BrowserURLError.executionFailed
}
}
func isRunning(_ browser: BrowserType) -> Bool {
let workspace = NSWorkspace.shared
let runningApps = workspace.runningApplications
return runningApps.contains { $0.bundleIdentifier == browser.bundleIdentifier }
}
}