feat: 支持双模式 exe 入口
This commit is contained in:
139
wechat_decrypt_launcher.py
Normal file
139
wechat_decrypt_launcher.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""WeChatDecrypt.exe 双模式入口。
|
||||
|
||||
无参数时启动 Web UI;带参数时分发到现有 CLI 脚本。该入口同时兼容
|
||||
PyInstaller onefile 里 Web UI 子进程使用的 ``sys.executable script.py``
|
||||
调用形态。
|
||||
"""
|
||||
|
||||
import os
|
||||
import runpy
|
||||
import sys
|
||||
|
||||
|
||||
MAIN_COMMANDS = {"decrypt", "export", "all", "status", "-s", "decode-images"}
|
||||
HELP_COMMANDS = {"help", "-h", "--help"}
|
||||
SCRIPT_ENTRYPOINTS = {
|
||||
"main.py",
|
||||
"monitor_web.py",
|
||||
"export_all_chats.py",
|
||||
"find_image_key.py",
|
||||
"decrypt_sns.py",
|
||||
"export_sns.py",
|
||||
"find_wxwork_keys.py",
|
||||
"decrypt_wxwork_db.py",
|
||||
"export_wxwork_messages.py",
|
||||
"voice_to_mp3.py",
|
||||
"batch_decrypt_images.py",
|
||||
"decrypt_db.py",
|
||||
}
|
||||
|
||||
|
||||
def _app_base_dir():
|
||||
if getattr(sys, "frozen", False):
|
||||
return os.path.dirname(sys.executable)
|
||||
return os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def _script_dir():
|
||||
return getattr(sys, "_MEIPASS", _app_base_dir())
|
||||
|
||||
|
||||
def _prepare_runtime():
|
||||
base_dir = _app_base_dir()
|
||||
os.environ["WECHAT_DECRYPT_APP_DIR"] = base_dir
|
||||
os.chdir(base_dir)
|
||||
|
||||
|
||||
def _configure_stdio():
|
||||
for stream in (sys.stdout, sys.stderr):
|
||||
if hasattr(stream, "reconfigure"):
|
||||
stream.reconfigure(encoding="utf-8", errors="replace")
|
||||
|
||||
|
||||
def print_usage(stream=None):
|
||||
stream = stream or sys.stdout
|
||||
stream.write(
|
||||
"WeChatDecrypt.exe 用法:\n"
|
||||
"\n"
|
||||
" WeChatDecrypt.exe 启动 Web UI\n"
|
||||
" WeChatDecrypt.exe web 启动 Web UI\n"
|
||||
" WeChatDecrypt.exe status 查看状态\n"
|
||||
" WeChatDecrypt.exe decrypt 提取密钥并解密数据库\n"
|
||||
" WeChatDecrypt.exe export [args...] 解密并批量导出聊天\n"
|
||||
" WeChatDecrypt.exe all 密钥 -> 解密 -> 导出\n"
|
||||
" WeChatDecrypt.exe decode-images [args...] 批量解密 .dat 图片\n"
|
||||
" WeChatDecrypt.exe export-all [args...] 直接调用 export_all_chats.py\n"
|
||||
"\n"
|
||||
"兼容脚本式调用:\n"
|
||||
" WeChatDecrypt.exe main.py decrypt\n"
|
||||
" WeChatDecrypt.exe export_all_chats.py --write-plan-csv export_plan.csv\n"
|
||||
)
|
||||
|
||||
|
||||
def _resolve_script(argv):
|
||||
if not argv:
|
||||
return "monitor_web.py", []
|
||||
|
||||
cmd = argv[0]
|
||||
if cmd == "web":
|
||||
return "monitor_web.py", argv[1:]
|
||||
if cmd in MAIN_COMMANDS:
|
||||
return "main.py", argv
|
||||
if cmd == "export-all":
|
||||
return "export_all_chats.py", argv[1:]
|
||||
if cmd in SCRIPT_ENTRYPOINTS:
|
||||
return cmd, argv[1:]
|
||||
return None, None
|
||||
|
||||
|
||||
def run_script(script, script_args):
|
||||
_prepare_runtime()
|
||||
script_path = os.path.join(_script_dir(), script)
|
||||
if not os.path.exists(script_path):
|
||||
script_path = os.path.join(_app_base_dir(), script)
|
||||
if not os.path.exists(script_path):
|
||||
raise FileNotFoundError(f"脚本不存在: {script_path}")
|
||||
|
||||
old_argv = sys.argv[:]
|
||||
try:
|
||||
sys.argv = [script] + list(script_args)
|
||||
try:
|
||||
runpy.run_path(script_path, run_name="__main__")
|
||||
except SystemExit as exc:
|
||||
if exc.code is None:
|
||||
return 0
|
||||
if isinstance(exc.code, int):
|
||||
return exc.code
|
||||
print(exc.code, file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
finally:
|
||||
sys.argv = old_argv
|
||||
|
||||
|
||||
def dispatch(argv=None, script_runner=None, stdout=None, stderr=None):
|
||||
argv = list(sys.argv[1:] if argv is None else argv)
|
||||
stdout = stdout or sys.stdout
|
||||
stderr = stderr or sys.stderr
|
||||
runner = script_runner or run_script
|
||||
|
||||
if argv and argv[0] in HELP_COMMANDS:
|
||||
print_usage(stdout)
|
||||
return 0
|
||||
|
||||
script, script_args = _resolve_script(argv)
|
||||
if script is None:
|
||||
print_usage(stdout)
|
||||
print(f"未知命令: {argv[0]}", file=stderr)
|
||||
return 2
|
||||
return runner(script, script_args)
|
||||
|
||||
|
||||
def main():
|
||||
_configure_stdio()
|
||||
sys.exit(dispatch())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user