File size: 5,941 Bytes
d3cadd5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | """浏览器检测和打开"""
import os
import shlex
import shutil
import subprocess
import platform
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class BrowserInfo:
id: str
name: str
path: str
supports_incognito: bool
incognito_arg: str = ""
# 浏览器配置
BROWSER_CONFIGS = {
"chrome": {
"names": ["google-chrome", "google-chrome-stable", "chrome", "chromium", "chromium-browser"],
"display": "Chrome",
"incognito": "--incognito",
},
"firefox": {
"names": ["firefox", "firefox-esr"],
"display": "Firefox",
"incognito": "--private-window",
},
"edge": {
"names": ["microsoft-edge", "microsoft-edge-stable", "msedge"],
"display": "Edge",
"incognito": "--inprivate",
},
"brave": {
"names": ["brave", "brave-browser"],
"display": "Brave",
"incognito": "--incognito",
},
"opera": {
"names": ["opera"],
"display": "Opera",
"incognito": "--private",
},
"vivaldi": {
"names": ["vivaldi", "vivaldi-stable"],
"display": "Vivaldi",
"incognito": "--incognito",
},
}
def detect_browsers() -> List[BrowserInfo]:
"""检测系统安装的浏览器"""
browsers = []
system = platform.system().lower()
if system == "windows":
import winreg
def normalize_exe_path(raw: str) -> Optional[str]:
if not raw:
return None
expanded = os.path.expandvars(raw.strip())
try:
parts = shlex.split(expanded, posix=False)
except ValueError:
parts = [expanded]
candidate = (parts[0] if parts else expanded).strip().strip('"')
if os.path.exists(candidate):
return candidate
lower = expanded.lower()
exe_idx = lower.find(".exe")
if exe_idx != -1:
candidate = expanded[:exe_idx + 4].strip().strip('"')
if os.path.exists(candidate):
return candidate
return None
def get_reg_path(exe_name: str) -> Optional[str]:
name = f"{exe_name}.exe"
for root in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER):
try:
with winreg.OpenKey(root, rf"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{name}") as key:
value, _ = winreg.QueryValueEx(key, "")
path = normalize_exe_path(value)
if path:
return path
except (FileNotFoundError, OSError, WindowsError):
pass
return None
for browser_id, config in BROWSER_CONFIGS.items():
path = None
for exe_name in config["names"]:
path = get_reg_path(exe_name)
if path:
break
if not path:
for exe_name in config["names"]:
path = shutil.which(exe_name)
if path:
break
if path:
browsers.append(BrowserInfo(
id=browser_id,
name=config["display"],
path=path,
supports_incognito=bool(config.get("incognito")),
incognito_arg=config.get("incognito", ""),
))
else:
for browser_id, config in BROWSER_CONFIGS.items():
for name in config["names"]:
path = shutil.which(name)
if path:
browsers.append(BrowserInfo(
id=browser_id,
name=config["display"],
path=path,
supports_incognito=bool(config.get("incognito")),
incognito_arg=config.get("incognito", ""),
))
break
# 添加默认浏览器选项
if browsers:
browsers.insert(0, BrowserInfo(
id="default",
name="默认浏览器",
path="xdg-open" if system == "linux" else "open",
supports_incognito=False,
incognito_arg="",
))
return browsers
def open_url(url: str, browser_id: str = "default", incognito: bool = False) -> bool:
"""用指定浏览器打开 URL"""
browsers = detect_browsers()
browser = next((b for b in browsers if b.id == browser_id), None)
if not browser:
# 降级到默认
browser = browsers[0] if browsers else None
if not browser:
return False
try:
if browser.id == "default":
# 使用系统默认浏览器
system = platform.system().lower()
if system == "linux":
subprocess.Popen(["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
elif system == "darwin":
subprocess.Popen(["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else:
os.startfile(url)
else:
# 使用指定浏览器
args = [browser.path]
if incognito and browser.supports_incognito and browser.incognito_arg:
args.append(browser.incognito_arg)
args.append(url)
subprocess.Popen(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return True
except Exception as e:
print(f"[Browser] 打开失败: {e}")
return False
def get_browsers_info() -> List[dict]:
"""获取浏览器信息列表"""
return [
{
"id": b.id,
"name": b.name,
"supports_incognito": b.supports_incognito,
}
for b in detect_browsers()
]
|