ok-script 0.0.99__tar.gz → 0.0.100__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.
Files changed (183) hide show
  1. {ok-script-0.0.99 → ok-script-0.0.100}/PKG-INFO +1 -1
  2. {ok-script-0.0.99 → ok-script-0.0.100}/ok/OK.py +2 -0
  3. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/DeviceManager.py +0 -1
  4. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +19 -16
  5. {ok-script-0.0.99 → ok-script-0.0.100}/ok/color/Color.py +33 -2
  6. {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/Config.py +5 -1
  7. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/CompressCoco.py +20 -15
  8. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/FeatureSet.py +21 -24
  9. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/FindFeature.py +11 -6
  10. {ok-script-0.0.99 → ok-script-0.0.100}/ok/firebase/Analytics.py +1 -1
  11. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/MainWindow.py +10 -12
  12. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/DebugTab.py +2 -3
  13. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/FrameWidget.py +1 -1
  14. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/StartCard.py +1 -1
  15. {ok-script-0.0.99 → ok-script-0.0.100}/ok/ocr/OCR.py +3 -1
  16. {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/BaseTask.py +3 -3
  17. {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/ExecutorOperation.py +29 -7
  18. {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/TaskExecutor.py +3 -1
  19. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/json.py +4 -8
  20. {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/PKG-INFO +1 -1
  21. {ok-script-0.0.99 → ok-script-0.0.100}/setup.py +1 -1
  22. {ok-script-0.0.99 → ok-script-0.0.100}/README.md +0 -0
  23. {ok-script-0.0.99 → ok-script-0.0.100}/ok/__init__.py +0 -0
  24. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/__init__.py +0 -0
  25. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/emulator_base.py +0 -0
  26. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/emulator_windows.py +0 -0
  27. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/platform_base.py +0 -0
  28. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/platform_windows.py +0 -0
  29. {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/utils.py +0 -0
  30. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/BaseCaptureMethod.py +0 -0
  31. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/HwndWindow.py +0 -0
  32. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/__init__.py +0 -0
  33. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/ADBCaptureMethod.py +0 -0
  34. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
  35. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/__init__.py +0 -0
  36. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/bin/__init__.py +0 -0
  37. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/image/ImageCaptureMethod.py +0 -0
  38. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/image/__init__.py +0 -0
  39. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
  40. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
  41. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
  42. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/__init__.py +0 -0
  43. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/d3d11.py +0 -0
  44. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/dump.py +0 -0
  45. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/utils.py +0 -0
  46. {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/window.py +0 -0
  47. {ok-script-0.0.99 → ok-script-0.0.100}/ok/color/__init__.py +0 -0
  48. {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/InfoDict.py +0 -0
  49. {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/__init__.py +0 -0
  50. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/Box.py +0 -0
  51. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/Feature.py +0 -0
  52. {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/__init__.py +0 -0
  53. {ok-script-0.0.99 → ok-script-0.0.100}/ok/firebase/__init__.py +0 -0
  54. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/App.py +0 -0
  55. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/Communicate.py +0 -0
  56. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/MessageWindow.py +0 -0
  57. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/StartController.py +0 -0
  58. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/TabTitles.py +0 -0
  59. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/__init__.py +0 -0
  60. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/AboutTab.py +0 -0
  61. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/HttpTextEdit.py +0 -0
  62. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/VersionCard.py +0 -0
  63. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/__init__.py +0 -0
  64. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/OKIcon.py +0 -0
  65. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/__init__.py +0 -0
  66. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/config.py +0 -0
  67. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/style_sheet.py +0 -0
  68. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/AspectRatioWidget.py +0 -0
  69. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/InfoWidget.py +0 -0
  70. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/LogWindow.py +0 -0
  71. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/Screenshot.py +0 -0
  72. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/__init__.py +0 -0
  73. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/__init__.py +0 -0
  74. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/path.py +0 -0
  75. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/update.py +0 -0
  76. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/icon/__init__.py +0 -0
  77. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/icon/icon.py +0 -0
  78. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/overlay/OverlayWindow.py +0 -0
  79. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/overlay/__init__.py +0 -0
  80. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/qss/__init__.py +0 -0
  81. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/resources.py +0 -0
  82. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/settings/SettingTab.py +0 -0
  83. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/settings/__init__.py +0 -0
  84. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/SelectCaptureListView.py +0 -0
  85. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/StartTab.py +0 -0
  86. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/__init__.py +0 -0
  87. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  88. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
  89. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
  90. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndDropDown.py +0 -0
  91. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
  92. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndList.py +0 -0
  93. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
  94. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
  95. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndWidget.py +0 -0
  96. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ModifyListDialog.py +0 -0
  97. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ModifyListItem.py +0 -0
  98. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
  99. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/StartButton.py +0 -0
  100. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskCard.py +0 -0
  101. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskOpButton.py +0 -0
  102. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskTab.py +0 -0
  103. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  104. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TriggerTaskTab.py +0 -0
  105. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/__init__.py +0 -0
  106. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/Alert.py +0 -0
  107. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/InitWorker.py +0 -0
  108. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/__init__.py +0 -0
  109. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/Card.py +0 -0
  110. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/EmptyCard.py +0 -0
  111. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/FramelessDialog.py +0 -0
  112. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  113. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  114. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/StartLoadingDialog.py +0 -0
  115. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/StatusBar.py +0 -0
  116. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/Tab.py +0 -0
  117. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/TabWidget.py +0 -0
  118. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  119. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  120. {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/__init__.py +0 -0
  121. {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/ADBInteraction.py +0 -0
  122. {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/BaseInteraction.py +0 -0
  123. {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/DoNothingInteraction.py +0 -0
  124. {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/Win32Interaction.py +0 -0
  125. {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/__init__.py +0 -0
  126. {ok-script-0.0.99 → ok-script-0.0.100}/ok/logging/Logger.py +0 -0
  127. {ok-script-0.0.99 → ok-script-0.0.100}/ok/logging/__init__.py +0 -0
  128. {ok-script-0.0.99 → ok-script-0.0.100}/ok/ocr/__init__.py +0 -0
  129. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  130. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  131. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  132. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  133. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  134. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  135. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  136. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  137. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  138. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Media/__init__.py +0 -0
  139. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  140. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Security/__init__.py +0 -0
  141. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  142. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  143. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/__init__.py +0 -0
  144. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/__init__.py +0 -0
  145. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/delegate.py +0 -0
  146. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/export.py +0 -0
  147. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/idldsl.py +0 -0
  148. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/inspectable.py +0 -0
  149. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/roapi.py +0 -0
  150. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/types.py +0 -0
  151. {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/winstring.py +0 -0
  152. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/BlackBarProcessor.py +0 -0
  153. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/PostProcessor.py +0 -0
  154. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveByInterval.py +0 -0
  155. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveByKeyPress.py +0 -0
  156. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveMethodBase.py +0 -0
  157. {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/__init__.py +0 -0
  158. {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/FeatureScene.py +0 -0
  159. {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/Scene.py +0 -0
  160. {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/__init__.py +0 -0
  161. {ok-script-0.0.99 → ok-script-0.0.100}/ok/stats/StreamStats.py +0 -0
  162. {ok-script-0.0.99 → ok-script-0.0.100}/ok/stats/__init__.py +0 -0
  163. {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/TriggerTask.py +0 -0
  164. {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/__init__.py +0 -0
  165. {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/GithubMultiDownloader.py +0 -0
  166. {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/Updater.py +0 -0
  167. {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/__init__.py +0 -0
  168. {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/gen_md5.py +0 -0
  169. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/Handler.py +0 -0
  170. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/__init__.py +0 -0
  171. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/exit_event.py +0 -0
  172. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/list.py +0 -0
  173. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/path.py +0 -0
  174. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/thread.py +0 -0
  175. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/win32_process.py +0 -0
  176. {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/yaml.py +0 -0
  177. {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/SOURCES.txt +0 -0
  178. {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/dependency_links.txt +0 -0
  179. {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/requires.txt +0 -0
  180. {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/top_level.txt +0 -0
  181. {ok-script-0.0.99 → ok-script-0.0.100}/setup.cfg +0 -0
  182. {ok-script-0.0.99 → ok-script-0.0.100}/tests/__init__.py +0 -0
  183. {ok-script-0.0.99 → ok-script-0.0.100}/tests/test_updater.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ok-script
3
- Version: 0.0.99
3
+ Version: 0.0.100
4
4
  Summary: Automation with Computer Vision for Python
5
5
  Home-page: https://github.com/ok-oldking/ok-script
6
6
  Author: ok-oldking
@@ -6,6 +6,7 @@ from typing import Dict, Any
6
6
  from PySide6.QtWidgets import QApplication
7
7
 
8
8
  import ok
9
+ from ok.config.Config import Config
9
10
  from ok.logging.Logger import get_logger, config_logger
10
11
  from ok.util.exit_event import ExitEvent
11
12
  from ok.util.path import install_path_isascii
@@ -31,6 +32,7 @@ class OK:
31
32
  def __init__(self, config: Dict[str, Any]):
32
33
  print(f"AutoHelper init, config: {config}")
33
34
  config["config_folder"] = config.get("config_folder") or 'configs'
35
+ Config.config_folder = config["config_folder"]
34
36
  config_logger(config)
35
37
  logger.info(f"AutoHelper init, config: {config}")
36
38
  ok.gui.ok = self
@@ -41,7 +41,6 @@ class DeviceManager:
41
41
  else:
42
42
  self.hwnd = None
43
43
  self.config = Config({"preferred": "none", "pc_full_path": "none", 'capture': 'windows'},
44
- app_config.get('config_folder'),
45
44
  "devices")
46
45
  self.capture_method = None
47
46
  self.handler = Handler(exit_event, 'RefreshAdb')
@@ -23,17 +23,17 @@ logger = get_logger(__name__)
23
23
  class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
24
24
  name = "Windows Graphics Capture"
25
25
  description = "fast, most compatible, capped at 60fps"
26
- last_dx_frame = None
27
- last_frame_time = 0
28
- frame_pool = None
29
- item = None
30
- session = None
31
- cputex = None
32
- rtdevice = None
33
- dxdevice = None
34
26
 
35
27
  def __init__(self, hwnd_window: HwndWindow):
36
28
  super().__init__(hwnd_window)
29
+ self.last_frame = None
30
+ self.last_frame_time = 0
31
+ self.frame_pool = None
32
+ self.item = None
33
+ self.session = None
34
+ self.cputex = None
35
+ self.rtdevice = None
36
+ self.dxdevice = None
37
37
  self.start_or_stop()
38
38
 
39
39
  def frame_arrived_callback(self, x, y):
@@ -41,7 +41,7 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
41
41
  self.last_frame_time = time.time()
42
42
  next_frame = self.frame_pool.TryGetNextFrame()
43
43
  if next_frame is not None:
44
- self.last_dx_frame = next_frame
44
+ self.last_frame = self.convert_dx_frame(next_frame)
45
45
  else:
46
46
  logger.warning('frame_arrived_callback TryGetNextFrame returned None')
47
47
  except Exception as e:
@@ -49,14 +49,10 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
49
49
  self.close()
50
50
  return
51
51
 
52
- def convert_dx_frame(self):
53
- frame = self.last_dx_frame
52
+ def convert_dx_frame(self, frame):
54
53
  if not frame:
55
54
  # logger.warning('convert_dx_frame self.last_dx_frame is none')
56
55
  return None
57
- start = time.time()
58
- dx_time = self.last_frame_time
59
- self.last_dx_frame = None
60
56
  need_reset_framepool = False
61
57
  if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
62
58
  need_reset_framepool = True
@@ -206,9 +202,16 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
206
202
  @override
207
203
  def do_get_frame(self):
208
204
  if self.start_or_stop():
209
- frame = self.convert_dx_frame()
205
+ frame = self.last_frame
206
+ self.last_frame = None
210
207
  if frame is None:
211
- return
208
+ if time.time() - self.last_frame_time > 10:
209
+ logger.warning(f'no frame for 10 sec, try to restart')
210
+ self.close()
211
+ self.last_frame_time = time.time()
212
+ return self.do_get_frame()
213
+ else:
214
+ return None
212
215
  latency = time.time() - self.last_frame_time
213
216
 
214
217
  frame = self.crop_image(frame)
@@ -42,6 +42,38 @@ def is_close_to_pure_color(image, max_colors=5000, percent=0.97):
42
42
  return percentage > percent
43
43
 
44
44
 
45
+ def keep_pixels_in_color_range(image, color_range):
46
+ lower_bound, upper_bound = color_range_to_bound(color_range)
47
+ mask = cv2.inRange(image, lower_bound, upper_bound)
48
+
49
+ # Apply mask to original image
50
+ result = cv2.bitwise_and(image, image, mask=mask)
51
+
52
+ # Count the number of white pixels in the mask
53
+ pixel_count = np.count_nonzero(mask)
54
+
55
+ return result, pixel_count
56
+
57
+
58
+ def get_connected_area_by_color(image, color_range, connectivity=4):
59
+ lower_bound, upper_bound = color_range_to_bound(color_range)
60
+
61
+ # Create mask
62
+ mask = cv2.inRange(image, lower_bound, upper_bound)
63
+
64
+ # Find connected components
65
+ num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=connectivity)
66
+
67
+ # Print the area of each connected component
68
+ return num_labels, stats
69
+
70
+
71
+ def color_range_to_bound(color_range):
72
+ lower_bound = np.array([color_range['b'][0], color_range['g'][0], color_range['r'][0]], dtype="uint8")
73
+ upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
74
+ return lower_bound, upper_bound
75
+
76
+
45
77
  def calculate_colorfulness(image, box=None):
46
78
  if box is not None:
47
79
  image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
@@ -111,8 +143,7 @@ def find_color_rectangles(image, color_range, min_width, min_height, max_width=-
111
143
  y_offset = 0
112
144
 
113
145
  # Convert color range to BGR format for OpenCV
114
- lower_bound = np.array([color_range['b'][0], color_range['g'][0], color_range['r'][0]], dtype="uint8")
115
- upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
146
+ lower_bound, upper_bound = color_range_to_bound(color_range)
116
147
 
117
148
  # Create a mask for the color range
118
149
  mask = cv2.inRange(image, lower_bound, upper_bound)
@@ -7,7 +7,9 @@ logger = get_logger(__name__)
7
7
 
8
8
 
9
9
  class Config(dict):
10
- def __init__(self, default, folder, name, validator=None):
10
+ config_folder = 'configs'
11
+
12
+ def __init__(self, default, name, folder=None, validator=None):
11
13
  """
12
14
  Initialize the Config object.
13
15
 
@@ -18,6 +20,8 @@ class Config(dict):
18
20
  """
19
21
  self.default = default
20
22
  self.validator = validator
23
+ if folder is None:
24
+ folder = self.config_folder
21
25
  self.config_file = get_path_relative_to_exe(folder, f"{name}.json")
22
26
 
23
27
  # Read the config file, if it exists, otherwise use default
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  import os
3
- import sys
4
3
 
5
4
  import cv2
6
5
  import numpy as np
@@ -10,8 +9,8 @@ from PIL.PngImagePlugin import PngInfo
10
9
  from ok.feature.FeatureSet import read_from_json
11
10
 
12
11
 
13
- def compress_coco(coco_json, canny_upper, canny_lower) -> None:
14
- feature_dict, *_ = read_from_json(coco_json, canny_lower=canny_lower, canny_upper=canny_upper)
12
+ def compress_coco(coco_json) -> None:
13
+ feature_dict, *_ = read_from_json(coco_json)
15
14
  with open(coco_json, 'r') as file:
16
15
  image_dict = {}
17
16
  data = json.load(file)
@@ -46,14 +45,22 @@ def compress_coco(coco_json, canny_upper, canny_lower) -> None:
46
45
  h, w = feature.mat.shape[:2]
47
46
  background[y:y + h, x:x + w] = feature.mat
48
47
 
49
- # Add metadata
50
- metadata = {
51
- "ok_compressed": "1"
52
- }
53
-
54
48
  # Save the image with metadata
55
49
  save_image_with_metadata(background, image_path)
56
50
 
51
+ replaced = False
52
+ for image in data['images']:
53
+ image['file_name'], replaced = replace_extension(image['file_name'])
54
+
55
+ if replaced:
56
+ with open(coco_json, 'w') as json_file:
57
+ json.dump(data, json_file, indent=4)
58
+
59
+
60
+ def replace_extension(filename):
61
+ if filename.endswith('.jpg'):
62
+ return filename[:-4] + '.png', True
63
+
57
64
 
58
65
  def save_image_with_metadata(image, image_path):
59
66
  # Convert OpenCV image (numpy array) to PIL Image
@@ -65,11 +72,9 @@ def save_image_with_metadata(image, image_path):
65
72
  metadata.add_text('ok_compressed', '1')
66
73
  metadata.add_text("Author", "ok_compress")
67
74
  metadata.add_text("Description", "This is a sample image")
68
-
75
+ new_path, replaced = replace_extension(image_path)
76
+ if replaced:
77
+ os.remove(image_path)
69
78
  # Save the image with metadata
70
- pil_image.save(image_path, 'PNG', optimize=True, pnginfo=metadata)
71
-
72
-
73
- if __name__ == '__main__':
74
- json_file = sys.argv[1]
75
- compress_coco(json_file)
79
+ pil_image.save(new_path, 'PNG', optimize=True, pnginfo=metadata)
80
+ return image_path
@@ -41,8 +41,6 @@ class FeatureSet:
41
41
  # Process images and annotations
42
42
  self.width = 0
43
43
  self.height = 0
44
- self.canny_lower = 50
45
- self.canny_higher = 150
46
44
  if default_threshold == 0:
47
45
  default_threshold = 0.95
48
46
  self.default_threshold = default_threshold
@@ -69,14 +67,12 @@ class FeatureSet:
69
67
  width (int): Target width for scaling images.
70
68
  height (int): Target height for scaling images.
71
69
  """
72
- self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height,
73
- self.canny_lower, self.canny_higher)
70
+ self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
74
71
  if self.debug and not compressed:
75
72
  from ok.feature.CompressCoco import compress_coco
76
73
  logger.info(f'coco not compressed try to compress the COCO dataset')
77
- compress_coco(self.coco_json, self.canny_lower, self.canny_higher)
78
- self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height,
79
- self.canny_lower, self.canny_higher)
74
+ compress_coco(self.coco_json)
75
+ self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
80
76
 
81
77
  def get_box_by_name(self, mat, category_name: str) -> Box:
82
78
  self.check_size(mat)
@@ -106,10 +102,10 @@ class FeatureSet:
106
102
 
107
103
  def find_one(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
108
104
  vertical_variance: float = 0,
109
- threshold=0, use_gray_scale=False) -> Box:
105
+ threshold=0, use_gray_scale=False, canny_lower=0, canny_higher=0) -> Box:
110
106
  boxes = self.find_feature(mat, category_name, horizontal_variance=horizontal_variance,
111
107
  vertical_variance=vertical_variance, threshold=threshold,
112
- use_gray_scale=use_gray_scale)
108
+ use_gray_scale=use_gray_scale, canny_lower=canny_lower, canny_higher=canny_higher)
113
109
  if len(boxes) > 1:
114
110
  logger.warning(f"find_one:found too many {len(boxes)} return first", file=sys.stderr)
115
111
  if len(boxes) >= 1:
@@ -117,7 +113,7 @@ class FeatureSet:
117
113
 
118
114
  def find_feature(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
119
115
  vertical_variance: float = 0, threshold: float = 0, use_gray_scale: bool = False, x=-1, y=-1,
120
- to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
116
+ to_x=-1, to_y=-1, width=-1, height=-1, box=None, canny_lower=0, canny_higher=0) -> List[Box]:
121
117
  """
122
118
  Find a feature within a given variance.
123
119
 
@@ -168,17 +164,19 @@ class FeatureSet:
168
164
 
169
165
  search_area = mat[search_y1:search_y2, search_x1:search_x2, :3]
170
166
  # Crop the search area from the image
171
- template = feature.mat
167
+
172
168
  if use_gray_scale:
173
169
  search_area = cv2.cvtColor(search_area, cv2.COLOR_BGR2GRAY)
174
- template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
175
- if category_name.startswith('edge_'):
176
- search_area = cv2.cvtColor(search_area, cv2.COLOR_BGR2GRAY)
177
- search_area = cv2.Canny(search_area, self.canny_lower, self.canny_higher)
178
- elif category_name.startswith('gray_'):
170
+ if len(feature.mat.shape) != 2:
171
+ feature.mat = cv2.cvtColor(feature.mat, cv2.COLOR_BGR2GRAY)
172
+ if canny_lower != 0 and canny_higher != 0:
179
173
  search_area = cv2.cvtColor(search_area, cv2.COLOR_BGR2GRAY)
174
+ search_area = cv2.Canny(search_area, canny_lower, canny_higher)
175
+ if len(feature.mat.shape) != 2:
176
+ feature.mat = cv2.cvtColor(feature.mat, cv2.COLOR_BGR2GRAY)
177
+ feature.mat = cv2.Canny(feature.mat, canny_lower, canny_higher)
180
178
 
181
- result = cv2.matchTemplate(search_area, template, cv2.TM_CCOEFF_NORMED)
179
+ result = cv2.matchTemplate(search_area, feature.mat, cv2.TM_CCOEFF_NORMED)
182
180
 
183
181
  # Define a threshold for acceptable matches
184
182
  locations = filter_and_sort_matches(result, threshold, feature_width, feature_height)
@@ -198,7 +196,7 @@ class FeatureSet:
198
196
  return result
199
197
 
200
198
 
201
- def read_from_json(coco_json, width=-1, height=-1, canny_lower=50, canny_upper=150):
199
+ def read_from_json(coco_json, width=-1, height=-1):
202
200
  feature_dict = {}
203
201
  box_dict = {}
204
202
  ok_compressed = None
@@ -255,18 +253,17 @@ def read_from_json(coco_json, width=-1, height=-1, canny_lower=50, canny_upper=1
255
253
  if category_name in feature_dict:
256
254
  raise ValueError(f"Multiple boxes found for category {category_name}")
257
255
  if not category_name.startswith('box_'):
258
- if ok_compressed:
259
- if category_name.startswith('edge_'):
260
- image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
261
- image = cv2.Canny(image, canny_lower, canny_upper)
262
- elif category_name.startswith('gray_'):
263
- image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
264
256
  feature_dict[category_name] = Feature(image, x, y)
265
257
  box_dict[category_name] = Box(x, y, image.shape[1], image.shape[0], name=category_name)
266
258
 
267
259
  return feature_dict, box_dict, ok_compressed
268
260
 
269
261
 
262
+ def replace_extension(filename):
263
+ if filename.endswith('.jpg'):
264
+ return filename[:-4] + '.png', True
265
+
266
+
270
267
  def filter_and_sort_matches(result, threshold, w, h):
271
268
  # Find all matches above the confidence threshold
272
269
  loc = np.where(result >= threshold)
@@ -11,9 +11,11 @@ class FindFeature:
11
11
  self.executor = None
12
12
 
13
13
  def find_feature(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
14
- use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
14
+ use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1, box=None, canny_lower=0,
15
+ canny_higher=0) -> List[Box]:
15
16
  return self.feature_set.find_feature(self.executor.frame, feature_name, horizontal_variance, vertical_variance,
16
- threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box)
17
+ threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box,
18
+ canny_lower=canny_lower, canny_higher=canny_higher)
17
19
 
18
20
  def get_box_by_name(self, name):
19
21
  return self.feature_set.get_box_by_name(self.executor.frame, name)
@@ -43,9 +45,11 @@ class FindFeature:
43
45
 
44
46
  def wait_click_feature(self, feature, horizontal_variance=0, vertical_variance=0, threshold=0, relative_x=0.5,
45
47
  relative_y=0.5,
46
- time_out=0, pre_action=None, post_action=None, box=None, raise_if_not_found=True):
48
+ time_out=0, pre_action=None, post_action=None, box=None, raise_if_not_found=True,
49
+ use_gray_scale=False, canny_lower=0, canny_higher=0):
47
50
  box = self.wait_until(
48
- lambda: self.find_one(feature, horizontal_variance, vertical_variance, threshold, box=box),
51
+ lambda: self.find_one(feature, horizontal_variance, vertical_variance, threshold, box=box,
52
+ use_gray_scale=use_gray_scale, canny_lower=canny_lower, canny_higher=canny_higher),
49
53
  time_out,
50
54
  pre_action,
51
55
  post_action, raise_if_not_found)
@@ -55,9 +59,10 @@ class FindFeature:
55
59
  return False
56
60
 
57
61
  def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
58
- use_gray_scale=False, box=None) -> Box:
62
+ use_gray_scale=False, box=None, canny_lower=0, canny_higher=0) -> Box:
59
63
  boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
60
- use_gray_scale=use_gray_scale, box=box)
64
+ use_gray_scale=use_gray_scale, box=box, canny_lower=canny_lower,
65
+ canny_higher=canny_higher)
61
66
  if len(boxes) > 0:
62
67
  if len(boxes) > 1:
63
68
  print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
@@ -83,7 +83,7 @@ class Analytics:
83
83
  @property
84
84
  def client_id(self):
85
85
  if self._config is None:
86
- self._config = Config({'client_id': ''}, self.app_config.get("config_folder") or "config", 'statistics')
86
+ self._config = Config({'client_id': ''}, 'statistics')
87
87
  if not self._config.get('client_id'):
88
88
  self._config['client_id'] = self.get_unique_client_id()
89
89
  else:
@@ -25,26 +25,26 @@ class Communicate(QObject):
25
25
  class MainWindow(MSFluentWindow):
26
26
  def __init__(self, config, icon, title, version, debug=False, about=None, exit_event=None):
27
27
  super().__init__()
28
+ logger.info('main window __init__')
28
29
  self.original_layout = None
29
30
  self.exit_event = exit_event
30
31
  self.start_tab = StartTab()
31
- self.first_tab = None
32
32
  self.onetime_tab = None
33
33
  self.trigger_tab = None
34
34
  self.emulator_starting_dialog = None
35
35
 
36
+ self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
37
+
36
38
  if len(ok.gui.executor.onetime_tasks) > 0:
37
39
  self.onetime_tab = OneTimeTaskTab()
38
- self.first_tab = self.onetime_tab
40
+ self.first_task_tab = self.onetime_tab
39
41
  self.addSubInterface(self.onetime_tab, FluentIcon.BOOK_SHELF, self.tr('Tasks'))
40
42
  if len(ok.gui.executor.trigger_tasks) > 0:
41
43
  self.trigger_tab = TriggerTaskTab()
42
- if self.first_tab is None:
43
- self.first_tab = self.trigger_tab
44
+ if self.first_task_tab is None:
45
+ self.first_task_tab = self.trigger_tab
44
46
  self.addSubInterface(self.trigger_tab, FluentIcon.ROBOT, self.tr('Triggers'))
45
47
 
46
- self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
47
-
48
48
  if debug:
49
49
  debug_tab = DebugTab(config, exit_event)
50
50
  self.addSubInterface(debug_tab, FluentIcon.DEVELOPER_TOOLS, self.tr('Debug'),
@@ -73,13 +73,14 @@ class MainWindow(MSFluentWindow):
73
73
  self.tray.setContextMenu(menu)
74
74
  self.tray.show()
75
75
 
76
- if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
77
- self.switchTo(self.start_tab)
76
+ # if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
77
+ # self.switchTo(self.start_tab)
78
78
 
79
79
  communicate.capture_error.connect(self.capture_error)
80
80
  communicate.notification.connect(self.show_notification)
81
81
  communicate.config_validation.connect(self.config_validation)
82
82
  communicate.starting_emulator.connect(self.starting_emulator)
83
+ logger.info('main window __init__ done')
83
84
 
84
85
  def starting_emulator(self, done, error, seconds_left):
85
86
  if error:
@@ -92,7 +93,6 @@ class MainWindow(MSFluentWindow):
92
93
  if self.emulator_starting_dialog is None:
93
94
  self.emulator_starting_dialog = StartLoadingDialog(seconds_left,
94
95
  self)
95
-
96
96
  else:
97
97
  self.emulator_starting_dialog.set_seconds_left(seconds_left)
98
98
  self.emulator_starting_dialog.show()
@@ -133,9 +133,7 @@ class MainWindow(MSFluentWindow):
133
133
  def navigate_tab(self, index):
134
134
  if index == "start":
135
135
  self.switchTo(self.start_tab)
136
- elif index == "first":
137
- self.switchTo(self.first_tab)
138
- elif index == "first" and self.onetime_tab is not None:
136
+ elif index == "onetime" and self.onetime_tab is not None:
139
137
  self.switchTo(self.onetime_tab)
140
138
  elif index == "trigger" and self.trigger_tab is not None:
141
139
  self.switchTo(self.trigger_tab)
@@ -28,10 +28,9 @@ class DebugTab(Tab):
28
28
  super().__init__()
29
29
 
30
30
  self.config = Config({'target_task': "", 'target_images': [], 'target_function': ""},
31
- app_config.get('config_folder'), 'debug')
31
+ 'debug')
32
32
  self.log_window_config = Config({'width': 800, 'height': 300, 'x': 0, 'y': 0, 'keyword': '',
33
- 'level': 'ALL', 'show': True},
34
- app_config.get('config_folder'), 'log_window')
33
+ 'level': 'ALL', 'show': True}, 'log_window')
35
34
  tool_widget = QWidget()
36
35
  layout = FlowLayout(tool_widget, False)
37
36
 
@@ -33,7 +33,7 @@ class FrameWidget(QWidget):
33
33
  relative = self.mapFromGlobal(QPoint(x / self.scaling, y / self.scaling))
34
34
  if self._mouse_position != relative and relative.x() > 0 and relative.y() > 0:
35
35
  self._mouse_position = relative
36
- self.update()
36
+ self.update()
37
37
  except Exception as e:
38
38
  logger.warning(f'GetCursorPos exception {e}')
39
39
 
@@ -46,7 +46,7 @@ class StartCard(SettingCard):
46
46
  elif ok.gui.executor.active_trigger_task_count():
47
47
  communicate.tab.emit("trigger")
48
48
  else:
49
- communicate.tab.emit("first")
49
+ communicate.tab.emit("start")
50
50
  self.status_bar.show()
51
51
 
52
52
  def clicked(self):
@@ -18,7 +18,7 @@ class OCR:
18
18
  def ocr(self, x=0, y=0, to_x=1, to_y=1, match: str | List[str] | Pattern[str] | List[Pattern[str]] | None = None,
19
19
  width=0, height=0, box: Box = None, name=None,
20
20
  threshold=0,
21
- frame=None, target_height=0):
21
+ frame=None, target_height=0, use_grayscale=False):
22
22
  if hasattr(self, 'paused') and self.paused:
23
23
  self.sleep(1)
24
24
  if threshold == 0:
@@ -42,6 +42,8 @@ class OCR:
42
42
  image = image[y:y + h, x:x + w]
43
43
  if not box.name and match:
44
44
  box.name = str(match)
45
+ if use_grayscale:
46
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
45
47
 
46
48
  image, scale_factor = resize_image(image, original_height, target_height)
47
49
 
@@ -136,8 +136,8 @@ class BaseTask(ExecutorOperation):
136
136
  def info_add(self, key, count=1):
137
137
  self.info[key] = self.info.get(key, 0) + count
138
138
 
139
- def load_config(self, folder):
140
- self.config = Config(self.default_config, folder, self.__class__.__name__, self.validate)
139
+ def load_config(self):
140
+ self.config = Config(self.default_config, self.__class__.__name__, validator=self.validate)
141
141
 
142
142
  def validate(self, key, value):
143
143
  message = self.validate_config(key, value)
@@ -168,5 +168,5 @@ class BaseTask(ExecutorOperation):
168
168
  def set_executor(self, executor):
169
169
  self.executor = executor
170
170
  self.feature_set = executor.feature_set
171
- self.load_config(executor.config_folder)
171
+ self.load_config()
172
172
  self.on_create()
@@ -1,3 +1,4 @@
1
+ import time
1
2
  from typing import List
2
3
 
3
4
  from ok.color.Color import calculate_color_percentage
@@ -7,6 +8,7 @@ from ok.gui.Communicate import communicate
7
8
 
8
9
  class ExecutorOperation:
9
10
  executor = None
11
+ last_click_time = 0
10
12
 
11
13
  def exit_is_set(self):
12
14
  return self.executor.exit_event.is_set()
@@ -32,13 +34,29 @@ class ExecutorOperation:
32
34
  def is_scene(self, the_scene):
33
35
  return isinstance(self.executor.current_scene, the_scene)
34
36
 
35
- def click(self, x: int | Box = -1, y=-1, move_back=False, name=None):
37
+ def reset_scene(self):
38
+ self.executor.reset_scene()
39
+
40
+ def click(self, x: int | Box = -1, y=-1, move_back=False, name=None, interval=-1):
36
41
  if isinstance(x, Box):
37
- self.click_box(x, move_back=move_back)
38
- return
42
+ return self.click_box(x, move_back=move_back)
43
+ if not self.check_interval(interval):
44
+ self.executor.reset_scene()
45
+ return False
39
46
  communicate.emit_draw_box("click", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="click")], "green")
40
47
  self.executor.reset_scene()
41
48
  self.executor.interaction.click(x, y, move_back, name=name)
49
+ return True
50
+
51
+ def check_interval(self, interval):
52
+ if interval <= 0:
53
+ return True
54
+ now = time.time()
55
+ if now - self.last_click_time < interval:
56
+ return False
57
+ else:
58
+ self.last_click_time = now
59
+ return True
42
60
 
43
61
  def mouse_down(self, x=-1, y=-1, name=None):
44
62
  frame = self.executor.nullable_frame()
@@ -52,8 +70,8 @@ class ExecutorOperation:
52
70
  communicate.emit_draw_box("mouse_up", self.box_of_screen(0.5, 0.5, width=0.01, height=0.01, name="click"),
53
71
  "green",
54
72
  frame)
55
- self.executor.reset_scene()
56
73
  self.executor.interaction.mouse_up()
74
+ self.executor.reset_scene()
57
75
 
58
76
  def right_click(self, x=-1, y=-1, move_back=False, name=None):
59
77
  communicate.emit_draw_box("right_click", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="right_click")],
@@ -75,8 +93,8 @@ class ExecutorOperation:
75
93
  self.executor.interaction.swipe(from_x, from_y, to_x, to_y, ms)
76
94
  self.sleep(duration)
77
95
 
78
- def screenshot(self, name=None):
79
- communicate.screenshot.emit(self.frame, name)
96
+ def screenshot(self, name=None, frame=None):
97
+ communicate.screenshot.emit(self.frame if frame is None else frame, name)
80
98
 
81
99
  def click_box_if_name_match(self, boxes, names, relative_x=0.5, relative_y=0.5):
82
100
  """
@@ -158,12 +176,16 @@ class ExecutorOperation:
158
176
  def sleep(self, timeout):
159
177
  self.executor.sleep(timeout)
160
178
 
161
- def send_key(self, key, down_time=0.02):
179
+ def send_key(self, key, down_time=0.02, interval=-1):
180
+ if not self.check_interval(interval):
181
+ self.executor.reset_scene()
182
+ return False
162
183
  frame = self.executor.nullable_frame()
163
184
  communicate.emit_draw_box("send_key", [Box(max(0, 0), max(0, 0), 20, 20, name="send_key_" + str(key))], "green",
164
185
  frame)
165
186
  self.executor.reset_scene()
166
187
  self.executor.interaction.send_key(key, down_time)
188
+ return True
167
189
 
168
190
  def send_key_down(self, key):
169
191
  self.executor.reset_scene()
@@ -257,8 +257,10 @@ class TaskExecutor:
257
257
 
258
258
  def execute(self):
259
259
  logger.info(f"start execute")
260
- last_frame_time = 0
261
260
  while not self.exit_event.is_set():
261
+ if self.paused:
262
+ logger.info(f'executor is paused sleep')
263
+ self.sleep(1)
262
264
  task, cycled = self.next_task()
263
265
  if not task:
264
266
  time.sleep(1)
@@ -17,11 +17,7 @@ def read_json_file(file_path) -> dict | None:
17
17
 
18
18
 
19
19
  def write_json_file(file_path, data):
20
- try:
21
- ensure_dir_for_file(file_path)
22
- with open(file_path, 'w', encoding='utf-8') as f:
23
- json.dump(data, f, indent=4, ensure_ascii=False)
24
- return True
25
- except Exception as e:
26
- print(f"Error writing to JSON file: {e}")
27
- return False
20
+ ensure_dir_for_file(file_path)
21
+ with open(file_path, 'w', encoding='utf-8') as f:
22
+ json.dump(data, f, indent=4, ensure_ascii=False)
23
+ return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ok-script
3
- Version: 0.0.99
3
+ Version: 0.0.100
4
4
  Summary: Automation with Computer Vision for Python
5
5
  Home-page: https://github.com/ok-oldking/ok-script
6
6
  Author: ok-oldking