# -*- coding: utf-8 -*- """在 Profile 目录内创建浏览器快捷方式(Windows .lnk)。""" from __future__ import annotations import logging import os import re import subprocess import sys from typing import Optional from service.browser_service import resolve_chromium_executable _WIN_LNK_FORBIDDEN = re.compile(r'[<>:"/\\|?*\x00-\x1f]') def _lnk_safe_filename(name: str, fallback: str = "browser") -> str: t = _WIN_LNK_FORBIDDEN.sub("_", (name or "").strip()) t = t.rstrip(" .") return t or fallback def _ps_single_quote(value: str) -> str: return "'" + value.replace("'", "''") + "'" def create_profile_browser_shortcut( profile_dir: str, account_label: str, log: Optional[logging.Logger] = None, ) -> Optional[str]: """ 在 profile_dir 内创建 {account_label}.lnk,目标为系统 Chrome/Edge + --user-data-dir。 非 Windows 或未安装 Chrome/Edge 时静默跳过,返回 None。 成功返回 .lnk 绝对路径。 """ if log is None: log = logging.getLogger(__name__) if sys.platform != "win32": log.debug("profile_shortcut_skip platform=%s", sys.platform) return None browser_exe = resolve_chromium_executable() if not browser_exe: log.warning("profile_shortcut_skip reason=no_chromium") return None profile_abs = os.path.abspath(profile_dir) os.makedirs(profile_abs, exist_ok=True) lnk_name = f"{_lnk_safe_filename(account_label)}.lnk" lnk_path = os.path.join(profile_abs, lnk_name) arguments = f'--user-data-dir="{profile_abs}"' working_dir = os.path.dirname(browser_exe) ps = ( "$WshShell = New-Object -ComObject WScript.Shell; " f"$s = $WshShell.CreateShortcut({_ps_single_quote(lnk_path)}); " f"$s.TargetPath = {_ps_single_quote(browser_exe)}; " f"$s.Arguments = {_ps_single_quote(arguments)}; " f"$s.IconLocation = {_ps_single_quote(browser_exe + ',0')}; " f"$s.WorkingDirectory = {_ps_single_quote(working_dir)}; " "$s.Save()" ) try: subprocess.run( ["powershell", "-NoProfile", "-NonInteractive", "-Command", ps], check=True, capture_output=True, text=True, ) except (OSError, subprocess.CalledProcessError) as exc: log.warning("profile_shortcut_failed profile_dir=%s error=%s", profile_abs, exc) return None if not os.path.isfile(lnk_path): log.warning("profile_shortcut_missing_after_create path=%s", lnk_path) return None log.info("profile_shortcut_created path=%s browser=%s", lnk_path, browser_exe) return lnk_path