ok-script 0.0.48__tar.gz → 0.0.50__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 (171) hide show
  1. {ok-script-0.0.48 → ok-script-0.0.50}/PKG-INFO +2 -1
  2. {ok-script-0.0.48 → ok-script-0.0.50}/ok/OK.py +3 -2
  3. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/DeviceManager.py +3 -4
  4. ok-script-0.0.50/ok/config/Config.py +132 -0
  5. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/App.py +6 -2
  6. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/Communicate.py +2 -0
  7. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/MainWindow.py +3 -3
  8. ok-script-0.0.50/ok/gui/about/AboutTab.py +135 -0
  9. ok-script-0.0.50/ok/gui/about/VersionCard.py +40 -0
  10. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/Screenshot.py +0 -1
  11. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/resources.py +2 -2
  12. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/start/SelectCaptureListView.py +5 -7
  13. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/start/StartCard.py +13 -8
  14. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/Tab.py +7 -3
  15. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/TaskExecutor.py +8 -2
  16. ok-script-0.0.50/ok/update/Updater.py +251 -0
  17. ok-script-0.0.50/ok/update/gen_md5.py +23 -0
  18. ok-script-0.0.50/ok/util/__init__.py +0 -0
  19. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/path.py +46 -0
  20. {ok-script-0.0.48 → ok-script-0.0.50}/ok_script.egg-info/PKG-INFO +2 -1
  21. {ok-script-0.0.48 → ok-script-0.0.50}/ok_script.egg-info/SOURCES.txt +7 -1
  22. {ok-script-0.0.48 → ok-script-0.0.50}/ok_script.egg-info/requires.txt +1 -0
  23. ok-script-0.0.50/ok_script.egg-info/top_level.txt +2 -0
  24. {ok-script-0.0.48 → ok-script-0.0.50}/setup.py +3 -2
  25. ok-script-0.0.50/tests/__init__.py +3 -0
  26. ok-script-0.0.50/tests/test_updater.py +25 -0
  27. ok-script-0.0.48/ok/config/Config.py +0 -100
  28. ok-script-0.0.48/ok/gui/about/AboutTab.py +0 -24
  29. ok-script-0.0.48/ok_script.egg-info/top_level.txt +0 -1
  30. {ok-script-0.0.48 → ok-script-0.0.50}/README.md +0 -0
  31. {ok-script-0.0.48 → ok-script-0.0.50}/ok/__init__.py +0 -0
  32. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/BaseCaptureMethod.py +0 -0
  33. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/HwndWindow.py +0 -0
  34. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/__init__.py +0 -0
  35. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/ADBCaptureMethod.py +0 -0
  36. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
  37. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/__init__.py +0 -0
  38. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/bin/__init__.py +0 -0
  39. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/targets.py +0 -0
  40. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/adb/vbox.py +0 -0
  41. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
  42. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
  43. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
  44. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
  45. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/__init__.py +0 -0
  46. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/d3d11.py +0 -0
  47. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/dump.py +0 -0
  48. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/utils.py +0 -0
  49. {ok-script-0.0.48 → ok-script-0.0.50}/ok/capture/windows/window.py +0 -0
  50. {ok-script-0.0.48 → ok-script-0.0.50}/ok/color/Color.py +0 -0
  51. {ok-script-0.0.48 → ok-script-0.0.50}/ok/color/__init__.py +0 -0
  52. {ok-script-0.0.48 → ok-script-0.0.50}/ok/config/InfoDict.py +0 -0
  53. {ok-script-0.0.48 → ok-script-0.0.50}/ok/config/__init__.py +0 -0
  54. {ok-script-0.0.48 → ok-script-0.0.50}/ok/feature/Box.py +0 -0
  55. {ok-script-0.0.48 → ok-script-0.0.50}/ok/feature/Feature.py +0 -0
  56. {ok-script-0.0.48 → ok-script-0.0.50}/ok/feature/FeatureSet.py +0 -0
  57. {ok-script-0.0.48 → ok-script-0.0.50}/ok/feature/FindFeature.py +0 -0
  58. {ok-script-0.0.48 → ok-script-0.0.50}/ok/feature/__init__.py +0 -0
  59. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/MessageWindow.py +0 -0
  60. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/TabTitles.py +0 -0
  61. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/__init__.py +0 -0
  62. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/about/__init__.py +0 -0
  63. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/common/OKIcon.py +0 -0
  64. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/common/__init__.py +0 -0
  65. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/common/config.py +0 -0
  66. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/common/style_sheet.py +0 -0
  67. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/AspectRatioWidget.py +0 -0
  68. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/DebugTab.py +0 -0
  69. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/FrameWidget.py +0 -0
  70. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/InfoWidget.py +0 -0
  71. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/LoggerWidget.py +0 -0
  72. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/debug/__init__.py +0 -0
  73. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/i18n/__init__.py +0 -0
  74. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/i18n/path.py +0 -0
  75. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/i18n/update.py +0 -0
  76. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/icon/__init__.py +0 -0
  77. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/icon/icon.py +0 -0
  78. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/overlay/OverlayWindow.py +0 -0
  79. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/overlay/__init__.py +0 -0
  80. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/qss/__init__.py +0 -0
  81. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/settings/SettingTab.py +0 -0
  82. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/settings/__init__.py +0 -0
  83. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/start/SelectHwndWindow.py +0 -0
  84. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/start/StartTab.py +0 -0
  85. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/start/__init__.py +0 -0
  86. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  87. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
  88. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
  89. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndDropDown.py +0 -0
  90. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
  91. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndList.py +0 -0
  92. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
  93. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
  94. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/LabelAndWidget.py +0 -0
  95. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/ModifyListDialog.py +0 -0
  96. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/ModifyListItem.py +0 -0
  97. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
  98. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/StartButton.py +0 -0
  99. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/TaskCard.py +0 -0
  100. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/TaskOpButton.py +0 -0
  101. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  102. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/TriggerTaskTab.py +0 -0
  103. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/tasks/__init__.py +0 -0
  104. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/util/Alert.py +0 -0
  105. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/util/InitWorker.py +0 -0
  106. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/util/__init__.py +0 -0
  107. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/Card.py +0 -0
  108. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/FramelessDialog.py +0 -0
  109. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  110. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  111. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/StatusBar.py +0 -0
  112. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/TabWidget.py +0 -0
  113. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  114. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  115. {ok-script-0.0.48 → ok-script-0.0.50}/ok/gui/widget/__init__.py +0 -0
  116. {ok-script-0.0.48 → ok-script-0.0.50}/ok/interaction/ADBInteraction.py +0 -0
  117. {ok-script-0.0.48 → ok-script-0.0.50}/ok/interaction/BaseInteraction.py +0 -0
  118. {ok-script-0.0.48 → ok-script-0.0.50}/ok/interaction/Win32Interaction.py +0 -0
  119. {ok-script-0.0.48 → ok-script-0.0.50}/ok/interaction/__init__.py +0 -0
  120. {ok-script-0.0.48 → ok-script-0.0.50}/ok/logging/Logger.py +0 -0
  121. {ok-script-0.0.48 → ok-script-0.0.50}/ok/logging/__init__.py +0 -0
  122. {ok-script-0.0.48 → ok-script-0.0.50}/ok/ocr/OCR.py +0 -0
  123. {ok-script-0.0.48 → ok-script-0.0.50}/ok/ocr/__init__.py +0 -0
  124. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  125. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  126. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  127. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  128. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  129. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  130. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  131. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  132. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  133. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Media/__init__.py +0 -0
  134. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  135. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Security/__init__.py +0 -0
  136. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  137. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  138. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/Windows/__init__.py +0 -0
  139. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/__init__.py +0 -0
  140. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/delegate.py +0 -0
  141. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/export.py +0 -0
  142. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/idldsl.py +0 -0
  143. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/inspectable.py +0 -0
  144. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/roapi.py +0 -0
  145. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/types.py +0 -0
  146. {ok-script-0.0.48 → ok-script-0.0.50}/ok/rotypes/winstring.py +0 -0
  147. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/BlackBarProcessor.py +0 -0
  148. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/PostProcessor.py +0 -0
  149. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/SaveByInterval.py +0 -0
  150. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/SaveByKeyPress.py +0 -0
  151. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/SaveMethodBase.py +0 -0
  152. {ok-script-0.0.48 → ok-script-0.0.50}/ok/save/__init__.py +0 -0
  153. {ok-script-0.0.48 → ok-script-0.0.50}/ok/scene/FeatureScene.py +0 -0
  154. {ok-script-0.0.48 → ok-script-0.0.50}/ok/scene/Scene.py +0 -0
  155. {ok-script-0.0.48 → ok-script-0.0.50}/ok/scene/__init__.py +0 -0
  156. {ok-script-0.0.48 → ok-script-0.0.50}/ok/stats/StreamStats.py +0 -0
  157. {ok-script-0.0.48 → ok-script-0.0.50}/ok/stats/__init__.py +0 -0
  158. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/BaseTask.py +0 -0
  159. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/ExecutorOperation.py +0 -0
  160. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/OneTimeTask.py +0 -0
  161. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/TriggerTask.py +0 -0
  162. {ok-script-0.0.48 → ok-script-0.0.50}/ok/task/__init__.py +0 -0
  163. {ok-script-0.0.48/ok/util → ok-script-0.0.50/ok/update}/__init__.py +0 -0
  164. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/exit_event.py +0 -0
  165. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/json.py +0 -0
  166. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/list.py +0 -0
  167. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/thread.py +0 -0
  168. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/win32_process.py +0 -0
  169. {ok-script-0.0.48 → ok-script-0.0.50}/ok/util/yaml.py +0 -0
  170. {ok-script-0.0.48 → ok-script-0.0.50}/ok_script.egg-info/dependency_links.txt +0 -0
  171. {ok-script-0.0.48 → ok-script-0.0.50}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ok-script
3
- Version: 0.0.48
3
+ Version: 0.0.50
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
@@ -21,6 +21,7 @@ Requires-Dist: PySide6-Fluent-Widgets>=1.5.6
21
21
  Requires-Dist: psutil>=5.9.8
22
22
  Requires-Dist: opencv-python>=4.9.0.80
23
23
  Requires-Dist: ok-d3dshot>=0.1.5
24
+ Requires-Dist: py7zr>=0.21.0
24
25
 
25
26
  # ok-script
26
27
 
@@ -28,6 +28,8 @@ class OK:
28
28
 
29
29
  def __init__(self, config: Dict[str, Any]):
30
30
  print(f"AutoHelper init, config: {config}")
31
+ config_logger(config)
32
+ logger.info(f"AutoHelper init, config: {config}")
31
33
  ok.gui.ok = self
32
34
  self.debug = config.get("debug", False)
33
35
  try:
@@ -44,6 +46,7 @@ class OK:
44
46
  self.device_manager.start()
45
47
  self.do_init()
46
48
  except Exception as e:
49
+ logger.error(f'__init__ error', e)
47
50
  self.quit()
48
51
  raise e
49
52
 
@@ -94,8 +97,6 @@ class OK:
94
97
  inference_num_threads = self.config.get('ocr').get('inference_num_threads', -1)
95
98
  self.ocr = RapidOCR(inference_num_threads=inference_num_threads)
96
99
 
97
- config_logger(self.config)
98
-
99
100
  if self.config.get('coco_feature_folder') is not None:
100
101
  coco_feature_folder = self.config.get('coco_feature_folder')
101
102
  from ok.feature.FeatureSet import FeatureSet
@@ -1,12 +1,10 @@
1
1
  import threading
2
2
 
3
3
  import win32gui
4
- from adbutils import AdbError
5
4
 
6
5
  from ok.capture.HwndWindow import HwndWindow, find_hwnd_by_title_and_exe
7
6
  from ok.capture.adb.ADBCaptureMethod import ADBCaptureMethod, do_screencap
8
7
  from ok.capture.adb.WindowsCaptureFactory import update_capture_method
9
- from ok.capture.adb.vbox import installed_emulator
10
8
  from ok.capture.windows.window import get_window_bounds
11
9
  from ok.config.Config import Config
12
10
  from ok.gui.Communicate import communicate
@@ -36,8 +34,7 @@ class DeviceManager:
36
34
  "DeviceManager")
37
35
  self.thread = None
38
36
  self.capture_method = None
39
- self.update_pc_device()
40
- self.start()
37
+ self.refresh()
41
38
 
42
39
  def refresh(self):
43
40
  if self.thread is None or not self.thread.is_alive():
@@ -121,6 +118,7 @@ class DeviceManager:
121
118
  return
122
119
  if not fast:
123
120
  self.connect_all()
121
+ from ok.capture.adb.vbox import installed_emulator
124
122
  installed_emulators = [] if fast else installed_emulator()
125
123
  for device in self.adb.list():
126
124
  logger.debug(f'adb.list() {device}')
@@ -295,6 +293,7 @@ class DeviceManager:
295
293
  def shell(self, *args, **kwargs):
296
294
  device = self.device
297
295
  if device is not None:
296
+ from adbutils import AdbError
298
297
  try:
299
298
  return device.shell(*args, **kwargs)
300
299
  except AdbError as e:
@@ -0,0 +1,132 @@
1
+ from ok.gui.Communicate import communicate
2
+ from ok.logging.Logger import get_logger
3
+ from ok.util.json import read_json_file, write_json_file
4
+ from ok.util.path import get_path_relative_to_exe
5
+
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ class Config(dict):
10
+ def __init__(self, default, folder, name, validator=None):
11
+ """
12
+ Initialize the Config object.
13
+
14
+ :param default: Default configuration values.
15
+ :param folder: Folder where the config file is stored.
16
+ :param name: Name of the config file.
17
+ :param validator: Optional function to validate key-value pairs.
18
+ """
19
+ self.default = default
20
+ self.validator = validator
21
+ self.config_file = get_path_relative_to_exe(folder, f"{name}.json")
22
+
23
+ # Read the config file, if it exists, otherwise use default
24
+ config = read_json_file(self.config_file)
25
+ if config is None:
26
+ self.reset_to_default()
27
+ else:
28
+ super().__init__(config)
29
+ modified = self.verify_config(default)
30
+ if modified:
31
+ self.save_file()
32
+ logger.debug(f'init self.config = {self}')
33
+
34
+ def save_file(self):
35
+ """
36
+ Save the current configuration to the file.
37
+ """
38
+ try:
39
+ write_json_file(self.config_file, self)
40
+ except Exception as e:
41
+ logger.error(f'save_file error: {e}')
42
+
43
+ def reset_to_default(self):
44
+ """
45
+ Reset the configuration to the default values.
46
+ """
47
+ super().clear()
48
+ self.update(self.default)
49
+ self.save_file()
50
+ logger.debug(f'reset_to_default self.config = {self}')
51
+
52
+ def pop(self, key, default=None):
53
+ """
54
+ Remove and return a value from the configuration.
55
+
56
+ :param key: The key to remove.
57
+ :param default: The default value if the key does not exist.
58
+ :return: The removed value.
59
+ """
60
+ result = super().pop(key, default)
61
+ self.save_file()
62
+ return result
63
+
64
+ def popitem(self):
65
+ """
66
+ Remove and return the last key-value pair from the configuration.
67
+ """
68
+ result = super().popitem()
69
+ self.save_file()
70
+ return result
71
+
72
+ def clear(self):
73
+ """
74
+ Clear all configuration values.
75
+ """
76
+ super().clear()
77
+ self.save_file()
78
+
79
+ def __setitem__(self, key, value):
80
+ if self.validate(key, value):
81
+ super().__setitem__(key, value)
82
+ self.save_file()
83
+
84
+ def __getitem__(self, key):
85
+ try:
86
+ return super().__getitem__(key)
87
+ except KeyError as e:
88
+ logger.error(f'KeyError: {key} not found in config: {self}')
89
+ raise e
90
+
91
+ def validate(self, key, value):
92
+ """
93
+ Validate a configuration key-value pair.
94
+
95
+ :param key: The key to validate.
96
+ :param value: The value to validate.
97
+ :return: True if valid, False otherwise.
98
+ """
99
+ if self.validator is not None:
100
+ valid, message = self.validator(key, value)
101
+ if not valid:
102
+ communicate.config_validation.emit(message)
103
+ return False
104
+ return True
105
+
106
+ def verify_config(self, default_config):
107
+ """
108
+ Verify the configuration against the default configuration.
109
+
110
+ :param default_config: The default configuration.
111
+ :return: True if the config was modified, False otherwise.
112
+ """
113
+ modified = False
114
+
115
+ # Remove entries that do not exist in default_config
116
+ for key in list(self.keys()):
117
+ if key not in default_config:
118
+ del self[key]
119
+ modified = True
120
+
121
+ # Check entries in default_config
122
+ for key, default_value in default_config.items():
123
+ if key not in self or not isinstance(self[key], type(default_value)):
124
+ self[key] = default_value
125
+ modified = True
126
+ elif self.validator is not None:
127
+ valid = self.validate(key, self[key])
128
+ if not valid:
129
+ self[key] = default_value
130
+ modified = True
131
+
132
+ return modified
@@ -13,6 +13,7 @@ from ok.gui.MessageWindow import MessageWindow
13
13
  from ok.gui.i18n.path import i18n_path
14
14
  from ok.gui.overlay.OverlayWindow import OverlayWindow
15
15
  from ok.logging.Logger import get_logger
16
+ from ok.update.Updater import Updater
16
17
 
17
18
  logger = get_logger(__name__)
18
19
 
@@ -32,6 +33,8 @@ class App:
32
33
  self.app.setAttribute(Qt.AA_DontCreateNativeWidgetSiblings)
33
34
  qconfig.theme = Theme.AUTO
34
35
 
36
+ self.updater = Updater(self.config, exit_event)
37
+
35
38
  self.about = self.config.get('about')
36
39
  self.title = self.config.get('gui_title')
37
40
  self.version = self.config.get('version')
@@ -75,8 +78,9 @@ class App:
75
78
  self.show_message_window(title, content)
76
79
 
77
80
  def show_main_window(self):
78
- self.main_window = MainWindow(self.icon, self.overlay, self.about, exit_event=self.exit_event)
79
- self.main_window.setWindowTitle(f'{self.title} {self.version}') # Set the window title here
81
+ self.main_window = MainWindow(self.icon, self.title, self.version, self.overlay, self.about,
82
+ exit_event=self.exit_event)
83
+ # Set the window title here
80
84
  self.main_window.setWindowIcon(self.icon)
81
85
  if self.overlay and ok.gui.device_manager.hwnd is not None:
82
86
  self.overlay_window = OverlayWindow(ok.gui.device_manager.hwnd)
@@ -20,6 +20,8 @@ class Communicate(QObject):
20
20
  config_validation: Signal = Signal(str)
21
21
  tab = Signal(str)
22
22
  capture_error = Signal()
23
+ check_update = Signal()
24
+ download_update = Signal(float, str, str, bool)
23
25
 
24
26
  def emit_draw_box(self, key: str = None, boxes=None, color=None, frame=None):
25
27
  self.draw_box.emit(key, boxes, color, frame)
@@ -20,7 +20,7 @@ class Communicate(QObject):
20
20
 
21
21
 
22
22
  class MainWindow(MSFluentWindow):
23
- def __init__(self, icon, debug=False, about=None, exit_event=None):
23
+ def __init__(self, icon, title, version, debug=False, about=None, exit_event=None):
24
24
  super().__init__()
25
25
  self.exit_event = exit_event
26
26
  self.start_tab = StartTab()
@@ -42,11 +42,11 @@ class MainWindow(MSFluentWindow):
42
42
  # self.addSubInterface(debug_tab, FluentIcon.COMMAND_PROMPT, self.tr('Debug'))
43
43
  # ... Add other tabs similarly
44
44
  if about:
45
- about_tab = AboutTab(about)
45
+ about_tab = AboutTab(icon, title, version, about)
46
46
  self.addSubInterface(about_tab, FluentIcon.QUESTION, self.tr('About'),
47
47
  position=NavigationItemPosition.BOTTOM)
48
48
  # Styling the tabs and content if needed, for example:
49
- self.setWindowTitle("Close Event Example")
49
+ self.setWindowTitle(f'{title} {version}')
50
50
 
51
51
  communicate.executor_paused.connect(self.executor_paused)
52
52
  communicate.tab.connect(self.navigate_tab)
@@ -0,0 +1,135 @@
1
+ from PySide6.QtCore import Qt
2
+ from PySide6.QtWidgets import QHBoxLayout, QLabel
3
+ from qfluentwidgets import TextEdit, PushButton, InfoBar, InfoBarPosition, ProgressBar
4
+
5
+ import ok.gui
6
+ from ok.capture.windows.dump import dump_threads
7
+ from ok.gui.Communicate import communicate
8
+ from ok.gui.about.VersionCard import VersionCard
9
+ from ok.gui.widget.Tab import Tab
10
+
11
+
12
+ class AboutTab(Tab):
13
+ def __init__(self, icon, title, version, about):
14
+ super().__init__()
15
+ self.version_card = VersionCard(icon, title, version, self)
16
+ # Create a QTextEdit instance
17
+ self.addWidget(self.version_card, align=Qt.AlignCenter)
18
+ if ok.gui.app.updater.enabled():
19
+ self.update_hbox = QHBoxLayout()
20
+ self.update_hbox.addStretch()
21
+ self.check_update_button = PushButton(self.tr("Check for updates"))
22
+ self.check_update_button.clicked.connect(self.check_update)
23
+ self.update_hbox.addWidget(self.check_update_button)
24
+ self.download_latest_button = PushButton()
25
+ self.download_latest_button.clicked.connect(self.download_latest)
26
+
27
+ self.update_hbox.addWidget(self.download_latest_button)
28
+ self.download_stable_button = PushButton(self.tr("Download stable version {version}").format(version=1))
29
+ self.download_stable_button.clicked.connect(self.download_stable)
30
+
31
+ self.update_hbox.addWidget(self.download_stable_button)
32
+
33
+ self.download_bar = ProgressBar(self)
34
+ self.download_bar.setFixedWidth(200)
35
+ self.update_hbox.addWidget(self.download_bar)
36
+
37
+ self.downloading_text = QLabel()
38
+ self.update_hbox.addWidget(self.downloading_text)
39
+
40
+ self.update_hbox.addStretch()
41
+ self.addLayout(self.update_hbox)
42
+ communicate.download_update.connect(self.download_update)
43
+ communicate.check_update.connect(self.update_update)
44
+ self.update_update_buttons(0)
45
+ text_edit = TextEdit()
46
+ text_edit.setHtml(about)
47
+ text_edit.setReadOnly(True)
48
+
49
+ # Set the layout on the widget
50
+ self.addWidget(text_edit)
51
+ if ok.gui.ok.debug:
52
+ dump_button = PushButton(self.tr("Dump Threads(HotKey:Ctrl+Alt+D)"))
53
+ dump_button.clicked.connect(dump_threads)
54
+ self.addWidget(dump_button)
55
+
56
+ def update_update_buttons(self, percent, progress=""):
57
+ if ok.gui.app.updater.latest_release and not ok.gui.app.updater.downloading:
58
+ self.download_latest_button.setText(self.tr("Download latest version {version} ({size})").format(
59
+ version=ok.gui.app.updater.latest_release.get('version'),
60
+ size=ok.gui.app.updater.latest_release.get('readable_size')))
61
+ self.download_latest_button.show()
62
+ else:
63
+ self.download_latest_button.hide()
64
+ if ok.gui.app.updater.stable_release and not ok.gui.app.updater.downloading:
65
+ self.download_stable_button.setText(self.tr("Download stable version {version} ({size})").format(
66
+ version=ok.gui.app.updater.stable_release.get('version'),
67
+ size=ok.gui.app.updater.stable_release.get('readable_size')))
68
+ self.download_stable_button.show()
69
+ else:
70
+ self.download_stable_button.hide()
71
+ if ok.gui.app.updater.downloading:
72
+ self.downloading_text.show()
73
+ self.downloading_text.setText(
74
+ self.tr('Downloading {progress} {percent}%').format(progress=progress, percent=format(percent, '.1f')))
75
+ self.download_bar.show()
76
+ self.download_bar.setValue(percent)
77
+ else:
78
+ self.downloading_text.hide()
79
+ self.download_bar.hide()
80
+
81
+ def download_update(self, percent, progress, done, error):
82
+ message = ""
83
+ if done:
84
+ if error:
85
+ bar = InfoBar.error
86
+ title = self.tr('Download Error:')
87
+ message = error
88
+ else:
89
+ bar = InfoBar.info
90
+ title = self.tr('Download Complete!')
91
+ bar(
92
+ title=title,
93
+ content=message,
94
+ orient=Qt.Horizontal,
95
+ isClosable=True,
96
+ position=InfoBarPosition.TOP,
97
+ duration=5000, # won't disappear automatically
98
+ parent=self
99
+ )
100
+ self.update_update_buttons(percent, progress)
101
+
102
+ def download_latest(self):
103
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.latest_release))
104
+
105
+ def download_stable(self):
106
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.stable_release))
107
+
108
+ def update_update(self):
109
+ self.check_update_button.setText(
110
+ self.tr("Check for update"))
111
+ self.check_update_button.setEnabled(True)
112
+ if ok.gui.app.updater.latest_release or ok.gui.app.updater.stable_release:
113
+ bar = InfoBar.info
114
+ message = self.tr('Found new version!')
115
+ elif ok.gui.app.updater.error:
116
+ bar = InfoBar.error
117
+ message = self.tr('Found new version!')
118
+ else:
119
+ bar = InfoBar.info
120
+ message = self.tr("This is the newest version!")
121
+ bar(
122
+ title="",
123
+ content=message,
124
+ orient=Qt.Horizontal,
125
+ isClosable=True,
126
+ position=InfoBarPosition.TOP,
127
+ duration=5000, # won't disappear automatically
128
+ parent=self
129
+ )
130
+ self.update_update_buttons(0)
131
+
132
+ def check_update(self):
133
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.check_for_updates())
134
+ self.check_update_button.setText(self.tr("Checking for updates"))
135
+ self.check_update_button.setEnabled(False)
@@ -0,0 +1,40 @@
1
+ from PySide6.QtCore import Qt
2
+ from PySide6.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
3
+ from qfluentwidgets import IconWidget, TextWrap, CardWidget
4
+
5
+
6
+ class VersionCard(CardWidget):
7
+ """ Sample card """
8
+
9
+ def __init__(self, icon, title, version, parent=None):
10
+ super().__init__(parent=parent)
11
+
12
+ self.iconWidget = IconWidget(icon, self)
13
+ self.titleLabel = QLabel(title, self)
14
+ self.contentLabel = QLabel(TextWrap.wrap(version, 45, False)[0], self)
15
+
16
+ self.hBoxLayout = QHBoxLayout(self)
17
+ self.vBoxLayout = QVBoxLayout()
18
+
19
+ self.setFixedSize(360, 90)
20
+ self.iconWidget.setFixedSize(48, 48)
21
+
22
+ self.hBoxLayout.setSpacing(28)
23
+ self.hBoxLayout.setContentsMargins(20, 0, 0, 0)
24
+ self.vBoxLayout.setSpacing(2)
25
+ self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
26
+ self.vBoxLayout.setAlignment(Qt.AlignVCenter)
27
+
28
+ self.hBoxLayout.setAlignment(Qt.AlignVCenter)
29
+ self.hBoxLayout.addWidget(self.iconWidget)
30
+ self.hBoxLayout.addLayout(self.vBoxLayout)
31
+ self.vBoxLayout.addStretch(1)
32
+ self.vBoxLayout.addWidget(self.titleLabel)
33
+ self.vBoxLayout.addWidget(self.contentLabel)
34
+ self.vBoxLayout.addStretch(1)
35
+
36
+ self.titleLabel.setObjectName('titleLabel')
37
+ self.contentLabel.setObjectName('contentLabel')
38
+
39
+ def mouseReleaseEvent(self, e):
40
+ super().mouseReleaseEvent(e)
@@ -36,7 +36,6 @@ class Screenshot(QObject):
36
36
  self.click_screenshot_folder = get_path_relative_to_exe(ok.gui.ok.config.get("click_screenshots_folder"))
37
37
  self.screenshot_folder = get_path_relative_to_exe(ok.gui.ok.config.get("screenshots_folder"))
38
38
  logger.debug(f"init Screenshot {self.screenshot_folder} {self.click_screenshot_folder}")
39
- print(f"init Screenshot {self.screenshot_folder} {self.screenshot_folder}")
40
39
  if self.click_screenshot_folder is not None or self.screenshot_folder is not None:
41
40
  self.task_queue = queue.Queue()
42
41
  self.exit_event.bind_queue(self.task_queue)
@@ -334,7 +334,7 @@ StartCard\x01\x03\x00\x00\x00\x08N\
334
334
  *\x89\xe6S\xd1Vh\x08\x00\x00\x00\x00\x06\x00\x00\x00\
335
335
  \x0dTrigger Tasks\x07\x00\
336
336
  \x00\x00\x09StartCard\x01\x03\x00\x00\
337
- \x00\x10{I_\x85\x90\x09b\xe9N\xfbR\xa1_\x00\
337
+ \x00\x10p\xb9Q\xfb\x90\x09b\xe9N\xfbR\xa1_\x00\
338
338
  Y\xcb\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1eWait\
339
339
  ing for task to \
340
340
  be enabled\x07\x00\x00\x00\x09S\
@@ -1160,7 +1160,7 @@ qt_resource_struct = b"\
1160
1160
  \x00\x00\x00>\x00\x01\x00\x00\x00\x01\x00\x00\x1a\x85\
1161
1161
  \x00\x00\x01\x8e2\xed>\xd3\
1162
1162
  \x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
1163
- \x00\x00\x01\x8f\xce\x0b<g\
1163
+ \x00\x00\x01\x8f\xcf\xc5~\xab\
1164
1164
  \x00\x00\x00T\x00\x02\x00\x00\x00\x05\x00\x00\x00\x0d\
1165
1165
  \x00\x00\x00\x00\x00\x00\x00\x00\
1166
1166
  \x00\x00\x00b\x00\x02\x00\x00\x00\x05\x00\x00\x00\x08\
@@ -9,20 +9,18 @@ class SelectCaptureListView(ListWidget):
9
9
 
10
10
  def update_for_device(self, device, hwnd, capture):
11
11
  if self.count() == 0:
12
- item = QListWidgetItem(self.tr(f"Game Window(Supports Background, Low Compatibility, Low Latency)"))
13
-
14
- # Add the QListWidgetItem to the QListWidget
12
+ item = QListWidgetItem(self.tr(f"Game Window"))
15
13
  self.addItem(item)
16
- tips = hwnd or self.tr("Supports Background, Low Compatibility, Low Latency")
14
+ tips = hwnd or ""
17
15
  if device == "windows":
18
16
  title = self.tr("Game Window")
19
17
  if self.count() == 2:
20
18
  self.takeItem(1)
21
19
  else:
22
- title = self.tr("Emulator Window")
20
+ title = self.tr("Emulator Window(Supports Background, Fast, Low Latency)")
23
21
  if self.count() == 1:
24
- item = QListWidgetItem(self.tr("ADB (Supports Background, High Compatibility, High Latency)"))
22
+ item = QListWidgetItem(self.tr("ADB(Supports Background, Slow, High Compatibility, High Latency)"))
25
23
  self.addItem(item)
26
- self.item(0).setText(f"{title}({tips})")
24
+ self.item(0).setText(f"{title} - {tips}")
27
25
  selected = 0 if capture == "windows" else 1
28
26
  self.setCurrentRow(selected)
@@ -143,16 +143,21 @@ class StartCard(SettingCard):
143
143
  if not ok.gui.executor.connected():
144
144
  self.status_bar.setTitle(self.tr("Game Window Disconnected"))
145
145
  self.status_bar.setState(True)
146
- elif not ok.gui.executor.can_capture():
147
- self.status_bar.setTitle(self.tr('Paused: PC Game Window Must Be in Front!'))
148
- self.status_bar.setState(True)
149
146
  elif active_trigger_task_count := ok.gui.executor.active_trigger_task_count():
150
- self.status_bar.setTitle(
151
- self.tr("Running") + ": " + str(active_trigger_task_count) + ' ' + self.tr("Trigger Tasks"))
152
- self.status_bar.setState(False)
147
+ if not ok.gui.executor.can_capture():
148
+ self.status_bar.setTitle(self.tr('Paused: PC Game Window Must Be in Front!'))
149
+ self.status_bar.setState(True)
150
+ else:
151
+ self.status_bar.setTitle(
152
+ self.tr("Running") + ": " + str(active_trigger_task_count) + ' ' + self.tr("Trigger Tasks"))
153
+ self.status_bar.setState(False)
153
154
  elif task := ok.gui.executor.current_task:
154
- self.status_bar.setTitle(self.tr("Running") + ": " + task.name)
155
- self.status_bar.setState(False)
155
+ if not ok.gui.executor.can_capture():
156
+ self.status_bar.setTitle(self.tr('Paused: PC Game Window Must Be in Front!'))
157
+ self.status_bar.setState(True)
158
+ else:
159
+ self.status_bar.setTitle(self.tr("Running") + ": " + task.name)
160
+ self.status_bar.setState(False)
156
161
  else:
157
162
  self.status_bar.setTitle(self.tr("Waiting for task to be enabled"))
158
163
  self.status_bar.setState(False)
@@ -29,9 +29,13 @@ class Tab(ScrollArea):
29
29
 
30
30
  def addCard(self, title, widget, stretch=0, parent=None):
31
31
  container = Card(title, widget)
32
- self.vBoxLayout.addWidget(container, stretch, Qt.AlignTop)
32
+ self.addWidget(container, stretch)
33
33
  return container
34
34
 
35
- def addWidget(self, widget, stretch=0):
36
- self.vBoxLayout.addWidget(widget, stretch, Qt.AlignTop)
35
+ def addWidget(self, widget, stretch=0, align=Qt.AlignTop):
36
+ self.vBoxLayout.addWidget(widget, stretch, align)
37
37
  return widget
38
+
39
+ def addLayout(self, layout, stretch=0):
40
+ self.vBoxLayout.addLayout(layout, stretch)
41
+ return layout
@@ -3,6 +3,7 @@ import time
3
3
  import traceback
4
4
 
5
5
  from ok.capture.BaseCaptureMethod import CaptureException
6
+ from ok.capture.adb.ADBCaptureMethod import ADBCaptureMethod
6
7
  from ok.capture.adb.DeviceManager import DeviceManager
7
8
  from ok.gui.Communicate import communicate
8
9
  from ok.logging.Logger import get_logger
@@ -73,6 +74,7 @@ class TaskExecutor:
73
74
  return self._frame
74
75
 
75
76
  def supports_screen_ratio(self, supported_ratio):
77
+ frame = self.method.get_frame() if not isinstance(self.method, ADBCaptureMethod) else None
76
78
  if supported_ratio is None:
77
79
  return True, None
78
80
  width = self.method.width
@@ -88,9 +90,13 @@ class TaskExecutor:
88
90
 
89
91
  # Calculate the difference between the actual and supported ratios
90
92
  difference = abs(actual_ratio - supported_ratio)
91
-
93
+ support = difference <= 0.01 * supported_ratio
94
+ if not support:
95
+ logger.error(f'resolution error {width}x{height} {frame is None}')
96
+ if not support and frame:
97
+ communicate.screenshot.emit(frame, "resolution_error")
92
98
  # Check if the difference is within 1%
93
- return difference <= 0.01 * supported_ratio, f"{width}x{height}"
99
+ return support, f"{width}x{height}"
94
100
 
95
101
  def can_capture(self):
96
102
  return self.method is not None and self.interaction is not None and self.interaction.should_capture()