# -*- coding: utf-8 -*- """ Data directory, profile path, CLI path debugging output. """ import os import re import sys from typing import Optional from jiangchang_skill_core.runtime_env import get_data_root, get_user_id from util.constants import SKILL_SLUG def get_skill_data_dir() -> str: path = os.path.join(get_data_root(), get_user_id(), SKILL_SLUG) os.makedirs(path, exist_ok=True) return path def get_db_path() -> str: return os.path.join(get_skill_data_dir(), "account-manager.db") def _runtime_paths_debug_text() -> str: """For debugging: print current data path info to stderr.""" env_root = (os.getenv("JIANGCHANG_DATA_ROOT") or "").strip() or "(未设置)" env_uid = (os.getenv("JIANGCHANG_USER_ID") or "").strip() or "(未设置→使用 _anon)" return ( "[account-manager] " f"JIANGCHANG_DATA_ROOT={env_root} | " f"JIANGCHANG_USER_ID={env_uid} | " f"实际数据根={get_data_root()} | " f"实际用户目录={get_user_id()} | " f"数据库文件={get_db_path()}" ) def _maybe_print_paths_debug_cli() -> None: """Set JIANGCHANG_ACCOUNT_DEBUG_PATHS=1 to print paths in stderr.""" v = (os.getenv("JIANGCHANG_ACCOUNT_DEBUG_PATHS") or "").strip().lower() if v in ("1", "true", "yes", "on"): print(_runtime_paths_debug_text(), file=sys.stderr) _WIN_FS_FORBIDDEN = re.compile(r'[<>:"/\\|?*\x00-\x1f]') _WIN_RESERVED_NAMES = frozenset( ["CON", "PRN", "AUX", "NUL"] + [f"COM{i}" for i in range(1, 10)] + [f"LPT{i}" for i in range(1, 10)] ) def _fs_safe_segment(name: str, fallback: str) -> str: """Single directory segment: strip Windows-unsafe chars; empty -> fallback.""" t = _WIN_FS_FORBIDDEN.sub("_", (name or "").strip()) t = t.rstrip(" .") if not t: t = fallback if t.upper() in _WIN_RESERVED_NAMES: t = f"_{t}" return t def get_default_profile_dir_for_web( platform_key: str, label: str, login_id: Optional[str] = None, domain: str = "generic", ) -> str: """ Generate a browser profile directory path. Structure: {DATA_ROOT}/{USER_ID}/account-manager/profiles/{domain}/{platform_key}/{safe_label}[_{login_id_suffix]/ This keeps profiles organized by domain and platform for easy identification in file explorer. """ label_seg = _fs_safe_segment(label, platform_key) login_suffix = "" if login_id: safe_login = _fs_safe_segment(login_id, "") if safe_login: login_suffix = f"_{safe_login[:16]}" path = os.path.join( get_skill_data_dir(), "profiles", _fs_safe_segment(domain, "generic"), _fs_safe_segment(platform_key, "unknown"), f"{label_seg}{login_suffix}", ) os.makedirs(path, exist_ok=True) return path