GameSentenceMiner 2.13.0__py3-none-any.whl → 2.13.1__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.
- GameSentenceMiner/locales/en_us.json +592 -0
- GameSentenceMiner/locales/ja_jp.json +591 -0
- GameSentenceMiner/locales/zh_cn.json +592 -0
- GameSentenceMiner/owocr/owocr/ocr.py +29 -32
- GameSentenceMiner/owocr/owocr/run.py +30 -64
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/RECORD +11 -8
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.13.0.dist-info → gamesentenceminer-2.13.1.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,6 @@ import json
|
|
11
11
|
import base64
|
12
12
|
from urllib.parse import urlparse, parse_qs
|
13
13
|
|
14
|
-
import jaconv
|
15
14
|
import numpy as np
|
16
15
|
import rapidfuzz.fuzz
|
17
16
|
from PIL import Image
|
@@ -95,6 +94,7 @@ def empty_post_process(text):
|
|
95
94
|
|
96
95
|
|
97
96
|
def post_process(text, keep_blank_lines=False):
|
97
|
+
import jaconv
|
98
98
|
if keep_blank_lines:
|
99
99
|
text = '\n'.join([''.join(i.split()) for i in text.splitlines()])
|
100
100
|
else:
|
@@ -436,7 +436,7 @@ class GoogleLens:
|
|
436
436
|
# res += '\n'
|
437
437
|
|
438
438
|
if return_coords:
|
439
|
-
x = (True, res,
|
439
|
+
x = (True, res, response_dict)
|
440
440
|
else:
|
441
441
|
x = (True, res)
|
442
442
|
|
@@ -887,7 +887,28 @@ class OneOCR:
|
|
887
887
|
except:
|
888
888
|
logger.warning('Error reading URL from config, OneOCR will not work!')
|
889
889
|
|
890
|
-
def
|
890
|
+
def get_regex(self, lang):
|
891
|
+
if lang == "ja":
|
892
|
+
self.regex = re.compile(r'[\u3041-\u3096\u30A1-\u30FA\u4E00-\u9FFF]')
|
893
|
+
elif lang == "zh":
|
894
|
+
self.regex = re.compile(r'[\u4E00-\u9FFF]')
|
895
|
+
elif lang == "ko":
|
896
|
+
self.regex = re.compile(r'[\uAC00-\uD7AF]')
|
897
|
+
elif lang == "ar":
|
898
|
+
self.regex = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
|
899
|
+
elif lang == "ru":
|
900
|
+
self.regex = re.compile(r'[\u0400-\u04FF\u0500-\u052F\u2DE0-\u2DFF\uA640-\uA69F\u1C80-\u1C8F]')
|
901
|
+
elif lang == "el":
|
902
|
+
self.regex = re.compile(r'[\u0370-\u03FF\u1F00-\u1FFF]')
|
903
|
+
elif lang == "he":
|
904
|
+
self.regex = re.compile(r'[\u0590-\u05FF\uFB1D-\uFB4F]')
|
905
|
+
elif lang == "th":
|
906
|
+
self.regex = re.compile(r'[\u0E00-\u0E7F]')
|
907
|
+
else:
|
908
|
+
self.regex = re.compile(
|
909
|
+
r'[a-zA-Z\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u1D00-\u1D7F\u1D80-\u1DBF\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF\uAB30-\uAB6F]')
|
910
|
+
|
911
|
+
def __call__(self, img, furigana_filter_sensitivity=0, return_coords=False):
|
891
912
|
lang = get_ocr_language()
|
892
913
|
if lang != self.initial_lang:
|
893
914
|
self.initial_lang = lang
|
@@ -911,6 +932,10 @@ class OneOCR:
|
|
911
932
|
json.dump(ocr_resp, f, indent=4, ensure_ascii=False)
|
912
933
|
# print(json.dumps(ocr_resp))
|
913
934
|
filtered_lines = [line for line in ocr_resp['lines'] if self.regex.search(line['text'])]
|
935
|
+
x_coords = [line['bounding_rect'][f'x{i}'] for line in filtered_lines for i in range(1, 5)]
|
936
|
+
y_coords = [line['bounding_rect'][f'y{i}'] for line in filtered_lines for i in range(1, 5)]
|
937
|
+
if x_coords and y_coords:
|
938
|
+
crop_coords = (min(x_coords) - 5, min(y_coords) - 5, max(x_coords) + 5, max(y_coords) + 5)
|
914
939
|
# logger.info(filtered_lines)
|
915
940
|
res = ''
|
916
941
|
skipped = []
|
@@ -964,30 +989,6 @@ class OneOCR:
|
|
964
989
|
# else:
|
965
990
|
# continue
|
966
991
|
# res += '\n'
|
967
|
-
elif sentence_to_check:
|
968
|
-
lines_to_build_area = []
|
969
|
-
widths = []
|
970
|
-
heights = []
|
971
|
-
for line in ocr_resp['lines']:
|
972
|
-
print(line['text'])
|
973
|
-
if sentence_to_check in line['text'] or line['text'] in sentence_to_check or rapidfuzz.fuzz.partial_ratio(sentence_to_check, line['text']) > 50:
|
974
|
-
lines_to_build_area.append(line)
|
975
|
-
res += line['text']
|
976
|
-
for word in line['words']:
|
977
|
-
widths.append(word['bounding_rect']['x2'] - word['bounding_rect']['x1'])
|
978
|
-
heights.append(word['bounding_rect']['y3'] - word['bounding_rect']['y1'])
|
979
|
-
|
980
|
-
x_coords = [line['bounding_rect'][f'x{i}'] for line in lines_to_build_area for i in
|
981
|
-
range(1, 5)]
|
982
|
-
y_coords = [line['bounding_rect'][f'y{i}'] for line in lines_to_build_area for i in
|
983
|
-
range(1, 5)]
|
984
|
-
if widths:
|
985
|
-
avg_width = sum(widths) / len(widths)
|
986
|
-
if heights:
|
987
|
-
avg_height = sum(heights) / len(heights)
|
988
|
-
if x_coords and y_coords:
|
989
|
-
crop_coords = (
|
990
|
-
min(x_coords) - 5, min(y_coords) - 5, max(x_coords) + 5, max(y_coords) + 5)
|
991
992
|
elif return_coords:
|
992
993
|
for line in filtered_lines:
|
993
994
|
for word in line['words']:
|
@@ -998,10 +999,6 @@ class OneOCR:
|
|
998
999
|
boxes.append(box)
|
999
1000
|
res = ocr_resp['text']
|
1000
1001
|
else:
|
1001
|
-
x_coords = [line['bounding_rect'][f'x{i}'] for line in filtered_lines for i in range(1, 5)]
|
1002
|
-
y_coords = [line['bounding_rect'][f'y{i}'] for line in filtered_lines for i in range(1, 5)]
|
1003
|
-
if x_coords and y_coords:
|
1004
|
-
crop_coords = (min(x_coords) - 5, min(y_coords) - 5, max(x_coords) + 5, max(y_coords) + 5)
|
1005
1002
|
res = ocr_resp['text']
|
1006
1003
|
|
1007
1004
|
except RuntimeError as e:
|
@@ -1019,7 +1016,7 @@ class OneOCR:
|
|
1019
1016
|
|
1020
1017
|
res = res.json()['text']
|
1021
1018
|
if return_coords:
|
1022
|
-
x = (True, res,
|
1019
|
+
x = (True, res, filtered_lines)
|
1023
1020
|
else:
|
1024
1021
|
x = (True, res, crop_coords)
|
1025
1022
|
if is_path:
|
@@ -44,7 +44,6 @@ import queue
|
|
44
44
|
from datetime import datetime
|
45
45
|
from PIL import Image, ImageDraw, UnidentifiedImageError
|
46
46
|
from loguru import logger
|
47
|
-
from pynput import keyboard
|
48
47
|
from desktop_notifier import DesktopNotifierSync
|
49
48
|
import psutil
|
50
49
|
|
@@ -384,6 +383,7 @@ class TextFiltering:
|
|
384
383
|
block_filtered = self.latin_extended_regex.findall(block)
|
385
384
|
else:
|
386
385
|
block_filtered = self.latin_extended_regex.findall(block)
|
386
|
+
|
387
387
|
if block_filtered:
|
388
388
|
orig_text_filtered.append(''.join(block_filtered))
|
389
389
|
else:
|
@@ -547,39 +547,6 @@ class ScreenshotThread(threading.Thread):
|
|
547
547
|
else:
|
548
548
|
raise ValueError('Window capture is only currently supported on Windows and macOS')
|
549
549
|
|
550
|
-
def __del__(self):
|
551
|
-
if self.macos_window_tracker_instance:
|
552
|
-
self.macos_window_tracker_instance.join()
|
553
|
-
elif self.windows_window_tracker_instance:
|
554
|
-
self.windows_window_tracker_instance.join()
|
555
|
-
|
556
|
-
def setup_persistent_windows_window_tracker(self):
|
557
|
-
global window_open
|
558
|
-
window_open = False
|
559
|
-
def setup_tracker():
|
560
|
-
global window_open
|
561
|
-
self.window_handle, window_title = self.get_windows_window_handle(self.screen_capture_window)
|
562
|
-
|
563
|
-
if not self.window_handle:
|
564
|
-
# print(f"Window '{screen_capture_window}' not found.")
|
565
|
-
return
|
566
|
-
|
567
|
-
set_dpi_awareness()
|
568
|
-
window_open = True
|
569
|
-
self.windows_window_tracker_instance = threading.Thread(target=self.windows_window_tracker)
|
570
|
-
self.windows_window_tracker_instance.start()
|
571
|
-
logger.opt(ansi=True).info(f'Selected window: {window_title}')
|
572
|
-
|
573
|
-
while not terminated:
|
574
|
-
if not window_open:
|
575
|
-
try:
|
576
|
-
setup_tracker()
|
577
|
-
except ValueError as e:
|
578
|
-
logger.error(f"Error setting up persistent windows window tracker: {e}")
|
579
|
-
break
|
580
|
-
time.sleep(5)
|
581
|
-
|
582
|
-
|
583
550
|
def get_windows_window_handle(self, window_title):
|
584
551
|
def callback(hwnd, window_title_part):
|
585
552
|
window_title = win32gui.GetWindowText(hwnd)
|
@@ -602,7 +569,7 @@ class ScreenshotThread(threading.Thread):
|
|
602
569
|
|
603
570
|
def windows_window_tracker(self):
|
604
571
|
found = True
|
605
|
-
while not terminated
|
572
|
+
while not terminated:
|
606
573
|
found = win32gui.IsWindow(self.window_handle)
|
607
574
|
if not found:
|
608
575
|
break
|
@@ -872,18 +839,9 @@ class OBSScreenshotThread(threading.Thread):
|
|
872
839
|
image_queue.put((result, True))
|
873
840
|
|
874
841
|
def connect_obs(self):
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
host=get_config().obs.host,
|
879
|
-
port=get_config().obs.port,
|
880
|
-
password=get_config().obs.password,
|
881
|
-
timeout=10
|
882
|
-
)
|
883
|
-
logger.info("Connected to OBS WebSocket.")
|
884
|
-
except Exception as e:
|
885
|
-
logger.error(f"Failed to connect to OBS: {e}")
|
886
|
-
self.obs_client = None
|
842
|
+
import GameSentenceMiner.obs as obs
|
843
|
+
obs.connect_to_obs_sync()
|
844
|
+
|
887
845
|
|
888
846
|
def run(self):
|
889
847
|
global last_image
|
@@ -895,9 +853,12 @@ class OBSScreenshotThread(threading.Thread):
|
|
895
853
|
def init_config(source=None, scene=None):
|
896
854
|
obs.update_current_game()
|
897
855
|
self.current_source = source if source else obs.get_active_source()
|
898
|
-
self.current_source_name = self.current_source.get(
|
856
|
+
self.current_source_name = self.current_source.get("sourceName") or None
|
899
857
|
self.current_scene = scene if scene else obs.get_current_game()
|
900
858
|
self.ocr_config = get_scene_ocr_config()
|
859
|
+
if not self.ocr_config:
|
860
|
+
logger.error("No OCR config found for the current scene.")
|
861
|
+
return
|
901
862
|
self.ocr_config.scale_to_custom_size(self.width, self.height)
|
902
863
|
|
903
864
|
# Register a scene switch callback in obsws
|
@@ -925,22 +886,23 @@ class OBSScreenshotThread(threading.Thread):
|
|
925
886
|
continue
|
926
887
|
|
927
888
|
if not self.ocr_config:
|
889
|
+
logger.info("No OCR config found for the current scene. Waiting for scene switch.")
|
928
890
|
time.sleep(1)
|
929
891
|
continue
|
892
|
+
|
893
|
+
if not self.current_source_name:
|
894
|
+
obs.update_current_game()
|
895
|
+
self.current_source = obs.get_active_source()
|
896
|
+
self.current_source_name = self.current_source.get("sourceName") or None
|
930
897
|
|
931
898
|
try:
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
height=self.height,
|
938
|
-
)
|
899
|
+
if not self.current_source_name:
|
900
|
+
logger.error("No active source found in the current scene.")
|
901
|
+
time.sleep(1)
|
902
|
+
continue
|
903
|
+
img = obs.get_screenshot_PIL(source_name=self.current_source_name, width=self.width, height=self.height, img_format='png', compression=80)
|
939
904
|
|
940
|
-
if
|
941
|
-
image_data = base64.b64decode(response.image_data.split(",")[1])
|
942
|
-
img = Image.open(io.BytesIO(image_data)).convert("RGBA")
|
943
|
-
|
905
|
+
if img is not None:
|
944
906
|
if not img.getbbox():
|
945
907
|
logger.info("OBS Not Capturing anything, sleeping.")
|
946
908
|
time.sleep(1)
|
@@ -1118,11 +1080,10 @@ def signal_handler(sig, frame):
|
|
1118
1080
|
|
1119
1081
|
|
1120
1082
|
def on_window_closed(alive):
|
1121
|
-
global terminated
|
1083
|
+
global terminated
|
1122
1084
|
if not (alive or terminated):
|
1123
1085
|
logger.info('Window closed or error occurred, terminated!')
|
1124
|
-
|
1125
|
-
# terminated = True
|
1086
|
+
terminated = True
|
1126
1087
|
|
1127
1088
|
|
1128
1089
|
def on_screenshot_combo():
|
@@ -1464,8 +1425,12 @@ def run(read_from=None,
|
|
1464
1425
|
read_from_readable.append(f'directory {read_from_path}')
|
1465
1426
|
|
1466
1427
|
if len(key_combos) > 0:
|
1467
|
-
|
1468
|
-
|
1428
|
+
try:
|
1429
|
+
from pynput import keyboard
|
1430
|
+
key_combo_listener = keyboard.GlobalHotKeys(key_combos)
|
1431
|
+
key_combo_listener.start()
|
1432
|
+
except ImportError:
|
1433
|
+
pass
|
1469
1434
|
|
1470
1435
|
if write_to in ('clipboard', 'websocket', 'callback'):
|
1471
1436
|
write_to_readable = write_to
|
@@ -1513,6 +1478,7 @@ def run(read_from=None,
|
|
1513
1478
|
filter_img = True
|
1514
1479
|
notify = False
|
1515
1480
|
last_screenshot_time = time.time()
|
1481
|
+
ocr_start_time = datetime.now()
|
1516
1482
|
|
1517
1483
|
if img == 0:
|
1518
1484
|
on_window_closed(False)
|
@@ -15,6 +15,9 @@ GameSentenceMiner/assets/icon32.png,sha256=Kww0hU_qke9_22wBuO_Nq0Dv2SfnOLwMhCyGg
|
|
15
15
|
GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB_7W4sqs,192487
|
16
16
|
GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
|
17
17
|
GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
|
18
|
+
GameSentenceMiner/locales/en_us.json,sha256=zv7qfr23G-os29yXfIE61_tYsTOwUjxF8ADH2YyJ0NA,24881
|
19
|
+
GameSentenceMiner/locales/ja_jp.json,sha256=PgAkkN7qmbtuRj5a3jHd9R9FNztamhmhRZysY6TwETU,26283
|
20
|
+
GameSentenceMiner/locales/zh_cn.json,sha256=h-YRSz2XN_TkymjkAH1MQ9KqGLE9_7Ru-N4yTqpm8_8,23615
|
18
21
|
GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
22
|
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=Ezj-0k6Wo-una91FvYhMp6KGkRhWYihXzLAoh_Wu2xY,5329
|
20
23
|
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
@@ -25,8 +28,8 @@ GameSentenceMiner/owocr/owocr/__init__.py,sha256=87hfN5u_PbL_onLfMACbc0F5j4KyIK9
|
|
25
28
|
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
26
29
|
GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
|
27
30
|
GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
|
28
|
-
GameSentenceMiner/owocr/owocr/ocr.py,sha256=
|
29
|
-
GameSentenceMiner/owocr/owocr/run.py,sha256=
|
31
|
+
GameSentenceMiner/owocr/owocr/ocr.py,sha256=jjm7TGIOaR-7JfoP_4B24uW7tLsxJL36s2kFndJy_SA,63025
|
32
|
+
GameSentenceMiner/owocr/owocr/run.py,sha256=Qm4srtzqj6tZhgicMME4SyjP6NP_2IQRN-AOzVzE828,66011
|
30
33
|
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
31
34
|
GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
35
|
GameSentenceMiner/util/audio_offset_selector.py,sha256=8Stk3BP-XVIuzRv9nl9Eqd2D-1yD3JrgU-CamBywJmY,8542
|
@@ -64,9 +67,9 @@ GameSentenceMiner/web/templates/index.html,sha256=Gv3CJvNnhAzIVV_QxhNq4OD-pXDt1v
|
|
64
67
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
65
68
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
66
69
|
GameSentenceMiner/wip/get_overlay_coords.py,sha256=pxTuOicSsMMmOLRQH0-3FPoQqsolbncvIMgX2q8ArHc,19787
|
67
|
-
gamesentenceminer-2.13.
|
68
|
-
gamesentenceminer-2.13.
|
69
|
-
gamesentenceminer-2.13.
|
70
|
-
gamesentenceminer-2.13.
|
71
|
-
gamesentenceminer-2.13.
|
72
|
-
gamesentenceminer-2.13.
|
70
|
+
gamesentenceminer-2.13.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
71
|
+
gamesentenceminer-2.13.1.dist-info/METADATA,sha256=plYR4MOiOcRPSsEHvWAJ6HNOWz6tFxHyfBdrqxUHCnQ,1463
|
72
|
+
gamesentenceminer-2.13.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
73
|
+
gamesentenceminer-2.13.1.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
74
|
+
gamesentenceminer-2.13.1.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
75
|
+
gamesentenceminer-2.13.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|