kotonebot 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

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 (107) hide show
  1. kotonebot/__init__.py +39 -39
  2. kotonebot/backend/bot.py +312 -312
  3. kotonebot/backend/color.py +525 -525
  4. kotonebot/backend/context/__init__.py +3 -3
  5. kotonebot/backend/context/context.py +1002 -1002
  6. kotonebot/backend/context/task_action.py +183 -183
  7. kotonebot/backend/core.py +86 -129
  8. kotonebot/backend/debug/entry.py +89 -89
  9. kotonebot/backend/debug/mock.py +78 -78
  10. kotonebot/backend/debug/server.py +222 -222
  11. kotonebot/backend/debug/vars.py +351 -351
  12. kotonebot/backend/dispatch.py +227 -227
  13. kotonebot/backend/flow_controller.py +196 -196
  14. kotonebot/backend/image.py +36 -5
  15. kotonebot/backend/loop.py +222 -208
  16. kotonebot/backend/ocr.py +535 -535
  17. kotonebot/backend/preprocessor.py +103 -103
  18. kotonebot/client/__init__.py +9 -9
  19. kotonebot/client/device.py +369 -529
  20. kotonebot/client/fast_screenshot.py +377 -377
  21. kotonebot/client/host/__init__.py +43 -43
  22. kotonebot/client/host/adb_common.py +101 -107
  23. kotonebot/client/host/custom.py +118 -118
  24. kotonebot/client/host/leidian_host.py +196 -196
  25. kotonebot/client/host/mumu12_host.py +353 -353
  26. kotonebot/client/host/protocol.py +214 -214
  27. kotonebot/client/host/windows_common.py +73 -58
  28. kotonebot/client/implements/__init__.py +65 -70
  29. kotonebot/client/implements/adb.py +89 -89
  30. kotonebot/client/implements/nemu_ipc/__init__.py +11 -11
  31. kotonebot/client/implements/nemu_ipc/external_renderer_ipc.py +284 -284
  32. kotonebot/client/implements/nemu_ipc/nemu_ipc.py +327 -327
  33. kotonebot/client/implements/remote_windows.py +188 -188
  34. kotonebot/client/implements/uiautomator2.py +85 -85
  35. kotonebot/client/implements/windows/__init__.py +1 -0
  36. kotonebot/client/implements/windows/print_window.py +133 -0
  37. kotonebot/client/implements/windows/send_message.py +324 -0
  38. kotonebot/client/implements/{windows.py → windows/windows.py} +175 -176
  39. kotonebot/client/protocol.py +69 -69
  40. kotonebot/client/registration.py +24 -24
  41. kotonebot/client/scaler.py +467 -0
  42. kotonebot/config/base_config.py +103 -96
  43. kotonebot/config/config.py +61 -0
  44. kotonebot/config/manager.py +36 -36
  45. kotonebot/core/__init__.py +13 -0
  46. kotonebot/core/entities/base.py +182 -0
  47. kotonebot/core/entities/compound.py +75 -0
  48. kotonebot/core/entities/ocr.py +117 -0
  49. kotonebot/core/entities/template_match.py +198 -0
  50. kotonebot/devtools/__init__.py +42 -0
  51. kotonebot/devtools/cli/__init__.py +6 -0
  52. kotonebot/devtools/cli/main.py +53 -0
  53. kotonebot/{tools → devtools}/mirror.py +354 -354
  54. kotonebot/devtools/project/project.py +41 -0
  55. kotonebot/devtools/project/scanner.py +202 -0
  56. kotonebot/devtools/project/schema.py +99 -0
  57. kotonebot/devtools/resgen/__init__.py +42 -0
  58. kotonebot/devtools/resgen/codegen.py +331 -0
  59. kotonebot/devtools/resgen/core.py +94 -0
  60. kotonebot/devtools/resgen/parsers.py +360 -0
  61. kotonebot/devtools/resgen/utils.py +158 -0
  62. kotonebot/devtools/resgen/validation.py +115 -0
  63. kotonebot/devtools/web/dist/assets/bootstrap-icons-BOrJxbIo.woff +0 -0
  64. kotonebot/devtools/web/dist/assets/bootstrap-icons-BtvjY1KL.woff2 +0 -0
  65. kotonebot/devtools/web/dist/assets/ext-language_tools-CD021WJ2.js +2577 -0
  66. kotonebot/devtools/web/dist/assets/index-B_m5f2LF.js +2836 -0
  67. kotonebot/devtools/web/dist/assets/index-BlEDyGGa.css +9 -0
  68. kotonebot/devtools/web/dist/assets/language-client-C9muzqaq.js +128 -0
  69. kotonebot/devtools/web/dist/assets/mode-python-CtHp76XS.js +476 -0
  70. kotonebot/devtools/web/dist/icons/symbol-class.svg +3 -0
  71. kotonebot/devtools/web/dist/icons/symbol-file.svg +3 -0
  72. kotonebot/devtools/web/dist/icons/symbol-method.svg +3 -0
  73. kotonebot/devtools/web/dist/index.html +25 -0
  74. kotonebot/devtools/web/server/__init__.py +0 -0
  75. kotonebot/devtools/web/server/rest_api.py +217 -0
  76. kotonebot/devtools/web/server/server.py +85 -0
  77. kotonebot/errors.py +76 -76
  78. kotonebot/interop/win/__init__.py +13 -9
  79. kotonebot/interop/win/_mouse.py +310 -310
  80. kotonebot/interop/win/message_box.py +313 -313
  81. kotonebot/interop/win/reg.py +37 -37
  82. kotonebot/interop/win/shake_mouse.py +224 -0
  83. kotonebot/interop/win/shortcut.py +43 -43
  84. kotonebot/interop/win/task_dialog.py +513 -513
  85. kotonebot/interop/win/window.py +89 -0
  86. kotonebot/logging/__init__.py +2 -2
  87. kotonebot/logging/log.py +17 -17
  88. kotonebot/primitives/__init__.py +19 -17
  89. kotonebot/primitives/geometry.py +1067 -862
  90. kotonebot/primitives/visual.py +143 -63
  91. kotonebot/ui/file_host/sensio.py +36 -36
  92. kotonebot/ui/file_host/tmp_send.py +54 -54
  93. kotonebot/ui/pushkit/__init__.py +3 -3
  94. kotonebot/ui/pushkit/image_host.py +88 -88
  95. kotonebot/ui/pushkit/protocol.py +13 -13
  96. kotonebot/ui/pushkit/wxpusher.py +54 -54
  97. kotonebot/ui/user.py +148 -148
  98. kotonebot/util.py +436 -436
  99. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/METADATA +84 -82
  100. kotonebot-0.7.0.dist-info/RECORD +109 -0
  101. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/WHEEL +1 -1
  102. kotonebot-0.7.0.dist-info/entry_points.txt +2 -0
  103. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/licenses/LICENSE +673 -673
  104. kotonebot/client/implements/adb_raw.py +0 -163
  105. kotonebot-0.5.0.dist-info/RECORD +0 -71
  106. /kotonebot/{tools → devtools/project}/__init__.py +0 -0
  107. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/top_level.txt +0 -0
@@ -1,89 +1,89 @@
1
- import os
2
- import runpy
3
- import shutil
4
- import argparse
5
- import importlib
6
- from pathlib import Path
7
- from threading import Thread
8
-
9
- from . import debug
10
- from kotonebot import logging
11
- from kotonebot.backend.context import init_context
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
- def _task_thread(task_module: str):
16
- """任务线程。"""
17
- runpy.run_module(task_module, run_name="__main__")
18
-
19
- def _parse_args():
20
- """解析命令行参数。"""
21
- parser = argparse.ArgumentParser(description='KotoneBot visual debug tool')
22
- parser.add_argument(
23
- '-s', '--save',
24
- help='Save dump image and results to the specified folder',
25
- type=str,
26
- metavar='PATH'
27
- )
28
- parser.add_argument(
29
- '-c', '--clear',
30
- help='Clear the dump folder before running',
31
- action='store_true'
32
- )
33
- parser.add_argument(
34
- '-t', '--config-type',
35
- help='The full path of the config data type. e.g. `kotonebot.tasks.common.BaseConfig`',
36
- type=str,
37
- metavar='TYPE',
38
- required=True
39
- )
40
- parser.add_argument(
41
- 'input_module',
42
- help='The module to run'
43
- )
44
- return parser.parse_args()
45
-
46
- def _start_task_thread(module: str):
47
- """启动任务线程。"""
48
- thread = Thread(target=_task_thread, args=(module,))
49
- thread.start()
50
-
51
- if __name__ == "__main__":
52
- args = _parse_args()
53
- debug.enabled = True
54
-
55
- # 设置保存路径
56
- if args.save:
57
- save_path = Path(args.save)
58
- debug.auto_save_to_folder = str(save_path)
59
- if not os.path.exists(save_path):
60
- os.makedirs(save_path)
61
- if args.clear:
62
- if debug.auto_save_to_folder:
63
- try:
64
- logger.info(f"Removing {debug.auto_save_to_folder}")
65
- shutil.rmtree(debug.auto_save_to_folder)
66
- except PermissionError:
67
- logger.warning(f"Failed to remove {debug.auto_save_to_folder}. Trying to remove all contents instead.")
68
- for root, dirs, files in os.walk(debug.auto_save_to_folder):
69
- for file in files:
70
- try:
71
- os.remove(os.path.join(root, file))
72
- except PermissionError:
73
- raise
74
-
75
-
76
- # 初始化上下文
77
- module_name, class_name = args.config_type.rsplit('.', 1)
78
- class_ = importlib.import_module(module_name).__getattribute__(class_name)
79
- init_context(config_type=class_)
80
-
81
- # 启动服务器
82
- from .server import app
83
- import uvicorn
84
-
85
- # 启动任务线程
86
- _start_task_thread(args.input_module)
87
-
88
- # 启动服务器
89
- uvicorn.run(app, host="127.0.0.1", port=8000, log_level='critical' if debug.hide_server_log else None)
1
+ import os
2
+ import runpy
3
+ import shutil
4
+ import argparse
5
+ import importlib
6
+ from pathlib import Path
7
+ from threading import Thread
8
+
9
+ from . import debug
10
+ from kotonebot import logging
11
+ from kotonebot.backend.context import init_context
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ def _task_thread(task_module: str):
16
+ """任务线程。"""
17
+ runpy.run_module(task_module, run_name="__main__")
18
+
19
+ def _parse_args():
20
+ """解析命令行参数。"""
21
+ parser = argparse.ArgumentParser(description='KotoneBot visual debug tool')
22
+ parser.add_argument(
23
+ '-s', '--save',
24
+ help='Save dump image and results to the specified folder',
25
+ type=str,
26
+ metavar='PATH'
27
+ )
28
+ parser.add_argument(
29
+ '-c', '--clear',
30
+ help='Clear the dump folder before running',
31
+ action='store_true'
32
+ )
33
+ parser.add_argument(
34
+ '-t', '--config-type',
35
+ help='The full path of the config data type. e.g. `kotonebot.tasks.common.BaseConfig`',
36
+ type=str,
37
+ metavar='TYPE',
38
+ required=True
39
+ )
40
+ parser.add_argument(
41
+ 'input_module',
42
+ help='The module to run'
43
+ )
44
+ return parser.parse_args()
45
+
46
+ def _start_task_thread(module: str):
47
+ """启动任务线程。"""
48
+ thread = Thread(target=_task_thread, args=(module,))
49
+ thread.start()
50
+
51
+ if __name__ == "__main__":
52
+ args = _parse_args()
53
+ debug.enabled = True
54
+
55
+ # 设置保存路径
56
+ if args.save:
57
+ save_path = Path(args.save)
58
+ debug.auto_save_to_folder = str(save_path)
59
+ if not os.path.exists(save_path):
60
+ os.makedirs(save_path)
61
+ if args.clear:
62
+ if debug.auto_save_to_folder:
63
+ try:
64
+ logger.info(f"Removing {debug.auto_save_to_folder}")
65
+ shutil.rmtree(debug.auto_save_to_folder)
66
+ except PermissionError:
67
+ logger.warning(f"Failed to remove {debug.auto_save_to_folder}. Trying to remove all contents instead.")
68
+ for root, dirs, files in os.walk(debug.auto_save_to_folder):
69
+ for file in files:
70
+ try:
71
+ os.remove(os.path.join(root, file))
72
+ except PermissionError:
73
+ raise
74
+
75
+
76
+ # 初始化上下文
77
+ module_name, class_name = args.config_type.rsplit('.', 1)
78
+ class_ = importlib.import_module(module_name).__getattribute__(class_name)
79
+ init_context(config_type=class_)
80
+
81
+ # 启动服务器
82
+ from .server import app
83
+ import uvicorn
84
+
85
+ # 启动任务线程
86
+ _start_task_thread(args.input_module)
87
+
88
+ # 启动服务器
89
+ uvicorn.run(app, host="127.0.0.1", port=8000, log_level='critical' if debug.hide_server_log else None)
@@ -1,79 +1,79 @@
1
- import time
2
- from typing_extensions import override
3
-
4
- import cv2
5
- from cv2.typing import MatLike
6
-
7
- from kotonebot import sleep
8
- from kotonebot.client.device import Device
9
-
10
- class Video:
11
- def __init__(self, path: str, fps: int):
12
- self.path = path
13
- self.fps = fps
14
- self.paused = False
15
- """是否暂停"""
16
- self.__cap = cv2.VideoCapture(path)
17
- self.__last_frame = None
18
- self.__last_time = 0
19
-
20
- def __iter__(self):
21
- return self
22
-
23
- def __next__(self):
24
- if self.paused:
25
- return self.__last_frame
26
- ret, frame = self.__cap.read()
27
- if not ret:
28
- raise StopIteration
29
- self.__last_frame = frame
30
- self.__last_time = time.time()
31
- if self.__last_time - time.time() < 1 / self.fps:
32
- sleep(1 / self.fps)
33
- return frame
34
-
35
- def pause(self):
36
- self.paused = True
37
-
38
- def resume(self):
39
- self.paused = False
40
-
41
- class MockDevice(Device):
42
- def __init__(
43
- self
44
- ):
45
- super().__init__()
46
- self.__video_stream = None
47
- self.__image = None
48
- self.__screen_size = None
49
-
50
- def load_video(self, path: str, fps: int):
51
- self.__video_stream = Video(path, fps)
52
- return self.__video_stream
53
-
54
- def load_image(self, img: str | MatLike):
55
- if isinstance(img, str):
56
- self.__image = cv2.imread(img)
57
- else:
58
- self.__image = img
59
- return self.__image
60
-
61
- def set_screen_size(self, width: int, height: int):
62
- self.__screen_size = (width, height)
63
-
64
- @override
65
- def screenshot(self):
66
- if self.__image is not None:
67
- return self.__image
68
- elif self.__video_stream is not None:
69
- return next(self.__video_stream)
70
- else:
71
- raise RuntimeError('No video stream loaded')
72
-
73
- @property
74
- @override
75
- def screen_size(self):
76
- if self.__screen_size is not None:
77
- return self.__screen_size
78
- else:
1
+ import time
2
+ from typing_extensions import override
3
+
4
+ import cv2
5
+ from cv2.typing import MatLike
6
+
7
+ from kotonebot import sleep
8
+ from kotonebot.client.device import Device
9
+
10
+ class Video:
11
+ def __init__(self, path: str, fps: int):
12
+ self.path = path
13
+ self.fps = fps
14
+ self.paused = False
15
+ """是否暂停"""
16
+ self.__cap = cv2.VideoCapture(path)
17
+ self.__last_frame = None
18
+ self.__last_time = 0
19
+
20
+ def __iter__(self):
21
+ return self
22
+
23
+ def __next__(self):
24
+ if self.paused:
25
+ return self.__last_frame
26
+ ret, frame = self.__cap.read()
27
+ if not ret:
28
+ raise StopIteration
29
+ self.__last_frame = frame
30
+ self.__last_time = time.time()
31
+ if self.__last_time - time.time() < 1 / self.fps:
32
+ sleep(1 / self.fps)
33
+ return frame
34
+
35
+ def pause(self):
36
+ self.paused = True
37
+
38
+ def resume(self):
39
+ self.paused = False
40
+
41
+ class MockDevice(Device):
42
+ def __init__(
43
+ self
44
+ ):
45
+ super().__init__()
46
+ self.__video_stream = None
47
+ self.__image = None
48
+ self.__screen_size = None
49
+
50
+ def load_video(self, path: str, fps: int):
51
+ self.__video_stream = Video(path, fps)
52
+ return self.__video_stream
53
+
54
+ def load_image(self, img: str | MatLike):
55
+ if isinstance(img, str):
56
+ self.__image = cv2.imread(img)
57
+ else:
58
+ self.__image = img
59
+ return self.__image
60
+
61
+ def set_screen_size(self, width: int, height: int):
62
+ self.__screen_size = (width, height)
63
+
64
+ @override
65
+ def screenshot(self):
66
+ if self.__image is not None:
67
+ return self.__image
68
+ elif self.__video_stream is not None:
69
+ return next(self.__video_stream)
70
+ else:
71
+ raise RuntimeError('No video stream loaded')
72
+
73
+ @property
74
+ @override
75
+ def screen_size(self):
76
+ if self.__screen_size is not None:
77
+ return self.__screen_size
78
+ else:
79
79
  raise RuntimeError('No screen size set')