ok-script 2.0.0b1__tar.gz → 2.0.0b3__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.
- {ok_script-2.0.0b1/ok_script.egg-info → ok_script-2.0.0b3}/PKG-INFO +51 -22
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/README.md +23 -0
- ok_script-2.0.0b3/diagnostics/qq_trace.py +101 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/__init__.py +17 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/events.py +1 -1
- ok_script-2.0.0b3/ok/gui/__init__.py +50 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/task/task.py +11 -0
- ok_script-2.0.0b3/ok/task/web.py +162 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/test/TaskTestCase.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/MainWindow.py +23 -23
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/MessageWindow.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/AboutTab.py +5 -5
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/LinksBar.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/VersionCard.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/debug/DebugTab.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/debug/OverlayWidget.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/debug/RunCodeTab.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/settings/GlobalConfigCard.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/settings/GlobalConfigTab.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/settings/SettingTab.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/StartCard.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/StartTab.py +12 -12
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ConfigCard.py +4 -4
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ConfigItemFactory.py +11 -11
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ConfigLabelAndWidget.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/EditTaskTab.py +17 -17
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndButtons.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndDoubleSpinBox.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndDropDown.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndFileSelector.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndGlobal.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndLineEdit.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndList.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndMultiSelection.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndSpinBox.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndSwitchButton.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndTextEdit.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/LabelAndWidget.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/MarkUpWindow.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ModifyListDialog.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ModifyListItem.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/OneTimeTaskTab.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/RecordScript.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ScheduleTaskTab.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/StartButton.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TaskCard.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TaskTab.py +4 -4
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TemplateFactory.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TemplateTab.py +13 -13
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TriggerTaskTab.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/Alert.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/app.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/BaseLoading.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/BaseWindow.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/Card.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/CustomTab.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/EmptyCard.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/ListTableWidgetItem.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/NumericTableWidgetItem.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/StatusBar.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/Tab.py +5 -5
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/YesNonWidgetItem.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/web/app.py +112 -0
- ok_script-2.0.0b3/ok/ui/web/server.py +690 -0
- ok_script-2.0.0b3/ok/ui/web/static/app.js +11 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/web/static/chunk-fluent.js +2 -2
- ok_script-2.0.0b3/ok/ui/web/static/index.css +1 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3/ok_script.egg-info}/PKG-INFO +51 -22
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok_script.egg-info/SOURCES.txt +7 -0
- ok_script-2.0.0b3/ok_script.egg-info/requires.txt +42 -0
- ok_script-2.0.0b3/ok_script.egg-info/top_level.txt +6 -0
- ok_script-2.0.0b3/pyproject.toml +125 -0
- ok_script-2.0.0b3/scripts/generate_web_i18n.py +57 -0
- ok_script-2.0.0b3/setup.py +17 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_accent_color.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_blur.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_config_card.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_expand_card_layout.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_global_config.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_main_window_notifications.py +3 -3
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_main_window_startup_tab.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_main_window_system_theme.py +11 -11
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_navigation_state.py +1 -1
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_notifications.py +2 -2
- ok_script-2.0.0b3/tests/test_package_metadata.py +35 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_pyappify_startup_update.py +3 -3
- ok_script-2.0.0b3/tests/test_qt_legacy_imports.py +12 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_start_controller.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_task_ui.py +5 -5
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_template_tab.py +2 -2
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_touch_scroll.py +1 -1
- ok_script-2.0.0b3/tests/test_web_server.py +511 -0
- ok_script-2.0.0b3/tests/test_web_task_tabs.py +143 -0
- ok_script-2.0.0b3/tests/test_web_ui_pages.py +224 -0
- ok_script-2.0.0b1/ok/gui/__init__.py +0 -10
- ok_script-2.0.0b1/ok/ui/web/server.py +0 -154
- ok_script-2.0.0b1/ok/ui/web/static/app.js +0 -11
- ok_script-2.0.0b1/ok/ui/web/static/index.css +0 -1
- ok_script-2.0.0b1/ok_script.egg-info/requires.txt +0 -22
- ok_script-2.0.0b1/ok_script.egg-info/top_level.txt +0 -1
- ok_script-2.0.0b1/setup.py +0 -79
- ok_script-2.0.0b1/tests/test_web_server.py +0 -235
- ok_script-2.0.0b1/tests/test_web_ui_pages.py +0 -125
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/LICENSE.txt +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/MANIFEST.in +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/__main__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/alas/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/alas/emulator_base.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/alas/emulator_windows.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/alas/platform_windows.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/alas/utils.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/deep.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/minitouch.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/nemu_ipc.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/nemu_utils.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/pool.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/timer.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/adb/util.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/windows/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/windows/d3d11.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/capture/windows/dump.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/cli.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/config_schema.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/downloads.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/icons.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/notifications.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/screenshot.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/script_editing.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/script_packager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/script_templates.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/start_controller.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/task_manager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/template_store.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/translation.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/core/ui_config.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/DeviceManager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/adb.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/base.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/bitblt.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/bitblt_utils.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/browser.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/desktop_duplication.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/hwnd_window.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/image.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/nemu_ipc.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/types.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/update.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/capture_methods/windows_graphics.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/adb.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/base.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/browser.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/do_nothing.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/foreground_post_message.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/genshin.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/keys.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/post_message.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/pydirect.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/pynput.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/interaction_methods/swipe.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/device/intercation.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/feature/Box.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/feature/Feature.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/feature/FeatureSet.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/feature/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/gui/util/pyappify_startup.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/manager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/messenger_images.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/pipeline.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/ppocr.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/providers.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/system.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/notification/windows_messenger.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ocr/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ocr/download_paddle_model.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/UI/ViewManagement/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/UI/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/Windows/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/delegate.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/export.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/idldsl.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/inspectable.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/roapi.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/types.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/rotypes/winstring.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/task/DiagnosisTask.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/task/TaskExecutor.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/task/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/task/exceptions.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/test/OKTestRunner.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/test/RunTests.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/test/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/third_party/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/third_party/paperclip.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/overlay/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/overlay/win32_gdi.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/Communicate.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/StartController.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/TabTitles.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/HttpTextEdit.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/ProjectCard.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/about/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/OKIcon.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/accent_color.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/config.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/design_system.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/icons.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/common/style_sheet.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/debug/Screenshot.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/debug/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/events.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/GettextTranslator.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/en_US.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/en_US.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/es_ES.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/es_ES.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/ja_JP.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/ja_JP.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/ko_KR.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/ko_KR.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/path.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/update.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/zh_CN.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/zh_CN.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/zh_TW.qm +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/i18n/zh_TW.ts +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/overlay/OverlayWindow.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/overlay/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/card.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/discord.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/heart.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/message_window.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/setting_interface.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/status_bar.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/stop.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/dark/tab.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/card.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/discord.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/heart.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/message_window.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/setting_interface.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/status_bar.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/stop.svg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qss/light/tab.qss +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/qt.qrc +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/resources.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/settings/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/LogWindow.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/SelectCaptureListView.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/SelectInteractionListView.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/start/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/PythonHighlighter.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/ScriptPackager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TaskManger.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TaskOpButton.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/TooltipTableWidget.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/tasks/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/InitWorker.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/download.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/pip_util.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/pyappify_startup.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/touch_scroll.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/util/windows_thumbnail.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/ExpandCardLayout.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/FlowLayout.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/FramelessDialog.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/ImageWidget.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/OkCompactSpinBox.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/SortingTableWidgetItem.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/StartLoadingDialog.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/TabWidget.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/UpdateConfigWidgetItem.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/WidgetWithVLabel.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/qt/widget/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/web/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/web/static/chunk-react.js +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/ui/web/static/index.html +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/update/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/update/copy_ok_folder.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/update/inline_ok_requirements.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/Analytics.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/GlobalConfig.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/__init__.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/blur.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/clazz.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/collection.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/color.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/config.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/explorer.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/file.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/gpu_driver_settings.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/handler.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/i18n.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/logger.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/partial_sync_repo.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/print_hwnd.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/process.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/window.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok/util/windows_schedule.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok_script.egg-info/entry_points.txt +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/ok_script.egg-info/not-zip-safe +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/setup.cfg +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_app.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_base_interaction.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_box.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_capture_update.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_cli.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_core_events.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_core_ui_services.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_device_manager.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_explorer.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_gpu_driver_settings.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_headless_imports.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_inline_ok_requirements.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_logger.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_missing_frame.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_nemu_ipc_capture.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_ok_mutex.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_overlay_custom_draw.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_process.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_qt_events.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_runtime_startup.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_task_executor_queue.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_translation_fallback.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_ui_config.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_web_app.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_web_i18n.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_web_ui_tasks.py +0 -0
- {ok_script-2.0.0b1 → ok_script-2.0.0b3}/tests/test_windows_graphics_capture.py +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ok-script
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0b3
|
|
4
4
|
Summary: Automation with Computer Vision for Python
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Author-email: ok-oldking <firedcto@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/ok-oldking/ok-script
|
|
7
|
+
Project-URL: Repository, https://github.com/ok-oldking/ok-script
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.14
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Operating System :: Microsoft :: Windows
|
|
16
15
|
Requires-Python: >=3.11
|
|
17
16
|
Description-Content-Type: text/markdown
|
|
@@ -24,28 +23,35 @@ Requires-Dist: psutil>=6.0.0
|
|
|
24
23
|
Requires-Dist: pydirectinput==1.0.4
|
|
25
24
|
Requires-Dist: pycaw==20240210
|
|
26
25
|
Requires-Dist: mouse==0.7.1
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
Requires-Dist: pynput>=1.8.1
|
|
27
|
+
Provides-Extra: default
|
|
28
|
+
Requires-Dist: numpy>=1.26.4; extra == "default"
|
|
29
|
+
Requires-Dist: Pillow>=10.0; extra == "default"
|
|
30
|
+
Requires-Dist: ok-d3dshot>=0.1.5; extra == "default"
|
|
31
|
+
Requires-Dist: OpenCC==1.2.0; extra == "default"
|
|
29
32
|
Provides-Extra: web
|
|
30
33
|
Requires-Dist: fastapi>=0.115.0; extra == "web"
|
|
31
34
|
Requires-Dist: uvicorn[standard]>=0.30.0; extra == "web"
|
|
32
35
|
Requires-Dist: pywebview>=5.4; extra == "web"
|
|
33
|
-
Provides-Extra:
|
|
34
|
-
Requires-Dist: PySide6-
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
Provides-Extra: qt
|
|
37
|
+
Requires-Dist: PySide6-Essentials>=6.7.0; extra == "qt"
|
|
38
|
+
Requires-Dist: PySideSix-Frameless-Window>=0.3.12; extra == "qt"
|
|
39
|
+
Requires-Dist: darkdetect>=0.8.0; extra == "qt"
|
|
40
|
+
Requires-Dist: PySide6-Fluent-Widgets>=1.8.3; extra == "qt"
|
|
41
|
+
Provides-Extra: adb
|
|
42
|
+
Requires-Dist: adbutils>=2.2.1; extra == "adb"
|
|
43
|
+
Provides-Extra: ocr
|
|
44
|
+
Requires-Dist: onnxocr-ppocrv5; extra == "ocr"
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
47
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
48
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
49
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
50
|
+
Requires-Dist: setuptools>=77; extra == "dev"
|
|
51
|
+
Requires-Dist: wheel; extra == "dev"
|
|
52
|
+
Requires-Dist: get-pypi-latest-version; extra == "dev"
|
|
53
|
+
Requires-Dist: mkdocs-material==9.7.7; extra == "dev"
|
|
44
54
|
Dynamic: license-file
|
|
45
|
-
Dynamic: provides-extra
|
|
46
|
-
Dynamic: requires-dist
|
|
47
|
-
Dynamic: requires-python
|
|
48
|
-
Dynamic: summary
|
|
49
55
|
|
|
50
56
|
# ok-script
|
|
51
57
|
|
|
@@ -82,6 +88,29 @@ ok-script 支持 Python 3.11 及以上版本,推荐使用 Python 3.12。
|
|
|
82
88
|
python -m pip install ok-script
|
|
83
89
|
```
|
|
84
90
|
|
|
91
|
+
只安装应用所需的依赖配置。`default` 为无界面模式,Web、Qt、ADB 和 OCR
|
|
92
|
+
能力分别按需安装:
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
python -m pip install "ok-script[default]"
|
|
96
|
+
python -m pip install "ok-script[qt]"
|
|
97
|
+
python -m pip install "ok-script[web]"
|
|
98
|
+
python -m pip install "ok-script[adb]"
|
|
99
|
+
python -m pip install "ok-script[ocr]"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
ok-script 不会自动选择 OpenCV。用户必须根据自己的应用选择版本,并且只安装
|
|
103
|
+
一个变体:`opencv-python`、`opencv-contrib-python`、`opencv-python-headless`
|
|
104
|
+
或 `opencv-contrib-python-headless`。
|
|
105
|
+
|
|
106
|
+
以无界面模式开发本仓库时,同时安装 `pyproject.toml` 中的 `default` 和 `dev`
|
|
107
|
+
依赖组;再根据需要添加 `--group web`、`--group qt`、`--group adb` 或
|
|
108
|
+
`--group ocr`:
|
|
109
|
+
|
|
110
|
+
```powershell
|
|
111
|
+
python -m pip install --editable . --group default --group dev
|
|
112
|
+
```
|
|
113
|
+
|
|
85
114
|
如果要创建完整的自动化项目,建议从 [`ok-script-app`](https://github.com/ok-oldking/ok-script-app) 模板开始,而不是直接在本仓库中编写业务脚本。
|
|
86
115
|
|
|
87
116
|
## 文档
|
|
@@ -33,6 +33,29 @@ ok-script 支持 Python 3.11 及以上版本,推荐使用 Python 3.12。
|
|
|
33
33
|
python -m pip install ok-script
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
只安装应用所需的依赖配置。`default` 为无界面模式,Web、Qt、ADB 和 OCR
|
|
37
|
+
能力分别按需安装:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
python -m pip install "ok-script[default]"
|
|
41
|
+
python -m pip install "ok-script[qt]"
|
|
42
|
+
python -m pip install "ok-script[web]"
|
|
43
|
+
python -m pip install "ok-script[adb]"
|
|
44
|
+
python -m pip install "ok-script[ocr]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
ok-script 不会自动选择 OpenCV。用户必须根据自己的应用选择版本,并且只安装
|
|
48
|
+
一个变体:`opencv-python`、`opencv-contrib-python`、`opencv-python-headless`
|
|
49
|
+
或 `opencv-contrib-python-headless`。
|
|
50
|
+
|
|
51
|
+
以无界面模式开发本仓库时,同时安装 `pyproject.toml` 中的 `default` 和 `dev`
|
|
52
|
+
依赖组;再根据需要添加 `--group web`、`--group qt`、`--group adb` 或
|
|
53
|
+
`--group ocr`:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
python -m pip install --editable . --group default --group dev
|
|
57
|
+
```
|
|
58
|
+
|
|
36
59
|
如果要创建完整的自动化项目,建议从 [`ok-script-app`](https://github.com/ok-oldking/ok-script-app) 模板开始,而不是直接在本仓库中编写业务脚本。
|
|
37
60
|
|
|
38
61
|
## 文档
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Trace QQ notification navigation without sending a message.
|
|
2
|
+
|
|
3
|
+
Usage: .venv\\Scripts\\python.exe diagnostics\\qq_trace.py [nickname]
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import cv2
|
|
13
|
+
import numpy as np
|
|
14
|
+
from types import SimpleNamespace
|
|
15
|
+
|
|
16
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
17
|
+
from ok.notification.windows_messenger import MessengerAutomation
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
OUT = Path(__file__).resolve().parents[1] / "logs" / "qq_trace"
|
|
21
|
+
OUT.mkdir(parents=True, exist_ok=True)
|
|
22
|
+
logging.basicConfig(
|
|
23
|
+
filename=OUT / "trace.log",
|
|
24
|
+
level=logging.INFO,
|
|
25
|
+
format="%(asctime)s.%(msecs)03d %(levelname)s %(message)s",
|
|
26
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
27
|
+
)
|
|
28
|
+
log = logging.getLogger("qq_trace")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def snap(automation: MessengerAutomation, hwnd: int, label: str) -> None:
|
|
32
|
+
try:
|
|
33
|
+
frame = automation._capture(hwnd)
|
|
34
|
+
path = OUT / f"{time.time_ns()}_{label}.png"
|
|
35
|
+
cv2.imwrite(str(path), frame)
|
|
36
|
+
log.info("screenshot label=%s path=%s shape=%s", label, path, frame.shape)
|
|
37
|
+
except Exception:
|
|
38
|
+
log.exception("screenshot_failed label=%s", label)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main() -> int:
|
|
42
|
+
nickname = (sys.argv[1] if len(sys.argv) > 1 else "文件传输助手").strip()
|
|
43
|
+
log.info("START nickname=%r", nickname)
|
|
44
|
+
automation = MessengerAutomation(
|
|
45
|
+
("QQ.exe",), SimpleNamespace(), window_titles=("QQ",),
|
|
46
|
+
dismiss_search_after_contact=True, post_activate=False,
|
|
47
|
+
)
|
|
48
|
+
hwnd = automation._find_hwnd()
|
|
49
|
+
log.info("find_hwnd hwnd=%s foreground=%s", hwnd, __import__("win32gui").GetForegroundWindow())
|
|
50
|
+
if not hwnd:
|
|
51
|
+
log.error("QQ window not found")
|
|
52
|
+
return 2
|
|
53
|
+
snap(automation, hwnd, "01_initial")
|
|
54
|
+
if not automation._wait_until_background(hwnd):
|
|
55
|
+
log.warning("wait_until_background returned false")
|
|
56
|
+
return 3
|
|
57
|
+
log.info("background_ready foreground=%s", __import__("win32gui").GetForegroundWindow())
|
|
58
|
+
snap(automation, hwnd, "02_background_ready")
|
|
59
|
+
search_region, contact_region, send_region = automation._layout_regions(hwnd)
|
|
60
|
+
log.info("layout search=%s contact=%s send=%s", search_region, contact_region, send_region)
|
|
61
|
+
search = automation._wait_text(hwnd, {"Search", "搜索"}, region=search_region, timeout=1.5)
|
|
62
|
+
log.info("search_ocr point=%s", search)
|
|
63
|
+
if search is None:
|
|
64
|
+
search = automation._search_field_point(hwnd)
|
|
65
|
+
log.info("search_fallback point=%s", search)
|
|
66
|
+
snap(automation, hwnd, "03_before_search_click")
|
|
67
|
+
target = automation._click(hwnd, search)
|
|
68
|
+
log.info("click search target=%s point=%s", target, search)
|
|
69
|
+
snap(automation, hwnd, "04_after_search_click")
|
|
70
|
+
time.sleep(1)
|
|
71
|
+
automation._clear_text(target)
|
|
72
|
+
log.info("clear search")
|
|
73
|
+
time.sleep(1)
|
|
74
|
+
automation._type_text(target, nickname)
|
|
75
|
+
log.info("type nickname=%r", nickname)
|
|
76
|
+
time.sleep(1)
|
|
77
|
+
snap(automation, hwnd, "05_after_typing")
|
|
78
|
+
contact_hwnd, contact = automation._wait_contact(hwnd, nickname, contact_region, timeout=8)
|
|
79
|
+
log.info("contact_result hwnd=%s point=%s", contact_hwnd, contact)
|
|
80
|
+
if contact is None:
|
|
81
|
+
log.error("contact not found")
|
|
82
|
+
automation._send_key(hwnd, 0x1B)
|
|
83
|
+
snap(automation, hwnd, "06_contact_not_found_escape")
|
|
84
|
+
return 4
|
|
85
|
+
automation._click(contact_hwnd, contact, focus=contact_hwnd == hwnd)
|
|
86
|
+
log.info("click contact target=%s point=%s", contact_hwnd, contact)
|
|
87
|
+
snap(automation, hwnd, "06_after_contact_click")
|
|
88
|
+
time.sleep(1)
|
|
89
|
+
automation._send_key(hwnd, 0x1B)
|
|
90
|
+
log.info("send escape to dismiss search overlay")
|
|
91
|
+
time.sleep(1)
|
|
92
|
+
snap(automation, hwnd, "07_after_escape")
|
|
93
|
+
send_box = automation._wait_text(hwnd, {"Send", "发送"}, region=send_region, timeout=3)
|
|
94
|
+
log.info("send_box=%s (dry-run; no message sent)", send_box)
|
|
95
|
+
snap(automation, hwnd, "08_final_dry_run")
|
|
96
|
+
log.info("END")
|
|
97
|
+
return 0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
raise SystemExit(main())
|
|
@@ -66,6 +66,7 @@ if TYPE_CHECKING:
|
|
|
66
66
|
WaitFailedException,
|
|
67
67
|
)
|
|
68
68
|
from ok.task.task import BaseTask, FindFeature, OCR, TriggerTask
|
|
69
|
+
from ok.task.web import WebCustomTab, WebTabConfig, task_tab_action, task_tab_query
|
|
69
70
|
from ok.util.Analytics import Analytics
|
|
70
71
|
from ok.util.GlobalConfig import (GlobalConfig, register_app_launcher_options,
|
|
71
72
|
register_basic_options, register_notification_options)
|
|
@@ -131,6 +132,10 @@ _LAZY_IMPORTS = {
|
|
|
131
132
|
'DiagnosisTask': ('ok.task.DiagnosisTask', 'DiagnosisTask'),
|
|
132
133
|
'BaseTask': ('ok.task.task', 'BaseTask'),
|
|
133
134
|
'TriggerTask': ('ok.task.task', 'TriggerTask'),
|
|
135
|
+
'WebTabConfig': ('ok.task.web', 'WebTabConfig'),
|
|
136
|
+
'WebCustomTab': ('ok.task.web', 'WebCustomTab'),
|
|
137
|
+
'task_tab_action': ('ok.task.web', 'task_tab_action'),
|
|
138
|
+
'task_tab_query': ('ok.task.web', 'task_tab_query'),
|
|
134
139
|
'FindFeature': ('ok.task.task', 'FindFeature'),
|
|
135
140
|
'OCR': ('ok.task.task', 'OCR'),
|
|
136
141
|
'Feature': ('ok.feature.Feature', 'Feature'),
|
|
@@ -947,13 +952,24 @@ class OK:
|
|
|
947
952
|
config_folder=self.config.get("config_folder"), debug=self.debug,
|
|
948
953
|
global_config=self.global_config, ocr_target_height=ocr_target_height,
|
|
949
954
|
config=self.config)
|
|
955
|
+
onetime_tasks = list(self.config.get('onetime_tasks', []))
|
|
956
|
+
ui_config = resolve_ui_config(self.config)
|
|
957
|
+
if ((ui_config is not None and ui_config["type"] == "web")
|
|
958
|
+
or self.config.get("web_runtime", False)):
|
|
959
|
+
from ok.task.web import configured_web_custom_tabs
|
|
960
|
+
existing = {tuple(task[:2]) for task in onetime_tasks
|
|
961
|
+
if isinstance(task, (list, tuple)) and len(task) >= 2}
|
|
962
|
+
for web_task in configured_web_custom_tabs(self.config.get('web_tabs', [])):
|
|
963
|
+
if tuple(web_task) not in existing:
|
|
964
|
+
onetime_tasks.append(web_task)
|
|
965
|
+
existing.add(tuple(web_task))
|
|
950
966
|
if self.should_init_task_manager_headless():
|
|
951
967
|
from ok.core.task_manager import TaskManager
|
|
952
968
|
else:
|
|
953
969
|
from ok.ui.qt.tasks.TaskManger import TaskManager
|
|
954
970
|
task_app = self.headless_app if self.should_init_task_manager_headless() else self.app
|
|
955
971
|
og.task_manager = TaskManager(task_executor=self.task_executor, app=task_app,
|
|
956
|
-
onetime_tasks=
|
|
972
|
+
onetime_tasks=onetime_tasks,
|
|
957
973
|
trigger_tasks=self.config.get('trigger_tasks', []),
|
|
958
974
|
scene=self.config.get('scene'))
|
|
959
975
|
og.executor = self.task_executor
|
|
@@ -80,7 +80,7 @@ class EventBus:
|
|
|
80
80
|
"blur_overlay", "clear_blur_overlay", "adb_devices",
|
|
81
81
|
"config_validation", "tab", "capture_error", "starting_emulator",
|
|
82
82
|
"quit", "start_success", "act", "copyright", "global_config",
|
|
83
|
-
"restart_admin",
|
|
83
|
+
"restart_admin", "task_tab",
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
def __init__(self):
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Compatibility namespace for the Qt UI moved to :mod:`ok.ui.qt`.
|
|
2
|
+
|
|
3
|
+
New code should import ``ok.ui.qt``. Existing ``ok.gui`` imports are redirected
|
|
4
|
+
to the same module objects so classes are not defined twice under the legacy
|
|
5
|
+
and current package names.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib import import_module
|
|
9
|
+
from importlib.abc import Loader, MetaPathFinder
|
|
10
|
+
from importlib.util import find_spec, spec_from_loader
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _QtAliasLoader(Loader):
|
|
16
|
+
def __init__(self, alias_name, target_name):
|
|
17
|
+
self.alias_name = alias_name
|
|
18
|
+
self.target_name = target_name
|
|
19
|
+
|
|
20
|
+
def create_module(self, spec):
|
|
21
|
+
return import_module(self.target_name)
|
|
22
|
+
|
|
23
|
+
def exec_module(self, module):
|
|
24
|
+
sys.modules[self.alias_name] = module
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _QtAliasFinder(MetaPathFinder):
|
|
28
|
+
legacy_prefix = f"{__name__}."
|
|
29
|
+
current_prefix = "ok.ui.qt."
|
|
30
|
+
|
|
31
|
+
def find_spec(self, fullname, path=None, target=None):
|
|
32
|
+
if not fullname.startswith(self.legacy_prefix):
|
|
33
|
+
return None
|
|
34
|
+
target_name = self.current_prefix + fullname[len(self.legacy_prefix):]
|
|
35
|
+
target_spec = find_spec(target_name)
|
|
36
|
+
if target_spec is None:
|
|
37
|
+
return None
|
|
38
|
+
return spec_from_loader(
|
|
39
|
+
fullname,
|
|
40
|
+
_QtAliasLoader(fullname, target_name),
|
|
41
|
+
origin=target_spec.origin,
|
|
42
|
+
is_package=target_spec.submodule_search_locations is not None,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if not any(isinstance(finder, _QtAliasFinder) for finder in sys.meta_path):
|
|
47
|
+
sys.meta_path.insert(0, _QtAliasFinder())
|
|
48
|
+
|
|
49
|
+
_compat = Path(__file__).resolve().parent
|
|
50
|
+
__path__ = [str(_compat), str(_compat.parent / "ui" / "qt")]
|
|
@@ -83,6 +83,10 @@ class ExecutorOperation:
|
|
|
83
83
|
"""
|
|
84
84
|
return self.executor.get_task_by_class(cls)
|
|
85
85
|
|
|
86
|
+
def get_tasks(self):
|
|
87
|
+
"""Return registered tasks without exposing the executor to extensions."""
|
|
88
|
+
return list(self.executor.get_all_tasks())
|
|
89
|
+
|
|
86
90
|
def box_in_horizontal_center(self, box, off_percent=0.02):
|
|
87
91
|
"""
|
|
88
92
|
Checks if a box is in the horizontal center.
|
|
@@ -1282,6 +1286,13 @@ class BaseTask(OCR):
|
|
|
1282
1286
|
communicate.screenshot.emit(frame, f'notification/notification_{index + 1}', False, None)
|
|
1283
1287
|
communicate.notification.emit(message, title, error, tray, show_tab, params, frames)
|
|
1284
1288
|
|
|
1289
|
+
def emit_web_event(self, event, payload=None):
|
|
1290
|
+
"""Publish a serializable event to this task's optional browser tab."""
|
|
1291
|
+
tab = getattr(self, "web_tab", None)
|
|
1292
|
+
if tab is None:
|
|
1293
|
+
raise RuntimeError(f"{self.__class__.__name__} does not declare web_tab")
|
|
1294
|
+
communicate.task_tab.emit(tab.id, str(event), payload)
|
|
1295
|
+
|
|
1285
1296
|
@property
|
|
1286
1297
|
def enabled(self):
|
|
1287
1298
|
return self._enabled
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Framework-neutral task-backed web tab declarations.
|
|
2
|
+
|
|
3
|
+
This module deliberately has no FastAPI or browser dependencies. Tasks can
|
|
4
|
+
declare a web tab without making the headless or Qt installations depend on
|
|
5
|
+
the web UI stack.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import inspect
|
|
11
|
+
import importlib
|
|
12
|
+
import importlib.util
|
|
13
|
+
import re
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, Callable, Literal
|
|
17
|
+
|
|
18
|
+
from ok.task.task import BaseTask
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_TAB_ID = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
|
|
22
|
+
_OPERATION_NAME = re.compile(r"^[a-z][a-z0-9_-]*$")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class WebTabConfig:
|
|
27
|
+
"""Metadata for a browser page owned by a task instance."""
|
|
28
|
+
|
|
29
|
+
id: str
|
|
30
|
+
name: str
|
|
31
|
+
asset_dir: str | Path
|
|
32
|
+
entrypoint: str = "index.js"
|
|
33
|
+
icon: str = "code"
|
|
34
|
+
position: Literal["scroll", "bottom"] = "scroll"
|
|
35
|
+
add_after_default_tabs: bool = True
|
|
36
|
+
task_controls: bool = True
|
|
37
|
+
|
|
38
|
+
def __post_init__(self) -> None:
|
|
39
|
+
if not _TAB_ID.fullmatch(self.id):
|
|
40
|
+
raise ValueError(
|
|
41
|
+
"WebTabConfig id must contain lowercase letters, digits, and single hyphens"
|
|
42
|
+
)
|
|
43
|
+
if not self.name.strip():
|
|
44
|
+
raise ValueError("WebTabConfig name is required")
|
|
45
|
+
if self.position not in {"scroll", "bottom"}:
|
|
46
|
+
raise ValueError(f"Unsupported WebTabConfig position: {self.position}")
|
|
47
|
+
entrypoint = Path(self.entrypoint)
|
|
48
|
+
if entrypoint.is_absolute() or ".." in entrypoint.parts:
|
|
49
|
+
raise ValueError("WebTabConfig entrypoint must stay inside asset_dir")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def resolved_asset_dir(self) -> Path:
|
|
53
|
+
return Path(self.asset_dir).resolve()
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def resolved_entrypoint(self) -> Path:
|
|
57
|
+
return (self.resolved_asset_dir / self.entrypoint).resolve()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _task_tab_operation(kind: Literal["query", "action"], name: str):
|
|
61
|
+
if not _OPERATION_NAME.fullmatch(name):
|
|
62
|
+
raise ValueError(f"Invalid task tab operation name: {name}")
|
|
63
|
+
|
|
64
|
+
def decorate(function: Callable[..., Any]) -> Callable[..., Any]:
|
|
65
|
+
setattr(function, "__task_tab_operation__", (kind, name))
|
|
66
|
+
return function
|
|
67
|
+
|
|
68
|
+
return decorate
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def task_tab_query(name: str):
|
|
72
|
+
"""Expose a read-only, explicitly named task method to its web tab."""
|
|
73
|
+
|
|
74
|
+
return _task_tab_operation("query", name)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def task_tab_action(name: str):
|
|
78
|
+
"""Expose a mutating, explicitly named task method to its web tab."""
|
|
79
|
+
|
|
80
|
+
return _task_tab_operation("action", name)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def task_tab_operations(task: BaseTask) -> dict[tuple[str, str], Callable[..., Any]]:
|
|
84
|
+
"""Return only methods explicitly allowlisted with the decorators above."""
|
|
85
|
+
|
|
86
|
+
operations: dict[tuple[str, str], Callable[..., Any]] = {}
|
|
87
|
+
# Static inspection is important here. BaseTask exposes properties such as
|
|
88
|
+
# ``frame`` whose getters wait for device capture; evaluating every member
|
|
89
|
+
# during web startup can therefore block before the server/window opens.
|
|
90
|
+
for attribute_name, descriptor in inspect.getmembers_static(task):
|
|
91
|
+
function = descriptor
|
|
92
|
+
if isinstance(function, (staticmethod, classmethod)):
|
|
93
|
+
function = function.__func__
|
|
94
|
+
function = getattr(function, "__func__", function)
|
|
95
|
+
operation = getattr(function, "__task_tab_operation__", None)
|
|
96
|
+
if operation is None:
|
|
97
|
+
continue
|
|
98
|
+
method = getattr(task, attribute_name)
|
|
99
|
+
if operation in operations:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"Duplicate task tab operation {operation[0]}/{operation[1]} "
|
|
102
|
+
f"on {task.__class__.__name__}"
|
|
103
|
+
)
|
|
104
|
+
operations[operation] = method
|
|
105
|
+
return operations
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def call_task_tab_operation(
|
|
109
|
+
task: BaseTask,
|
|
110
|
+
kind: Literal["query", "action"],
|
|
111
|
+
name: str,
|
|
112
|
+
payload: dict[str, Any] | None = None,
|
|
113
|
+
) -> Any:
|
|
114
|
+
"""Invoke one allowlisted operation with either zero args or one payload."""
|
|
115
|
+
|
|
116
|
+
method = task_tab_operations(task).get((kind, name))
|
|
117
|
+
if method is None:
|
|
118
|
+
raise ValueError(f"Unknown task tab {kind}: {name}")
|
|
119
|
+
parameters = list(inspect.signature(method).parameters.values())
|
|
120
|
+
if not parameters:
|
|
121
|
+
return method()
|
|
122
|
+
if len(parameters) == 1:
|
|
123
|
+
return method(payload or {})
|
|
124
|
+
raise TypeError(
|
|
125
|
+
f"Task tab operation {task.__class__.__name__}.{method.__name__} "
|
|
126
|
+
"must accept zero arguments or one payload argument"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class WebCustomTab(BaseTask):
|
|
131
|
+
"""A non-runnable task-shaped service that owns a browser-only page."""
|
|
132
|
+
|
|
133
|
+
def __init__(self, *args, **kwargs):
|
|
134
|
+
super().__init__(*args, **kwargs)
|
|
135
|
+
self.visible = False
|
|
136
|
+
self.support_schedule_task = False
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def configured_web_custom_tabs(web_tabs) -> list[list[str]]:
|
|
140
|
+
"""Validate task-backed pages from the web-only ``web_tabs`` config."""
|
|
141
|
+
|
|
142
|
+
resolved: list[list[str]] = []
|
|
143
|
+
seen: set[tuple[str, str]] = set()
|
|
144
|
+
for entry in web_tabs or []:
|
|
145
|
+
if not isinstance(entry, (list, tuple)) or len(entry) != 2:
|
|
146
|
+
raise ValueError("Each web_tabs entry must be [module, class_name]")
|
|
147
|
+
task_module, task_class = entry
|
|
148
|
+
if not isinstance(task_module, str) or not isinstance(task_class, str):
|
|
149
|
+
raise TypeError("web_tabs module and class_name must be strings")
|
|
150
|
+
identity = (task_module, task_class)
|
|
151
|
+
if identity in seen:
|
|
152
|
+
continue
|
|
153
|
+
if importlib.util.find_spec(task_module) is None:
|
|
154
|
+
raise ModuleNotFoundError(f"Configured web tab module not found: {task_module}")
|
|
155
|
+
candidate = getattr(importlib.import_module(task_module), task_class, None)
|
|
156
|
+
if not isinstance(candidate, type) or not issubclass(candidate, WebCustomTab):
|
|
157
|
+
raise TypeError(
|
|
158
|
+
f"Configured web tab {task_module}.{task_class} must extend WebCustomTab"
|
|
159
|
+
)
|
|
160
|
+
seen.add(identity)
|
|
161
|
+
resolved.append([task_module, task_class])
|
|
162
|
+
return resolved
|