GameSentenceMiner 2.16.12__tar.gz → 2.17.0__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.
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/anki.py +1 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/gametext.py +2 -1
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/obs.py +29 -2
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/owocr_area_selector.py +1 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/get_overlay_coords.py +78 -11
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/database_api.py +4 -4
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/shared.js +4 -4
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/PKG-INFO +1 -1
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/pyproject.toml +2 -2
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ai/ai_prompting.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/config_gui.py +1 -1
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/gsm.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/locales/en_us.json +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/locales/ja_jp.json +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/locales/zh_cn.json +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/owocr_helper.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/ocr.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/run.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/furigana_filter_preview.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/ss_selector.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/window_transparency.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/configuration.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/db.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/electron_config.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/ffmpeg.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/win10toast/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/win10toast/__main__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/vad.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/events.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/gsm_websocket.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/kanji-grid.css +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/search.css +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/shared.css +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/stats.css +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/anki_stats.js +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/database.js +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/kanji-grid.js +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/search.js +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/stats.js +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/stats.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/anki_stats.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/components/navigation.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/components/theme-styles.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/database.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/index.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/search.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/stats.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/wip/__init___.py +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/LICENSE +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/README.md +0 -0
- {gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/setup.cfg +0 -0
|
@@ -490,6 +490,7 @@ def update_card_from_same_sentence(last_card, lines, game_line):
|
|
|
490
490
|
card_queue.pop(0)
|
|
491
491
|
logger.error(f"Error saving replay buffer: {e}")
|
|
492
492
|
return
|
|
493
|
+
return
|
|
493
494
|
anki_result = anki_results[game_line.id]
|
|
494
495
|
if anki_result.success:
|
|
495
496
|
note, last_card = get_initial_card_info(last_card, lines)
|
|
@@ -83,6 +83,7 @@ async def listen_websockets():
|
|
|
83
83
|
line_time = None
|
|
84
84
|
while True:
|
|
85
85
|
message = await websocket.recv()
|
|
86
|
+
message_received_time = datetime.now()
|
|
86
87
|
if not message:
|
|
87
88
|
continue
|
|
88
89
|
logger.debug(message)
|
|
@@ -97,7 +98,7 @@ async def listen_websockets():
|
|
|
97
98
|
logger.info
|
|
98
99
|
if current_clipboard != current_line:
|
|
99
100
|
try:
|
|
100
|
-
await handle_new_text_event(current_clipboard, line_time if line_time else
|
|
101
|
+
await handle_new_text_event(current_clipboard, line_time if line_time else message_received_time)
|
|
101
102
|
except Exception as e:
|
|
102
103
|
logger.error(f"Error handling new text event: {e}", exc_info=True)
|
|
103
104
|
except (websockets.ConnectionClosed, ConnectionError, InvalidStatus, ConnectionResetError, Exception) as e:
|
|
@@ -6,6 +6,7 @@ import threading
|
|
|
6
6
|
import time
|
|
7
7
|
import logging
|
|
8
8
|
import contextlib
|
|
9
|
+
import shutil
|
|
9
10
|
|
|
10
11
|
import psutil
|
|
11
12
|
|
|
@@ -189,13 +190,24 @@ def start_obs():
|
|
|
189
190
|
except ValueError:
|
|
190
191
|
print("Invalid PID found in file. Launching new OBS instance.")
|
|
191
192
|
except OSError:
|
|
192
|
-
print("No process found with the stored PID. Launching new OBS instance.")
|
|
193
|
+
print("No process found with the stored PID. Launching new OBS instance.")
|
|
193
194
|
|
|
194
195
|
obs_path = get_obs_path()
|
|
195
196
|
if not os.path.exists(obs_path):
|
|
196
197
|
print(f"OBS not found at {obs_path}. Please install OBS.")
|
|
197
198
|
return None
|
|
198
199
|
try:
|
|
200
|
+
sentinel_folder = os.path.join(configuration.get_app_directory(), 'obs-studio', 'config', 'obs-studio', '.sentinel')
|
|
201
|
+
if os.path.exists(sentinel_folder):
|
|
202
|
+
try:
|
|
203
|
+
if os.path.isdir(sentinel_folder):
|
|
204
|
+
shutil.rmtree(sentinel_folder)
|
|
205
|
+
else:
|
|
206
|
+
os.remove(sentinel_folder)
|
|
207
|
+
print(f"Deleted sentinel folder: {sentinel_folder}")
|
|
208
|
+
except Exception as e:
|
|
209
|
+
print(f"Failed to delete sentinel folder: {e}")
|
|
210
|
+
|
|
199
211
|
obs_process = subprocess.Popen([obs_path, '--disable-shutdown-check', '--portable', '--startreplaybuffer', ], cwd=os.path.dirname(obs_path))
|
|
200
212
|
obs_process_pid = obs_process.pid
|
|
201
213
|
with open(OBS_PID_FILE, "w") as f:
|
|
@@ -663,8 +675,23 @@ def main():
|
|
|
663
675
|
update_current_game()
|
|
664
676
|
print("Testing `get_current_game`:", get_current_game())
|
|
665
677
|
disconnect_from_obs()
|
|
678
|
+
|
|
679
|
+
def create_scene():
|
|
680
|
+
with connection_pool.get_client() as client:
|
|
681
|
+
# Extract fields from request_json
|
|
682
|
+
request_json = r'{"sceneName":"SILENT HILL f","inputName":"SILENT HILL f - Capture","inputKind":"window_capture","inputSettings":{"mode":"window","window":"SILENT HILL f :UnrealWindow:SHf-Win64-Shipping.exe","capture_audio":true,"cursor":false,"method":"2"}}'
|
|
683
|
+
request_dict = json.loads(request_json)
|
|
684
|
+
scene_name = request_dict.get('sceneName')
|
|
685
|
+
input_name = request_dict.get('inputName')
|
|
686
|
+
input_kind = request_dict.get('inputKind')
|
|
687
|
+
input_settings = request_dict.get('inputSettings')
|
|
688
|
+
input_settings['method'] = 2
|
|
689
|
+
# Remove sceneName from request_dict if needed for create_input
|
|
690
|
+
request_dict.pop('sceneName', None)
|
|
691
|
+
response = client.create_input(inputName=input_name, inputKind=input_kind, sceneName=scene_name, inputSettings=input_settings, sceneItemEnabled=True)
|
|
666
692
|
|
|
667
693
|
if __name__ == '__main__':
|
|
668
694
|
logging.basicConfig(level=logging.INFO)
|
|
669
695
|
connect_to_obs_sync()
|
|
670
|
-
set_fit_to_screen_for_scene_items(get_current_scene())
|
|
696
|
+
# set_fit_to_screen_for_scene_items(get_current_scene())
|
|
697
|
+
create_scene()
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/owocr_area_selector.py
RENAMED
|
@@ -328,6 +328,7 @@ class ScreenSelector:
|
|
|
328
328
|
"How to Use:\n"
|
|
329
329
|
" • Left Click + Drag: Create a capture area (green).\n"
|
|
330
330
|
" • Shift + Left Click + Drag: Create an exclusion area (orange).\n"
|
|
331
|
+
" • Ctrl + Left Click + Drag: Create a secondary (menu) area (purple).\n"
|
|
331
332
|
" • Right-Click on a box: Delete it.\n\n"
|
|
332
333
|
"Hotkeys:\n"
|
|
333
334
|
" • Ctrl + S: Save and Quit\n"
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/get_overlay_coords.py
RENAMED
|
@@ -9,11 +9,11 @@ import time
|
|
|
9
9
|
from PIL import Image
|
|
10
10
|
from typing import Dict, Any, List, Tuple
|
|
11
11
|
import json
|
|
12
|
-
from rapidfuzz
|
|
12
|
+
from rapidfuzz import fuzz
|
|
13
13
|
|
|
14
14
|
# Local application imports
|
|
15
15
|
from GameSentenceMiner.ocr.gsm_ocr_config import set_dpi_awareness
|
|
16
|
-
from GameSentenceMiner.util.configuration import OverlayEngine, get_config, is_windows, is_beangate, logger
|
|
16
|
+
from GameSentenceMiner.util.configuration import OverlayEngine, get_config, get_temporary_directory, is_windows, is_beangate, logger
|
|
17
17
|
from GameSentenceMiner.util.electron_config import get_ocr_language
|
|
18
18
|
from GameSentenceMiner.obs import get_screenshot_PIL
|
|
19
19
|
from GameSentenceMiner.web.texthooking_page import send_word_coordinates_to_overlay
|
|
@@ -93,7 +93,8 @@ class OverlayThread(threading.Thread):
|
|
|
93
93
|
super().__init__()
|
|
94
94
|
self.overlay_processor = OverlayProcessor()
|
|
95
95
|
self.loop = asyncio.new_event_loop()
|
|
96
|
-
self.daemon = True
|
|
96
|
+
self.daemon = True
|
|
97
|
+
self.first_time_run = True
|
|
97
98
|
|
|
98
99
|
def run(self):
|
|
99
100
|
"""Runs the overlay processing loop."""
|
|
@@ -103,11 +104,18 @@ class OverlayThread(threading.Thread):
|
|
|
103
104
|
async def overlay_loop(self):
|
|
104
105
|
"""Main loop to periodically process and send overlay data."""
|
|
105
106
|
while True:
|
|
106
|
-
if
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
if overlay_server_thread.has_clients():
|
|
108
|
+
if get_config().overlay.periodic:
|
|
109
|
+
await self.overlay_processor.find_box_and_send_to_overlay('')
|
|
110
|
+
await asyncio.sleep(get_config().overlay.periodic_interval)
|
|
111
|
+
elif self.first_time_run:
|
|
112
|
+
await self.overlay_processor.find_box_and_send_to_overlay('')
|
|
113
|
+
self.first_time_run = False
|
|
114
|
+
else:
|
|
115
|
+
await asyncio.sleep(3)
|
|
109
116
|
else:
|
|
110
|
-
|
|
117
|
+
self.first_time_run = True
|
|
118
|
+
await asyncio.sleep(3)
|
|
111
119
|
|
|
112
120
|
class OverlayProcessor:
|
|
113
121
|
"""
|
|
@@ -125,6 +133,8 @@ class OverlayProcessor:
|
|
|
125
133
|
self.lens = None
|
|
126
134
|
self.regex = None
|
|
127
135
|
self.ready = False
|
|
136
|
+
self.last_oneocr_result = None
|
|
137
|
+
self.last_lens_result = None
|
|
128
138
|
|
|
129
139
|
try:
|
|
130
140
|
if self.config.overlay.websocket_port and all([GoogleLens, get_regex]):
|
|
@@ -221,6 +231,8 @@ class OverlayProcessor:
|
|
|
221
231
|
monitor = self.get_monitor_workarea(0) # Get primary monitor work area
|
|
222
232
|
sct_img = sct.grab(monitor)
|
|
223
233
|
img = Image.frombytes('RGB', sct_img.size, sct_img.bgra, 'raw', 'BGRX')
|
|
234
|
+
|
|
235
|
+
img.save(os.path.join(get_temporary_directory(), "latest_overlay_screenshot.png"))
|
|
224
236
|
|
|
225
237
|
return img, monitor['width'], monitor['height']
|
|
226
238
|
|
|
@@ -261,6 +273,8 @@ class OverlayProcessor:
|
|
|
261
273
|
paste_x = math.floor(x1)
|
|
262
274
|
paste_y = math.floor(y1)
|
|
263
275
|
composite_img.paste(cropped_image, (paste_x, paste_y))
|
|
276
|
+
|
|
277
|
+
composite_img.save(os.path.join(get_temporary_directory(), "latest_overlay_screenshot_trimmed.png"))
|
|
264
278
|
|
|
265
279
|
return composite_img
|
|
266
280
|
|
|
@@ -277,7 +291,7 @@ class OverlayProcessor:
|
|
|
277
291
|
return []
|
|
278
292
|
if self.oneocr:
|
|
279
293
|
# 2. Use OneOCR to find general text areas (fast)
|
|
280
|
-
|
|
294
|
+
res, text, oneocr_results, crop_coords_list = self.oneocr(
|
|
281
295
|
full_screenshot,
|
|
282
296
|
return_coords=True,
|
|
283
297
|
multiple_crop_coords=True,
|
|
@@ -285,8 +299,19 @@ class OverlayProcessor:
|
|
|
285
299
|
furigana_filter_sensitivity=None, # Disable furigana filtering
|
|
286
300
|
)
|
|
287
301
|
|
|
302
|
+
text_str = "".join([text for text in text if self.regex.match(text)])
|
|
303
|
+
|
|
304
|
+
# RapidFuzz fuzzy match 90% to not send the same results repeatedly
|
|
305
|
+
if self.last_oneocr_result:
|
|
306
|
+
|
|
307
|
+
score = fuzz.ratio(text_str, self.last_oneocr_result)
|
|
308
|
+
if score >= 80:
|
|
309
|
+
logger.info("OneOCR results are similar to the last results (score: %d). Skipping overlay update.", score)
|
|
310
|
+
return
|
|
311
|
+
self.last_oneocr_result = text_str
|
|
312
|
+
|
|
288
313
|
logger.info("Sending OneOCR results to overlay.")
|
|
289
|
-
await send_word_coordinates_to_overlay(oneocr_results)
|
|
314
|
+
await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
|
|
290
315
|
|
|
291
316
|
# If User Home is beangate
|
|
292
317
|
if is_beangate:
|
|
@@ -317,9 +342,19 @@ class OverlayProcessor:
|
|
|
317
342
|
if len(res) != 3:
|
|
318
343
|
return
|
|
319
344
|
|
|
320
|
-
|
|
345
|
+
success, text_list, coords = res
|
|
346
|
+
|
|
347
|
+
text_str = "".join([text for text in text_list if self.regex.match(text)])
|
|
348
|
+
|
|
349
|
+
# RapidFuzz fuzzy match 90% to not send the same results repeatedly
|
|
350
|
+
if self.last_lens_result:
|
|
351
|
+
score = fuzz.ratio(text_str, self.last_lens_result)
|
|
352
|
+
if score >= 80:
|
|
353
|
+
logger.info("Google Lens results are similar to the last results (score: %d). Skipping overlay update.", score)
|
|
354
|
+
return
|
|
355
|
+
self.last_lens_result = text_str
|
|
321
356
|
|
|
322
|
-
if not
|
|
357
|
+
if not success or not coords:
|
|
323
358
|
return
|
|
324
359
|
|
|
325
360
|
# 5. Process the high-accuracy results into the desired format
|
|
@@ -433,6 +468,38 @@ class OverlayProcessor:
|
|
|
433
468
|
"x3": center_x + half_w, "y3": center_y + half_h,
|
|
434
469
|
"x4": center_x - half_w, "y4": center_y + half_h,
|
|
435
470
|
}
|
|
471
|
+
|
|
472
|
+
def _convert_oneocr_results_to_percentages(
|
|
473
|
+
self,
|
|
474
|
+
oneocr_results: List[Dict[str, Any]],
|
|
475
|
+
monitor_width: int,
|
|
476
|
+
monitor_height: int
|
|
477
|
+
) -> List[Dict[str, Any]]:
|
|
478
|
+
"""
|
|
479
|
+
Converts OneOCR results with pixel coordinates to percentages relative to the monitor size.
|
|
480
|
+
"""
|
|
481
|
+
converted_results = []
|
|
482
|
+
for item in oneocr_results:
|
|
483
|
+
bbox = item.get("bounding_rect", {})
|
|
484
|
+
if not bbox:
|
|
485
|
+
continue
|
|
486
|
+
# Convert each coordinate to a percentage of the monitor dimensions
|
|
487
|
+
converted_bbox = {
|
|
488
|
+
key: (value / monitor_width if "x" in key else value / monitor_height)
|
|
489
|
+
for key, value in bbox.items()
|
|
490
|
+
}
|
|
491
|
+
converted_item = item.copy()
|
|
492
|
+
converted_item["bounding_rect"] = converted_bbox
|
|
493
|
+
converted_results.append(converted_item)
|
|
494
|
+
for word in converted_item.get("words", []):
|
|
495
|
+
word_bbox = word.get("bounding_rect", {})
|
|
496
|
+
if word_bbox:
|
|
497
|
+
word["bounding_rect"] = {
|
|
498
|
+
key: (value / monitor_width if "x" in key else value / monitor_height)
|
|
499
|
+
for key, value in word_bbox.items()
|
|
500
|
+
}
|
|
501
|
+
# logger.info(f"Converted OneOCR results to percentages: {converted_results}")
|
|
502
|
+
return converted_results
|
|
436
503
|
|
|
437
504
|
async def main_test_screenshot():
|
|
438
505
|
"""
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/database_api.py
RENAMED
|
@@ -335,8 +335,8 @@ def register_database_api_routes(app):
|
|
|
335
335
|
if afk_timer is not None:
|
|
336
336
|
try:
|
|
337
337
|
afk_timer = int(afk_timer)
|
|
338
|
-
if afk_timer <
|
|
339
|
-
return jsonify({'error': 'AFK timer must be between
|
|
338
|
+
if afk_timer < 0 or afk_timer > 600:
|
|
339
|
+
return jsonify({'error': 'AFK timer must be between 0 and 600 seconds'}), 400
|
|
340
340
|
settings_to_update['afk_timer_seconds'] = afk_timer
|
|
341
341
|
except (ValueError, TypeError):
|
|
342
342
|
return jsonify({'error': 'AFK timer must be a valid integer'}), 400
|
|
@@ -344,8 +344,8 @@ def register_database_api_routes(app):
|
|
|
344
344
|
if session_gap is not None:
|
|
345
345
|
try:
|
|
346
346
|
session_gap = int(session_gap)
|
|
347
|
-
if session_gap <
|
|
348
|
-
return jsonify({'error': 'Session gap must be between
|
|
347
|
+
if session_gap < 0 or session_gap > 7200:
|
|
348
|
+
return jsonify({'error': 'Session gap must be between 0 and 7200 seconds (0 to 2 hours)'}), 400
|
|
349
349
|
settings_to_update['session_gap_seconds'] = session_gap
|
|
350
350
|
except (ValueError, TypeError):
|
|
351
351
|
return jsonify({'error': 'Session gap must be a valid integer'}), 400
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/shared.js
RENAMED
|
@@ -392,8 +392,8 @@ class SettingsManager {
|
|
|
392
392
|
|
|
393
393
|
if (this.afkTimerInput) {
|
|
394
394
|
const afkTimer = parseInt(this.afkTimerInput.value);
|
|
395
|
-
if (isNaN(afkTimer) || afkTimer <
|
|
396
|
-
this.showError('AFK timer must be between
|
|
395
|
+
if (isNaN(afkTimer) || afkTimer < 0 || afkTimer > 600) {
|
|
396
|
+
this.showError('AFK timer must be between 0 and 600 seconds');
|
|
397
397
|
return;
|
|
398
398
|
}
|
|
399
399
|
settings.afk_timer_seconds = afkTimer;
|
|
@@ -401,8 +401,8 @@ class SettingsManager {
|
|
|
401
401
|
|
|
402
402
|
if (this.sessionGapInput) {
|
|
403
403
|
const sessionGap = parseInt(this.sessionGapInput.value);
|
|
404
|
-
if (isNaN(sessionGap) || sessionGap <
|
|
405
|
-
this.showError('Session gap must be between
|
|
404
|
+
if (isNaN(sessionGap) || sessionGap < 0 || sessionGap > 7200) {
|
|
405
|
+
this.showError('Session gap must be between 0 and 7200 seconds (0 to 2 hours)');
|
|
406
406
|
return;
|
|
407
407
|
}
|
|
408
408
|
settings.session_gap_seconds = sessionGap;
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "GameSentenceMiner"
|
|
10
|
-
version = "2.
|
|
10
|
+
version = "2.17.0"
|
|
11
11
|
description = "A tool for mining sentences from games. Update: Overlay?"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
@@ -57,7 +57,7 @@ dependencies = [
|
|
|
57
57
|
"obsws-python~=1.7.2",
|
|
58
58
|
"numpy==2.2.6",
|
|
59
59
|
"regex",
|
|
60
|
-
"faster-whisper~=1.2.0"
|
|
60
|
+
"faster-whisper~=1.2.0",
|
|
61
61
|
]
|
|
62
62
|
|
|
63
63
|
# This creates a command-line script named `gamesentenceminer` that will
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -417,10 +417,10 @@ class ConfigApp:
|
|
|
417
417
|
self.create_screenshot_tab()
|
|
418
418
|
self.create_audio_tab()
|
|
419
419
|
self.create_obs_tab()
|
|
420
|
-
self.create_profiles_tab()
|
|
421
420
|
self.create_ai_tab()
|
|
422
421
|
self.create_advanced_tab()
|
|
423
422
|
self.create_overlay_tab()
|
|
423
|
+
self.create_profiles_tab()
|
|
424
424
|
# self.create_wip_tab()
|
|
425
425
|
|
|
426
426
|
def add_reset_button(self, frame, category, row, column=0, recreate_tab=None):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/gsm_ocr_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/ocr/owocr_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/__init__.py
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/__main__.py
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/owocr/owocr/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/tools/ss_selector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/communication/send.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/downloader/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/electron_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/notification.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/win10toast/__init__.py
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/util/win10toast/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/gsm_websocket.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/search.css
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/shared.css
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/css/stats.css
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/favicon.ico
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/favicon.svg
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/anki_stats.js
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/database.js
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/kanji-grid.js
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/search.js
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/js/stats.js
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/site.webmanifest
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/static/style.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/database.html
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/index.html
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/search.html
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/stats.html
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/templates/utility.html
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner/web/texthooking_page.py
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/requires.txt
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12 → gamesentenceminer-2.17.0}/GameSentenceMiner.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|