ascript 1.3.2__tar.gz → 1.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ascript-1.3.2 → ascript-1.3.4}/PKG-INFO +1 -1
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/env.py +3 -31
- ascript-1.3.4/ascript/windows/system/pip.py +175 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/app_store_window.html +26 -2
- ascript-1.3.4/ascript/windows/ui/web_window.py +268 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript.egg-info/PKG-INFO +1 -1
- {ascript-1.3.2 → ascript-1.3.4}/pyproject.toml +1 -1
- ascript-1.3.2/ascript/windows/system/pip.py +0 -122
- ascript-1.3.2/ascript/windows/ui/web_window.py +0 -117
- {ascript-1.3.2 → ascript-1.3.4}/MANIFEST.in +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/README.md +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/hooks/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/hooks/hook-ascript.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/daos/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/daos/screen.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/hardware/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/hardware/keyboard.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/hardware/logitech_driver.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/hardware/mouse.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp310-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp311-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp312-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp313-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp314-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp38-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/license/achttp.cp39-win_amd64.pyd +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/media/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/libs/logitech/x64/LogitechGkeyEnginesWrapper.dll +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/libs/logitech/x86/LogitechGkeyEnginesWrapper.dll +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/__init__py.win.template +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/build.as.win.template +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/build.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/logo_windows.ico +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/windows/main.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/windows/pyproject.toml +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/resources/templates/windows/res/img/logo.ico +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/as_cv.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/find_colors.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/find_images.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/ocr/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/ocr/rapidocr_hook.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/screen/screen_core.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/store/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/device.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/easy_print.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/exception/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/key_value.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/r.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/system/runtime.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/__init__.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/action.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/action.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/action.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/action.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/colors_tool.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/colors_tool.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/colors_tool.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/colors_tool.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/config.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/config.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/config.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/config.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/dumptool.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/dumptool.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/dumptool.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/dumptool.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/eel_api.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/eel_api.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/eel_api.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/eel_api.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/mouse_catch.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/mouse_catch.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/mouse_catch.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/mouse_catch.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/plug_manager.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/plug_manager.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/plug_manager.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/__pycache__/plug_manager.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/action.json +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/action.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/colors_tool.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/config.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/dumptool.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/eel_api.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/__init__.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/__init__.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/__init__.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/__init__.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/plug.cpython-310.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/plug.cpython-312.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/plug.cpython-313.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/__pycache__/plug.cpython-39.pyc +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/gpplug/plug.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/mouse_catch.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/plug_manager.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/colors.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/css/screen.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/css/viewtree.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/flot_control.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/ico/favicon.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/ico/paintpalette.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/svg/find_colors.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/svg/find_images.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/svg/illustration-6.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/svg/img_default.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/img/svg/ocr.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/colors.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/gp_plug.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/image_mouse.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/img_view.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/plug.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/screen.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/screen_api.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/screen/screen_maker.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/utils/map.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/utils/upload.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/viewtree/niv_js.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/js/viewtree/vtree.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap/css/bootstrap.min.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap/js/bootstrap.bundle.min.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/0-circle.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/0-square.svg +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.json +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.min.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.scss +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/feather-icons/dist/feather.min.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/feather-icons/dist/icons.json +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/core.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/jquery.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/jquery.min.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/jquery.min.js.zip +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/jquery.slim.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery/jquery.slim.min.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.min.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/css/zTreeStyle.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_close.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_open.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/2.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/3.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/4.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/5.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/6.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/7.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/8.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/diy/9.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/line_conn.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/loading.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/tree-node-btn.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/jquery-zTree/js/jquery.ztree.all.min.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/css/jquery.treeview.css +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/file.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/ico_loading.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/icon4.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/icon5.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/icon6.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/py.png +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-black-line.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-black.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-default-line.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-default.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam-line.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-gray-line.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-gray.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-red-line.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/img/treeview-red.gif +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/js/jquery.treeview.edit.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/libs/treeview/js/jquery.treeview.js +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/license_window.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/plugs/a.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/plugs/demo.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/plugs/find_colors.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/plugs/find_images.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/plugs/rapidocr.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/tools/web/vtree.html +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/app_store_window.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/draw_window.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/flot_test.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/flot_window.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/ui/license_window.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/utils/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/utils/node_utils.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/utils/screen_utils.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/window/Selector.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/window/Window.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/window/__init__.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript/windows/window/launcher.py +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript.egg-info/SOURCES.txt +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript.egg-info/dependency_links.txt +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript.egg-info/requires.txt +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/ascript.egg-info/top_level.txt +0 -0
- {ascript-1.3.2 → ascript-1.3.4}/setup.cfg +0 -0
|
@@ -7,7 +7,8 @@ import ctypes
|
|
|
7
7
|
import psutil
|
|
8
8
|
import time
|
|
9
9
|
from pkginfo import Wheel # 确保主环境已安装 pkginfo
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
from .pip import Pip
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
CREATE_NEW_CONSOLE = 0x00000010
|
|
@@ -214,35 +215,6 @@ class EnvManager:
|
|
|
214
215
|
shutil.rmtree(env_dir, ignore_errors=True)
|
|
215
216
|
return False
|
|
216
217
|
|
|
217
|
-
def _get_best_index(self):
|
|
218
|
-
"""测速选择最快的 PyPI 镜像源。
|
|
219
|
-
|
|
220
|
-
对比官方源和清华源的响应时间,返回延迟最低的源地址。
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
str: 最快的 PyPI 镜像源 URL。
|
|
224
|
-
"""
|
|
225
|
-
sources = {
|
|
226
|
-
"tsinghua": "https://pypi.tuna.tsinghua.edu.cn/simple",
|
|
227
|
-
"pypi": "https://pypi.org/simple"
|
|
228
|
-
}
|
|
229
|
-
best_url = sources["pypi"] # 默认官方兜底
|
|
230
|
-
min_time = 999.0
|
|
231
|
-
|
|
232
|
-
for name, url in sources.items():
|
|
233
|
-
try:
|
|
234
|
-
start = time.time()
|
|
235
|
-
# timeout 设短一点,1秒内没反应就说明该源当前不佳
|
|
236
|
-
with urllib.request.urlopen(url, timeout=1.0) as res:
|
|
237
|
-
if res.getcode() == 200:
|
|
238
|
-
duration = time.time() - start
|
|
239
|
-
if duration < min_time:
|
|
240
|
-
min_time = duration
|
|
241
|
-
best_url = url
|
|
242
|
-
except:
|
|
243
|
-
continue
|
|
244
|
-
return best_url
|
|
245
|
-
|
|
246
218
|
def _execute_combined_install(self, user_id, wheel_path, env_dir, show_console):
|
|
247
219
|
"""分三步部署: 创建 venv → 自检 venv python.exe → pip 安装 wheel。
|
|
248
220
|
|
|
@@ -292,7 +264,7 @@ class EnvManager:
|
|
|
292
264
|
f" 提示: {hint}"
|
|
293
265
|
)
|
|
294
266
|
|
|
295
|
-
index_url =
|
|
267
|
+
index_url = Pip.get_best_index()
|
|
296
268
|
print(f"[{user_id}] 自动择源完成,选用: {index_url}")
|
|
297
269
|
timeout = getattr(self, 'config', {}).get('timeout', 15)
|
|
298
270
|
pip_args = [
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
import re
|
|
4
|
+
import time
|
|
5
|
+
import threading
|
|
6
|
+
import urllib.request
|
|
7
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Pip:
|
|
11
|
+
"""
|
|
12
|
+
Python 包管理工具类,具备自动择源功能。
|
|
13
|
+
"""
|
|
14
|
+
# 备选镜像源列表
|
|
15
|
+
MIRRORS = {
|
|
16
|
+
"tsinghua": "https://pypi.tuna.tsinghua.edu.cn/simple",
|
|
17
|
+
"aliyun": "https://mirrors.aliyun.com/pypi/simple/",
|
|
18
|
+
"ustc": "https://pypi.mirrors.ustc.edu.cn/simple/",
|
|
19
|
+
"pypi": "https://pypi.org/simple",
|
|
20
|
+
}
|
|
21
|
+
# 兜底源:所有探测都失败时使用,绝不拿慢的官方源兜底
|
|
22
|
+
_FALLBACK_INDEX = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
23
|
+
|
|
24
|
+
# 吞吐探测参数:单源最多下 1.5 秒 或 3MB 即停;连接超时 2 秒
|
|
25
|
+
_PROBE_TIME_BUDGET = 1.5
|
|
26
|
+
_PROBE_SIZE_CAP = 3 * 1024 * 1024
|
|
27
|
+
_PROBE_CONNECT_TIMEOUT = 2.0
|
|
28
|
+
|
|
29
|
+
# 进程内缓存:择源结果复用,避免每装一个包都重新测速
|
|
30
|
+
_cached_index = None
|
|
31
|
+
_cache_lock = threading.Lock()
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def _probe_throughput(url: str) -> float:
|
|
35
|
+
"""限量下载该镜像的 simple 索引,返回实测吞吐量(字节/秒)。失败返回 0。
|
|
36
|
+
|
|
37
|
+
测的是真实下载速度而非连接延迟 —— 镜像源常见"连得上但限速",
|
|
38
|
+
延迟低不代表下得快。
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
req = urllib.request.Request(url, headers={"User-Agent": "ascript-pip-probe"})
|
|
42
|
+
start = time.time()
|
|
43
|
+
downloaded = 0
|
|
44
|
+
with urllib.request.urlopen(req, timeout=Pip._PROBE_CONNECT_TIMEOUT) as resp:
|
|
45
|
+
if resp.getcode() != 200:
|
|
46
|
+
return 0.0
|
|
47
|
+
while True:
|
|
48
|
+
chunk = resp.read(64 * 1024)
|
|
49
|
+
if not chunk:
|
|
50
|
+
break
|
|
51
|
+
downloaded += len(chunk)
|
|
52
|
+
if (time.time() - start) >= Pip._PROBE_TIME_BUDGET \
|
|
53
|
+
or downloaded >= Pip._PROBE_SIZE_CAP:
|
|
54
|
+
break
|
|
55
|
+
elapsed = time.time() - start
|
|
56
|
+
if elapsed <= 0 or downloaded == 0:
|
|
57
|
+
return 0.0
|
|
58
|
+
return downloaded / elapsed
|
|
59
|
+
except Exception:
|
|
60
|
+
return 0.0
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def get_best_index() -> str:
|
|
64
|
+
"""并行测各镜像的实测下载吞吐量,返回最快的源。结果进程内缓存。"""
|
|
65
|
+
if Pip._cached_index:
|
|
66
|
+
return Pip._cached_index
|
|
67
|
+
|
|
68
|
+
with Pip._cache_lock:
|
|
69
|
+
if Pip._cached_index: # 双重检查,避免并发安装时重复测速
|
|
70
|
+
return Pip._cached_index
|
|
71
|
+
|
|
72
|
+
# 预填所有键:worker 只更新值、不新增键,这样万一 join 超时后掉队
|
|
73
|
+
# 线程仍在写,下面 max() 遍历也不会撞上"字典大小被改"。
|
|
74
|
+
results = {name: 0.0 for name in Pip.MIRRORS}
|
|
75
|
+
|
|
76
|
+
def worker(name, url):
|
|
77
|
+
results[name] = Pip._probe_throughput(url)
|
|
78
|
+
|
|
79
|
+
threads = [
|
|
80
|
+
threading.Thread(target=worker, args=(n, u), daemon=True)
|
|
81
|
+
for n, u in Pip.MIRRORS.items()
|
|
82
|
+
]
|
|
83
|
+
for t in threads:
|
|
84
|
+
t.start()
|
|
85
|
+
# join 超时仅作兜底(探测线程内部已有超时,正常 3.5s 内结束);
|
|
86
|
+
# 必须长于单次探测最坏耗时 = 连接超时 + 下载预算。
|
|
87
|
+
for t in threads:
|
|
88
|
+
t.join(timeout=Pip._PROBE_CONNECT_TIMEOUT + Pip._PROBE_TIME_BUDGET + 1.0)
|
|
89
|
+
|
|
90
|
+
best = max(results, key=results.get)
|
|
91
|
+
Pip._cached_index = Pip.MIRRORS[best] if results[best] > 0 \
|
|
92
|
+
else Pip._FALLBACK_INDEX
|
|
93
|
+
return Pip._cached_index
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def is_installed(package_spec: str) -> bool:
|
|
97
|
+
"""检查指定包是否已安装。
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
package_spec: 包名或带版本约束的包规范,如 "requests" 或 "requests>=2.28"。
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
bool: 已安装返回 True,未安装返回 False。
|
|
104
|
+
"""
|
|
105
|
+
package_name = re.split(r'[<>=!]', package_spec)[0].strip()
|
|
106
|
+
try:
|
|
107
|
+
version(package_name)
|
|
108
|
+
return True
|
|
109
|
+
except PackageNotFoundError:
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def install(package_spec: str, upgrade: bool = False, index_url: str = None) -> bool:
|
|
114
|
+
"""安装 Python 包。
|
|
115
|
+
|
|
116
|
+
如果未指定 index_url,则自动测速选择最快的镜像源进行安装。
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
package_spec: 包名或带版本约束的包规范,如 "requests>=2.28"。
|
|
120
|
+
upgrade: 是否升级到最新版本,默认 False。
|
|
121
|
+
index_url: 指定的 PyPI 镜像源 URL,默认 None(自动择源)。
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
bool: 安装成功返回 True,失败返回 False。
|
|
125
|
+
"""
|
|
126
|
+
# 自动择源逻辑
|
|
127
|
+
target_index = index_url if index_url else Pip.get_best_index()
|
|
128
|
+
|
|
129
|
+
command = [sys.executable, "-m", "pip", "install", package_spec]
|
|
130
|
+
|
|
131
|
+
if target_index:
|
|
132
|
+
command.extend(["-i", target_index])
|
|
133
|
+
if target_index.startswith("http://"):
|
|
134
|
+
host = target_index.split("/")[2].split(":")[0]
|
|
135
|
+
command.extend(["--trusted-host", host])
|
|
136
|
+
|
|
137
|
+
if upgrade:
|
|
138
|
+
command.append("--upgrade")
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
subprocess.check_call(command)
|
|
142
|
+
return True
|
|
143
|
+
except subprocess.CalledProcessError:
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def ensure(package_spec: str, index_url: str = None) -> bool:
|
|
148
|
+
"""确保指定包已安装,未安装则自动安装。
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
package_spec: 包名或带版本约束的包规范。
|
|
152
|
+
index_url: 指定的 PyPI 镜像源 URL,默认 None(自动择源)。
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
bool: 包已存在或安装成功返回 True,安装失败返回 False。
|
|
156
|
+
"""
|
|
157
|
+
if Pip.is_installed(package_spec):
|
|
158
|
+
return True
|
|
159
|
+
return Pip.install(package_spec, index_url=index_url)
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def remove(package_name: str) -> bool:
|
|
163
|
+
"""卸载指定的 Python 包。
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
package_name: 要卸载的包名。
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
bool: 卸载成功返回 True,失败返回 False。
|
|
170
|
+
"""
|
|
171
|
+
try:
|
|
172
|
+
subprocess.check_call([sys.executable, "-m", "pip", "uninstall", package_name, "-y"])
|
|
173
|
+
return True
|
|
174
|
+
except subprocess.CalledProcessError:
|
|
175
|
+
return False
|
|
@@ -192,6 +192,14 @@
|
|
|
192
192
|
let isDeploying = false;
|
|
193
193
|
let lastKnownRunning = false;
|
|
194
194
|
|
|
195
|
+
// 诊断:直连 pywebview 桥接写日志,不走 callPython(callPython 本身可能是故障点)
|
|
196
|
+
function _jslog(m) {
|
|
197
|
+
try { window.pywebview.api.call_internal('_diag', ['JS: ' + m]); } catch (e) {}
|
|
198
|
+
}
|
|
199
|
+
let _initStarted = false;
|
|
200
|
+
_jslog('inline script started, callPython=' + (typeof window.callPython)
|
|
201
|
+
+ ', pywebview=' + (typeof window.pywebview));
|
|
202
|
+
|
|
195
203
|
window.updateDownloadProgress = function(percent) {
|
|
196
204
|
const progressBg = document.getElementById('btn-progress');
|
|
197
205
|
const btnText = document.getElementById('btn-text');
|
|
@@ -331,9 +339,15 @@
|
|
|
331
339
|
|
|
332
340
|
// 其余函数 (init, goBack, renderDetailPage等) 全部保持不变...
|
|
333
341
|
async function init() {
|
|
342
|
+
if (_initStarted) { _jslog('init() re-entry blocked'); return; }
|
|
343
|
+
_initStarted = true;
|
|
344
|
+
_jslog('init() START');
|
|
334
345
|
try {
|
|
346
|
+
_jslog('init: before refreshHistory');
|
|
335
347
|
await refreshHistory();
|
|
348
|
+
_jslog('init: before get_init_config');
|
|
336
349
|
const config = await window.callPython("get_init_config");
|
|
350
|
+
_jslog('init: get_init_config -> ' + JSON.stringify(config));
|
|
337
351
|
if (config && config.default_id) {
|
|
338
352
|
isSingleAppMode = true;
|
|
339
353
|
await handleSearch(config.default_id);
|
|
@@ -342,7 +356,8 @@
|
|
|
342
356
|
document.getElementById('home-page').style.display = 'flex';
|
|
343
357
|
requestAnimationFrame(() => { setTimeout(hideLoader, 50); });
|
|
344
358
|
}
|
|
345
|
-
|
|
359
|
+
_jslog('init() DONE');
|
|
360
|
+
} catch (e) { _jslog('init() CATCH: ' + e); hideLoader(); }
|
|
346
361
|
}
|
|
347
362
|
|
|
348
363
|
async function refreshHistory() {
|
|
@@ -396,6 +411,7 @@
|
|
|
396
411
|
}
|
|
397
412
|
|
|
398
413
|
function hideLoader() {
|
|
414
|
+
_jslog('hideLoader called');
|
|
399
415
|
const loader = document.getElementById('init-loader');
|
|
400
416
|
if (loader.style.display === 'none') return;
|
|
401
417
|
loader.style.opacity = '0';
|
|
@@ -451,7 +467,15 @@
|
|
|
451
467
|
refreshHistory();
|
|
452
468
|
}
|
|
453
469
|
|
|
454
|
-
|
|
470
|
+
// 同时兼容两种时序:注入早于本脚本时直接执行,否则等待事件
|
|
471
|
+
_jslog('script bottom, callPython=' + (typeof window.callPython));
|
|
472
|
+
if (window.callPython) {
|
|
473
|
+
_jslog('taking direct init() path');
|
|
474
|
+
init();
|
|
475
|
+
} else {
|
|
476
|
+
_jslog('registering onPythonReady listener');
|
|
477
|
+
window.addEventListener('onPythonReady', init);
|
|
478
|
+
}
|
|
455
479
|
</script>
|
|
456
480
|
</body>
|
|
457
481
|
</html>
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import subprocess
|
|
3
|
+
import tempfile
|
|
4
|
+
import ctypes
|
|
5
|
+
import webbrowser
|
|
6
|
+
import datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import webview
|
|
10
|
+
import os
|
|
11
|
+
from typing import Optional, Callable, Dict
|
|
12
|
+
|
|
13
|
+
# WebView2 运行时:官方下载页 + 常青版引导安装器(约 2MB,联网拉取完整运行时)
|
|
14
|
+
_WEBVIEW2_DOWNLOAD_URL = "https://developer.microsoft.com/microsoft-edge/webview2/"
|
|
15
|
+
_WEBVIEW2_BOOTSTRAPPER_URL = "https://go.microsoft.com/fwlink/p/?LinkId=2124703"
|
|
16
|
+
|
|
17
|
+
# 诊断日志:定位握手故障点,写到用户主目录
|
|
18
|
+
_DIAG_LOG = os.path.join(os.path.expanduser("~"), "ascript_diag.log")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _diag(msg, reset=False):
|
|
22
|
+
"""把诊断信息写入 ~/ascript_diag.log。reset=True 时清空重写。"""
|
|
23
|
+
try:
|
|
24
|
+
mode = "w" if reset else "a"
|
|
25
|
+
ts = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|
26
|
+
with open(_DIAG_LOG, mode, encoding="utf-8") as f:
|
|
27
|
+
f.write(f"[{ts}] {msg}\n")
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Win32 MessageBox 标志位与返回值
|
|
33
|
+
_MB_YESNO = 0x04
|
|
34
|
+
_MB_ICONERROR = 0x10
|
|
35
|
+
_MB_ICONWARNING = 0x30
|
|
36
|
+
_MB_ICONINFORMATION = 0x40
|
|
37
|
+
_IDYES = 6
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _msgbox(text: str, title: str = "AScript", style: int = _MB_ICONERROR) -> int:
|
|
41
|
+
"""弹出 Windows 原生消息框。"""
|
|
42
|
+
return ctypes.windll.user32.MessageBoxW(0, text, title, style)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _install_webview2() -> bool:
|
|
46
|
+
"""下载并静默安装 WebView2 Runtime。成功返回 True。"""
|
|
47
|
+
try:
|
|
48
|
+
import requests
|
|
49
|
+
bootstrapper = os.path.join(tempfile.gettempdir(), "MicrosoftEdgeWebview2Setup.exe")
|
|
50
|
+
_diag("downloading WebView2 bootstrapper")
|
|
51
|
+
with requests.get(_WEBVIEW2_BOOTSTRAPPER_URL, stream=True, timeout=120) as resp:
|
|
52
|
+
resp.raise_for_status()
|
|
53
|
+
with open(bootstrapper, "wb") as f:
|
|
54
|
+
for chunk in resp.iter_content(chunk_size=1024 * 64):
|
|
55
|
+
f.write(chunk)
|
|
56
|
+
_diag("running WebView2 bootstrapper /silent /install")
|
|
57
|
+
result = subprocess.run([bootstrapper, "/silent", "/install"], timeout=600)
|
|
58
|
+
_diag(f"WebView2 installer returncode={result.returncode}")
|
|
59
|
+
return result.returncode == 0
|
|
60
|
+
except Exception as e:
|
|
61
|
+
_diag(f"WebView2 install failed: {e!r}")
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _install_webview2_with_ui() -> bool:
|
|
66
|
+
"""带进度窗口地安装 WebView2。MS 静默安装器不汇报百分比,
|
|
67
|
+
故用滚动式(不确定模式)进度条表示"正在进行"。tkinter 不可用时退化为无窗口安装。"""
|
|
68
|
+
state = {"ok": False, "done": False}
|
|
69
|
+
|
|
70
|
+
def worker():
|
|
71
|
+
state["ok"] = _install_webview2()
|
|
72
|
+
state["done"] = True
|
|
73
|
+
|
|
74
|
+
t = threading.Thread(target=worker, daemon=True)
|
|
75
|
+
t.start()
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
import tkinter as tk
|
|
79
|
+
from tkinter import ttk
|
|
80
|
+
|
|
81
|
+
root = tk.Tk()
|
|
82
|
+
root.title("AScript - 安装运行环境")
|
|
83
|
+
root.resizable(False, False)
|
|
84
|
+
w, h = 400, 140
|
|
85
|
+
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
|
|
86
|
+
root.geometry(f"{w}x{h}+{(sw - w) // 2}+{(sh - h) // 2}")
|
|
87
|
+
root.attributes("-topmost", True)
|
|
88
|
+
root.protocol("WM_DELETE_WINDOW", lambda: None) # 安装中禁止关闭
|
|
89
|
+
|
|
90
|
+
tk.Label(root, text="正在下载并安装 Microsoft Edge WebView2 运行时").pack(pady=(26, 4))
|
|
91
|
+
tk.Label(root, text="约需 1-2 分钟,请勿关闭此窗口...", fg="#666").pack()
|
|
92
|
+
bar = ttk.Progressbar(root, mode="indeterminate", length=340)
|
|
93
|
+
bar.pack(pady=18)
|
|
94
|
+
bar.start(15)
|
|
95
|
+
|
|
96
|
+
def poll():
|
|
97
|
+
if state["done"]:
|
|
98
|
+
bar.stop()
|
|
99
|
+
root.destroy()
|
|
100
|
+
else:
|
|
101
|
+
root.after(200, poll)
|
|
102
|
+
|
|
103
|
+
root.after(200, poll)
|
|
104
|
+
root.mainloop()
|
|
105
|
+
except Exception as e:
|
|
106
|
+
_diag(f"progress UI unavailable, installing without it: {e!r}")
|
|
107
|
+
t.join() # 没有 UI 也要等安装完成
|
|
108
|
+
|
|
109
|
+
return state["ok"]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# 注入到页面的桥接代码:定义 callPython 并派发 onPythonReady。
|
|
113
|
+
# 故意使用现代语法(async / ...rest)—— 既是功能需要,也是引擎能力探针:
|
|
114
|
+
# 真正的 WebView2/Chromium 能解析,IE/MSHTML 会抛 SyntaxError。
|
|
115
|
+
# IIFE + callPython 存在性判断 → 多次注入也幂等。
|
|
116
|
+
_INJECTION_CODE = """
|
|
117
|
+
(function () {
|
|
118
|
+
if (window.callPython) { return; }
|
|
119
|
+
window.callPython = async function (fnName, ...args) {
|
|
120
|
+
return await window.pywebview.api.call_internal(fnName, args);
|
|
121
|
+
};
|
|
122
|
+
try { window.pywebview.api.call_internal('_diag', ['JS: callPython injected']); } catch (e) {}
|
|
123
|
+
window.dispatchEvent(new CustomEvent('onPythonReady'));
|
|
124
|
+
})();
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class WebWindow:
|
|
129
|
+
"""基于 pywebview 的 Web 窗口基类。"""
|
|
130
|
+
|
|
131
|
+
def __init__(self, html_path: str, project_root: Optional[str] = None):
|
|
132
|
+
self.project_root = os.path.abspath(project_root) if project_root else os.getcwd()
|
|
133
|
+
self.abs_path = os.path.abspath(html_path)
|
|
134
|
+
self._exposed_functions: Dict[str, Callable] = {}
|
|
135
|
+
self.webview_instance = None
|
|
136
|
+
self._return_value = None
|
|
137
|
+
self._injected = False
|
|
138
|
+
self._engine_error_handled = False
|
|
139
|
+
|
|
140
|
+
def expose(self, func: Callable):
|
|
141
|
+
"""将 Python 函数暴露给前端 JavaScript 调用。"""
|
|
142
|
+
self._exposed_functions[func.__name__] = func
|
|
143
|
+
return func
|
|
144
|
+
|
|
145
|
+
def _inject(self, source: str):
|
|
146
|
+
"""注入 callPython 桥接并派发 onPythonReady。可被多个时机触发,幂等。"""
|
|
147
|
+
if self._injected or self._engine_error_handled:
|
|
148
|
+
return
|
|
149
|
+
_diag(f"_inject START, source={source}")
|
|
150
|
+
try:
|
|
151
|
+
self.webview_instance.evaluate_js(_INJECTION_CODE)
|
|
152
|
+
self._injected = True
|
|
153
|
+
_diag(f"_inject DONE, source={source}")
|
|
154
|
+
except Exception as e:
|
|
155
|
+
_diag(f"_inject ERROR, source={source}: {e!r}")
|
|
156
|
+
# SyntaxError 是确凿信号:现代引擎绝不会对合法的现代 JS 报 SyntaxError,
|
|
157
|
+
# 只有 IE/MSHTML 才会 → 据此判定引擎不可用。不查注册表,不会误判。
|
|
158
|
+
# 其它异常(多为时机问题)只记录,留给另一个注入时机重试。
|
|
159
|
+
if "SyntaxError" in str(e):
|
|
160
|
+
self._handle_engine_error()
|
|
161
|
+
|
|
162
|
+
def _handle_engine_error(self):
|
|
163
|
+
"""检测到当前是 IE/MSHTML 引擎(WebView2 不可用)。
|
|
164
|
+
现代 JS 在此引擎下无法运行,关闭卡死的窗口并引导用户安装 WebView2。"""
|
|
165
|
+
if self._engine_error_handled:
|
|
166
|
+
return
|
|
167
|
+
self._engine_error_handled = True
|
|
168
|
+
_diag("ENGINE ERROR: modern JS rejected -> WebView2 not in use (MSHTML fallback)")
|
|
169
|
+
# 先隐藏卡死的窗口,但不要 destroy —— destroy 会让 webview.start 返回、
|
|
170
|
+
# 主线程退出,把后面的安装进度窗口一起带走。等安装流程走完再关。
|
|
171
|
+
try:
|
|
172
|
+
self.webview_instance.hide()
|
|
173
|
+
except Exception:
|
|
174
|
+
pass
|
|
175
|
+
choice = _msgbox(
|
|
176
|
+
"AScript 无法启动:界面引擎回退到了过时的 IE 内核,\n"
|
|
177
|
+
"通常是缺少 Microsoft Edge WebView2 运行时。\n\n"
|
|
178
|
+
"是否现在自动下载并安装?(约 1-2 分钟,需联网)",
|
|
179
|
+
"缺少运行环境", _MB_YESNO | _MB_ICONWARNING)
|
|
180
|
+
if choice == _IDYES:
|
|
181
|
+
if _install_webview2_with_ui():
|
|
182
|
+
_msgbox("WebView2 安装完成,请重新启动 AScript。", "AScript", _MB_ICONINFORMATION)
|
|
183
|
+
else:
|
|
184
|
+
_msgbox("自动安装失败,即将打开下载页面,请手动安装后重新启动程序。")
|
|
185
|
+
webbrowser.open(_WEBVIEW2_DOWNLOAD_URL)
|
|
186
|
+
else:
|
|
187
|
+
_msgbox("已取消。请手动安装 WebView2 运行时后重新启动程序:\n" + _WEBVIEW2_DOWNLOAD_URL)
|
|
188
|
+
# 全部处理完,关闭窗口让 webview.start 返回、进程干净退出
|
|
189
|
+
try:
|
|
190
|
+
self.webview_instance.destroy()
|
|
191
|
+
except Exception:
|
|
192
|
+
pass
|
|
193
|
+
|
|
194
|
+
def show(self, title: str = "AScript Window", debug=False, block: bool = True, **kwargs):
|
|
195
|
+
"""创建并显示 Web 窗口。"""
|
|
196
|
+
_diag(f"show() called, html={self.abs_path}, block={block}", reset=True)
|
|
197
|
+
|
|
198
|
+
class ApiBridge:
|
|
199
|
+
"""JavaScript 与 Python 之间的 API 桥接。"""
|
|
200
|
+
|
|
201
|
+
def __init__(self, funcs):
|
|
202
|
+
self._funcs = funcs
|
|
203
|
+
|
|
204
|
+
def call_internal(self, func_name, args):
|
|
205
|
+
_diag(f"call_internal ENTER: {func_name} args={args!r}")
|
|
206
|
+
f = self._funcs.get(func_name)
|
|
207
|
+
if not f:
|
|
208
|
+
_diag(f"call_internal: '{func_name}' NOT FOUND")
|
|
209
|
+
return None
|
|
210
|
+
try:
|
|
211
|
+
result = f(*args)
|
|
212
|
+
_diag(f"call_internal EXIT: {func_name} -> {repr(result)[:200]}")
|
|
213
|
+
return result
|
|
214
|
+
except Exception as e:
|
|
215
|
+
_diag(f"call_internal ERROR: {func_name}: {e!r}")
|
|
216
|
+
print(f"Error calling {func_name}: {e}")
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
# 诊断用:让 JS 也能往同一份日志里写
|
|
220
|
+
self._exposed_functions.setdefault("_diag", lambda m: _diag(str(m)))
|
|
221
|
+
|
|
222
|
+
file_url = Path(self.abs_path).as_uri()
|
|
223
|
+
self.webview_instance = webview.create_window(
|
|
224
|
+
title=title,
|
|
225
|
+
url=file_url,
|
|
226
|
+
js_api=ApiBridge(self._exposed_functions),
|
|
227
|
+
**kwargs
|
|
228
|
+
)
|
|
229
|
+
_diag("window created")
|
|
230
|
+
|
|
231
|
+
def on_loaded(*args):
|
|
232
|
+
_diag(f"events.loaded fired, args={args!r}")
|
|
233
|
+
self._inject("events.loaded")
|
|
234
|
+
|
|
235
|
+
def on_start():
|
|
236
|
+
# webview.start 的启动钩子,作为 events.loaded 的兜底注入时机
|
|
237
|
+
_diag("webview.start hook fired")
|
|
238
|
+
self._inject("start-hook")
|
|
239
|
+
|
|
240
|
+
self.webview_instance.events.loaded += on_loaded
|
|
241
|
+
_diag("events.loaded subscribed")
|
|
242
|
+
|
|
243
|
+
# 强制 edgechromium:装了 WebView2 时确保用它。
|
|
244
|
+
# 但 pywebview 在 WebView2 缺失时会"静默回退"到 MSHTML 且不抛异常,
|
|
245
|
+
# 所以真正的判定靠 _inject 里对真实引擎的运行时探测,而非这里。
|
|
246
|
+
if block:
|
|
247
|
+
try:
|
|
248
|
+
_diag("calling webview.start (block) gui=edgechromium")
|
|
249
|
+
webview.start(on_start, debug=debug, gui='edgechromium')
|
|
250
|
+
_diag("webview.start returned")
|
|
251
|
+
except Exception as e:
|
|
252
|
+
_diag(f"webview.start raised: {e!r}")
|
|
253
|
+
return self._return_value
|
|
254
|
+
else:
|
|
255
|
+
def _run():
|
|
256
|
+
try:
|
|
257
|
+
_diag("calling webview.start (thread) gui=edgechromium")
|
|
258
|
+
webview.start(on_start, debug=debug, gui='edgechromium')
|
|
259
|
+
except Exception as e:
|
|
260
|
+
_diag(f"webview.start raised (thread): {e!r}")
|
|
261
|
+
|
|
262
|
+
t = threading.Thread(target=_run, daemon=True)
|
|
263
|
+
t.start()
|
|
264
|
+
|
|
265
|
+
def close(self):
|
|
266
|
+
"""关闭并销毁 Web 窗口。"""
|
|
267
|
+
if self.webview_instance:
|
|
268
|
+
self.webview_instance.destroy()
|