diff options
author | Maxim Devaev <[email protected]> | 2024-10-23 22:14:47 +0300 |
---|---|---|
committer | Maxim Devaev <[email protected]> | 2024-10-23 22:14:47 +0300 |
commit | 76d70d08381f4503518eeb30b3259e57db64ed78 (patch) | |
tree | 98eda3113b0a5cac0bf4f31c529a4c2451691ece | |
parent | a26aee3543883faf9a5b83832b274604f4f69263 (diff) |
new ocr event format
-rw-r--r-- | kvmd/apps/kvmd/api/streamer.py | 21 | ||||
-rw-r--r-- | kvmd/apps/kvmd/ocr.py | 30 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 14 | ||||
-rw-r--r-- | web/share/js/kvm/ocr.js | 45 | ||||
-rw-r--r-- | web/share/js/kvm/session.js | 2 |
5 files changed, 64 insertions, 48 deletions
diff --git a/kvmd/apps/kvmd/api/streamer.py b/kvmd/apps/kvmd/api/streamer.py index fc8e01de..81f255d0 100644 --- a/kvmd/apps/kvmd/api/streamer.py +++ b/kvmd/apps/kvmd/api/streamer.py @@ -97,25 +97,6 @@ class StreamerApi: self.__streamer.remove_snapshot() return make_json_response() - # ===== - - async def get_ocr(self) -> dict: # XXX: Ugly hack - enabled = self.__ocr.is_available() - default: list[str] = [] - available: list[str] = [] - if enabled: - default = self.__ocr.get_default_langs() - available = self.__ocr.get_available_langs() - return { - "ocr": { - "enabled": enabled, - "langs": { - "default": default, - "available": available, - }, - }, - } - @exposed_http("GET", "/streamer/ocr") async def __ocr_handler(self, _: Request) -> Response: - return make_json_response(await self.get_ocr()) + return make_json_response({"ocr": (await self.__ocr.get_state())}) diff --git a/kvmd/apps/kvmd/ocr.py b/kvmd/apps/kvmd/ocr.py index 0a632d9d..e110a720 100644 --- a/kvmd/apps/kvmd/ocr.py +++ b/kvmd/apps/kvmd/ocr.py @@ -37,6 +37,7 @@ from ctypes import c_void_p from ctypes import c_char from typing import Generator +from typing import AsyncGenerator from PIL import ImageOps from PIL import Image as PilImage @@ -107,9 +108,32 @@ class Ocr: def __init__(self, data_dir_path: str, default_langs: list[str]) -> None: self.__data_dir_path = data_dir_path self.__default_langs = default_langs - - def is_available(self) -> bool: - return bool(_libtess) + self.__notifier = aiotools.AioNotifier() + + async def get_state(self) -> dict: + enabled = bool(_libtess) + default: list[str] = [] + available: list[str] = [] + if enabled: + default = self.get_default_langs() + available = self.get_available_langs() + return { + "enabled": enabled, + "langs": { + "default": default, + "available": available, + }, + } + + async def trigger_state(self) -> None: + self.__notifier.notify() + + async def poll_state(self) -> AsyncGenerator[dict, None]: + while True: + await self.__notifier.wait() + yield (await self.get_state()) + + # ===== def get_default_langs(self) -> list[str]: return list(self.__default_langs) diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index 4b6b57a0..b88bc6b7 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -152,6 +152,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins __EV_GPIO_STATE = "gpio_state" __EV_INFO_STATE = "info_state" __EV_STREAMER_STATE = "streamer_state" + __EV_OCR_STATE = "ocr_state" def __init__( # pylint: disable=too-many-arguments,too-many-locals self, @@ -185,7 +186,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins self.__stream_forever = stream_forever self.__hid_api = HidApi(hid, keymap_path, ignore_keys, mouse_x_range, mouse_y_range) # Ugly hack to get keymaps state - self.__streamer_api = StreamerApi(streamer, ocr) # Same hack to get ocr langs state self.__apis: list[object] = [ self, AuthApi(auth_manager), @@ -195,7 +195,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins self.__hid_api, AtxApi(atx), MsdApi(msd), - self.__streamer_api, + StreamerApi(streamer, ocr), ExportApi(info_manager, atx, user_gpio), RedfishApi(info_manager, atx), ] @@ -206,7 +206,8 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins _Subsystem.make(hid, "HID", "hid_state").add_source("hid_keymaps_state", self.__hid_api.get_keymaps, None, None), _Subsystem.make(atx, "ATX", "atx_state"), _Subsystem.make(msd, "MSD", "msd_state"), - _Subsystem.make(streamer, "Streamer", "streamer_state").add_source("streamer_ocr_state", self.__streamer_api.get_ocr, None, None), + _Subsystem.make(streamer, "Streamer", self.__EV_STREAMER_STATE), + _Subsystem.make(ocr, "OCR", self.__EV_OCR_STATE), _Subsystem.make(info_manager, "Info manager", self.__EV_INFO_STATE), ] @@ -370,6 +371,8 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins await self.__poll_info_state(poller) case self.__EV_STREAMER_STATE: await self.__poll_streamer_state(poller) + case self.__EV_OCR_STATE: + await self.__poll_ocr_state(poller) case _: async for state in poller: await self._broadcast_ws_event(event_type, state) @@ -399,3 +402,8 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins prev.update(state) if "features" in prev: # Complete/Full await self._broadcast_ws_event(self.__EV_STREAMER_STATE, prev, legacy=True) + + async def __poll_ocr_state(self, poller: AsyncGenerator[dict, None]) -> None: + async for state in poller: + await self._broadcast_ws_event(self.__EV_OCR_STATE, state, legacy=False) + await self._broadcast_ws_event("streamer_ocr_state", {"ocr": state}, legacy=True) diff --git a/web/share/js/kvm/ocr.js b/web/share/js/kvm/ocr.js index 13e1b887..849b19b1 100644 --- a/web/share/js/kvm/ocr.js +++ b/web/share/js/kvm/ocr.js @@ -34,7 +34,7 @@ export function Ocr(__getGeometry) { var __start_pos = null; var __end_pos = null; - var __selection = null; + var __sel = null; var __init__ = function() { tools.el.setOnClick($("stream-ocr-button"), function() { @@ -54,7 +54,7 @@ export function Ocr(__getGeometry) { $("stream-ocr-window").onkeyup = function(event) { event.preventDefault(); if (event.code === "Enter") { - if (__selection) { + if (__sel) { __recognizeSelection(); wm.closeWindow($("stream-ocr-window")); } @@ -71,11 +71,14 @@ export function Ocr(__getGeometry) { /************************************************************************/ self.setState = function(state) { - let enabled = (state && state.ocr.enabled && !tools.browser.is_mobile); + let enabled = (state && state.enabled && !tools.browser.is_mobile); if (enabled) { let el = $("stream-ocr-lang-selector"); - tools.selector.setValues(el, state.ocr.langs.available); - tools.selector.setSelectedValue(el, tools.storage.get("stream.ocr.lang", state.ocr.langs["default"])); + el.options.length = 0; + for (let lang of state.langs.available) { + tools.selector.addOption(el, lang, lang); + } + el.value = tools.storage.get("stream.ocr.lang", state.langs["default"]); } tools.feature.setEnabled($("stream-ocr"), enabled); $("stream-ocr-led").className = (enabled ? "led-gray" : "hidden"); @@ -94,23 +97,23 @@ export function Ocr(__getGeometry) { __end_pos = __getGlobalPosition(event); let width = Math.abs(__start_pos.x - __end_pos.x); let height = Math.abs(__start_pos.y - __end_pos.y); - let el_selection = $("stream-ocr-selection"); - el_selection.style.left = Math.min(__start_pos.x, __end_pos.x) + "px"; - el_selection.style.top = Math.min(__start_pos.y, __end_pos.y) + "px"; - el_selection.style.width = width + "px"; - el_selection.style.height = height + "px"; - tools.hidden.setVisible(el_selection, (width > 1 || height > 1)); + let el = $("stream-ocr-selection"); + el.style.left = Math.min(__start_pos.x, __end_pos.x) + "px"; + el.style.top = Math.min(__start_pos.y, __end_pos.y) + "px"; + el.style.width = width + "px"; + el.style.height = height + "px"; + tools.hidden.setVisible(el, (width > 1 || height > 1)); } }; var __endSelection = function(event) { __changeSelection(event); - let el_selection = $("stream-ocr-selection"); + let el = $("stream-ocr-selection"); let ok = ( - el_selection.offsetWidth > 1 && el_selection.offsetHeight > 1 + el.offsetWidth > 1 && el.offsetHeight > 1 && __start_pos !== null && __end_pos !== null ); - tools.hidden.setVisible(el_selection, ok); + tools.hidden.setVisible(el, ok); if (ok) { let rect = $("stream-box").getBoundingClientRect(); let rel_left = Math.min(__start_pos.x, __end_pos.x) - rect.left; @@ -119,14 +122,14 @@ export function Ocr(__getGeometry) { let rel_top = Math.min(__start_pos.y, __end_pos.y) - rect.top + offset; let rel_bottom = Math.max(__start_pos.y, __end_pos.y) - rect.top + offset; let geo = __getGeometry(); - __selection = { + __sel = { "left": tools.remap(rel_left, geo.x, geo.width, 0, geo.real_width), "right": tools.remap(rel_right, geo.x, geo.width, 0, geo.real_width), "top": tools.remap(rel_top, geo.y, geo.height, 0, geo.real_height), "bottom": tools.remap(rel_bottom, geo.y, geo.height, 0, geo.real_height), }; } else { - __selection = null; + __sel = null; } __start_pos = null; __end_pos = null; @@ -154,7 +157,7 @@ export function Ocr(__getGeometry) { tools.hidden.setVisible($("stream-ocr-selection"), false); __start_pos = null; __end_pos = null; - __selection = null; + __sel = null; }; var __recognizeSelection = function() { @@ -164,10 +167,10 @@ export function Ocr(__getGeometry) { let params = { "ocr": 1, "ocr_langs": $("stream-ocr-lang-selector").value, - "ocr_left": __selection.left, - "ocr_top": __selection.top, - "ocr_right": __selection.right, - "orc_bottom": __selection.bottom, + "ocr_left": __sel.left, + "ocr_top": __sel.top, + "ocr_right": __sel.right, + "orc_bottom": __sel.bottom, }; tools.httpGet("/api/streamer/snapshot", params, function(http) { if (http.status === 200) { diff --git a/web/share/js/kvm/session.js b/web/share/js/kvm/session.js index 1e7fefcd..523b4097 100644 --- a/web/share/js/kvm/session.js +++ b/web/share/js/kvm/session.js @@ -368,7 +368,7 @@ export function Session() { case "atx_state": __atx.setState(data.event); break; case "msd_state": __msd.setState(data.event); break; case "streamer_state": __streamer.setState(data.event); break; - case "streamer_ocr_state": __ocr.setState(data.event); break; + case "ocr_state": __ocr.setState(data.event); break; } }; |