ok-script 0.0.58__tar.gz → 0.0.60__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 (174) hide show
  1. {ok-script-0.0.58 → ok-script-0.0.60}/PKG-INFO +1 -1
  2. {ok-script-0.0.58 → ok-script-0.0.60}/ok/OK.py +2 -0
  3. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/BaseCaptureMethod.py +3 -0
  4. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/HwndWindow.py +1 -1
  5. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/DeviceManager.py +13 -12
  6. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/vbox.py +19 -19
  7. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/BaseWindowsCaptureMethod.py +8 -0
  8. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/dump.py +5 -1
  9. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/App.py +3 -0
  10. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/Communicate.py +1 -1
  11. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/MainWindow.py +10 -5
  12. ok-script-0.0.60/ok/gui/about/AboutTab.py +145 -0
  13. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/about/VersionCard.py +40 -4
  14. ok-script-0.0.60/ok/gui/debug/DebugTab.py +53 -0
  15. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/Screenshot.py +28 -22
  16. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/resources.py +515 -475
  17. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/Tab.py +7 -0
  18. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/BaseTask.py +1 -1
  19. {ok-script-0.0.58 → ok-script-0.0.60}/ok/update/GithubMultiDownloader.py +3 -2
  20. {ok-script-0.0.58 → ok-script-0.0.60}/ok/update/Updater.py +41 -48
  21. ok-script-0.0.60/ok/util/Handler.py +94 -0
  22. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/exit_event.py +7 -0
  23. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/path.py +8 -3
  24. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/win32_process.py +31 -0
  25. {ok-script-0.0.58 → ok-script-0.0.60}/ok_script.egg-info/PKG-INFO +1 -1
  26. {ok-script-0.0.58 → ok-script-0.0.60}/ok_script.egg-info/SOURCES.txt +1 -0
  27. {ok-script-0.0.58 → ok-script-0.0.60}/setup.py +1 -1
  28. ok-script-0.0.58/ok/gui/about/AboutTab.py +0 -160
  29. ok-script-0.0.58/ok/gui/debug/DebugTab.py +0 -17
  30. {ok-script-0.0.58 → ok-script-0.0.60}/README.md +0 -0
  31. {ok-script-0.0.58 → ok-script-0.0.60}/ok/__init__.py +0 -0
  32. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/__init__.py +0 -0
  33. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/ADBCaptureMethod.py +0 -0
  34. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
  35. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/__init__.py +0 -0
  36. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/bin/__init__.py +0 -0
  37. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/adb/targets.py +0 -0
  38. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
  39. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
  40. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
  41. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/__init__.py +0 -0
  42. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/d3d11.py +0 -0
  43. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/utils.py +0 -0
  44. {ok-script-0.0.58 → ok-script-0.0.60}/ok/capture/windows/window.py +0 -0
  45. {ok-script-0.0.58 → ok-script-0.0.60}/ok/color/Color.py +0 -0
  46. {ok-script-0.0.58 → ok-script-0.0.60}/ok/color/__init__.py +0 -0
  47. {ok-script-0.0.58 → ok-script-0.0.60}/ok/config/Config.py +0 -0
  48. {ok-script-0.0.58 → ok-script-0.0.60}/ok/config/InfoDict.py +0 -0
  49. {ok-script-0.0.58 → ok-script-0.0.60}/ok/config/__init__.py +0 -0
  50. {ok-script-0.0.58 → ok-script-0.0.60}/ok/feature/Box.py +0 -0
  51. {ok-script-0.0.58 → ok-script-0.0.60}/ok/feature/Feature.py +0 -0
  52. {ok-script-0.0.58 → ok-script-0.0.60}/ok/feature/FeatureSet.py +0 -0
  53. {ok-script-0.0.58 → ok-script-0.0.60}/ok/feature/FindFeature.py +0 -0
  54. {ok-script-0.0.58 → ok-script-0.0.60}/ok/feature/__init__.py +0 -0
  55. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/MessageWindow.py +0 -0
  56. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/TabTitles.py +0 -0
  57. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/__init__.py +0 -0
  58. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/about/HttpTextEdit.py +0 -0
  59. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/about/__init__.py +0 -0
  60. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/common/OKIcon.py +0 -0
  61. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/common/__init__.py +0 -0
  62. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/common/config.py +0 -0
  63. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/common/style_sheet.py +0 -0
  64. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/AspectRatioWidget.py +0 -0
  65. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/FrameWidget.py +0 -0
  66. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/InfoWidget.py +0 -0
  67. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/LoggerWidget.py +0 -0
  68. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/debug/__init__.py +0 -0
  69. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/i18n/__init__.py +0 -0
  70. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/i18n/path.py +0 -0
  71. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/i18n/update.py +0 -0
  72. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/icon/__init__.py +0 -0
  73. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/icon/icon.py +0 -0
  74. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/overlay/OverlayWindow.py +0 -0
  75. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/overlay/__init__.py +0 -0
  76. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/qss/__init__.py +0 -0
  77. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/settings/SettingTab.py +0 -0
  78. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/settings/__init__.py +0 -0
  79. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/start/SelectCaptureListView.py +0 -0
  80. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/start/SelectHwndWindow.py +0 -0
  81. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/start/StartCard.py +0 -0
  82. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/start/StartTab.py +0 -0
  83. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/start/__init__.py +0 -0
  84. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  85. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
  86. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
  87. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndDropDown.py +0 -0
  88. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
  89. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndList.py +0 -0
  90. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
  91. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
  92. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/LabelAndWidget.py +0 -0
  93. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/ModifyListDialog.py +0 -0
  94. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/ModifyListItem.py +0 -0
  95. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
  96. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/StartButton.py +0 -0
  97. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/TaskCard.py +0 -0
  98. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/TaskOpButton.py +0 -0
  99. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  100. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/TriggerTaskTab.py +0 -0
  101. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/tasks/__init__.py +0 -0
  102. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/util/Alert.py +0 -0
  103. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/util/InitWorker.py +0 -0
  104. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/util/__init__.py +0 -0
  105. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/Card.py +0 -0
  106. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/EmptyCard.py +0 -0
  107. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/FramelessDialog.py +0 -0
  108. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  109. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  110. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/StatusBar.py +0 -0
  111. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/TabWidget.py +0 -0
  112. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  113. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  114. {ok-script-0.0.58 → ok-script-0.0.60}/ok/gui/widget/__init__.py +0 -0
  115. {ok-script-0.0.58 → ok-script-0.0.60}/ok/interaction/ADBInteraction.py +0 -0
  116. {ok-script-0.0.58 → ok-script-0.0.60}/ok/interaction/BaseInteraction.py +0 -0
  117. {ok-script-0.0.58 → ok-script-0.0.60}/ok/interaction/Win32Interaction.py +0 -0
  118. {ok-script-0.0.58 → ok-script-0.0.60}/ok/interaction/__init__.py +0 -0
  119. {ok-script-0.0.58 → ok-script-0.0.60}/ok/logging/Logger.py +0 -0
  120. {ok-script-0.0.58 → ok-script-0.0.60}/ok/logging/__init__.py +0 -0
  121. {ok-script-0.0.58 → ok-script-0.0.60}/ok/ocr/OCR.py +0 -0
  122. {ok-script-0.0.58 → ok-script-0.0.60}/ok/ocr/__init__.py +0 -0
  123. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  124. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  125. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  126. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  127. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  128. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  129. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  130. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  131. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  132. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Media/__init__.py +0 -0
  133. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  134. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Security/__init__.py +0 -0
  135. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  136. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  137. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/Windows/__init__.py +0 -0
  138. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/__init__.py +0 -0
  139. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/delegate.py +0 -0
  140. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/export.py +0 -0
  141. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/idldsl.py +0 -0
  142. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/inspectable.py +0 -0
  143. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/roapi.py +0 -0
  144. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/types.py +0 -0
  145. {ok-script-0.0.58 → ok-script-0.0.60}/ok/rotypes/winstring.py +0 -0
  146. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/BlackBarProcessor.py +0 -0
  147. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/PostProcessor.py +0 -0
  148. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/SaveByInterval.py +0 -0
  149. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/SaveByKeyPress.py +0 -0
  150. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/SaveMethodBase.py +0 -0
  151. {ok-script-0.0.58 → ok-script-0.0.60}/ok/save/__init__.py +0 -0
  152. {ok-script-0.0.58 → ok-script-0.0.60}/ok/scene/FeatureScene.py +0 -0
  153. {ok-script-0.0.58 → ok-script-0.0.60}/ok/scene/Scene.py +0 -0
  154. {ok-script-0.0.58 → ok-script-0.0.60}/ok/scene/__init__.py +0 -0
  155. {ok-script-0.0.58 → ok-script-0.0.60}/ok/stats/StreamStats.py +0 -0
  156. {ok-script-0.0.58 → ok-script-0.0.60}/ok/stats/__init__.py +0 -0
  157. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/ExecutorOperation.py +0 -0
  158. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/OneTimeTask.py +0 -0
  159. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/TaskExecutor.py +0 -0
  160. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/TriggerTask.py +0 -0
  161. {ok-script-0.0.58 → ok-script-0.0.60}/ok/task/__init__.py +0 -0
  162. {ok-script-0.0.58 → ok-script-0.0.60}/ok/update/__init__.py +0 -0
  163. {ok-script-0.0.58 → ok-script-0.0.60}/ok/update/gen_md5.py +0 -0
  164. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/__init__.py +0 -0
  165. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/json.py +0 -0
  166. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/list.py +0 -0
  167. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/thread.py +0 -0
  168. {ok-script-0.0.58 → ok-script-0.0.60}/ok/util/yaml.py +0 -0
  169. {ok-script-0.0.58 → ok-script-0.0.60}/ok_script.egg-info/dependency_links.txt +0 -0
  170. {ok-script-0.0.58 → ok-script-0.0.60}/ok_script.egg-info/requires.txt +0 -0
  171. {ok-script-0.0.58 → ok-script-0.0.60}/ok_script.egg-info/top_level.txt +0 -0
  172. {ok-script-0.0.58 → ok-script-0.0.60}/setup.cfg +0 -0
  173. {ok-script-0.0.58 → ok-script-0.0.60}/tests/__init__.py +0 -0
  174. {ok-script-0.0.58 → ok-script-0.0.60}/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.58
3
+ Version: 0.0.60
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
@@ -9,7 +9,9 @@ import ok
9
9
  from ok.logging.Logger import get_logger, config_logger
10
10
  from ok.util.exit_event import ExitEvent
11
11
  from ok.util.path import install_path_isascii
12
+ from ok.util.win32_process import check_mutex
12
13
 
14
+ check_mutex()
13
15
  logger = get_logger(__name__)
14
16
 
15
17
 
@@ -51,6 +51,9 @@ class BaseCaptureMethod:
51
51
  except Exception as e:
52
52
  raise CaptureException() from e
53
53
 
54
+ def __str__(self):
55
+ return f'{self.__class__.__name__}_{self.width}x{self.height}'
56
+
54
57
  def do_get_frame(self):
55
58
  pass
56
59
 
@@ -136,7 +136,7 @@ class HwndWindow:
136
136
  return ""
137
137
 
138
138
  def __str__(self) -> str:
139
- return f"title:{self.title},exe:{self.exe_name},width:{self.width},height:{self.height},exists:{self.exists},visible:{self.visible}"
139
+ return f"title:{self.title}_{self.exe_name}_{self.width}x{self.height}_{self.exists}_{self.visible}"
140
140
 
141
141
 
142
142
  def find_hwnd_by_title_and_exe(title, exe_name):
@@ -1,5 +1,3 @@
1
- import threading
2
-
3
1
  import win32gui
4
2
 
5
3
  from ok.capture.HwndWindow import HwndWindow, find_hwnd_by_title_and_exe
@@ -11,6 +9,7 @@ from ok.gui.Communicate import communicate
11
9
  from ok.interaction.ADBInteraction import ADBBaseInteraction
12
10
  from ok.interaction.Win32Interaction import Win32Interaction
13
11
  from ok.logging.Logger import get_logger
12
+ from ok.util.Handler import Handler
14
13
 
15
14
  logger = get_logger(__name__)
16
15
 
@@ -32,14 +31,13 @@ class DeviceManager:
32
31
  windows_capture_config.get('exe'))
33
32
  self.config = Config({"devices": {}, "preferred": "none", "pc_full_path": None}, config_folder,
34
33
  "DeviceManager")
35
- self.thread = None
36
34
  self.capture_method = None
37
- self.refresh()
35
+ self.handler = Handler(exit_event, 'RefreshAdb')
36
+ self.handler.post(self.do_refresh, 5)
38
37
 
39
38
  def refresh(self):
40
- if self.thread is None or not self.thread.is_alive():
41
- self.thread = threading.Thread(target=self.do_refresh, name="refresh adb")
42
- self.thread.start()
39
+ logger.debug('calling refresh')
40
+ self.handler.post(self.do_refresh, remove_existing=True)
43
41
 
44
42
  @property
45
43
  def device_dict(self):
@@ -61,14 +59,17 @@ class DeviceManager:
61
59
  logger.debug(f'connect adb')
62
60
  return self._adb
63
61
 
62
+ def adb_connect(self, addr):
63
+ try:
64
+ self.adb.connect(addr, timeout=2)
65
+ except Exception as e:
66
+ logger.error("adb connect error", e)
67
+
64
68
  def connect_all(self):
65
69
  if not self._connect_all:
66
70
  for device in self.device_dict.values():
67
71
  if device["device"] == "adb":
68
- try:
69
- self.adb.connect(device['address'])
70
- except Exception as e:
71
- logger.error("adb connect error", e)
72
+ self.adb_connect(device['address'])
72
73
  self._connect_all = True
73
74
  logger.debug(f'connect_all')
74
75
 
@@ -124,7 +125,7 @@ class DeviceManager:
124
125
  logger.debug(f'adb.list() {device}')
125
126
  for emulator in installed_emulators:
126
127
  logger.debug(f"installed_emulator: {emulator}")
127
- self.adb.connect(emulator.adb_address, timeout=1)
128
+ self.adb_connect(emulator.adb_address)
128
129
  device_list = self.adb.device_list()
129
130
  device_list = sorted(device_list, key=lambda x: x.serial)
130
131
  adb_connected = []
@@ -27,25 +27,6 @@ class VBoxSerever(VBoxClass):
27
27
 
28
28
  import ctypes
29
29
 
30
- vbox_clsids = [
31
- VBoxClass('{20190809-47b9-4a1e-82b2-07ccd5323c3f}', 'LDPlayer', 'ld'),
32
- VBoxClass('{20191216-47b9-4a1e-82b2-07ccd5323c3f}', 'LDPlayer9', 'ld9'),
33
- VBoxClass('{88888888-47b9-4a1e-82b2-07ccd5323c3f}', 'Nox', 'nox'),
34
- VBoxClass('{baf3f651-58d8-429d-97ad-2b5699b43567}', 'BlueStacks', 'bstk'),
35
- VBoxClass('{b1a7a4f2-47b9-4a1e-82b2-07ccd5323c3a}', 'Memu', 'memu'),
36
- VBoxClass('{81919390-a492-11e5-a837-0800200c9a66}', 'MuMu', 'mumu'),
37
- VBoxClass('{23cd1535-edaa-4f21-a4ab-45d97fd1d58b}', 'MuMu 12',
38
- 'mumu 12'),
39
- # ('{B1A7A4F2-47B9-4A1E-82B2-07CCD5323C3F}', 'Oracle', 'oracle'), # nobody uses this
40
- ]
41
-
42
- OpenProcess = ctypes.windll.kernel32.OpenProcess
43
- OpenProcess.argtypes = [ctypes.c_uint32, ctypes.c_bool, ctypes.c_uint32]
44
- OpenProcess.restype = ctypes.c_void_p
45
- PROCESS_QUERY_INFORMATION = 0x0400
46
- CloseHandle = ctypes.windll.kernel32.CloseHandle
47
- CloseHandle.argtypes = [ctypes.c_void_p]
48
-
49
30
 
50
31
  def get_server(clsid):
51
32
  try:
@@ -60,6 +41,24 @@ def get_server(clsid):
60
41
 
61
42
  # current process's privilege must equal to the target process's privilege, can raise a error if not
62
43
  def installed_emulator():
44
+ vbox_clsids = [
45
+ VBoxClass('{20190809-47b9-4a1e-82b2-07ccd5323c3f}', 'LDPlayer', 'ld'),
46
+ VBoxClass('{20191216-47b9-4a1e-82b2-07ccd5323c3f}', 'LDPlayer9', 'ld9'),
47
+ VBoxClass('{88888888-47b9-4a1e-82b2-07ccd5323c3f}', 'Nox', 'nox'),
48
+ VBoxClass('{baf3f651-58d8-429d-97ad-2b5699b43567}', 'BlueStacks', 'bstk'),
49
+ VBoxClass('{b1a7a4f2-47b9-4a1e-82b2-07ccd5323c3a}', 'Memu', 'memu'),
50
+ VBoxClass('{81919390-a492-11e5-a837-0800200c9a66}', 'MuMu', 'mumu'),
51
+ VBoxClass('{23cd1535-edaa-4f21-a4ab-45d97fd1d58b}', 'MuMu 12',
52
+ 'mumu 12'),
53
+ # ('{B1A7A4F2-47B9-4A1E-82B2-07CCD5323C3F}', 'Oracle', 'oracle'), # nobody uses this
54
+ ]
55
+
56
+ OpenProcess = ctypes.windll.kernel32.OpenProcess
57
+ OpenProcess.argtypes = [ctypes.c_uint32, ctypes.c_bool, ctypes.c_uint32]
58
+ OpenProcess.restype = ctypes.c_void_p
59
+ PROCESS_QUERY_INFORMATION = 0x0400
60
+ CloseHandle = ctypes.windll.kernel32.CloseHandle
61
+ CloseHandle.argtypes = [ctypes.c_void_p]
63
62
  logger.debug('enumerating vbox targets')
64
63
  vbox_servers: list[VBoxSerever] = []
65
64
  for vboxcls in vbox_clsids:
@@ -84,6 +83,7 @@ def installed_emulator():
84
83
 
85
84
  logger.debug(f'running VirtualBox servers: {running_servers}')
86
85
  results = []
86
+ server = ""
87
87
  try:
88
88
  for server in running_servers:
89
89
  logger.debug(f'checking {server}')
@@ -34,3 +34,11 @@ class BaseWindowsCaptureMethod(BaseCaptureMethod):
34
34
 
35
35
  def clickable(self):
36
36
  return self.hwnd_window is not None and self.hwnd_window.visible
37
+
38
+ def __str__(self):
39
+ result = f'{self.__class__.__name__}_{self.width}x{self.height}'
40
+ if self.hwnd_window is None:
41
+ result += '_no_window'
42
+ else:
43
+ result += f'_{self.hwnd_window}'
44
+ return result
@@ -1,15 +1,18 @@
1
+ import subprocess
1
2
  import sys
2
- import traceback
3
3
  import threading
4
+ import traceback
4
5
 
5
6
  from ok.util.path import get_path_relative_to_exe
6
7
 
8
+
7
9
  def get_thread_name(thread_id):
8
10
  for thread in threading.enumerate():
9
11
  if thread.ident == thread_id:
10
12
  return thread.name
11
13
  return "" # Return empty string if the thread name is not found
12
14
 
15
+
13
16
  def dump_threads():
14
17
  # Get the stack trace for each thread
15
18
  thread_dumps = []
@@ -25,3 +28,4 @@ def dump_threads():
25
28
 
26
29
  with open(output_file, "w") as file:
27
30
  file.write("\n\n".join(thread_dumps))
31
+ subprocess.Popen(r'explorer /select,"{}"'.format(output_file))
@@ -8,6 +8,7 @@ from qfluentwidgets import FluentTranslator, qconfig, Theme
8
8
 
9
9
  import ok
10
10
  import ok.gui.resources
11
+ from ok.firebase.FireBaseAnalytics import FireBaseAnalytics
11
12
  from ok.gui.Communicate import communicate
12
13
  from ok.gui.MainWindow import MainWindow
13
14
  from ok.gui.MessageWindow import MessageWindow
@@ -47,6 +48,8 @@ class App:
47
48
  self.main_window = None
48
49
  self.exit_event = exit_event
49
50
  self.icon = QIcon(self.config.get('gui_icon') or ":/icon/icon.ico")
51
+ if self.config.get('firebase'):
52
+ self.fire_base_analytics = FireBaseAnalytics(self.config, self.exit_event)
50
53
 
51
54
  translator = QTranslator(self.app)
52
55
  full_path = os.path.join(i18n_path, f"{self.locale.name()}")
@@ -12,7 +12,7 @@ class Communicate(QObject):
12
12
  task_info = Signal()
13
13
  window = Signal(bool, int, int, int, int, int, int, float)
14
14
  loading_progress = Signal(str)
15
- notification = Signal(str, str, bool)
15
+ notification = Signal(str, str, bool, bool)
16
16
  executor_paused: Signal = Signal(bool)
17
17
  screenshot = Signal(np.ndarray, str)
18
18
  update_overlay = Signal()
@@ -7,6 +7,7 @@ import ok.gui
7
7
  from ok.capture.windows.dump import dump_threads
8
8
  from ok.gui.Communicate import communicate
9
9
  from ok.gui.about.AboutTab import AboutTab
10
+ from ok.gui.debug.DebugTab import DebugTab
10
11
  from ok.gui.start.StartTab import StartTab
11
12
  from ok.gui.tasks.OneTimeTaskTab import OneTimeTaskTab
12
13
  from ok.gui.tasks.TriggerTaskTab import TriggerTaskTab
@@ -41,8 +42,13 @@ class MainWindow(MSFluentWindow):
41
42
  # debug_tab = DebugTab()
42
43
  # self.addSubInterface(debug_tab, FluentIcon.COMMAND_PROMPT, self.tr('Debug'))
43
44
  # ... Add other tabs similarly
45
+ if debug:
46
+ debug_tab = DebugTab(exit_event)
47
+ self.addSubInterface(debug_tab, FluentIcon.DEVELOPER_TOOLS, self.tr('Debug'),
48
+ position=NavigationItemPosition.BOTTOM)
49
+
44
50
  if about:
45
- about_tab = AboutTab(icon, title, version, about)
51
+ about_tab = AboutTab(icon, title, version, debug, about)
46
52
  self.addSubInterface(about_tab, FluentIcon.QUESTION, self.tr('About'),
47
53
  position=NavigationItemPosition.BOTTOM)
48
54
  # Styling the tabs and content if needed, for example:
@@ -82,7 +88,7 @@ class MainWindow(MSFluentWindow):
82
88
  )
83
89
  self.tray.showMessage(title, message)
84
90
 
85
- def show_notification(self, message, title=None, error=None):
91
+ def show_notification(self, message, title=None, error=False, tray=True):
86
92
  bar = InfoBar.error if error else InfoBar.info
87
93
  if title is None:
88
94
  title = f"{self.tr('Error') if error else 'Info'}:"
@@ -95,9 +101,8 @@ class MainWindow(MSFluentWindow):
95
101
  duration=5000, # won't disappear automatically
96
102
  parent=self.window()
97
103
  )
98
- if title is None:
99
- title = self.title
100
- self.tray.showMessage(title, message)
104
+ if tray:
105
+ self.tray.showMessage(title, message)
101
106
 
102
107
  def capture_error(self):
103
108
  self.show_notification(self.tr('Please check whether the game window is selected correctly!'),
@@ -0,0 +1,145 @@
1
+ from PySide6.QtCore import Qt
2
+ from PySide6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout
3
+ from qfluentwidgets import PushButton, InfoBar, InfoBarPosition
4
+
5
+ import ok.gui
6
+ from ok.gui.Communicate import communicate
7
+ from ok.gui.about.VersionCard import VersionCard
8
+ from ok.gui.widget.Tab import Tab
9
+ from ok.logging.Logger import get_logger
10
+
11
+ logger = get_logger(__name__)
12
+
13
+
14
+ class AboutTab(Tab):
15
+ def __init__(self, icon, title, version, debug, about):
16
+ super().__init__()
17
+ self.version_card = VersionCard(icon, title, version, debug, self)
18
+ # Create a QTextEdit instance
19
+ self.addWidget(self.version_card)
20
+ about_label = QLabel()
21
+ about_label.setText(about)
22
+ about_label.setWordWrap(True)
23
+ about_label.setOpenExternalLinks(True)
24
+
25
+ # Set the layout on the widget
26
+ self.addWidget(about_label)
27
+ if ok.gui.app.updater.enabled():
28
+ self.download_latest_button = PushButton(self.tr('Download Release'))
29
+ self.download_latest_button.clicked.connect(self.download_latest)
30
+ self.download_latest_debug_button = PushButton(self.tr('Download Debug'))
31
+ self.download_latest_debug_button.clicked.connect(self.download_latest_debug)
32
+
33
+ self.latest_hbox = QHBoxLayout()
34
+ self.addLayout(self.latest_hbox)
35
+ self.latest_label = QLabel()
36
+ self.latest_label.setWordWrap(True)
37
+ self.latest_hbox.addWidget(self.latest_label, stretch=1)
38
+ self.download_latest_vbox = QVBoxLayout()
39
+ self.latest_hbox.addLayout(self.download_latest_vbox, stretch=0)
40
+ self.download_latest_vbox.addWidget(self.download_latest_button, stretch=0)
41
+ self.download_latest_vbox.addWidget(self.download_latest_debug_button, stretch=0)
42
+ self.download_latest_vbox.addStretch(1)
43
+
44
+ self.download_stable_button = PushButton(self.tr('Download Release'))
45
+ self.download_stable_button.clicked.connect(self.download_stable)
46
+ self.download_stable_debug_button = PushButton(self.tr('Download Debug'))
47
+ self.download_stable_debug_button.clicked.connect(self.download_stable_debug)
48
+ self.stable_hbox = QHBoxLayout()
49
+ self.stable_label = QLabel()
50
+ self.stable_label.setWordWrap(True)
51
+ self.addLayout(self.stable_hbox)
52
+ self.stable_hbox.addWidget(self.stable_label, stretch=1)
53
+
54
+ self.download_stable_vbox = QVBoxLayout()
55
+ self.stable_hbox.addLayout(self.download_stable_vbox, stretch=0)
56
+ self.download_stable_vbox.addWidget(self.download_stable_button, stretch=0)
57
+ self.download_stable_vbox.addWidget(self.download_stable_debug_button, stretch=0)
58
+ self.download_stable_vbox.addStretch(1)
59
+
60
+ communicate.download_update.connect(self.download_update)
61
+ communicate.check_update.connect(self.update_update)
62
+
63
+ self.update_update_buttons()
64
+
65
+ def update_update_buttons(self):
66
+ if ok.gui.app.updater.latest_release:
67
+ self.latest_label.setText(self.get_version_text(ok.gui.app.updater.latest_release))
68
+ has_release_asset = ok.gui.app.updater.latest_release is not None and ok.gui.app.updater.latest_release.get(
69
+ 'release_asset') is not None
70
+ self.download_latest_button.setVisible(has_release_asset)
71
+ has_release_debug = ok.gui.app.updater.latest_release is not None and ok.gui.app.updater.latest_release.get(
72
+ 'debug_asset') is not None
73
+ self.download_latest_debug_button.setVisible(has_release_debug)
74
+ self.latest_label.setVisible(has_release_asset or has_release_debug)
75
+
76
+ if ok.gui.app.updater.stable_release:
77
+ self.stable_label.setText(self.get_version_text(ok.gui.app.updater.stable_release))
78
+
79
+ has_release_asset = ok.gui.app.updater.stable_release is not None and ok.gui.app.updater.stable_release.get(
80
+ 'release_asset') is not None
81
+ self.download_stable_button.setVisible(has_release_asset)
82
+ has_release_debug = ok.gui.app.updater.stable_release is not None and ok.gui.app.updater.stable_release.get(
83
+ 'debug_asset') is not None
84
+ self.download_stable_debug_button.setVisible(has_release_debug)
85
+ self.stable_label.setVisible(has_release_asset or has_release_debug)
86
+
87
+ self.download_latest_button.setDisabled(ok.gui.app.updater.downloading)
88
+ self.download_stable_button.setDisabled(ok.gui.app.updater.downloading)
89
+ self.download_stable_debug_button.setDisabled(ok.gui.app.updater.downloading)
90
+ self.download_latest_debug_button.setDisabled(ok.gui.app.updater.downloading)
91
+
92
+ def update_update(self, error):
93
+ self.update_update_buttons()
94
+
95
+ def get_version_text(self, release):
96
+ text = "<h3>{title}: {version}</h3>"
97
+ if release.get('prerelease'):
98
+ title = self.tr('Beta Version')
99
+ else:
100
+ title = self.tr('Stable Version')
101
+ text = text.format(title=title, version=release.get('version'))
102
+ text += "<p>{date}</p>".format(date=release.get('date'))
103
+ text += "<p>{notes}</p>".format(notes=text_to_html_paragraphs(release.get('notes')))
104
+ return text
105
+
106
+ def download_update(self, percent, progress, done, error):
107
+ if done:
108
+ if error:
109
+ title = self.tr('Download Error:')
110
+ message = error
111
+ InfoBar.error(
112
+ title=title,
113
+ content=message,
114
+ orient=Qt.Horizontal,
115
+ isClosable=True,
116
+ position=InfoBarPosition.TOP,
117
+ duration=5000, # won't disappear automatically
118
+ parent=self
119
+ )
120
+
121
+ self.update_update_buttons()
122
+
123
+ @staticmethod
124
+ def download_latest():
125
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.latest_release, False))
126
+
127
+ @staticmethod
128
+ def download_latest_debug():
129
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.latest_release, True))
130
+
131
+ @staticmethod
132
+ def download_stable():
133
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.stable_release, False))
134
+
135
+ @staticmethod
136
+ def download_stable_debug():
137
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.download(ok.gui.app.updater.stable_release, True))
138
+
139
+
140
+ def text_to_html_paragraphs(text):
141
+ # Split the text into lines
142
+ lines = text.split('\n')
143
+
144
+ # Wrap each line in a <p> tag and join them
145
+ return ''.join(f'<p>{line}</p>' for line in lines)
@@ -1,16 +1,19 @@
1
1
  from PySide6.QtCore import Qt
2
2
  from PySide6.QtWidgets import QLabel
3
- from qfluentwidgets import SettingCard, PushButton, ProgressBar, InfoBar, InfoBarPosition
3
+ from qfluentwidgets import SettingCard, PushButton, ProgressBar, InfoBar, InfoBarPosition, MessageBox
4
4
 
5
5
  import ok
6
6
  from ok.gui.Communicate import communicate
7
+ from ok.logging.Logger import get_logger
8
+
9
+ logger = get_logger(__name__)
7
10
 
8
11
 
9
12
  class VersionCard(SettingCard):
10
13
  """ Sample card """
11
14
 
12
- def __init__(self, icon, title, version, parent=None):
13
- super().__init__(icon, title, version)
15
+ def __init__(self, icon, title, version, debug, parent=None):
16
+ super().__init__(icon, title, f'{version} {self.get_type(debug)}')
14
17
  self.downloading_text = QLabel()
15
18
  self.hBoxLayout.addWidget(self.downloading_text)
16
19
  self.hBoxLayout.addSpacing(16)
@@ -25,11 +28,17 @@ class VersionCard(SettingCard):
25
28
  self.check_update_button.clicked.connect(self.check_update)
26
29
  self.hBoxLayout.addWidget(self.check_update_button)
27
30
  self.hBoxLayout.addSpacing(16)
31
+ self.update_button = PushButton()
32
+ self.update_button.clicked.connect(self.show_update_dialog)
33
+ self.hBoxLayout.addWidget(self.update_button)
34
+ self.hBoxLayout.addSpacing(16)
28
35
  self.update_buttons(0, "")
29
36
  communicate.check_update.connect(self.update_update)
30
37
  communicate.download_update.connect(self.download_update)
31
38
 
32
39
  def download_update(self, percent, progress, done, error):
40
+ if done and not error:
41
+ self.show_update_dialog()
33
42
  self.update_buttons(percent, progress)
34
43
 
35
44
  def update_buttons(self, percent, progress):
@@ -42,6 +51,33 @@ class VersionCard(SettingCard):
42
51
  else:
43
52
  self.downloading_text.hide()
44
53
  self.download_bar.hide()
54
+ if ok.gui.app.updater.to_update:
55
+ self.update_button.setText(
56
+ self.tr('Update to {version} {type}').format(version=ok.gui.app.updater.to_update.get('version'),
57
+ type=self.get_type()))
58
+ self.update_button.setVisible(ok.gui.app.updater.to_update is not None)
59
+
60
+ def get_type(self, debug=None):
61
+ if debug is None and ok.gui.app.updater.to_update is not None:
62
+ debug = ok.gui.app.updater.to_update.get('debug')
63
+ return self.tr('Debug') if debug else self.tr('Release')
64
+
65
+ def show_update_dialog(self):
66
+ title = self.tr('Update Now')
67
+ content = self.tr(
68
+ "Are you sure you want to update to {version} {type}?".format(
69
+ version=ok.gui.app.updater.to_update.get(
70
+ 'version'), type=self.get_type())) + '\n\n' + ok.gui.app.updater.to_update.get(
71
+ 'notes')
72
+
73
+ w = MessageBox(title, content, self.window())
74
+ w.setContentCopyable(True)
75
+ if w.exec():
76
+ logger.info("user click update")
77
+ self.do_update()
78
+
79
+ def do_update(self):
80
+ ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.update())
45
81
 
46
82
  def update_update(self, error):
47
83
  title = self.tr('Info')
@@ -67,6 +103,6 @@ class VersionCard(SettingCard):
67
103
  self.check_update_button.setEnabled(True)
68
104
 
69
105
  def check_update(self):
70
- ok.gui.app.updater.async_run(lambda: ok.gui.app.updater.check_for_updates())
106
+ ok.gui.app.updater.check_for_updates()
71
107
  self.check_update_button.setText(self.tr("Checking for updates"))
72
108
  self.check_update_button.setEnabled(False)
@@ -0,0 +1,53 @@
1
+ import subprocess
2
+
3
+ from PySide6.QtWidgets import QWidget
4
+ from qfluentwidgets import PushButton, FlowLayout
5
+
6
+ import ok.gui
7
+ from ok.capture.windows.dump import dump_threads
8
+ from ok.gui.widget.Tab import Tab
9
+ from ok.logging.Logger import get_logger
10
+ from ok.util.Handler import Handler
11
+
12
+ logger = get_logger(__name__)
13
+
14
+
15
+ class DebugTab(Tab):
16
+ def __init__(self, exit_event):
17
+ super().__init__()
18
+ widget = QWidget()
19
+ layout = FlowLayout(widget, False)
20
+
21
+ layout.setContentsMargins(0, 0, 0, 0)
22
+ layout.setVerticalSpacing(20)
23
+ layout.setHorizontalSpacing(10)
24
+ self.addWidget(widget)
25
+ self.handler = Handler(exit_event, "DebugTab")
26
+
27
+ dump_button = PushButton(self.tr("Dump Threads(HotKey:Ctrl+Alt+D)"))
28
+ dump_button.clicked.connect(lambda: self.handler.post(dump_threads))
29
+ layout.addWidget(dump_button)
30
+
31
+ capture_button = PushButton(self.tr("Capture Screenshot"))
32
+ capture_button.clicked.connect(lambda: self.handler.post(self.capture))
33
+ layout.addWidget(capture_button)
34
+
35
+ open_log_folder = PushButton(self.tr("Open Logs"))
36
+
37
+ def capture(self):
38
+ if ok.gui.device_manager.capture_method is not None:
39
+ logger.info(f'ok.gui.device_manager.capture_method {ok.gui.device_manager.capture_method}')
40
+ capture = str(ok.gui.device_manager.capture_method)
41
+ frame = ok.gui.device_manager.capture_method.do_get_frame()
42
+ if frame is not None:
43
+ file_path = ok.gui.ok.screenshot.generate_screen_shot(frame, ok.gui.ok.screenshot.ui_dict,
44
+ ok.gui.ok.screenshot.screenshot_folder, capture)
45
+
46
+ # Use subprocess.Popen to open the file explorer and select the file
47
+ subprocess.Popen(r'explorer /select,"{}"'.format(file_path))
48
+ logger.info(f'captured screenshot: {capture}')
49
+ self.alert_info(self.tr('Capture Success'))
50
+ else:
51
+ self.alert_error(self.tr('Capture returned None'))
52
+ else:
53
+ self.alert_error(self.tr('No Capture Available or Selected'))
@@ -107,31 +107,35 @@ class Screenshot(QObject):
107
107
  pil_image = self.to_pil_image(frame)
108
108
  if pil_image is None:
109
109
  return
110
- self.save_pil_image(name + '_original', folder, pil_image)
110
+
111
+ originl_name = self.save_pil_image(name + '_original', folder, pil_image)
111
112
  # Ensure no fill
112
113
  draw = ImageDraw.Draw(pil_image)
113
114
 
114
115
  frame_ratio = 1
115
- for key, value in ui_dict.items():
116
- boxes = value[0]
117
- color = tuple([int(x) for x in value[2].getRgb()]) # Convert QColor to BGR tuple
118
- for box in boxes:
119
- width = int(box.width * frame_ratio)
120
- height = int(box.height * frame_ratio)
121
- if width <= 0 or height <= 0:
122
- logger.error(f"box height and width <=0 {box}")
123
- continue
124
- x = int(box.x * frame_ratio)
125
- y = int(box.y * frame_ratio)
126
- # Draw a rectangle. Arguments are (x, y, width, height).
127
- # Adjust these values according to the desired size and position.
128
- draw.rectangle([x, y, x + width, y + height], outline=color, width=2)
129
- # Put text
130
- draw.text((x, y + height + 8), f"{box.name or key}_{round(box.confidence * 100)}", fill=color,
131
- font=self.pil_font)
132
- self.save_pil_image(name + '_boxed', folder, pil_image)
133
-
134
- def save_pil_image(self, name, folder, pil_image):
116
+ if len(ui_dict) > 0:
117
+ for key, value in ui_dict.items():
118
+ boxes = value[0]
119
+ color = tuple([int(x) for x in value[2].getRgb()]) # Convert QColor to BGR tuple
120
+ for box in boxes:
121
+ width = int(box.width * frame_ratio)
122
+ height = int(box.height * frame_ratio)
123
+ if width <= 0 or height <= 0:
124
+ logger.error(f"box height and width <=0 {box}")
125
+ continue
126
+ x = int(box.x * frame_ratio)
127
+ y = int(box.y * frame_ratio)
128
+ # Draw a rectangle. Arguments are (x, y, width, height).
129
+ # Adjust these values according to the desired size and position.
130
+ draw.rectangle([x, y, x + width, y + height], outline=color, width=2)
131
+ # Put text
132
+ draw.text((x, y + height + 8), f"{box.name or key}_{round(box.confidence * 100)}", fill=color,
133
+ font=self.pil_font)
134
+ self.save_pil_image(name + '_boxed', folder, pil_image)
135
+ return originl_name
136
+
137
+ @staticmethod
138
+ def save_pil_image(name, folder, pil_image):
135
139
 
136
140
  now = datetime.now()
137
141
 
@@ -145,7 +149,9 @@ class Screenshot(QObject):
145
149
  try:
146
150
  pil_image.save(file)
147
151
  except OSError:
148
- pil_image.save(os.path.join(folder, f"{time_string}.png"))
152
+ file = os.path.join(folder, f"{time_string}.png")
153
+ pil_image.save(file)
154
+ return file
149
155
 
150
156
  def stop(self):
151
157
  logger.debug(f'stop screenshot')