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.
- kotonebot/__init__.py +39 -39
- kotonebot/backend/bot.py +312 -312
- kotonebot/backend/color.py +525 -525
- kotonebot/backend/context/__init__.py +3 -3
- kotonebot/backend/context/context.py +1002 -1002
- kotonebot/backend/context/task_action.py +183 -183
- kotonebot/backend/core.py +86 -129
- kotonebot/backend/debug/entry.py +89 -89
- kotonebot/backend/debug/mock.py +78 -78
- kotonebot/backend/debug/server.py +222 -222
- kotonebot/backend/debug/vars.py +351 -351
- kotonebot/backend/dispatch.py +227 -227
- kotonebot/backend/flow_controller.py +196 -196
- kotonebot/backend/image.py +36 -5
- kotonebot/backend/loop.py +222 -208
- kotonebot/backend/ocr.py +535 -535
- kotonebot/backend/preprocessor.py +103 -103
- kotonebot/client/__init__.py +9 -9
- kotonebot/client/device.py +369 -529
- kotonebot/client/fast_screenshot.py +377 -377
- kotonebot/client/host/__init__.py +43 -43
- kotonebot/client/host/adb_common.py +101 -107
- kotonebot/client/host/custom.py +118 -118
- kotonebot/client/host/leidian_host.py +196 -196
- kotonebot/client/host/mumu12_host.py +353 -353
- kotonebot/client/host/protocol.py +214 -214
- kotonebot/client/host/windows_common.py +73 -58
- kotonebot/client/implements/__init__.py +65 -70
- kotonebot/client/implements/adb.py +89 -89
- kotonebot/client/implements/nemu_ipc/__init__.py +11 -11
- kotonebot/client/implements/nemu_ipc/external_renderer_ipc.py +284 -284
- kotonebot/client/implements/nemu_ipc/nemu_ipc.py +327 -327
- kotonebot/client/implements/remote_windows.py +188 -188
- kotonebot/client/implements/uiautomator2.py +85 -85
- kotonebot/client/implements/windows/__init__.py +1 -0
- kotonebot/client/implements/windows/print_window.py +133 -0
- kotonebot/client/implements/windows/send_message.py +324 -0
- kotonebot/client/implements/{windows.py → windows/windows.py} +175 -176
- kotonebot/client/protocol.py +69 -69
- kotonebot/client/registration.py +24 -24
- kotonebot/client/scaler.py +467 -0
- kotonebot/config/base_config.py +103 -96
- kotonebot/config/config.py +61 -0
- kotonebot/config/manager.py +36 -36
- kotonebot/core/__init__.py +13 -0
- kotonebot/core/entities/base.py +182 -0
- kotonebot/core/entities/compound.py +75 -0
- kotonebot/core/entities/ocr.py +117 -0
- kotonebot/core/entities/template_match.py +198 -0
- kotonebot/devtools/__init__.py +42 -0
- kotonebot/devtools/cli/__init__.py +6 -0
- kotonebot/devtools/cli/main.py +53 -0
- kotonebot/{tools → devtools}/mirror.py +354 -354
- kotonebot/devtools/project/project.py +41 -0
- kotonebot/devtools/project/scanner.py +202 -0
- kotonebot/devtools/project/schema.py +99 -0
- kotonebot/devtools/resgen/__init__.py +42 -0
- kotonebot/devtools/resgen/codegen.py +331 -0
- kotonebot/devtools/resgen/core.py +94 -0
- kotonebot/devtools/resgen/parsers.py +360 -0
- kotonebot/devtools/resgen/utils.py +158 -0
- kotonebot/devtools/resgen/validation.py +115 -0
- kotonebot/devtools/web/dist/assets/bootstrap-icons-BOrJxbIo.woff +0 -0
- kotonebot/devtools/web/dist/assets/bootstrap-icons-BtvjY1KL.woff2 +0 -0
- kotonebot/devtools/web/dist/assets/ext-language_tools-CD021WJ2.js +2577 -0
- kotonebot/devtools/web/dist/assets/index-B_m5f2LF.js +2836 -0
- kotonebot/devtools/web/dist/assets/index-BlEDyGGa.css +9 -0
- kotonebot/devtools/web/dist/assets/language-client-C9muzqaq.js +128 -0
- kotonebot/devtools/web/dist/assets/mode-python-CtHp76XS.js +476 -0
- kotonebot/devtools/web/dist/icons/symbol-class.svg +3 -0
- kotonebot/devtools/web/dist/icons/symbol-file.svg +3 -0
- kotonebot/devtools/web/dist/icons/symbol-method.svg +3 -0
- kotonebot/devtools/web/dist/index.html +25 -0
- kotonebot/devtools/web/server/__init__.py +0 -0
- kotonebot/devtools/web/server/rest_api.py +217 -0
- kotonebot/devtools/web/server/server.py +85 -0
- kotonebot/errors.py +76 -76
- kotonebot/interop/win/__init__.py +13 -9
- kotonebot/interop/win/_mouse.py +310 -310
- kotonebot/interop/win/message_box.py +313 -313
- kotonebot/interop/win/reg.py +37 -37
- kotonebot/interop/win/shake_mouse.py +224 -0
- kotonebot/interop/win/shortcut.py +43 -43
- kotonebot/interop/win/task_dialog.py +513 -513
- kotonebot/interop/win/window.py +89 -0
- kotonebot/logging/__init__.py +2 -2
- kotonebot/logging/log.py +17 -17
- kotonebot/primitives/__init__.py +19 -17
- kotonebot/primitives/geometry.py +1067 -862
- kotonebot/primitives/visual.py +143 -63
- kotonebot/ui/file_host/sensio.py +36 -36
- kotonebot/ui/file_host/tmp_send.py +54 -54
- kotonebot/ui/pushkit/__init__.py +3 -3
- kotonebot/ui/pushkit/image_host.py +88 -88
- kotonebot/ui/pushkit/protocol.py +13 -13
- kotonebot/ui/pushkit/wxpusher.py +54 -54
- kotonebot/ui/user.py +148 -148
- kotonebot/util.py +436 -436
- {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/METADATA +84 -82
- kotonebot-0.7.0.dist-info/RECORD +109 -0
- {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/WHEEL +1 -1
- kotonebot-0.7.0.dist-info/entry_points.txt +2 -0
- {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/licenses/LICENSE +673 -673
- kotonebot/client/implements/adb_raw.py +0 -163
- kotonebot-0.5.0.dist-info/RECORD +0 -71
- /kotonebot/{tools → devtools/project}/__init__.py +0 -0
- {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import warnings
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing_extensions import deprecated
|
|
5
|
-
from typing import Callable, ParamSpec, TypeVar, overload, Literal
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
from .context import ContextStackVars, ScreenshotMode
|
|
9
|
-
from ...errors import TaskNotFoundError
|
|
10
|
-
|
|
11
|
-
P = ParamSpec('P')
|
|
12
|
-
R = TypeVar('R')
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
TaskRunAtType = Literal['pre', 'post', 'manual', 'regular'] | str
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@dataclass
|
|
19
|
-
class Task:
|
|
20
|
-
name: str
|
|
21
|
-
id: str
|
|
22
|
-
description: str
|
|
23
|
-
func: Callable
|
|
24
|
-
priority: int
|
|
25
|
-
"""
|
|
26
|
-
任务优先级,数字越大优先级越高。
|
|
27
|
-
"""
|
|
28
|
-
run_at: TaskRunAtType = 'regular'
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@dataclass
|
|
32
|
-
class Action:
|
|
33
|
-
name: str
|
|
34
|
-
description: str
|
|
35
|
-
func: Callable
|
|
36
|
-
priority: int
|
|
37
|
-
"""
|
|
38
|
-
动作优先级,数字越大优先级越高。
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
task_registry: dict[str, Task] = {}
|
|
43
|
-
action_registry: dict[str, Action] = {}
|
|
44
|
-
current_callstack: list[Task|Action] = []
|
|
45
|
-
|
|
46
|
-
def _placeholder():
|
|
47
|
-
raise NotImplementedError('Placeholder function')
|
|
48
|
-
|
|
49
|
-
def task(
|
|
50
|
-
name: str,
|
|
51
|
-
task_id: str|None = None,
|
|
52
|
-
description: str|None = None,
|
|
53
|
-
*,
|
|
54
|
-
pass_through: bool = False,
|
|
55
|
-
priority: int = 0,
|
|
56
|
-
screenshot_mode: ScreenshotMode = 'auto',
|
|
57
|
-
run_at: TaskRunAtType = 'regular'
|
|
58
|
-
):
|
|
59
|
-
"""
|
|
60
|
-
`task` 装饰器,用于标记一个函数为任务函数。
|
|
61
|
-
|
|
62
|
-
:param name: 任务名称
|
|
63
|
-
:param task_id: 任务 ID。如果为 None,则使用函数名称作为 ID。
|
|
64
|
-
:param description: 任务描述。如果为 None,则使用函数的 docstring 作为描述。
|
|
65
|
-
:param pass_through:
|
|
66
|
-
默认情况下, @task 装饰器会包裹任务函数,跟踪其执行情况。
|
|
67
|
-
如果不想跟踪,则设置此参数为 False。
|
|
68
|
-
:param priority: 任务优先级,数字越大优先级越高。
|
|
69
|
-
:param run_at: 任务运行时间。
|
|
70
|
-
"""
|
|
71
|
-
# 设置 ID
|
|
72
|
-
# 获取 caller 信息
|
|
73
|
-
def _task_decorator(func: Callable[P, R]) -> Callable[P, R]:
|
|
74
|
-
nonlocal description, task_id
|
|
75
|
-
description = description or func.__doc__ or ''
|
|
76
|
-
# TODO: task_id 冲突检测
|
|
77
|
-
task_id = task_id or func.__name__
|
|
78
|
-
task = Task(name, task_id, description, _placeholder, priority, run_at)
|
|
79
|
-
task_registry[name] = task
|
|
80
|
-
logger.debug(f'Task "{name}" registered.')
|
|
81
|
-
if pass_through:
|
|
82
|
-
return func
|
|
83
|
-
else:
|
|
84
|
-
def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
85
|
-
current_callstack.append(task)
|
|
86
|
-
vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
|
|
87
|
-
ret = func(*args, **kwargs)
|
|
88
|
-
ContextStackVars.pop()
|
|
89
|
-
current_callstack.pop()
|
|
90
|
-
return ret
|
|
91
|
-
task.func = _wrapper
|
|
92
|
-
return _wrapper
|
|
93
|
-
return _task_decorator
|
|
94
|
-
|
|
95
|
-
@overload
|
|
96
|
-
def action(func: Callable[P, R]) -> Callable[P, R]: ...
|
|
97
|
-
|
|
98
|
-
@deprecated('Use `action` with screenshot_mode=`manual` instead.')
|
|
99
|
-
@overload
|
|
100
|
-
def action(
|
|
101
|
-
name: str,
|
|
102
|
-
*,
|
|
103
|
-
description: str|None = None,
|
|
104
|
-
pass_through: bool = False,
|
|
105
|
-
priority: int = 0,
|
|
106
|
-
screenshot_mode: Literal['manual-inherit'],
|
|
107
|
-
) -> Callable[[Callable[P, R]], Callable[P, R]]: ...
|
|
108
|
-
|
|
109
|
-
@overload
|
|
110
|
-
def action(
|
|
111
|
-
name: str,
|
|
112
|
-
*,
|
|
113
|
-
description: str|None = None,
|
|
114
|
-
pass_through: bool = False,
|
|
115
|
-
priority: int = 0,
|
|
116
|
-
screenshot_mode: ScreenshotMode | None = None,
|
|
117
|
-
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
118
|
-
"""
|
|
119
|
-
`action` 装饰器,用于标记一个函数为动作函数。
|
|
120
|
-
|
|
121
|
-
:param name: 动作名称。如果为 None,则使用函数的名称作为名称。
|
|
122
|
-
:param description: 动作描述。如果为 None,则使用函数的 docstring 作为描述。
|
|
123
|
-
:param pass_through:
|
|
124
|
-
默认情况下, @action 装饰器会包裹动作函数,跟踪其执行情况。
|
|
125
|
-
如果不想跟踪,则设置此参数为 False。
|
|
126
|
-
:param priority: 动作优先级,数字越大优先级越高。
|
|
127
|
-
:param screenshot_mode: 截图模式。
|
|
128
|
-
"""
|
|
129
|
-
...
|
|
130
|
-
|
|
131
|
-
def action(*args, **kwargs):
|
|
132
|
-
def _register(func: Callable, name: str, description: str|None = None, priority: int = 0) -> Action:
|
|
133
|
-
description = description or func.__doc__ or ''
|
|
134
|
-
action = Action(name, description, func, priority)
|
|
135
|
-
action_registry[name] = action
|
|
136
|
-
logger.debug(f'Action "{name}" registered.')
|
|
137
|
-
return action
|
|
138
|
-
|
|
139
|
-
if len(args) == 1 and isinstance(args[0], Callable):
|
|
140
|
-
func = args[0]
|
|
141
|
-
action = _register(_placeholder, func.__name__, func.__doc__)
|
|
142
|
-
def _wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
143
|
-
current_callstack.append(action)
|
|
144
|
-
vars = ContextStackVars.push()
|
|
145
|
-
ret = func(*args, **kwargs)
|
|
146
|
-
ContextStackVars.pop()
|
|
147
|
-
current_callstack.pop()
|
|
148
|
-
return ret
|
|
149
|
-
action.func = _wrapper
|
|
150
|
-
return _wrapper
|
|
151
|
-
else:
|
|
152
|
-
name = args[0]
|
|
153
|
-
description = kwargs.get('description', None)
|
|
154
|
-
pass_through = kwargs.get('pass_through', False)
|
|
155
|
-
priority = kwargs.get('priority', 0)
|
|
156
|
-
screenshot_mode = kwargs.get('screenshot_mode', None)
|
|
157
|
-
if screenshot_mode == 'manual-inherit':
|
|
158
|
-
warnings.warn('`screenshot_mode=manual-inherit` is deprecated. Use `screenshot_mode=manual` instead.')
|
|
159
|
-
def _action_decorator(func: Callable):
|
|
160
|
-
nonlocal pass_through
|
|
161
|
-
action = _register(_placeholder, name, description)
|
|
162
|
-
pass_through = kwargs.get('pass_through', False)
|
|
163
|
-
if pass_through:
|
|
164
|
-
return func
|
|
165
|
-
else:
|
|
166
|
-
def _wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
167
|
-
current_callstack.append(action)
|
|
168
|
-
vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
|
|
169
|
-
ret = func(*args, **kwargs)
|
|
170
|
-
ContextStackVars.pop()
|
|
171
|
-
current_callstack.pop()
|
|
172
|
-
return ret
|
|
173
|
-
action.func = _wrapper
|
|
174
|
-
return _wrapper
|
|
175
|
-
return _action_decorator
|
|
176
|
-
|
|
177
|
-
def tasks_from_id(task_ids: list[str]) -> list[Task]:
|
|
178
|
-
result = []
|
|
179
|
-
for tid in task_ids:
|
|
180
|
-
target = next(task for task in task_registry.values() if task.id == tid)
|
|
181
|
-
if target is None:
|
|
182
|
-
raise TaskNotFoundError(f'Task "{tid}" not found.')
|
|
183
|
-
result.append(target)
|
|
1
|
+
import logging
|
|
2
|
+
import warnings
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing_extensions import deprecated
|
|
5
|
+
from typing import Callable, ParamSpec, TypeVar, overload, Literal
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from .context import ContextStackVars, ScreenshotMode
|
|
9
|
+
from ...errors import TaskNotFoundError
|
|
10
|
+
|
|
11
|
+
P = ParamSpec('P')
|
|
12
|
+
R = TypeVar('R')
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
TaskRunAtType = Literal['pre', 'post', 'manual', 'regular'] | str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Task:
|
|
20
|
+
name: str
|
|
21
|
+
id: str
|
|
22
|
+
description: str
|
|
23
|
+
func: Callable
|
|
24
|
+
priority: int
|
|
25
|
+
"""
|
|
26
|
+
任务优先级,数字越大优先级越高。
|
|
27
|
+
"""
|
|
28
|
+
run_at: TaskRunAtType = 'regular'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class Action:
|
|
33
|
+
name: str
|
|
34
|
+
description: str
|
|
35
|
+
func: Callable
|
|
36
|
+
priority: int
|
|
37
|
+
"""
|
|
38
|
+
动作优先级,数字越大优先级越高。
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
task_registry: dict[str, Task] = {}
|
|
43
|
+
action_registry: dict[str, Action] = {}
|
|
44
|
+
current_callstack: list[Task|Action] = []
|
|
45
|
+
|
|
46
|
+
def _placeholder():
|
|
47
|
+
raise NotImplementedError('Placeholder function')
|
|
48
|
+
|
|
49
|
+
def task(
|
|
50
|
+
name: str,
|
|
51
|
+
task_id: str|None = None,
|
|
52
|
+
description: str|None = None,
|
|
53
|
+
*,
|
|
54
|
+
pass_through: bool = False,
|
|
55
|
+
priority: int = 0,
|
|
56
|
+
screenshot_mode: ScreenshotMode = 'auto',
|
|
57
|
+
run_at: TaskRunAtType = 'regular'
|
|
58
|
+
):
|
|
59
|
+
"""
|
|
60
|
+
`task` 装饰器,用于标记一个函数为任务函数。
|
|
61
|
+
|
|
62
|
+
:param name: 任务名称
|
|
63
|
+
:param task_id: 任务 ID。如果为 None,则使用函数名称作为 ID。
|
|
64
|
+
:param description: 任务描述。如果为 None,则使用函数的 docstring 作为描述。
|
|
65
|
+
:param pass_through:
|
|
66
|
+
默认情况下, @task 装饰器会包裹任务函数,跟踪其执行情况。
|
|
67
|
+
如果不想跟踪,则设置此参数为 False。
|
|
68
|
+
:param priority: 任务优先级,数字越大优先级越高。
|
|
69
|
+
:param run_at: 任务运行时间。
|
|
70
|
+
"""
|
|
71
|
+
# 设置 ID
|
|
72
|
+
# 获取 caller 信息
|
|
73
|
+
def _task_decorator(func: Callable[P, R]) -> Callable[P, R]:
|
|
74
|
+
nonlocal description, task_id
|
|
75
|
+
description = description or func.__doc__ or ''
|
|
76
|
+
# TODO: task_id 冲突检测
|
|
77
|
+
task_id = task_id or func.__name__
|
|
78
|
+
task = Task(name, task_id, description, _placeholder, priority, run_at)
|
|
79
|
+
task_registry[name] = task
|
|
80
|
+
logger.debug(f'Task "{name}" registered.')
|
|
81
|
+
if pass_through:
|
|
82
|
+
return func
|
|
83
|
+
else:
|
|
84
|
+
def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
85
|
+
current_callstack.append(task)
|
|
86
|
+
vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
|
|
87
|
+
ret = func(*args, **kwargs)
|
|
88
|
+
ContextStackVars.pop()
|
|
89
|
+
current_callstack.pop()
|
|
90
|
+
return ret
|
|
91
|
+
task.func = _wrapper
|
|
92
|
+
return _wrapper
|
|
93
|
+
return _task_decorator
|
|
94
|
+
|
|
95
|
+
@overload
|
|
96
|
+
def action(func: Callable[P, R]) -> Callable[P, R]: ...
|
|
97
|
+
|
|
98
|
+
@deprecated('Use `action` with screenshot_mode=`manual` instead.')
|
|
99
|
+
@overload
|
|
100
|
+
def action(
|
|
101
|
+
name: str,
|
|
102
|
+
*,
|
|
103
|
+
description: str|None = None,
|
|
104
|
+
pass_through: bool = False,
|
|
105
|
+
priority: int = 0,
|
|
106
|
+
screenshot_mode: Literal['manual-inherit'],
|
|
107
|
+
) -> Callable[[Callable[P, R]], Callable[P, R]]: ...
|
|
108
|
+
|
|
109
|
+
@overload
|
|
110
|
+
def action(
|
|
111
|
+
name: str,
|
|
112
|
+
*,
|
|
113
|
+
description: str|None = None,
|
|
114
|
+
pass_through: bool = False,
|
|
115
|
+
priority: int = 0,
|
|
116
|
+
screenshot_mode: ScreenshotMode | None = None,
|
|
117
|
+
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
118
|
+
"""
|
|
119
|
+
`action` 装饰器,用于标记一个函数为动作函数。
|
|
120
|
+
|
|
121
|
+
:param name: 动作名称。如果为 None,则使用函数的名称作为名称。
|
|
122
|
+
:param description: 动作描述。如果为 None,则使用函数的 docstring 作为描述。
|
|
123
|
+
:param pass_through:
|
|
124
|
+
默认情况下, @action 装饰器会包裹动作函数,跟踪其执行情况。
|
|
125
|
+
如果不想跟踪,则设置此参数为 False。
|
|
126
|
+
:param priority: 动作优先级,数字越大优先级越高。
|
|
127
|
+
:param screenshot_mode: 截图模式。
|
|
128
|
+
"""
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
def action(*args, **kwargs):
|
|
132
|
+
def _register(func: Callable, name: str, description: str|None = None, priority: int = 0) -> Action:
|
|
133
|
+
description = description or func.__doc__ or ''
|
|
134
|
+
action = Action(name, description, func, priority)
|
|
135
|
+
action_registry[name] = action
|
|
136
|
+
logger.debug(f'Action "{name}" registered.')
|
|
137
|
+
return action
|
|
138
|
+
|
|
139
|
+
if len(args) == 1 and isinstance(args[0], Callable):
|
|
140
|
+
func = args[0]
|
|
141
|
+
action = _register(_placeholder, func.__name__, func.__doc__)
|
|
142
|
+
def _wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
143
|
+
current_callstack.append(action)
|
|
144
|
+
vars = ContextStackVars.push()
|
|
145
|
+
ret = func(*args, **kwargs)
|
|
146
|
+
ContextStackVars.pop()
|
|
147
|
+
current_callstack.pop()
|
|
148
|
+
return ret
|
|
149
|
+
action.func = _wrapper
|
|
150
|
+
return _wrapper
|
|
151
|
+
else:
|
|
152
|
+
name = args[0]
|
|
153
|
+
description = kwargs.get('description', None)
|
|
154
|
+
pass_through = kwargs.get('pass_through', False)
|
|
155
|
+
priority = kwargs.get('priority', 0)
|
|
156
|
+
screenshot_mode = kwargs.get('screenshot_mode', None)
|
|
157
|
+
if screenshot_mode == 'manual-inherit':
|
|
158
|
+
warnings.warn('`screenshot_mode=manual-inherit` is deprecated. Use `screenshot_mode=manual` instead.')
|
|
159
|
+
def _action_decorator(func: Callable):
|
|
160
|
+
nonlocal pass_through
|
|
161
|
+
action = _register(_placeholder, name, description)
|
|
162
|
+
pass_through = kwargs.get('pass_through', False)
|
|
163
|
+
if pass_through:
|
|
164
|
+
return func
|
|
165
|
+
else:
|
|
166
|
+
def _wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
167
|
+
current_callstack.append(action)
|
|
168
|
+
vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
|
|
169
|
+
ret = func(*args, **kwargs)
|
|
170
|
+
ContextStackVars.pop()
|
|
171
|
+
current_callstack.pop()
|
|
172
|
+
return ret
|
|
173
|
+
action.func = _wrapper
|
|
174
|
+
return _wrapper
|
|
175
|
+
return _action_decorator
|
|
176
|
+
|
|
177
|
+
def tasks_from_id(task_ids: list[str]) -> list[Task]:
|
|
178
|
+
result = []
|
|
179
|
+
for tid in task_ids:
|
|
180
|
+
target = next(task for task in task_registry.values() if task.id == tid)
|
|
181
|
+
if target is None:
|
|
182
|
+
raise TaskNotFoundError(f'Task "{tid}" not found.')
|
|
183
|
+
result.append(target)
|
|
184
184
|
return result
|
kotonebot/backend/core.py
CHANGED
|
@@ -1,129 +1,86 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from kotonebot.
|
|
10
|
-
|
|
11
|
-
from kotonebot.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return self.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def width(self) -> int:
|
|
90
|
-
return self.x2 - self.x1
|
|
91
|
-
|
|
92
|
-
@property
|
|
93
|
-
def height(self) -> int:
|
|
94
|
-
return self.y2 - self.y1
|
|
95
|
-
|
|
96
|
-
@property
|
|
97
|
-
def rect(self) -> RectTuple:
|
|
98
|
-
return self.x1, self.y1, self.width, self.height
|
|
99
|
-
|
|
100
|
-
class HintPoint(Point):
|
|
101
|
-
def __init__(self, x: int, y: int, *, name: str | None = None, description: str | None = None):
|
|
102
|
-
super().__init__(x, y, name=name)
|
|
103
|
-
self.description = description
|
|
104
|
-
|
|
105
|
-
def __repr__(self) -> str:
|
|
106
|
-
return f'HintPoint<"{self.name}" at ({self.x}, {self.y})>'
|
|
107
|
-
|
|
108
|
-
def unify_image(image: MatLike | str | Image, transparent: bool = False) -> MatLike:
|
|
109
|
-
if isinstance(image, str):
|
|
110
|
-
if not transparent:
|
|
111
|
-
image = cv2_imread(image)
|
|
112
|
-
else:
|
|
113
|
-
image = cv2_imread(image, cv2.IMREAD_UNCHANGED)
|
|
114
|
-
elif isinstance(image, Image):
|
|
115
|
-
if transparent:
|
|
116
|
-
image = image.data_with_alpha
|
|
117
|
-
else:
|
|
118
|
-
image = image.data
|
|
119
|
-
return image
|
|
120
|
-
|
|
121
|
-
logger = logging.getLogger(__name__)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if __name__ == '__main__':
|
|
125
|
-
hint_box = HintBox(100, 100, 200, 200, source_resolution=(1920, 1080))
|
|
126
|
-
print(hint_box.rect)
|
|
127
|
-
print(hint_box.width)
|
|
128
|
-
print(hint_box.height)
|
|
129
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from typing import TYPE_CHECKING, Callable
|
|
3
|
+
from typing_extensions import deprecated
|
|
4
|
+
|
|
5
|
+
import cv2
|
|
6
|
+
from cv2.typing import MatLike
|
|
7
|
+
|
|
8
|
+
from kotonebot.util import cv2_imread
|
|
9
|
+
from kotonebot.primitives import RectTuple, Rect, Point
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from kotonebot.primitives.visual import Image
|
|
12
|
+
else:
|
|
13
|
+
from kotonebot.primitives.visual import Image as _PrimitivesImage
|
|
14
|
+
Image = deprecated('Use kotonebot.primitives.Image instead.')(_PrimitivesImage)
|
|
15
|
+
|
|
16
|
+
@deprecated('unused')
|
|
17
|
+
class Ocr:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
text: str | Callable[[str], bool],
|
|
21
|
+
*,
|
|
22
|
+
language: str = 'jp',
|
|
23
|
+
):
|
|
24
|
+
self.text = text
|
|
25
|
+
self.language = language
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# TODO: 这里的其他类应该移动到 primitives 模块下面
|
|
29
|
+
class HintBox(Rect):
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
x1: int,
|
|
33
|
+
y1: int,
|
|
34
|
+
x2: int,
|
|
35
|
+
y2: int,
|
|
36
|
+
*,
|
|
37
|
+
name: str | None = None,
|
|
38
|
+
description: str | None = None,
|
|
39
|
+
source_resolution: tuple[int, int],
|
|
40
|
+
):
|
|
41
|
+
super().__init__(x1, y1, x2 - x1, y2 - y1, name=name)
|
|
42
|
+
self.description = description
|
|
43
|
+
self.source_resolution = source_resolution
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def width(self) -> int:
|
|
47
|
+
return self.x2 - self.x1
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def height(self) -> int:
|
|
51
|
+
return self.y2 - self.y1
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def rect(self) -> RectTuple:
|
|
55
|
+
return self.x1, self.y1, self.width, self.height
|
|
56
|
+
|
|
57
|
+
class HintPoint(Point):
|
|
58
|
+
def __init__(self, x: int, y: int, *, name: str | None = None, description: str | None = None):
|
|
59
|
+
super().__init__(x, y, name=name)
|
|
60
|
+
self.description = description
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
return f'HintPoint<"{self.name}" at ({self.x}, {self.y})>'
|
|
64
|
+
|
|
65
|
+
def unify_image(image: MatLike | str | Image, transparent: bool = False) -> MatLike:
|
|
66
|
+
if isinstance(image, str):
|
|
67
|
+
if not transparent:
|
|
68
|
+
image = cv2_imread(image)
|
|
69
|
+
else:
|
|
70
|
+
image = cv2_imread(image, cv2.IMREAD_UNCHANGED)
|
|
71
|
+
elif isinstance(image, Image):
|
|
72
|
+
if transparent:
|
|
73
|
+
image = image.data_with_alpha
|
|
74
|
+
else:
|
|
75
|
+
image = image.data
|
|
76
|
+
return image
|
|
77
|
+
|
|
78
|
+
logger = logging.getLogger(__name__)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == '__main__':
|
|
82
|
+
hint_box = HintBox(100, 100, 200, 200, source_resolution=(1920, 1080))
|
|
83
|
+
print(hint_box.rect)
|
|
84
|
+
print(hint_box.width)
|
|
85
|
+
print(hint_box.height)
|
|
86
|
+
|